[Write-up] SQL injection 💉 - Union-based ⌨

SQL injection là một trong những lỗ hổng cơ bản và phổ biến nhất trong server side.

Có thể tím hiểu những kiến thức cơ bản và học hỏi thêm ở trang này: https://www.netsparker.com/blog/web-security/sql-injection-cheat-sheet/

Mình sẽ sử dụng một lab khá phổ biến chính là DVWA (Damn Vulnerable Web Application) để thực hiện bài này. Có thể tải tại đây: http://www.dvwa.co.uk/

Vô vấn đề chính thôi. SERVER ON!!!✅

0x01. LOW-LEVEL (Non-Filter)
Ở đây, DVWA cung cấp cho 1 user input là 1 textbox với field data là user_id và 5 id:
Và khi mình nhập vào đây "1":
và thêm nữa là url: http://134.0.0.124/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#
và tiếp tục thử số "5":
và param trên url: http://134.0.0.124/dvwa/vulnerabilities/sqli/?id=5&Submit=Submit#
2 giá trị trên cho mình biết câu lệnh trên SQL: SELECT col1,col2,(hoặc nhiều hơn) FROM table nào đó WHERE user_id = (giá trị truyền vào từ param id) #
Giờ mình sẽ truyền vào 1 command luôn cho giá trị là TRUE như: 'or''=' hay 1 or 1 = 1 hoặc 1'or'1'='1
và param trên url sẽ như này: http://134.0.0.124/dvwa/vulnerabilities/sqli/?id=%27or%27%27%3D%27&Submit=Submit#
Vậy là đã xác định được, NOW TIME TO SCAN DATABASE!!! 
Mình sẽ dùng lệnh UNION để xác định số lượng columns mà câu truy vấn SQL của server đã select.
*NOTE: UNION nó sẽ chỉ cho phép select bằng số lượng columns của câu truy vấn SELECT trước.
Thế là số lượng columns mà SELECT trước dùng là nhiều hơn nữa, giờ mình sẽ tăng lên 2:
và nó có trả kết quả, vậy là ta có câu lệnh SQL là: SELECT col1,col2 FROM table nào đó WHERE user_id = (giá trị truyền vào từ param id) #
Sau khi nắm bắt được số lượng columns rồi, giờ mình sẽ tiến hành dò table_name có trong database. Mình sẽ dùng một object là information_schema, obj này sẽ cung cấp cho mình các thông tin về tables, columns, views, procedures, vân vân và mây mưa :v
Đây chỉ là phần crop thôi nhé (bạn nào muốn xem full thì here)
Nó sẽ show toàn bộ table đang có trong database nhưng mình chỉ cần những cái cần thiết thôi nên sẽ thu hẹp phạm vi lại bằng WHERE ... like...
và mình được 2 table đáng nghi nhất là "users" và "user", như vậy ta có câu truy vấn SQL như sau:
  • SELECT col1,col2 FROM users WHERE user_id = (giá trị truyền vào từ param id) #
         hoặc
  • SELECT col1,col2 FROM user WHERE user_id = (giá trị truyền vào từ param id) #
Mình sẽ thử với table "users", tiếp tục với information_schema để dò các columns trong table này:
Toàn bộ columns trong table "users" đã được show ra và có những thông tin cần thiết như user_id, user, password. À còn có 2 columns có vẻ liên quan đến kết quả ở khung "First name" và "Surname".
Vậy là câu truy vấn SQL như sau: SELECT first_name,last_name FROM users WHERE user_id = (giá trị truyền vào từ param id) #
Giờ xem column "user" và "password" có gì nào:

Vì chỉ được select đúng bằng số lượng của SELECT trước nên mình sử dụng hàm concat() đế có thể gom lại thành 1 string. Ở đây ta có được các username và password nhưng bị hash bằng MD5.
Low-level is completed !!!
0x02. MEDIUM-LEVEL (addslashs bypass)
Ở level này, DVWA dùng user input là 1 list option gồm 5 user_id

Và sử dụng Method POST nên mình sẽ dùng burp để intercept request và repeat
Thử submit để intercept hehe
và ta được 2 param là id và Submit nhưng chỉ cần quan tâm đến id thôi :v
Thử truyền 1 command test vào nhỉ :3
'or''=' nhưng mình không thể để như thế mà nhập vào được phải đổi thành hex để cho nó phù hợp với codec của URL => 'or''=' -> %27%6f%72%27%27%3d%27
Vậy là mình có 1 request như này và send thôi :v

