十一、SQL 注入
作者:Peter Yaworski
譯者:飛龍
協(xié)議:CC BY-NC-SA 4.0
描述
SQL 注入声滥,或者 SQLi 允許黑客將 SQL 語句注入到目標(biāo)中并訪問它們的數(shù)據(jù)庫。它的潛力是無窮的确徙,通常使其成為高回報的漏洞,例如鄙皇,攻擊者能夠執(zhí)行所有或一些 CURD 操作(創(chuàng)建、讀取仰挣、更新伴逸、刪除)來獲取數(shù)據(jù)庫信息。攻擊者甚至能夠完成遠(yuǎn)程命令執(zhí)行膘壶。
SQLi 攻擊通常是未轉(zhuǎn)義輸入的結(jié)果错蝴,輸入被傳給站點,并用作數(shù)據(jù)庫查詢的一部分颓芭。它的一個例子是:
$name = $_GET['name'];
$query = "SELECT * FROM users WHERE name = $name";
這里顷锰,來自用戶輸入的傳入值直接被插入到了數(shù)據(jù)庫查詢中。如果用戶輸入了test' or 1=1
亡问,查詢就會返回第一條記錄官紫,其中name = test or 1=1
,所以為第一行≈菖海現(xiàn)在在其他情況下束世,你可能會得到:
$query = "SELECT * FROM users WHERE (name = $name AND password = 12345");
這里,如果你使用了相同的載荷床玻,你的語句最后會變成:
$query = "SELECT * FROM users WHERE (name = 'test' OR 1=1 AND password = 12345");
所以這里毁涉,查詢會表現(xiàn)得有些不同(至少是 MySQL)。我們會獲取所有記錄锈死,其中名稱是test
贫堰,或者密碼是12345
穆壕。很顯然我們沒有完成搜索數(shù)據(jù)庫第一條記錄的目標(biāo)。因此其屏,我們需要忽略密碼參數(shù)粱檀,并能夠使用注釋來實現(xiàn),test' or 1=1;--
漫玄。這里茄蚯,我們所做的事情,就是添加一個分號來合理結(jié)束 SQL 語句睦优,并且立即添加兩個短橫線(和一個空格)來把后面的所有東西標(biāo)記為注釋渗常。因此不會被求職。它的結(jié)果會和我們初始的例子一樣汗盘。
示例
1. Drupal SQL 注入
難度:中
URL:任意版本小于 7.32 的 Drupal 站點
報告鏈接皱碘;https://hackerone.com/reports/31756
報告日期:2014.10.17
獎金:$3000
描述:
Drupal 是一個流行的內(nèi)容管理系統(tǒng),用于構(gòu)建網(wǎng)站隐孽,非常相思雨 WordPress 和 Joomla癌椿。它以 PHP 編寫,并且基于模塊菱阵,意思是新的功能可以通過安裝模塊來添加到 Drupal 站點中踢俄。Drupal 社區(qū)已經(jīng)編寫了上千個,并且使他們可免費獲取晴及。其中的例子包括電子商務(wù)都办,三方繼承,內(nèi)容產(chǎn)品虑稼,以及其他琳钉。但是,每個 Drupal 的安裝都包含想用的核心模塊系列蛛倦,用于運行平臺歌懒,并且需要數(shù)據(jù)庫的鏈接。這些通常都以 Drupal 核心來指代溯壶。
在 2014 年及皂,Drupal 安全小組為 Drupal 核心發(fā)布了一個緊急安全更新,表明所有 Drupal 站點都存在 SQL 注入漏洞茸塞,它能夠由匿名用戶來完成躲庄。這一漏洞允許攻擊者控制任意沒有更新的 Drupal 站點。
對于漏洞來說钾虐, Stefan Horst 發(fā)現(xiàn)了 Drupal 開發(fā)者不當(dāng)實現(xiàn)了數(shù)據(jù)庫查詢的包裝功能噪窘,它能夠被攻擊者濫用。更具體來說,Drupal 使用 PHP 數(shù)據(jù)對象(PDO)作為結(jié)構(gòu)用于訪問數(shù)據(jù)庫倔监。Drupal 核心的開發(fā)者編寫了代碼來調(diào)用這些 PDO 函數(shù)直砂,并且在其他開發(fā)者編寫代碼來和 Drupal 數(shù)據(jù)庫交互的任何時候,這些代碼都可以使用浩习。這在軟件開發(fā)中是個最佳時間静暂。它的原因是為了讓 Drupal 能夠用于不同類型的數(shù)據(jù)庫(MySQL、Postgres谱秽,一起其它)洽蛀,移除復(fù)雜性并提供標(biāo)準(zhǔn)化。
現(xiàn)在結(jié)果是疟赊,Stefan 發(fā)現(xiàn)了 Drupal 包裝器代碼對傳給 SQL 查詢的數(shù)組數(shù)據(jù)做了一個錯誤的假設(shè)郊供。這里是原始代碼:
foreach ($data as $i => $value) {
[...]
$new_keys[$key . '_' . $i] = $value;
}
你能夠之處錯誤(我都不能)嘛?開發(fā)者的假設(shè)為近哟,數(shù)組數(shù)據(jù)始終含有數(shù)字鍵驮审,例如0, 1, 2
以及其他($i
的值)。并且所以它們將$key
變量連接到$i
吉执,并且使其等于value
疯淫。這里是來自 Drupal 的db_query
函數(shù),通常的查詢的樣子戳玫。
db_query("SELECT * FROM {users} WHERE name IN (:name)", array(':name'=>array('user1','user2')));
這里熙掺,db_query
函數(shù)接受數(shù)據(jù)庫查詢SELECT * FROM {users} WHERE name IN (:name)
,以及值的數(shù)組來替換查詢中的占位符量九。在 PHP 中适掰,當(dāng)你將數(shù)組聲明為array('value','value2',value3')
,它實際上創(chuàng)建了[0 =>'value',1=>'value2',2=>'value3']
荠列,其中每個值都可以通過數(shù)字鍵來訪問。所以這里载城,:name
變量被數(shù)組中的值替換肌似。你從中獲取到的東西是:
SELECT * FROM users WHERE name IN (:name_0, :name_1)
到目前為止很好。當(dāng)你獲取不含有數(shù)字鍵的數(shù)組時诉瓦,問題就來了川队,像這樣:
db_query("SELECT * FROM {users} where name IN (:name)",
array(':name'=>array('test) -- ' => 'user1','test' => 'user2')));
這里,:name
是個數(shù)組睬澡,它的鍵是'test) –', 'test'
固额。你可以看到為什么嘛?當(dāng) Drupal 收到它并且處理數(shù)組來創(chuàng)建查詢時煞聪,我們會得到:
SELECT * FROM users WHERE name IN (:name_test) -- , :name_test)
看出這是為什么可能需要一些技巧斗躏,所以讓我們過一遍它∥舾基于上面描述的foreach
啄糙,Drupal 會遍歷數(shù)組中的每個元素笛臣。所以,對于第一個迭代$i = test) –
以及$value = user1
∷肀現(xiàn)在沈堡,$key
是查詢中的(:name)
,并且和$i
組合之后燕雁,我們得到了name_test) –
诞丽。對于第二個迭代,$i = test
并且$value = user2
拐格,所以組合$key
和$i
之后僧免,我們得到了name_test
,結(jié)果是個:name_test
的占位符禁荒,它等于user2
猬膨。
現(xiàn)在,知道這些之后呛伴,Drupal 包裝 PHP PDO 對象的事實就登場了勃痴,因為 PDO 允許多重查詢。所以热康,攻擊者能夠傳遞惡意輸入沛申,例如實際的 SQL 查詢來為任何的數(shù)組鍵創(chuàng)建管理員用戶,它作為多重查詢解釋和執(zhí)行姐军。
重要結(jié)論
SQLi 似乎更難于發(fā)現(xiàn)铁材,至少基于為了這本書搜索的報告。這個例子很有意思奕锌,因為它并不是提交單引號和截斷查詢著觉。反之,它全部關(guān)于 Drupal 的代碼如何處理傳給內(nèi)部函數(shù)的數(shù)組惊暴。這并不易于通過黑盒測試發(fā)現(xiàn)(其中你并不接觸任何代碼)饼丘。這里的重要結(jié)論是,尋找機(jī)會來修改傳給站點的輸入格式辽话,所以在 URL 接受
?name
作為參數(shù)的地方肄鸽,嘗試傳入類似?name[]
的數(shù)組,來觀察站點如何處理油啤。它也可能不會造成 SQLi典徘,但是可能會導(dǎo)致其他有趣的行為。
總結(jié)
SQLi 對站點來說十分重要和危險益咬。尋找這一類型的漏洞可能導(dǎo)致站點的完整的 CURD 權(quán)限逮诲。在其他情況下,它可能擴(kuò)展為遠(yuǎn)程代碼執(zhí)行。Drupal 的例子實際上是這些例子之一汛骂,它們證明了攻擊者可以通過漏洞來執(zhí)行代碼罕模。在尋找它們的時候,不要僅僅留意向查詢傳遞未轉(zhuǎn)義單引號和雙引號的可能性帘瞭,也要注意以非預(yù)期方式提供數(shù)據(jù)的可能性淑掌,例如在 POST 數(shù)據(jù)中提交數(shù)組參數(shù)。