文件上传漏洞(一)

文件上传漏洞

概念

是什么?

由于开发人员未对上传的文件进行严格的验证和过滤,导致用户可以上传一些不合法的文件到服务器中,危害服务器安全。


后果?

用户可以上传非法文件,控制整个网站甚至整个服务器。


文件上传过程

客户端发送文件->服务器接受文件->判断文件是否合法->临时文件->移动到指定目录。


php文件上传

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
40
41
42
<?php
/*
文件上传代码
文件上传时会返回一些代码 返回客户端 客户端根据这些值判断上传是否正常
0; 没有错误发生,文件上传成功。
1; 上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值。
2; 上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。
3; 文件只有部分被上传。
4; 没有文件被上传。
*/// 判断返回的状态码是否大于0
if ($_POST["sub"]) {
if ($_FILES["file"]["error"] > 0) {
echo "Error:" . $_FILES["file"]["error"] . "<br/>";
} else {
$uplaod_path = '../upload' . '/' . $_FILES["file"]["name"];
$tmp_file = $_FILES["file"]["tmp_name"];
// 输出文件名
echo "Upload:" . $_FILES["file"]["name"] . "<br/>";
// 输出文件类型
echo "Type:" . $_FILES["file"]["type"] . "<br/>";
// 输出文件大小
echo "Size:" . ($_FILES["file"]["size"] / 1024) . "Kb<br/>";
// 输出临时储存的位置
echo "Stored in:" . $_FILES["file"]["tmp_name"] . "<br/>";
// 移动到指定目录
move_uploaded_file($tmp_file, $uplaod_path);
}
}

?>
<!DOCTYPE html>
<html>
<head></head>
<body>
<form action="#" method="post" enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="sub" value="Submit" />
</form>
</body>
</html>

修复意见

在网站中需要存在上传模块,需要做好权限认证,不能让匿名用户可访问。

文件上传目录设置为禁止脚本文件执行。这样设置即使被上传后门的动态脚本也不能解析,导致攻击者放弃这个攻击途径。

设置上传白名单,白名单只允许图片上传如,jpg,png,gif 其他文件均不允许上传

上传的后缀名,一定要设置成图片格式如 jpg,png,gif


绕过、攻击方法

寻找文件上传

文件上传常见在头像,文件编辑器,上传图片,上传媒体等。

常见可执行文件后缀名

asp,asa,cdx,cer,php,aspx,ashx,jsp,php3,php.a,shtml,phtml

例如,(任意文件上传)

页面没有任何过滤与检验,可以上传任意文件,且上传目录支持解析可执行文件,危害性及大


文件上传绕过js

有些网站在用户提交时会用JS来判断用户上传的格式是否正确,JS验证是不会提交数据包到服务器的,所以可以通过浏览器F12查看网络是否有数据来判断是不是在前端的验证。

image-20220826115343339

绕过方法:

方法一:直接把验证文件的JS代码删除或者关闭JS。

方法二:将文件改为合法后缀名后抓包再改为可执行文件。

直接关JS,我这里利用火狐浏览器插件Disable JavaScript


文件上传绕过content-Type

有时候服务器会通过检测content-type类型来判断文件是否合法,而content-type类型是可以通过抓包的方式修改的,抓包后吧content-type修改为合法类型即可以绕过。

方法:
方法一:上传可执行文件,然后抓包通过修改content-type为合法文件类型进行绕过。

方法二:上传合法文件,然后抓包通过修改文件名后缀进行绕过。

两个方法其实是一样的,结果都是文件为可执行文件,content-type类型为合法文件,主要在于content-type类型为合法类型来绕过验证。

文件上传绕过黑名单

有时候会在文件上传的地方做黑名单进行限制,如果发现用户上传的文件名后缀在黑名单中则禁止上传

绕过方法:

不使用黑名单中的后缀名

image-20220826174824366