Reponse nhận được là đây:
Lỗi? không lỗi đâu, mà là có một filter các kí tự đặc biệt và nó sẽ addslashs vào xen kẽ những kí tự đó. Thế thì phải thay bằng 1 command khác như 1 or 1=1 chẳng hạn.
Tương tự như trên mình cũng phải đổi thành hex và ta có reponse:
TIME TO SCAN DATABASE!!!
Tìm số lượng col select trong câu query của SQL y chang như LOW-LEVEL nhưng ở đây nó cần 1 value để có thể truy vấn đến nữa, nên cần phải thêm 1 value vào command và value đó phải tồn tại.
Do đó mà mình sẽ chọn 1 value trong trong list option {1,2,3,4,5}
Thêm nữa do đây nó có 1 filter addslashs nên những command như ' union select null, table_name from information_schema.tables where table_name like 'user%' phải điều chỉnh lại -> 1 union select null, table_name from information_schema.tables where table_name like char(117, 115, 101, 114, 37) 
'user%' = char(117, 115, 101, 114, 37)
Như vậy mình có 1 request:
Và reponse
Tương tự như thế thì có những reponse:
Medium-level is completed !!!

0x03. HIGH-LEVEL (LIMIT result)
High-level khá tương đồng với low-level chỉ khác ở một vài điểm
Đây là UI đập vào mặt :v
khi Click vào sẽ có 1 window mới mở ra
Đây sẽ là nơi user input vào và data sẽ output ở UI kia
Soi một chút source-code xem có gì lạ không nhỉ
Chả gì lạ hết cả :)))
Nhưng nếu phân tích vào thì có thể hiểu thêm đấy :v
Tại sao nó lại dùng kiểu user input như này???
Cách này nhằm mục đích ngăn những tool dò database như sqlmap chẳng hạn.
Send value = 1 thử xem có gì lạ không nhỉ :3
vẫn như mấy level trước chả có gì lạ nhỉ...
Thế thì thử 1 command test xem sao 'or''='
có reponse này :v thế là không bị addslash nhỉ
Hmmm... nhưng mà có một điều lạ ở đây là nó không list hết 5 user_id nhỉ
Lượn lại câu query SQL của low-level:
SELECT first_name,last_name FROM users WHERE user_id = $id
Câu query trên nó không hề limit row select, nên có thể ở high-level đã được thêm vào để limit số lượng row select.
Như vậy câu query có thể là:
SELECT first_name,last_name FROM users WHERE user_id = $id LIMIT 1
Nói thêm về LIMIT thì nó là dùng để limit lại số row được select, cụ thể như ở đây là LIMIT 1 thì nó limit lại chỉ 1 row được select và trả result. Ngoài ra còn có một cách viết khác của LIMIT nữa là LIMIT 20,5 thì 20 là số thứ tự của row bắt đầu được select và 5 là số row được limit.
Như vậy mình chỉ cần cho nó thành comment là xong :)) bằng cách thêm các kí tự đánh dấu cmt như: # // --
Do đó câu query sẽ biến thành:
SELECT first_name,last_name FROM users WHERE user_id = 1' union select 1,2 # LIMIT 1
Như vậy là đã xong rồi mọi bước còn lại như low-level và chỉ cần thêm kí tự comment vào là done.
High-level is completed !!!
 0x04. Cracking Pwd (Bonus)
Dựa vào user và password đã scan được ở trên mình sẽ tạo 1 file text và dùng tool John The Ripper để crack
0xFF. Cách phòng chống SQL injection

  • Type của value, nếu là number thì if (is_numeric($value)) hay if (is_int($value)). Nếu là string thì phải xác định length rõ ràng.
  • Tránh tạo query bằng cách cộng chuỗi như:
    $query = "SELECT first_name,last_name FROM users WHERE user_id='$id';";
    Có thể sử dụng bindParam và PDO để đẩy value vào trong query.
  • Dùng rowCount để xác định vào giới hạn số lượng kết quả trả về của SQL.

Comments

Popular posts from this blog

[Write-up] HTTP - Hố bug nho nhỏ

[Tip&Trick] SSH-Tunnel Socks5 cho host không thể truy cập internet