[DreamHack] [Pwnable] basic_exploitation_002

image.png

NX하나만 걸려있다.

코드 분석부터 진행하겠다.

#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() 실행 시 포맷스트링을 입력하면 그대로 주소로 출력하는 취약점을 활용한 문제이다.

즉, buf의 4바이트 단위 조각들이 그대로 printf의 가변 인자 슬롯이 된다.

이 구조 덕분에 “포맷스트링(문자열)”은 buf[0]부터 시작되어 %...를 해석하고,

가변 인자 참조(%n, %k$hn)는 buf의 다음 4바이트 슬롯들을 그대로 사용한다.

따라서 포맷 문자열은 깨끗한 ASCII로 구성하고,

쓰고 싶은 주소(예: exit@GOT, exit@GOT+2)는 buf의 뒤쪽 가변 슬롯 위치(예: 10번째, 11번째 슬롯)에

원시 4바이트 값으로 배치하면 된다.

포맷 문자열 끝에는 \\x00로 종료(문자열 종료)해도, 가변 인자 슬롯의 “메모리 값”은 그대로 남아 있으므로

%10$hn 처럼 포지셔널(직접 인덱스) 지정자를 쓰면 그 슬롯을 정상적으로 참조할 수 있다.