#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;
}
오잉? 카나리가 없다. ㄷㄷ
코드를 보면 buf 크기는 0x40인데 read에서 buf 크기보다 크게 입력할 수 있다.(0x400) -> bof
스택을 그려보자
매우 간단하다.
pattern 이용해 확인해 보면 72개 이후로 ret 값이 덮인다. ㅇㅇ
코드에는 system 함수와 "/bin/sh" 문자열이 존재하지 않는다. 따라서 libc에 있는 system 함수를 해야 한다.
libc 버전을 알기 위해 코드에서 사용하는 함수들의 got 값 (실제 라이브러리 주소)을 이용해 버전을 확인하자!
puts(read_got) -> 실제 read 함수의 주소를 출력한다.
주소를 받아와서 libc database에 주소를 넣고 버전을 찾아보자.
... 왜 안 나오는지 모르겠다. 추측으로는 libc database 안에 해당 버전이 없어서 출력이 안 되는 거 같다..
libc 버전을 알아야 하는데.. 흠.. 이 문제 같은 경우에는 바이너리와 라이브러리를 제공해 준다.
따라서 pwntools에서 사용하면 된다. ㅋ (라이브러리를 안 주면 어떡하지..?)
라이브러리를 제공해 주면 위에서 직접 주소를 찾아서 안 넣어도 된다.
libc.so.6이다. 이걸 사용하자.
문제 파일에서 제공되는 libc를 pwntools에 올리려면, 다운로드한 libc의 경로를 지정해 주면 된다. -> libc = ELF('./libc.so.6')
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를 완성해 보자
성공!
알게 된 점!
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 |