天天看點

Web Hacking 101 中文版 十一、SQL 注入十一、SQL 注入

十一、SQL 注入

作者:Peter Yaworski

譯者:

飛龍 協定: CC BY-NC-SA 4.0

描述

SQL 注入,或者 SQLi 允許黑客将 SQL 語句注入到目标中并通路它們的資料庫。它的潛力是無窮的,通常使其成為高回報的漏洞,例如,攻擊者能夠執行所有或一些 CURD 操作(建立、讀取、更新、删除)來擷取資料庫資訊。攻擊者甚至能夠完成遠端指令執行。

SQLi 攻擊通常是未轉義輸入的結果,輸入被傳給站點,并用作資料庫查詢的一部分。它的一個例子是:

$name = $_GET['name']; 
$query = "SELECT * FROM users WHERE name = $name";           

這裡,來自使用者輸入的傳入值直接被插入到了資料庫查詢中。如果使用者輸入了

test' or 1=1

,查詢就會傳回第一條記錄,其中

name = test or 1=1

,是以為第一行。現在在其他情況下,你可能會得到:

$query = "SELECT * FROM users WHERE (name = $name AND password = 12345");           

這裡,如果你使用了相同的載荷,你的語句最後會變成:

$query = "SELECT * FROM users WHERE (name = 'test' OR 1=1 AND password = 12345");           

是以這裡,查詢會表現得有些不同(至少是 MySQL)。我們會擷取所有記錄,其中名稱是

test

,或者密碼是

12345

。很顯然我們沒有完成搜尋資料庫第一條記錄的目标。是以,我們需要忽略密碼參數,并能夠使用注釋來實作,

test' or 1=1;--

。這裡,我們所做的事情,就是添加一個分号來合理結束 SQL 語句,并且立即添加兩個短橫線(和一個空格)來把後面的所有東西标記為注釋。是以不會被求職。它的結果會和我們初始的例子一樣。

示例

1. Drupal SQL 注入

難度:中

URL:任意版本小于 7.32 的 Drupal 站點

報告連結;

https://hackerone.com/reports/31756

報告日期:2014.10.17

獎金:$3000

描述:

Drupal 是一個流行的内容管理系統,用于建構網站,非常相思雨 WordPress 和 Joomla。它以 PHP 編寫,并且基于子產品,意思是新的功能可以通過安裝子產品來添加到 Drupal 站點中。Drupal 社群已經編寫了上千個,并且使他們可免費擷取。其中的例子包括電子商務,三方繼承,内容産品,以及其他。但是,每個 Drupal 的安裝都包含想用的核心子產品系列,用于運作平台,并且需要資料庫的連結。這些通常都以 Drupal 核心來指代。

在 2014 年,Drupal 安全小組為 Drupal 核心釋出了一個緊急安全更新,表明所有 Drupal 站點都存在 SQL 注入漏洞,它能夠由匿名使用者來完成。這一漏洞允許攻擊者控制任意沒有更新的 Drupal 站點。

對于漏洞來說, Stefan Horst 發現了 Drupal 開發者不當實作了資料庫查詢的包裝功能,它能夠被攻擊者濫用。更具體來說,Drupal 使用 PHP 資料對象(PDO)作為結構用于通路資料庫。Drupal 核心的開發者編寫了代碼來調用這些 PDO 函數,并且在其他開發者編寫代碼來和 Drupal 資料庫互動的任何時候,這些代碼都可以使用。這在軟體開發中是個最佳時間。它的原因是為了讓 Drupal 能夠用于不同類型的資料庫(MySQL、Postgres,一起其它),移除複雜性并提供标準化。

現在結果是,Stefan 發現了 Drupal 包裝器代碼對傳給 SQL 查詢的數組資料做了一個錯誤的假設。這裡是原始代碼:

foreach ($data as $i => $value) { 
    [...] 
    $new_keys[$key . '_' . $i] = $value; 
}           

你能夠之處錯誤(我都不能)嘛?開發者的假設為,數組資料始終含有數字鍵,例如

0, 1, 2

以及其他(

$i

的值)。并且是以它們将

$key

變量連接配接到

$i

,并且使其等于

value

。這裡是來自 Drupal 的

db_query

函數,通常的查詢的樣子。

db_query("SELECT * FROM {users} WHERE name IN (:name)", array(':name'=>array('user1','user2')));           

這裡,

db_query

函數接受資料庫查詢

SELECT * FROM {users} WHERE name IN (:name)

,以及值的數組來替換查詢中的占位符。在 PHP 中,當你将數組聲明為

array('value','value2',value3')

,它實際上建立了

[0 =>'value',1=>'value2',2=>'value3']

,其中每個值都可以通過數字鍵來通路。是以這裡,

:name

變量被數組中的值替換。你從中擷取到的東西是:

SELECT * FROM users WHERE name IN (:name_0, :name_1)           

到目前為止很好。當你擷取不含有數字鍵的數組時,問題就來了,像這樣:

db_query("SELECT * FROM {users} where name IN (:name)", 
array(':name'=>array('test) -- ' => 'user1','test' => 'user2')));           

:name

是個數組,它的鍵是

'test) –', 'test'

。你可以看到為什麼嘛?當 Drupal 收到它并且處理數組來建立查詢時,我們會得到:

SELECT * FROM users WHERE name IN (:name_test) -- , :name_test)           

看出這是為什麼可能需要一些技巧,是以讓我們過一遍它。基于上面描述的

foreach

,Drupal 會周遊數組中的每個元素。是以,對于第一個疊代

$i = test) –

以及

$value = user1

。現在,

$key

是查詢中的

(:name)

,并且和

$i

組合之後,我們得到了

name_test) –

。對于第二個疊代,

$i = test

并且

$value = user2

,是以組合

$key

$i

之後,我們得到了

name_test

,結果是個

:name_test

的占位符,它等于

user2

現在,知道這些之後,Drupal 包裝 PHP PDO 對象的事實就登場了,因為 PDO 允許多重查詢。是以,攻擊者能夠傳遞惡意輸入,例如實際的 SQL 查詢來為任何的數組鍵建立管理者使用者,它作為多重查詢解釋和執行。

重要結論

SQLi 似乎更難于發現,至少基于為了這本書搜尋的報告。這個例子很有意思,因為它并不是送出單引号和截斷查詢。反之,它全部關于 Drupal 的代碼如何處理傳給内部函數的數組。這并不易于通過黑盒測試發現(其中你并不接觸任何代碼)。這裡的重要結論是,尋找機會來修改傳給站點的輸入格式,是以在 URL 接受

?name

作為參數的地方,嘗試傳入類似

?name[]

的數組,來觀察站點如何處理。它也可能不會造成 SQLi,但是可能會導緻其他有趣的行為。

總結

SQLi 對站點來說十分重要和危險。尋找這一類型的漏洞可能導緻站點的完整的 CURD 權限。在其他情況下,它可能擴充為遠端代碼執行。Drupal 的例子實際上是這些例子之一,它們證明了攻擊者可以通過漏洞來執行代碼。在尋找它們的時候,不要僅僅留意向查詢傳遞未轉義單引号和雙引号的可能性,也要注意以非預期方式提供資料的可能性,例如在 POST 資料中送出數組參數。