**Write up for Freshman 2023** --- **Pierre De Fermat** ![image](https://hackmd.io/_uploads/SyfbdgJNp.png) * Đề cho 1 file nén, tải về và giải nén ta được file như dưới ![image](https://hackmd.io/_uploads/BJyddg1Ea.png) * Thử kiểm tra thì file không có canary -> có thể overflow stack * Chạy file 1 lần để xem file làm gì thì báo thiếu flag.txt -> tạo flag.txt để debug ![image](https://hackmd.io/_uploads/r1q6dekEa.png) ![image](https://hackmd.io/_uploads/B1sJv-1Vp.png) * Khi chạy file ta được yêu cầu nhập độ dài của tên, mình thử 123 thì không có gì xảy ra thêm ![image](https://hackmd.io/_uploads/SysLFeJNp.png) * Thử dùng IDA decompile thì biết độ dài tên phải nằm trong khoảng 2 - 40 ![image](https://hackmd.io/_uploads/Skx5FlyNT.png) * Để ý ở đây có hàm fgets và hàm snprintf. Dùng Ghidra để decompile thì thấy file flag sẽ được lưu vào địa chỉ của local_118, cùng với đó là hàm snprintf sẽ làm gì đó với local_d8, sau đó in ra local_a8 ![image](https://hackmd.io/_uploads/rycYce1N6.png) * Thử dùng gdb để debug vài lần thì phát hiện có lỗi format strings ![image](https://hackmd.io/_uploads/BJEqsekNa.png) * Vậy thì có thể hàm snprintf sẽ print nội dung tại &local_d8 ra, sau đó truyền output vào local_a8, nên khi printf bên dưới vẫn xuất hiện bug format string * Thử break trước và sau khi chạy hàm snprintf để debug thì phát hiện flag chứa trong stack, cùng với đó là xâu mình nhập sau khi được format cũng ở trong stack sau khi chạy hàm snprintf + Trước khi chạy hàm snprintf: ![image](https://hackmd.io/_uploads/HyWZTl1Ep.png) + Sau khi chạy hàm snprintf: ![image](https://hackmd.io/_uploads/B1wQTgJVp.png) * Có thể thẩy rõ ràng xâu ban đầu vẫn được lưu ở offset của local_d8, xâu sau khi format được lưu ở local_a8 * Có điều cần chú ý ở đây là format %x sẽ leak stack -> thử %x nhiều lần thì phát hiện stack sẽ leak ra địa chỉ và số 1, 0 với địa chỉ giảm dần(từ dưới lên), sau đó leak dần từ trên xuống(by somehow) -> dò số lần leak để đến flag * ![image](https://hackmd.io/_uploads/HJX_RgkE6.png) * Và điều đáng chú ý là khi leak nhiều lần thì %x sẽ leak địa chỉ, 1, 0, nhưng khi leak từ trên xuống thì chuyển qua leak nội dung của stack mà mình thấy (Cụ thể là các địa chỉ 0x0005555605e, 0x00005556019.....) dưới dạng string sau khi được format liên tục => Tìm cách để leak đến vùng chứa flag `` Mình vẫn chưa hiểu đoạn này tại sao lại có chuyện stack leak ngược như vậy nhưng khi thấy càng leak nó càng đi xuống và gần với flag thì mình tận dụng `` * Trong lúc tìm cách leak %x nhanh hơn thì mình phát hiện có synctax %(k)$llx sẽ leak ra nội dung tương đương với lần gõ %x thứ k => thử dùng dò flag ở lần leak thứ bao nhiêu * ![image](https://hackmd.io/_uploads/ByTYZ-JEp.png) * Thử hết thì thấy strings sẽ xuất hiện ở lần leak thứ 20 nhưng nội dung bị đảo và viết dưới dạng hex, cùng với đó là các lần leak 21, 22, 23,... sẽ ra nội dung phía sau của flag nhưng bị revese -> leak ngược lại từ cuối về đầu sau đó reverse 1 lần cho dễ ``Thực ra đây là nhận xét của mình sau khi solve được bài, còn trong lúc thi não mình ngừng chạy từ lúc phát hiện có thể lấy flag bằng %20$llx, cùng với đó là để demo flag full 'a' nên không phát hiện bị miss nội dung của flag, cũng như không nghĩ đến việc thử viết liên tiếp để ra flag 1 lần mà chạy tay chục lần(?) nên tốn nhiều thời gian để lấy flag dù tiếp cận đúng...`` * Vì demo flag của mình có sẵn độ dài nên biết flag sẽ khoảng bao nhiêu lần leak, nhưng trên host thì chưa biết nên mình thử dò thì thấy flag nằm trong khoảng từ lần leak 20 -> 27 * Tuy nhiên độ dài xâu tối đa chỉ có 40, 1 lần leak sẽ tốn 7 kí tự => leak 2 lần liên tiếp sẽ có nội dung đầy đủ của flag * ![image](https://hackmd.io/_uploads/SkZQrZyVT.png) `e52e0b007d3f3f3f3f3f5f6674635f79726576335f6e695f646165645f73695f336c623472336e6c75765f674e317274735f74346d7233665f733330647b3157` * Decode đoạn hex sang string thấy có flag và bị revese: ![image](https://hackmd.io/_uploads/B1bqrWJE6.png) ``å. �}?????_ftc_yrev3_ni_daed_si_3lb4r3nluv_gN1rts_t4mr3f_s30d{1W`` => Lấy xâu reverse ta được flag **W1{d03s_f3rm4t_str1Ng_vuln3r4bl3_is_dead_in_3very_ctf_?????}** * Lần này tuy chỉ giải được 1 bài nhưng mình học được nhiều thứ qua những cái bug mình gặp phải: - IDA và Ghidra vẫn chỉ dùng để đọc, gdb mới là chân ái (mình tốn cả buổi sáng cũng chỉ vì debug bằng não trên IDA, Ghidra mà không thử chạy gdb để xem nó hoạt động như thế nào) - Flag không nên để full 1 kí tự, có format sao cho dễ debug (mình tốn thêm 30p chỉ vì flag full a mà mình chỉ leak các byte chẵn nên không biết bị thiếu flag) - Học code python, dùng pwntools để trở nên provjp thay vì chạy tay (May mắn đây chỉ là freshman nên các anh cho dề dễ thở, tưởng tượng chỉ cho 7 kí tự và flag dài 2 chục lần leak thì..) - Search Google cũng là 1 kĩ năng