NỘI DUNG
Kết thúc nội dung Penetration Testing Step 3 – Các đường chấm mút với DOM based Cross-Site Scripting (tiếp theo và hết), tôi tạm thời đóng lại câu chuyện với Cross-Site Scripting – XSS. Kỳ này tôi sẽ chuyển sang một đối tượng khác nhưng cũng khá nổi tiếng trong trong làng Penetration Testing là SQL injection.
Trong bài giới thiệu đầu tiên này, hiển nhiên tôi sẽ không hùng hổ bay vô demo múa lửa tung tóe mà sẽ chỉ dạo đầu nhẹ nhàng để giới thiệu về SQL injection cũng như một số phương thức khai thác cơ bản. Các phần chi tiết hơn tôi sẽ bàn tiếp trong các kỳ sau.
Nhắc lại: Nếu bạn chưa biết Penetration Testing là gì thì vui lòng de lại xem nội dung Penetration Testing – 6 điều tối thiểu bạn cần biết.
#1. Trước hết, SQL injection là cái gì?
SQL injection là dạng lỗ hổng bảo mật phổ biến trên các ứng dụng web cho phép các đối tượng tấn công thao túng các query (câu truy vấn). Cụ thể, dạng lỗ hổng này xuất phát từ việc các dữ liệu input của người dùng chưa được sát khuẩn (unsanitized) mà đã được đút thẳng vô query rồi đẩy vô cơ sở dữ liệu để thực thi.
Thông thường query sẽ tương tác với cơ sở dữ liệu theo 2 kiểu là ghi dữ liệu vào hoặc đọc lấy dữ liệu ra. Tuy nhiên, sẽ có khả năng đối tượng tấn công thao túng các câu truy vấn này để thực thi các hành vi mờ ám khác thay vì đọc hoặc ghi dữ liệu như thông thường.
Query có thể hiểu đại khái là các dòng chỉ dẫn để yêu cầu database (cơ sở dữ liệu) xử lý. Tác động có thể bao gồm việc cho phép đối tượng tấn công đọc được dữ liệu vượt thẩm quyền (ví dụ password, thông tin thẻ tín dụng, thông tin của các người dùng khác) hay thậm chí chỉnh sửa hoặc xóa luôn mịa dữ liệu làm ảnh hưởng đến hoạt động của ứng dụng. Đôi khi, đối tượng tấn công còn có thể triển khai các dạng tấn công leo thang để xâm phạm vô cả hạ tầng của ứng dụng, tạo backdoor, làm tổ, đẻ trứng các kiểu.
Sơ đồ minh họa một ví dụ dạng SQL injection UNION attack được trình bày như sau (nếu bạn đọc qua thấy rối quá thì cũng không sao, tôi sẽ quay lại diễn giải kỹ nội dung này sau).
Nguồn: portswigger.net
Lưu ý: Structured Query Language – SQL (Ngôn ngữ truy vấn có cấu trúc) là ngôn ngữ chính dùng để tương tác với Relational Databases (cơ sở dữ liệu quan hệ). Relational Databases bao gồm 1 hoặc nhiều tables (bảng) và mỗi bảng sẽ có 1 hoặc nhiều cột. Ví dụ so sánh đơn giản của Relational Database MySQL với một đối thủ NoSQL là mongDB như sau.
Nguồn: phoenixnap.com
#2. Các thể loại SQL injection phổ biến mà bạn có thể chấm mút
Thực tế sẽ có rất nhiều dạng lỗ hổng SQL injection cũng như nhiều phương thức, kỹ thuật tấn công tùy thuộc vào tình hình thực tế của mục tiêu. Tuy nhiên, nhìn chung bạn sẽ hay gặp một số thể loại SQL injection phổ biến như sau:
- Retrieving hidden data: Với loại này, bạn sẽ có thể thao túng SQL query để database trả về các kết quả mà đáng lý bạn không được phép truy cập;
- Subverting application logic: Trường hợp này, bạn sẽ thao túng query để đâm thọc vô quá trình xử lý logic của ứng dụng. Đây là kiểu hay gặp trong tình huống xử lý đăng nhập của user. Đối tượng tấn công có thể dùng thủ thuật để cắn xén query nhằm thoát khỏi yêu cầu cung cấp password;
- UNION attack: Với dạng này, bạn sẽ có thể truy cập dữ liệu từ nhiều bảng khác nhau của database với từ khóa UNION;
- Examining the database: Kiểu này bạn sẽ có thể truy cập thông tin về phiên bản và cấu trúc của database. Các thông tin sẽ là bàn đạp để bạn tinh chỉnh các phương án tấn công để tăng tính hiệu quả;
- Blind SQL injection: Đây là kiểu tấn công mà kết quả của query bạn thao túng không gửi trả về trong response. Khoan! Không gửi kết quả gì về thì biết mịa gì mà tấn với chả công? Vâng, bởi vậy nó mới có tên gọi là “Blind” – tấn công kiểu mù quáng. Điểm nhấn quan trọng đối với kỹ thuật tấn công này là thử nghiệm các thay đổi trên query và ghi nhận sự khác biệt (nếu có) trong các response nhận về. Loại này hiển nhiên đòi hỏi kỹ thuật phức tạp và nhiều thời gian hơn để thử nghiệm và phân tích dữ liệu từ các response.
#3. Có gì trong SQL query cơ bản?
Tùy thuộc các software packages, bạn có thể bắt gặp một số biến thể, tuy nhiên standard syntax của SQL query nhìn chung là giống nhau. Ví dụ SELECT query dùng để hiển thị tất các columns và records trong bảng user như sau:
SELECT * FROM users;
Lưu ý: Asterisk – “*” (dấu sao) ngay sau SELECT command ý muốn chọn tất cả colums có thể có
Bạn cũng có thể đưa ra query tinh tế hơn với conditional clause (mệnh đề điều kiện) thông qua việc sử dụng từ khóa WHERE. Ví dụ như sau:
SELECT username FROM users WHERE id=1;
Lúc này bạn có thể hốt các username trong bảng users với điều kiện user đó có id = 1
.
Ngoài SELECT, bạn cũng có thể sử dụng các thao tác INSERT/UPDATE/DELETE tương ứng với việc thêm/xóa/sửa dữ liệu trong các bảng của database.
#4. Bắt đầu SQL injection attack từ đâu?
#4.1 Những “mũi chích” đầu tiên với SQL injection
Như tôi trình bày ở Mục 2, tùy thuộc tình tình hình thực tế, bạn có thể có nhiều phương án triển khai SQL injection attack khác nhau. Tuy nhiên, việc đầu tiên cần làm trước khi chọc ngoáy lỗ hổng SQL injection là xác định các vị trí để bạn có thể thể tuồn dữ liệu vào database.
Với SQL, single quote (‘) được sử dụng như string delimiter (có chức năng phân tách chuỗi) nên bạn có thể sử dụng con hàng này để thăm dò các vị trí tiềm năng để “chích” thử một mũi SQL vào. Nếu ăn ở tốt, bạn có thể nhận về kết quả database error, báo hiệu ứng dụng xử lý single quote không chuẩn cmn mực nên khả năng là bạn có thể chấm mút ở vị trí này. Dựa vào thông tin quý giá này, bạn có thể triển phương thức tấn công thử nghiệm bằng cách chèn single quote vào từng field (trường thông tin) có khả năng được đẩy vào database.
Lưu ý: Nếu đang kiểm tra ứng dụng dạng White Box (tức là dạng mà mấy ông quản lý của mục tiêu chơi cởi mở, bạn cần biết thông tin gì để thực hiện Penetration Testing đều được cung cấp hết) và truy cập được source code của ứng dụng thì có thể dò tìm cách các SQL query được xây dựng để nhanh chóng xác định phương thức tấn công thử nghiệm
Xem xét một ví dụ SQL query với PHP code khi người dùng gửi hàng username và password để đăng nhập như sau:
$query = "select * from users where username = 'gamo' and password = 'incorrect' ";
Bạn có thể mông má lại query trên bằng cách thay username bằng single quote thành kiểu:
$query = "select * from users where username = ''' and password = 'incorrect' ";
Với kiểu này query sẽ chỉ được đọc với giá trị username bằng rỗng như sau:
$query = "select * from users where username = ''
Và làm phát sinh ra một cái đoạn vớ vẩn kế tiếp:
' and password = '
Ở đây hiển nhiên đám vớ vẩn này nó sẽ làm phát sinh ra lỗi syntax error đôi khi kèm thêm các thông tin quý giá như database software (dạng Examining the database trình bày trong Mục 2) để bạn có thêm tư liệu chuẩn bị cho các đòn đánh thâm độc hơn.
#4.2 Minh họa mũi SQL injection xuyên thủng cơ chế xác thực theo kiểu Subverting application logic
Chuyển sang một thể loại đâm thọc phổ biến kế tiếp liên quan đến quá trình xác thực (dạng Subverting application logic trình bày trong Mục 2). Bạn có thể chỉnh cái query thành kiểu như:
$query = "select * from users where username = 'gamo' or 1=1;# ' and password = 'incorrect' ";
Bạn có thể thấy một số vấn đề đầu tiên ở đây là pound character (#). Ký tự này được sử dụng như comment maker của MySQL/MariaDB (tức là đánh dấu đám đứng sau cái pound character chỉ để đọc cho vui chứ không thực thi gì sất). Điều này có nghĩ là query thực tế chỉ còn là:
$query = "select * from users where username = 'gamo' or 1=1;
Điểm lưu ý thứ hai là sự xuất hiện của cái đám or 1=1. Đám này bình thường trong rất vô hại và nhạt nhẽo vì chắc chỉ có mấy ông triết gia rảnh rỗi mới tranh cãi coi một có bằng một hay không.
Tuy nhiên, nếu đọc lại cả cái query, bạn sẽ thấy nó khá là thâm. Tôi đọc lại cái query như sau: “Ê ku (database), mở cho anh xem các dòng và cột trong bảng users có username là gamo hoặc khi một bằng một”. Như tôi nói trên, vì 1=1
sẽ luôn trả về kết quả True (đúng) nên lúc này database sẽ phụt ra tất tần tật các thông tin của bảng users, có thể bao gồm cả thông tin password.
Lưu ý, với một số ngôn ngữ, bạn có thể không được phép chạy query để húp hết dữ liệu một lần mà chỉ được ăn mỗi lần một dòng. Với trường hợp đụng phải lỗi này, bạn có thể dùng thêm từ khóa LIMIT để thoát vòng kiểm soát kiểu như sau:
$query = "select * from users where username = 'gamo' or 1=1 LIMIT 1;
Phù, thế là tôi đã giới thiệu xong phần dạo đầu nhẹ nhàng tình cảm với SQL injection rồi đấy. Trong các kỳ tiếp theo, tôi sẽ giới thiệu các nội dung demo để bạn có thể hình dung rõ hơn các phương thức tấn công mục tiêu với SQL injection.
1 thought on “Penetration Testing Step 3 – Dấn thân vào nghiệp chích choác với SQL injection”