rtld

oogu ㅣ 2023. 3. 12. 11:53

// gcc -o rtld rtld.c -fPIC -pie

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <dlfcn.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);
}

void get_shell() {
    system("/bin/sh");
}

int main()
{
    long addr;
    long value; 

    initialize();

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

    printf("addr: ");
    scanf("%ld", &addr);

    printf("value: ");
    scanf("%ld", &value);

    *(long *)addr = value;
    return 0;
}

[그림 1-1]

GOT Overwrite가 가능하다.

stdout 라이브러리 주소를 출력해 줘서 libc base 주소를 구할 수 있고 임의의 주소를 덮는 취약점이 존재한다.

get_shell 함수가 존재하지만 PIE가 있어서 어떻게 사용해야 할지 모르겠다...

[그림 1-2]

ld base 주소를 구하고 _dl_rtld_lock_recursive 함수 값을 덮으면 get_shell로 덮어보자

 

remote 환경이 16.04 버전이라 도커로 하자!

[그림 1-3]
[그림 1-4]

stdout 라이브러리 주소를 이용해 libc_base 주소를 구했다.

이제 libc와 ld offset은 항상 같기 때문에 gdb로 offset을 구해보자.

[그림 1-5]

[그림 1-4] 참고하면 ld가 libc 보다 높은 주소에 있는걸 알 수 있다.

[그림 1-6]

offset은 0x3ca000이다.

[그림 1-7]
[그림 1-8]

ld base 주소를 구했다!

[그림 1-9]

_dl_rtld_lock_recursive는 _rtld_global + 3848 위치에 존재한다.

[그림 2-1]

[그림 2-1]처럼 dl_rtld_lock_recursive 주소를 구할 수 있다.

PIE가 enabled 되어있는데 get_shell 주소를 구할 방법을 못 찾겠어서 one_gadget 사용으로 방법을 바꿨다.

[그림 2-2]
[그림 2-3]
[그림 2-4]

local에서는 shell이 실행되었다.

[그림 2-5]

성공!

remote에서는 shell이 될 때가 있고 안될 때가 있는데

실행될 때마다 one_gadget 조건을 만족할 때가 있고 안될 때가 있어서 그런 거 같다. -> 내 생각

[그림 2-6]

최종 익스 코드

 

 

알 게 된점

1. 눈에 보이는 코드가 안되면 다른 방법도 생각하자...

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

send_sig  (0) 2023.03.15
Sigreturn-Oriented Progamming  (0) 2023.03.14
environ  (0) 2023.03.06
master_canary  (1) 2023.02.15
seccomp  (0) 2023.02.13