(writeup) ångstromCTF 2023
queue


- bài này là fmtstr đơn giản thôi
- script:
actf{st4ck_it_queue_it_a619ad974c864b22}
gaga

- trong 3 cái nc thì cái nc cuối đc cho biết là sẽ cho ta toàn bộ flag, còn 2 cái đầu thì ra phân nữa
- check file + checksec


- main chỉ vỏn vẹn nhiêu đây nên hướng đi là ret2libc
- sau khi leak libc cơ bản thì thấy local và server hoàn toàn khác nhau
- ta có thể lấy libc trong Dockerfile hoặc trên libc.blukat.me đều đc
- trong Docker là
libc-2.31.so
, ở bluekat là libc6_2.31-0ubuntu9.9_amd64.so
- ta pwninit luôn
- và phần còn lại là '/bin/sh' với system thôi, ret để stack né xmm0


actf{b4by's_f1rst_pwn!_3857ffd6bfdf775e}


- ở hàm main có set biến called, khiến cho mình thực thi lại hàm
main
không được (ban đầu tính tạo shell)

- khả năng là ret2win, nhưng khổ là ROPgadget k tồn tại 2 thanh ghi $rdi và $rsi
- ta sẽ chơi dơ nhảy vào win() bỏ qua 2 thằng if
- vì ta skip khá nhiều nên khi đọc flag từ file, sẽ k tồn tại nơi có thể ghi vào
- hint:
thanh $rbp trỏ ở vùng địa chỉ được phép ghi
- vậy việc của ta là jump tới win hoi
- ta sẽ nhảy ở <win+117> tức là sau 2 thằng kiểm tra if

- ở lần nhập đầu là Ammount, sẽ thiết lập lượng byte cho phép ở lần nhập thứ 2, ta sẽ chọn 64 byte
- ở lần nhập thứ 2 Content, ta sẽ ow save_rbp, pop_rbp, win
- với pop_rbp là 0x00000000404a00 ( tăng thêm 0xa00 cho dư dả)



- thấy hiện tượng lạ ở đây =)))
- theo như nghe hướng dẫn đây là lệnh chống bruitforce
- việc ta cần làm làm copy cái
curl -sSfL https:/...
qua terminal khác để run
- mỗi lần kết nối tới server sẽ có 1 cái "proof of work" (chứng minh cái work mình k có bruteforce)
- nên ta thêm 1 số tham số

actf{y0u_f0und_a_usefu1_widg3t!_30db5c45a07ac981}
leek



- ở đây ta thấy 1 vòng lặp cấp phát bộ nhớ liên tục


với số lần lặp là từ 0 đến bé hơn 0x64=100 tổng là 100 lần
- hàm if() ở đây ta cần phải thoả mãn

so sánh s và s2 trong 32 byte
- s2 được nhập từ fgets() ở trên
- và s dc lấy từ hàm input(v9)
với v9 dc nhập vào từ đầu

- biến v9 còn dược lấy làm cho hàm malloc
- đoán nhẹ đây là kỹ thuật Heap Overflow
- ta debug thử, so sánh 32 byte thì ở input(v9) và fgets(s2) ta đều nhập 32
- break tại hàm
strncmp
so sánh s và s2


- lúc này ta thấy 2 đối số hoàn toàn khác nhau, có thể malloc chưa đủ
- debug lần 2, ta sẽ cho s 50 byte, s2 vẫn 32 byte

- lúc này có vẻ đúng, nhưng đã đủ 32 byte so sánh giống nhau chưa thì chưa rõ

32 là full cái heap 0x4052a0
40 là full dòng đầu 0x4052c0 (8)
48 là full dòng 2 của 0x4052c8 (16)
50 là liếm thêm 2 byte của địa chỉ tiếp theo
mục tiêu là ghi full 0x4052d0 (24) đến full 0x4052d8 (32)
tổng cần ghi: 64 byte
- coi như ta đã pass dc hàm if(strncmp) đó đi
- tiếp theo đến gets(v9)

- đọc v9 xong r free(s) rồi free(v9)
- lúc này lần nhập là bên trong heap

