ISITDTU Quals 2024
Solutions for some challenges in ISITDTU Quals 2024
ISITDTU Quals 2024
rev/animal
- 31 solves / 100 pts / by kinjazz
- Given files: animal.7z
- Description: Find the hidden animal
Solution
Đề bài cho chúng ta một file PE64. Mở bằng IDA64, tổng quan chương trình sẽ như sau
Chương trình yêu cầu nhập flag có độ dài 36 ký tự, trong đó có điều kiện check ở một số idex cụ thể.
Khi click vào hàm check_flag
, ta nhận được thông báo lỗi như sau
Qua tab IDA View chế độ non-graph, ta thấy đây chỉ là một lệnh gọi hàm bình thường
Vậy mình sẽ debug từng dòng và sửa các kết quả check để chương trình tới được đến đoạn này. Đây là chương trình khi mình nhảy vào rax
Ấn phím p
để create function và thu được đống mã giả của hàm này như sau
|
|
Tới đây chúng ta sẽ biết được luôn phải dùng Z3 để tìm ra flag. Lời giải của mình như sau
|
|
Flag thu được là ISITDTU{a_g0lden_cat_1n_y0ur_area!!}
rev/re01
- 46 solves / 100 pts
- Given files: re01.zip
- Description: VC++ ;)
Solution
Đề bài cho chúng ta một file PE64, mở bằng IDA64, quan sát tổng thể ta có thể thấy chương trình dùng SHA1 để hash input và so sánh với chuỗi hash eeeddf4ae0c3364f189a37f79c9d7223a1d60ac7
Sau một hồi thử crack chuỗi hash kia không được, mình tiếp tục đi xem có function nào đáng nghi không. Và đây chính là hàm mà mình chú ý tới TlsCallback_0
Chương trình sử dụng anti-debug và gọi nó trong hàm TLS. Mình đặt breakpoint ở đoạn check IsDebuggerPresent
và sửa giá trị cho ZF
để chương trình tiếp tục được đi vào trong hàm sub_140004000
Chúng ta dễ dàng nhận ra input length = 58. Mình sẽ tạo mới input và debug lại. Kiểm tra các giá trị ở đoạn so sánh, ta biết được điều kiện check flag sẽ là
|
|
Dễ dàng lấy toàn bộ giá trị của v7
và xor ngược lại, ta thu được flag ISITDTU{Congrats_You_Solved_TLS_Callback_Re01_Have_Fun_:)}
|
|
rev/re02
- 29 solves / 100 pts
- Given files: re02.zip
- Description: NES, good luck ;)
Solution
Đề bài cho chúng ta một file re02.nes
, đây là một Nintendo ROM image file. Sau một hồi tìm kiếm, mình tìm được tool FCEUX
có thể emulate và debug file này.
Mở chương trình lên thì thấy một màn hình đen kịt
Vào tab Debug → Hex Editor thấy 3 byte đầu nhảy liên tục, chứng tỏ rằng chương trình vẫn đang hoạt động bình thường.
Sau khi thử nhập một vài phím và check toàn bộ dữ liệu trong tab Hex Editor, mình phát hiện input được xuất hiện ở các địa chỉ:
- 0x0300
- 0x0B00
- 0x1300
- 0x1B00
và có một số đặc điểm như sau:
- Độ dài tối đa input là 16
- Có 7 phím được chấp nhận và nó sẽ được map như sau:
s
→a
d
→u
f
→t
up arrow
→n
right arrow
→i
down arrow
→h
left arrow
→l
Sau khi đã biết chỗ nhập input thì chỗ check flag sẽ nằm ở đâu?
Mình vào tab Debug → Debugger, tìm đoạn code nào có chứa 300
(địa chỉ input) hoặc lệnh cmp
thì ra được đoạn này
Nếu tinh ý, ta có thể nhận ra các block check input khá tương tự nhau. Lấy các giá trị ở địa chỉ 300, 301 và 302 cộng với nhau, sau đó so sánh với 0x4A. Ví dụ cho block check đầu tiên sẽ là
|
|
Thực hiện tương tự cho các block sau, chúng ta có thể tìm ra được mapped_input
bằng Z3
|
|
Kết quả thu được là tuanlinhlinhtuan
,** bây giờ ta chỉ cần nhập input đúng với các key đã được map sẽ có được flag là ISITDTU{Throw_back_the_nested_if_NES_have_funnnn_:)}
rev/The Chamber of Flag
- 28 solves / 100 pts / by ks75vl
- Given files: TheChamberOfFlag_11BA527D91D85F332DEBC3145E3E1C4A.zip
- Description: Try to unlock the Chamber and get the Flag.
Solution
Đề bài cho chúng ta một file PE64, chạy thử chương trình, ta thấy có 2 option để lựa chọn:
- login
- input secret key
- about
Mình thử nhập secret và nhận thấy:
- Độ dài secret = 6
- Nhập sai sẽ cho nhập tiếp
Mở file bằng IDA64, chương trình nhìn rất lớn và phức tạp. Mình nhảy qua tab string và nhận thấy chương trình có gọi các hàm encrypt của WinAPI.
Trace theo các hàm này, mình tìm ra được hàm sub_7FF6A0F51530
thực hiện việc mã hóa input và đi kiểm tra tính hợp lệ của nó.
Sau khi debug và decrypt AlgId
, chúng ta biết được chương trình sử dụng hash SHA256. Thông tin chi tiết các bạn có thể đọc thêm ở đây https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptopenalgorithmprovider
Tiếp tục debug và ta lấy được checked_hash
= 26F2D45844BFDBC8E5A2AE67149AA6C50E897A2A48FBF479D1BFB9F0D4E24544
Với input có độ dài 6 ký tự, mình sẽ dùng hashcat
để bruteforce nhằm tìm ra giá trị tương ứng với mã hash này. Kết quả thu được là 808017
Đăng nhập thành công, chúng ta chọn option flag nhưng lại xuất hiện thông báo flag crashed.
Sau khi xref chuỗi trên, mình tìm ra được đoạn code có liên quan tới chuỗi trên ở đây.
Đi phân tích hàm sub_7FF7AFB110C8
, ta thấy nó decrypt dữ liệu bằng thuật toán AES mode CBC.
|
|
Nhưng khi chạy đến cuối hàm thì gặp lỗi này.
Lỗi này gây ra do rcx
chưa trỏ đúng vào vị trí bộ nhớ.
Lúc này, mình tìm xung quanh các thanh ghi rcx
để xem nó bị ảnh hưởng bởi thanh ghi nào. Ta thấy có rax
và rbx
tác động tới nó
Do rax
trên stack nên mình bỏ qua, tìm xung quanh giá trị của rbx
, ta thấy có đống dữ liệu rất khả nghi.
Đưa rcx
trỏ về đây, chạy nốt chương trình và thu được flag ISITDTU{STATIC_STRUCt_INITIALIZATION_FAiLED}
pwn/shellcode 1
- 68 solves / 100 pts / by code016hiro
- Given files: shellcode1.rar
- Description:
nc 152.69.210.130 3001
Solution
Về tổng quan, chương trình đọc flag, lưu nó trên 1 vùng nhớ được mmap
rồi xóa flag đó đi. Chương trình tiếp tục mmap
một vùng nhớ mới cho shellcode với full quyền rwx và cho phép chúng ta chạy shellcode đó.
Khi nhảy vào shellcode, check vmmap
, ta có thể thấy được vùng nhớ lưu flag nằm ngay dưới shellcode và cách nhau 0x1000 byte. Vậy nếu ta sử dụng được syscall write
thì hoàn toàn có thể đọc được flag.
Kiểm tra seccomp, ta thấy các syscall như read
, write
, open
, execve
, openat
đều không được phép sử dụng.
|
|
Để bypass được các hạn chế phía trên, mình sẽ sử dụng syscall writev
thay thế cho write
để đọc flag.
|
|
trong đó iovec
có cấu trúc như sau
|
|
Vậy mình sẽ chỉ định cho iov_base
là địa chỉ vùng nhớ chứa flag, iov_len
là 0x100.
Khi nhảy vào shellcode, rdx
chứa giá trị của địa chỉ shellcode. Vậy nên địa chỉ của vùng nhớ flag sẽ là rdx + 0x1000
.
|
|
Flag là ISITDTU{061e8c26e3cf9bfad4e22879994048c8257b17d8}
pwn/shellcode 2
- 61 solves / 100 pts / by code016hiro
- Given files: shellcode2.rar
- Description:
nc 152.69.210.130 3002
Solution
Decompile file đề bài cho bằng IDA64, ta có thể thấy chương trình mmap
cho vùng nhớ ở địa chỉ 0xAABBCC00 kích thước 0x1000 byte với full quyền rwx.
|
|
Những opcode chẵn trong shellcode sẽ bị thay đổi thành nop
làm cho nó không hoạt động được.
Có một bài write-up của giải UIUCTF 2022 nói rất chi tiết về việc build lại toàn bộ các instruction với opcode lẻ cần thiết cho việc lấy shell mà các bạn có thể tham khảo. Mình sẽ giải bài này với hướng tiếp cận khác so với write-up phía trên.
Chúng ta có thể thấy, khi chương trình chuẩn bị nhảy vào shellcode, các giá trị của các thanh ghi như rax
, rdi
, rsi
và rdx
đều hợp lệ cho việc gọi syscall read
.
Vậy payload đầu tiên chúng ta chỉ cần gọi syscall
để chương trình tiếp tục được nhập input lần thứ hai. Vì đã pass qua vòng for
check opcode chẵn lẻ, nên tại lần nhập thứ hai này, ta chỉ cần viết shellcode lấy shell như thông thường.
|
|
Flag là ISITDTU{95acf3a6b3e1afc243fbad70fbd60a6be00541c62c6d651d1c10179b41113bda}
pwn/Game of Luck
- 43 solves / 100 pts
- Given files: chal
- Description:
nc 152.69.210.130 2004
Solution
Overview & Find bug
Chương trình chính sau khi được rename lại như sau
|
|
trong đó hàm game
là hàm xử lý chính
Nhìn tổng quan, có 2 lựa chọn cho người chơi:
- Lấy giá trị ngẫu nhiên trong khoảng [0, 100] qua hàm
get_random_number
. - Chơi game đoán giá trị ngẫu nhiên thông qua hàm
play
.
|
|
Ở trong hàm play
này, ta thấy được có bug Format String ở hàm enter_name
.
|
|
Exploit
Chúng ta chỉ có 1 bug duy nhất FSB trong hàm play
. Mình sẽ tiếp tục tìm kiếm xem có cách nào để tái sử dụng bug này được nhiều lần hay không.
Quay về hàm game
, đây là đoạn code khiến mình quan tâm nhất.
|
|
Nhập duy nhất một chữ số unsigned int, nghĩa là chỉ được nhập trong khoảng [0, 9]. Vì vậy, việc choice = 68
là bất khả thi. Có 2 điều chúng ta cần quan tâm ở đây đó là:
- Nếu nhập input không đúng với fmt của hàm
scanf
thìchoice
sẽ không bị thay đổi giá trị. - Đứng ở góc độ hàm
main
nhìn xuống, giá trịchoice
trong hàmgame
nằm ở vị trírbp-0xC
, đây cũng chính là địa chỉ chứa giá trị random của hàmget_random_number
.
Tới đây thì ý tưởng đã rõ. Chúng ta sẽ spam mãi cho tới khi lấy được lucky number = 68. Tiếp tục nhập choice
với -
để sử dụng được bug FMT nhiều lần.
Bên cạnh đó, nhìn vào hàm get_int_number
sẽ thấy nó cho phép nhập vào mảng buf
. Ta sẽ overwrite atoi@got
thành system
, khi đó atoi("/bin/sh")
sẽ là system("/bin/sh")
.
|
|
Full exploit
|
|
Flag thu được là ISITDTU{a0e1948f76e189794b7377d8e3b585bfa99d7ed0de7e6a6ff01c2fd95bdf3f72}
.