注入攻擊是web安全領域中一種最為常見的攻擊方式。注入攻擊的本質,就是把用戶輸入的數據當做代碼執行。這里有兩個關鍵條件,第一是用戶能夠控制輸入,第二個就是原本程序要執行的代碼,將用戶輸入的數據進行了拼接,所以防御的思想就是基於上述兩個條件。
SQL注入第一次為公眾所知,是在1998年的著名黑客雜志<<Phrack>>上,一位名叫rfp的黑客發表了一片題為“NT Web Technolog Vulnerabities”的文章。
一個簡單的SQL注入的典型例子:
var username;
變量username為用戶所提交,正常情況下,假如用戶輸入“XiaoMing”,那么SQL語句會執行:
select * from UserTable where username='XiaoMing';
若用戶輸入一段有特別含義的SQL語句,比如:
XiaoMing' ;drop table UserTable--
那么SQL語句在實際執行時就會如下:
select * from UserTable where username='XiaoMing';drop table UserTable--'
現在變成了查詢后,再執行一個drop表的操作,而這個操作,使用戶構造了惡意數據的結果。
在SQL注入的過程中,如果網站的Web服務器開啟了消息回顯,則可以根據回顯的錯誤消息,探測網站用的是什么數據庫,例如:錯誤提示Microsoft.JET Database Engine錯誤,則說明是通過JET引擎連接數據庫,表明數據庫為ACESS數據庫,如果是ODBC的話,則說明是MSSQL數據庫。
數據庫的判斷方法有很多,這里大致說下我了解到的幾種方法思路,不詳細展開。
第一種基於特定函數:不同的數據庫對應着的函數名稱不一樣,如len()和length(),@@version()和version()在MSSQL,Mysql數據庫中不一樣,substring()和substr()在oracle和Mysql中不一樣
第二種基於輔助符號的判斷: “ / * ”是Mysql中的注釋符。 “ --”是Oracle和MSSQL支持的注釋符,";"子查詢標識符,Oracle不支持多行查詢。結合以上符合多種作何判斷。
第三種基於錯誤回顯信息判斷:針對數據庫引擎的判斷。
盲注(Blind Injection)
在沒有回顯消息的時候,可以進行SQL盲注,最常見的盲注驗證方法就是構造簡單的條件語句,根據返回頁面是否發生改變,來判斷SQL語句是否得到了執行。
1.簡單的 and 1=1 和 and 1=2
例如攻擊者構造如下條件的語句:
http://newspaper.com/items.php?id=2 and 1=2
SQL語句由於“1=2”是個假命題,所以攻擊者看到頁面將為空或者是一個出錯的頁面。
為了進一步確定注入是否存在,攻擊者必須再次驗證這個過程:
http://newspaper.com/items.php?id=2 and 1=1
如果這個請求頁面正常返回了,則說明SQL語句的"and"成功執行,那么就可以判斷“id”參數存在SQL注入漏洞了。
在這個攻擊過程中,服務器雖然關閉了錯誤回顯,但是通過攻擊者簡單的條件構造,再對比返回結果的差異,就可以判斷出SQL注入漏洞是否存在,這就是盲注的工作原理。
Timing Attack(邊信道攻擊)
在Mysql中,有一個benchmark()函數,用來測試函數性能的,benchmark(count,expr)函數的執行結果就是將expr表達式執行count次數。因此,利用這個函數,可以讓同一個函數執行若干次,使得結果返回時間比平時要長;通過時間長短的變化,可以判斷出注入語句是否執行成功。這是一種邊信道攻擊,這個技巧在盲注中稱為Timing Attack。
接下來我們使用這種技巧完成攻擊,先構造攻擊參數id值為:
2 UNION SELECT IF(SUBSTRING(current,1,1)=CHAR(119),BENCHMARK(5000000,ENCODE('MSG','by 5 seconds')),null)
這段Payload判斷數據庫名的第一個字母是否為小寫的w。如果判斷為真,則會通過BENCHMARK()函數造成較長的時延;如果不為真,則該語句將很快執行完。攻擊者遍歷所有字母,直到將整個數據庫名稱全部驗證完成為止。與此相似的還可以通過以下函數獲得一些額外信息:
database():當前連接的數據庫名稱
system_user():數據庫的系統用戶
current_user():登錄到數據庫的當前用戶
last_insert_id():最后一次進行插入操作數據庫的事務id
若當前數據庫用戶(current_user)有寫權限。可以將信息寫入本地磁盤中。比如寫入web目錄中,攻擊者就可以下載這些文件:
2 Union All SELECT * FROM information_schema.tables where table_schema='mysql' ORDER BY table_name DESC INTO OUTFILE '/path/location/on/server/www/schema.txt '
或者是寫入一個webshell:
2 Union All SELECT "<? system($_REQUEST['cmd']); ?>" ,2,3,4 INTO OUTFILE "var/www/html/temp/c.php" --
在不同數據庫中,有着類似benchmark()函數,可以被Timing Attack利用。例如:
MySql數據庫中的 benchmark(1000000,expr)和sleep(5)
PostgreSQL數據庫中的PG_SLEEP(5)和GENERATE_SERIES(1,1000000)
MSSQL Server中的 WAITFOR DELAY '0:0:5'