- sau lần nhập đó là free() 2 lần với 2 biến s và v9
- vậy thì ta cho payload vừa đủ:

payload = b'A'*24 + p64(0x31)

- vì sendafter hay sendlineafter lâu lắc nên bỏ after luôn cho nó lẹ

actf{very_133k_of_y0u_777522a2c32b7dd6}
(writeup) ångstromCTF 2024
Presidential
- viết bằng python nhưng phương thức hoạt động là C
- đọc source cũng có thể hiểu: nhập vào u_can_do_it rồi gán vào buf, sau đó gọi hàm f()
nói nôm na là thực thi ấy
- solution: chèn shellcode dưới dạng byte
48BB2F62696E2F736800534889E74831F64831D248C7C03B0000000F05

actf{python_is_memory_safe_4a105261}
Exam



main()
- dễ dàng thấy đc mục tiêu ta là trust_level > threshold
- input ta là "%d" (4 byte), không được nhập âm
- setup trust_level bằng 0 trừ đi input

- và trust_level sẽ -1 mỗi lần mình input chuỗi "I'm comfirm … this exam.\n"
- value của threshold:

- thế ta sẽ nhập detrust là
0x7fffffff
(dương cực đại) rồi trừ để ra trust_level là 0x80000001
- để lớn hơn threshold :
0x7ffffffe
, ta cần trust_level = 0x7fffffff
bằng cách giảm đi 2 lần
0x80000001
-> 0x80000000
-> 0x7fffffff

actf{manifesting_those_fives}
Bap Bap Bap


- dễ thấy được đây là lỗi BOF lẫn FMTSTR
- ta chỉ việc vừa leak vừa return lại main (PIE tắt)
- rồi ret2libc

actf{baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaap____}
og


go()
- thấy được BOF lẫn FMTSTR, có PIE tắt nhưng ở đây có canary và chương trình chỉ nhập 1 lần rồi kết thúc
- tận dụng khả năng check canary từ
__stack_chk_fail
để ghi đè lại main()
- sau đó dùng fmtstr để ow one_gadget

actf{you_really_thought_you_could_overwrite_printf_with_system_huh}
heapify

- thấy luôn BUG từ gets() nhưng lạ một cái khi malloc() cái đầu, chương trình tự malloc() thêm 1 chunk để copy payload dù trong source lẫn ida không có chức năng ấy

tạo chunk 0x30 nhưng lòi thêm chunk bên dưới
- có set NULL sau khi free() dù cho malloc() size thoải mái
- có gets() ta có thể ctrl được top_chunk
- nhưng libc đi kèm là 2.35 –-> k có hook lẫn House of Orange
- nhưng lại có House of Tangerine (giống Orange) exploit được
leak libc
- đầu tiên ta sẽ tạo fake chunk
- ta sẽ bỏ qua chunk đầu (vì dưới cái chunk tự malloc() từ đề, khó khai thác)
- sau đó ta sẽ xoá 1 chunk rồi malloc() lại cùng size để reused chunk rồi ow next_chunk có size sẽ vào ubin nếu free()
- khi đã có ubin, đồng nghĩa với next_chunk của ubin sẽ chứa main_area dù mình chưa free (do sự gộp chunk)
- rồi ta malloc() lại size bất kì rồi show next_chunk của ubin
leak heap
- để leak heap, ta cứ việc tạo chunk mới rồi free() sẽ chứa fw_pointer
lưu ý libc 2.35 là có cơ chế xor bảo vệ tcache
ow got
- ta sẽ tcache poisoning bằng cách tạo 3 tcache rồi sửa fw_pointer
- về ow GOT thằng nào thì mình sẽ debug sâu khi puts ra khi show nha

call tới hàm *ABS*+0xa86a0@plt
hơi lạ

rồi jmp tới $rip+0x1f1bfd

vậy offset mình là 0x21a098
cộng 8 do nó return địa chỉ tiếp theo
get flag

actf{wh3re_did_my_pr3c1ous_fr33_hook_go??}