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

int main(int argc, char *argv[]) {
    char buf[0x40] = {};

    initialize();

    read(0, buf, 0x400);
    write(1, buf, sizeof(buf));

    return 0;
}

 

[그림 1-1]

오잉? 카나리가 없다. ㄷㄷ

코드를 보면 buf 크기는 0x40인데 read에서 buf 크기보다 크게 입력할 수 있다.(0x400) -> bof

스택을 그려보자

[그림 1-2]

매우 간단하다.

[그림 1-3]

pattern 이용해 확인해 보면 72개 이후로 ret 값이 덮인다. ㅇㅇ

코드에는 system 함수와 "/bin/sh" 문자열이 존재하지 않는다. 따라서 libc에 있는 system 함수를 해야 한다.

libc 버전을 알기 위해 코드에서 사용하는 함수들의 got 값 (실제 라이브러리 주소)을 이용해 버전을 확인하자!

[그림 1-4]

puts(read_got) -> 실제 read 함수의 주소를 출력한다.

[그림 1-5]

주소를 받아와서 libc database에 주소를 넣고 버전을 찾아보자.

[그림 1-6]

... 왜 안 나오는지 모르겠다. 추측으로는 libc database 안에 해당 버전이 없어서 출력이 안 되는 거 같다..

libc 버전을 알아야 하는데.. 흠.. 이 문제 같은 경우에는 바이너리와 라이브러리를 제공해 준다.

따라서 pwntools에서 사용하면 된다. ㅋ (라이브러리를 안 주면 어떡하지..?)

라이브러리를 제공해 주면 위에서 직접 주소를 찾아서 안 넣어도 된다.

[그림 1-7]

libc.so.6이다. 이걸 사용하자.

[그림 1-8]

문제 파일에서 제공되는 libc를 pwntools에 올리려면, 다운로드한 libc의 경로를 지정해 주면 된다. -> libc = ELF('./libc.so.6')

[그림 1-9]

libc.symbols ['puts'] -> 라이브러리 base로부터 puts 함수의 offset를 알려준다.

[그림 1-9]를 해석하면 libc base 주소와 libc puts offset 주소를 더하면 puts 주소가 됩니다.

쉽게 말해 libc base 주소는 라이브러리가 메모리에 매핑된 주소이다.

libc puts offset은 libc base로부터 offset 이므로 두 값을 더하면 실제 puts 함수의 주소가 된다!

이렇게 system 함수 주소를 찾고 payload를 완성해 보자

 

[그림 2-1]
[그림 2-2]

성공!

 

알게 된 점!

1. 익스 짤 때 p.interactive() 먼저 하자.. (정신 건강에 좋다..)

2.  sizeof(배열) -> 배열 크기만큼 가져온다. 즉, write(1, buf, sizeof(buf)) 코드에서 buf의 크기만큼만 화면에 출력해 준다.

'Dreamhack - pwnable' 카테고리의 다른 글

basic_rop_x86 (GOT Overwrite)  (0) 2023.01.15
basic_rop_x64 (ret2main)  (0) 2023.01.15
Return Oriented Programming  (0) 2023.01.13
Return to Library  (0) 2023.01.11
Static Link vs. Dynamic Link  (0) 2022.12.29