Hook Overwrite (2)

oogu ㅣ 2023. 1. 19. 09:50

서론


Hook 은 갈고리라는 뜻이 있습니다. 컴퓨터 과학에서는 운영체제가 어떤 코드를 실행하려 할 때, 이를 낚아채어 다른 코드가 실행되게 하는 것을 Hooking(후킹)이라고 부르며, 이때 실행되는 코드를 Hook이라고 부릅니다.

Hook Overwrite은 훅의 특징을 이용한 공격 기법입니다.

Full RELRO가 적용되더라도 libc의 데이터 영역에는 쓰기가 가능하므로 Full RELRO 우회가 가능하다.

 

 

malloc, free, realloc hook


C언어에서 메모리의 동적 할당과 해제를 담당하는 함수로는 malloc, free, realloc이 대표적입니다. 각 함수는 libc.so에 구현되어 있습니다.

[그림 1-1]

libc 에는 이 함수들의 디버깅 편의를 위해 훅 변수가 정의되어 있습니다. 예를 들어, malloc 함수는 __malloc_hook변수의 값이 NULL이 아닌지 검사하고, 아니라면 malloc을 수행하기 전에 __malloc_hook이 가리키는 함수 or 코를 먼저 실행합니다. 이때, malloc의 인자는 훅 함수에 전달됩니다. 같은 방식으로 free, realloc도 각각 __free_hook, __realloc_hook이라는 훅 변수를 사용합니다.

// __malloc_hook
void *__libc_malloc (size_t bytes)
{
  mstate ar_ptr;
  void *victim;
  void *(*hook) (size_t, const void *)
    = atomic_forced_read (__malloc_hook); // malloc hook read
  if (__builtin_expect (hook != NULL, 0))
    return (*hook)(bytes, RETURN_ADDRESS (0)); // call hook
#if USE_TCACHE
  /* int_free also calls request2size, be careful to not pad twice.  */
  size_t tbytes;
  checked_request2size (bytes, tbytes);
  size_t tc_idx = csize2tidx (tbytes);
  // ...
}

 

 

hook의 위치와 권한


__malloc_hook, __free_hoo, __realloc_hook은 관련된 함수들과 마찬가지로 libc.so 에 정의되어 있습니다.

[그림 1-2]

이 변수들의 오프셋은 각각 0x3ed8e8, 0x3ebc30, 0x3ebc28인데, 섹션 헤더 정보를 참조하면 libc.so의 bss 섹션에 포함됨을 알 수 있습니다. bss 섹션은 쓰기가 가능하므로 이 변수들의 값은 조작될 수 있습니다.

[그림 1-3]

 

 

Hook Overwrite


앞서 배운 정보를 종합해보면, malloc, free, realloc에는 각각에 대응되는 훅 변수가 존재하며, 앞서 설명한 바와 같이 이들은 libc의 bss 섹션에 위치하여 실행 중에 덮어쓰는 것이 가능합니다. 또한, 훅을 실행할 때 기존 함수에 전달한 인자를 같이 전달해 주기 때문에 __malloc_hook을 system 함수의 주소로 덮고, malloc(“/bin/sh”)을 호출하여 셸을 획득하는 등의 공격이 가능합니다.

// Name: fho-poc.c
// Compile: gcc -o fho-poc fho-poc.c
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
const char *buf="/bin/sh";
int main() {
  printf("\"__free_hook\" now points at \"system\"\n");
  __free_hook = (void *)system;
  printf("call free(\"/bin/sh\")\n");
  free(buf);
}

위 코드는 훅을 덮는 공격이 가능함을 보이는 Proof-of-Concept(PoC)입니다. 컴파일하고 실행하면, __free_hook을 system 함수로 덮고, free(“/bin/sh”)를 호출하자 셸이 획득되는 것을 확인할 수 있습니다.

[그림 1-4]

__free_hook 이 system 함수로 덮이고 실행되면 쉽게 free(buf) -> system("/bin/sh") 로 생각할 수 있습니다.

Full RELRO가 적용된 바이너리에도 라이브러리의 훅에는 쓰기 권한이 남아있기 때문에 이러한 공격을 고려해볼 수 있습니다.

 

 

키워드


  • Hooking: 어떤 함수, 프로그램, 라이브러리를 실행하려 할 때 이를 가로채서 다른 코드가 실행되게 하는 기법. 디버깅, 모니터링, 트레이싱에 사용될 수 있으며, 공격자에 의해 키로깅이나 루트킷 제작에 사용될 수 있음.
  • Hook Overwrite: 바이너리에 존재하는 훅을 덮어써서 특정 함수를 호출할 때, 악의적인 코드가 실행되게 하는 공격 기법. 메모리 관리와 관련된 malloc, free, realloc등의 함수가 라이브러리에 쓰기 가능한 훅 포인터를 가지고 있어서 공격에 사용될 수 있음. Full RELRO를 우회하는 데 사용될 수 있음.
  • 훅 외의 다른 함수 포인터들에도 유사한 방법으로 공격을 시도할 수 있습니다.

'Dreamhack - pwnable' 카테고리의 다른 글

hook  (0) 2023.01.19
fho  (0) 2023.01.19
_hook Overwrite  (0) 2023.01.18
PIE (Position-Independent Executable)  (0) 2023.01.16
RELRO (RELocation Read-Only)  (0) 2023.01.16