문제 설명

이 문제는 작동하고 있는 서비스(hook)의 바이너리와 소스코드가 주어집니다.
프로그램의 취약점을 찾고 _hook Overwrite 공격 기법으로 익스플로잇해 셸을 획득한 후, “flag” 파일을 읽으세요.
“flag” 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{…} 입니다.


Environment

Ubuntu 16.04
Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      No PIE (0x400000)


풀이

hook.c의 소스 코드는 아래와 같다. 소스 코드를 살펴보면 전 문제인 oneshot 문제와 동일하게 stdout의 주소를 %p 포맷스트링을 사용하여 주소를 출력해주어 라이브러리 베이스 주소를 구할 수 있다. 두 번째로 사용자에게 size를 입력받고, size만큼 할당된 데이터 값을 입력하고, ptr[0]을 참조한 값에 ptr[1] 값을 넣어준다. 마지막으로 코드 부분에 /bin/sh 문자열도 주어진 것을 볼 수 있다.

// gcc -o init_fini_array init_fini_array.c -Wl,-z,norelro
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}

void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    signal(SIGALRM, alarm_handler);
    alarm(60);
}

int main(int argc, char *argv[]) {
    long *ptr;
    size_t size;

    initialize();

    printf("stdout: %p\n", stdout);

    printf("Size: ");
    scanf("%ld", &size);

    ptr = malloc(size);

    printf("Data: ");
    read(0, ptr, size);

    *(long *)*ptr = *(ptr+1);

    free(ptr);
    free(ptr);

    system("/bin/sh");
    return 0;
}


보호 기법이 Full RELRO 이므로 GOT Overwite 공격은 불가한 것을 알 수 있다. 따라서 __malloc_hook, __realloc_hook, __free_hook의 후킹 함수는 메모리 할당 함수로 gcc 2.33 버전 이하에서 이 함수를 사용하여 Hook Overwite하여 공격이 가능하다.


익스플로잇 시나리오를 생각해보면 stdout의 주소를 출력해주므로, 전에 있던 oneshot 문제처럼 stdout의 라이브러리 심볼 이름을 찾아내고 라이브러리 베이스 주소를 찾아낸다. 다음으로 size를 넉넉하게 입력해주고 read 함수에서 ptr 변수에 후킹 함수 다음으로 “/bin/bash” 문자열이나 one_gadget을 넣어주어 쉘을 실행시켜 주면 될 것이다.


stdout의 라이브러리 심볼 이름을 찾기 위해 gdb로 stdout@GLIBC_2.2.5에서 si 명령으로 진입하면 다음과 같이 _IO_2_1_stdout_인 것을 알 수 있다.

image-20240411232015066


이제 free_hook의 주소는 위 stdout에서 라이브러리 베이스 주소를 구한 후, 라이브러리 베이스 주소와 libc.symbols[“__free_hook”]의 주소 값을 더하면 free_hook의 주소를 구할 수 있다. 다음으로 “/bin/bash”의 주소나 one_gadget을 구하여 다음 값으로 입력해주면 되겠다.


one_gadget은 저번 문제에 풀어보았으므로 코드에 있는 /bin/bash 문자열은 gdb로 hook 바이너리를 로드하고 disassemble main 명령으로 system 함수가 call 될 때 인자에 들어가는 0x400a11 주소가 /bin/bash의 주소이다.

image-20240411233057577


이제 익스플로잇 코드를 작성하면 되는데 PIE 보호 기법이 비활성화 되어 데이터 영역이 무작위 주소에 매핑되지 않았으므로 코드를 작성하면 다음과 같다.

  • pwntools의 remote 및 ELF 함수를 이용해 공격할 호스트 및 라이브러리와 바이너리 지정
  • bin_bash 변수에 /bin/bash 문자열 주소 지정
  • stdout: 이 입력될 때까지 데이터 입력받기
  • 줄바꿈 문자 빼고 16진수로 stdout의 주소 형 변환
  • libc.symbols를 이용해 라이브러리 베이스 주소 구하기
  • 베이스 주소와 더하여 free_hook 주소 구하기
  • ptr[0]에는 free_hook과 ptr[1]에는 bin_bash 주소 넣어주기
  • Size에 넉넉히 400 입력 후 엔터
  • Data에 위 ptr 변수 입력 후 엔터
  • slog 함수로 각 변수 데이터 값 출력
  • p.interactive 함수로 쉘 상호작용

image-20240411235333738

image-20240411235918910

댓글남기기