經典的MySQL Duplicate entry報錯注入


SQL注射取數據的方式有多種:

  1. 利用union select查詢直接在頁面上返回數據,這種最為常見,一個前提是攻擊者能夠構造閉合的查詢。
  2.  Oracle中利用監聽UTL_HTTP.request發起的HTTP請求,把QuerySet反彈回攻擊者的主機。當然,HTTP服務器對URL的長度有一定限制,因此每次可返回的數據量不可過多。
  3.  基於錯誤消息取數據,前提是頁面能夠響應詳細的錯誤描述。它的一個優點是,我們可能不必太費力去猜測和閉合SQL(可以構造子查詢,讓MySQL在子查詢中報錯)。
  4.  盲注,頁面不會顯示錯誤消息。常見基於布爾的盲注、基於時間的盲注,此類注射點利用價值相對要低一點,猜解數據的時間較長。

本篇簡單說明非常經典的基於錯誤回顯的MySQL注射。最重要的,就是理解下面的SQL查詢:

select count(*),floor(rand(0)*2)x from information_schema.character_sets group by x;

上面的這條SQL將報錯: Duplicate entry ‘1’ for key ‘group_key’

如下圖

mysql_error_1

1. 為什么MySQL注射要用information_schema庫?

答案是這個庫是MySQL自帶的,安裝之后就創建好了,所有賬號都有權限訪問。攻擊者無需猜解庫名、表名。跟Oracle注射使用dual類似。

2. 如何利用報錯取數據?

利用報錯,攻擊者把目標數據concat連接到floor()函數的前后即可。

例如,下面的語句用於獲取MySQL Server版本,構造:

mysql> select count(*),concat( floor(rand(0)*2), 0x5e5e5e, version(), 0x5e5e5e) x from information_schema.character_sets
group by x;
ERROR 1062 (23000): Duplicate entry ‘1^^^5.5.28^^^’ for key ‘group_key’

通過報錯,即可知道當前數據庫是5.5.28。0x5e5e5e是3個尖括號的16進制表示。 自動化SQL注射工具通常會在目標數據前后做類似的標記,方便程序提取。

加上標記,也可以方便攻擊者在大的頁面中搜索。

3. 為何這條語句會報錯?

rand(0)是把0作為生成隨機數的種子。首先明確一點,無論查詢多少次,無論在哪台MySQL Server上查詢,連續rand(0)生成的序列是固定的。

 

 

應用floor函數(取浮點數的整數部分)后,結果變成了:

 

 

可以看到,第二行和第三行的值都是1。這也是最終引起MySQL報錯Duplicate entry的地方。

實際上,我們分開執行下面的兩種查詢,都是不會出錯的:

a) select floor(rand(0)*2) x from information_schema.character_sets group by x;

上面的查詢根據x列的值進行分組,得到:

 

 

b) select count(*), floor(rand(0)*2) x from information_schema.character_sets;

得到information_schema.character_sets總共有39行:

 

 

請注意,這里x的值出現的是0。

c) 將上述語句結合后即報錯

select count(*), floor(rand(0)*2) x from information_schema.character_sets group by x;

我們預期的結果, 其實是:

 

 

然而MySQL在內部處理中間結果的時候,出現了意外,導致報錯。

參考鏈接: SQL Injection attack – What does this do?


免責聲明!

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



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