可以看出黑名单中有.asp,.aspx,.php,.jsp,这时如果服务器中间件为iis,我们可以上传.asa .cer .cdx后缀文件,如果网站中允许.net执行,可以上传ashx代替aspx,当然前提得是服务器会解析执行这些脚本,并且不同中间件有不同的特性

在apache中,如果在AddType application/x-httpd-php .php .phtml .php3开启了application/x-httpd-php(有的版本默认开启),那么.phtml .php3就会被解析成PHP文件。


文件上传.htaccess重写绕过

什么是.htaccess文件?:

​ .htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过.htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。
​ 有时服务器通过黑名单限制了我们所有可以上传的可执行文件名后缀,但是服务器开启了重写并且允许上传.htaccess文件,我们就可以通过该文件借助绕过。

image-20220826180930382

同样是黑名单并且包括了所有的可执行文件后缀名,但是没有.htaccess

我们可以先上传.htaccess文件内容:

1
2
3
4
<IfModule mime_module>
SetHandler application/x-httpd-php # 在当前目录下,所有文件都会被解析成PHP。
# AddType application/x-httpd-php .jpg 在当前目录下,所有jpg文件都会被解析成PHP。
</IfModule>

或者:

1
2
3
<FilesMatch "phpinfo.jpg">
SetHandler application/x-httpd-php # 在当前目录下,如果匹配到`phpinfo.jpg`文件,则当做PHP代码执行。
</FilesMatch>

建议使用第二种,第一种会误伤其他文件,我们先把写好的.htaccess文件上传进去(前面的点一定要带上)


文件上传大小写绕过

有时候服务器采用黑名单进行验证,但是并没有对大小写进行严格的限制,我们对后缀名进行大小写即可成功绕过


文件上传空格绕过

有时候文件上传采用黑名单,但是没有去掉空格,我们上传时抓包,在文件名后缀后加一个空格即可绕过


文件上传利用windows特性绕过

在Windows中,phpinfo.php.后缀名后面的.系统会自动忽略,所以如果对方服务器为Windows,并且没有对最后的这个.进行过滤,那么我们就可以利用这个特性进行绕过。

img


文件上传利用NTFS交换数据流::$DATA

NTFS交换数据流(Alternate Data Streams,简称ADS),这是NTFS磁盘格式的特性之一。在Windows系统中,文件名+::DATA的格式会当成文件流处理,我们可以利用这个来绕过过滤。:

:$DATA:一个单引号时会上传文件但是没有内容。

image-20220830163146223

黑名单,删除了末尾的点,并且将后缀名转换为了小写并去空。

我们利用::$DATA来进行绕过,首先上传phpinfo.php并进行抓包:

image-20220830163647259

img


文件上传利用windows的叠加特征

在Windows环境下,上传文件名为phpinfo.php:.jpg时,会在目录下生成空白文件phpinfo.php。

再利用PHP和Windows环境的叠加属性:

在正则匹配时以下符号相等:

双引号”等于点.,

大于>等于问号?,

小于<等于星号*,

那么phpinfo.<等于phpinfo.*/ phpinfo.<<<等于phpinfo.*** / phpinfo.>>>等于phpinfo.???。
img

思路

我们可以先上传phpinfo.php:.jpg绕过过滤并在目录生成空白文件,然后再上传phpinfo.>>>来匹配并覆盖phpinfo.php

环境:upload-labs关卡:9

img

代码设置了黑名单并限制了所有能上传的可执行文件后缀,过滤了点大小写::$DATA和空格,我们上面的方法都不能用了,那么我们先上传phpinfo.php:.jpg

img

上传成功,我们进目录看一下:

img

可以看到生成了phpinfo.php并且里面没有任何内容,那么我们接着上传phpinfo.>>>:

img

上传成功,我们再去目录看一下:

img

可以看到里面已经有东西了,那是因为phpinfo.>>>匹配到了phpinfo.php并重新覆盖了。


文件上传双写绕过

有时候会将黑名单中的内容替换成空,但只替换了一次,我们就可以使用双写绕过。