CTF解题笔记

只能说坑。。。

要不是看了大神的write up 我觉得不会想到。。。


http://blog.csdn.net/qq_34841823/article/details/54287419


1.因缺思汀的绕过

解题路径:http://ctf5.shiyanbar.com/web/pcat/index.php

打开后是一个登录框类似的东西,查看页面源码可以看到有source:source.txt的字样


打开连接:http://ctf5.shiyanbar.com/web/pcat/source.txt

可以看到登录的PHP逻辑:

[php]  view plain  copy
 
  1. "font-size:18px;">
  2. error_reporting(0);  
  3.   
  4. if (!isset($_POST['uname']) || !isset($_POST['pwd'])) {  
  5.     echo ''."
    "
    ;  
  6.     echo ''."
    "
    ;  
  7.     echo ''."
    "
    ;  
  8.     echo ''."
    "
    ;  
  9.     echo ''."
    "
    ;  
  10.     echo ''."
    "
    ;  
  11.     die;  
  12. }  
  13.   
  14. function AttackFilter($StrKey,$StrValue,$ArrReq){    
  15.     if (is_array($StrValue)){  
  16.         $StrValue=implode($StrValue);  
  17.     }  
  18.     if (preg_match("/".$ArrReq."/is",$StrValue)==1){     
  19.         print "姘村彲杞借垷锛屼害鍙禌鑹囷紒";  
  20.         exit();  
  21.     }  
  22. }  
  23.   
  24. $filter = "and|select|from|where|union|join|sleep|benchmark|,||";  
  25. foreach($_POST as $key=>$value){   
  26.     AttackFilter($key,$value,$filter);  
  27. }  
  28.   
  29. $con = mysql_connect("XXXXXX","XXXXXX","XXXXXX");  
  30. if (!$con){  
  31.     die('Could not connect: ' . mysql_error());  
  32. }  
  33. $db="XXXXXX";  
  34. mysql_select_db($db$con);  
  35. $sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";  
  36. $query = mysql_query($sql);   
  37. if (mysql_num_rows($query) == 1) {   
  38.     $key = mysql_fetch_array($query);  
  39.     if($key['pwd'] == $_POST['pwd']) {  
  40.         print "CTF{XXXXXX}";  
  41.     }else{  
  42.         print "浜﹀彲璧涜墖锛�";  
  43.     }  
  44. }else{  
  45.     print "涓€棰楄禌鑹囷紒";  
  46. }  
  47. mysql_close($con);  
  48. ?>  

可以看到,这里面有SQL的一个过滤器,把一些sql的关键字例如benchmark,join等都过滤了

而且sql查询语句是:

[php]  view plain  copy
 
  1. "font-size:18px;">SELECT * FROM interest WHERE uname = '{$_POST['uname']}  
  2.   
又由:
[php]  view plain  copy
 
  1. "font-size:18px;">mysql_num_rows($query) == 1  
这个判断可以得知数据库中的记录就只有一条,这部分逻辑大概就是然后通过提交的uname查询出结果,如果结果只有一条则继续,如果查询结果中的pwd字段和post过去的key值相同,则给出flag。
这时就要用到注入的一个小技巧,我们使用group by pwd with rollup 来在查询结果后加一行,并且这一行pwd字段的值为NULL
在mysql官方文档中是这样描述rollup函数的:
CTF解题笔记_第1张图片
CTF解题笔记_第2张图片
大概的意思就是在GROUP BY子句中使用WITH ROLLUP会在数据库中加入一行用来计算总数,ROLLUP子句的更加详细的用法,可以参考mysql的官方文档,此处就不多做赘述了。
再结合limit和offset就可以写出一个payload
即:输入的用户名为:' or 1=1 group by pwd with rollup limit 1 offset 2 #
这里解释一下此时执行的SQL:
SELECT * FROM interest where uname=' ' or 1=1 
group by pwd with rollup  (在数据库中添加一行使得pwd=NULL)
limit 1 (只查询一行)
offset 2  (从第二行开始查询)
#注释
此时密码只要为空即可查询成功
CTF解题笔记_第3张图片



2.登陆一下好吗??
解题路径:http://ctf5.shiyanbar.com/web/wonderkun/web/index.html
题目说这个过滤了很多敏感符号,于是先构造一下常用的payload:' or 1=1 #
CTF解题笔记_第4张图片
发现or 和 #都被过滤掉了,通过测试发现--也被过滤了,看起来是很吓人,但是不过幸好'没有被过滤,于是构造payload:
username = travis'='
password=travis'='
CTF解题笔记_第5张图片
这个时候成果获得flag
为什么这样可以绕过呢?
当提交username=travis'='&password=travis'='
语句会变成如下:
select * from user where username='travis'='' and password='travis'=''
这时候还不够清晰,我提取前一段判断出来(后面的同样道理)
username='travis'=''
这是有2个等号,然后计算顺序从左到右,
先计算username='travis' 一般数据库里不可能有我这个小名(若有,你就换一个字符串),所以这里返回值为0(相当于false)
然后0='' 这个结果呢?看到这里估计你也懂了,就是返回1(相当于true)

所以这样的注入相当于
select * from user where 1 and 1
也等于 select * from user
(这题只有筛选出来的结果有3个以上才会显示flag,没有就一直说“对不起,没有此用户!!”)

面那个比较是弱类型的比较,
以下情况都会为true
1='1'
1='1.0'
1='1后接字母(再后面有数字也可以)'
0='除了非0数字开头的字符串'
(总体上只要前面达成0的话,要使语句为true很简单,所以这题的万能密码只要按照我上面的法子去写一大把)


你可能感兴趣的:(ctf)