이 정보는 **Ubuntu 16.04** 운영체제에서 특정 바이너리 파일의 보안 구성 상태를 나타냅니다. 각 보안 기능의 의미를 설명하겠습니다.
### 분석
1. **Arch: i386-32-little**
- **설명**: 바이너리가 **32비트 아키텍처**로 컴파일되었으며, **리틀 엔디안** 형식으로 데이터가 저장됩니다.
- **영향**: 32비트 아키텍처는 64비트에 비해 보안 및 주소 공간 보호가 제한적일 수 있습니다.
2. **RELRO: Partial RELRO**
- **설명**: **RELRO**(Relocation Read-Only)는 **프로그램의 특정 메모리 영역을 읽기 전용으로 설정하여 취약점을 악용하는 것을 어렵게 하는 보호 기법**입니다.
- **Partial RELRO**: 일부만 읽기 전용으로 보호합니다. 이 경우 **GOT (Global Offset Table)**는 읽기-쓰기 상태로 남아있어 특정 공격에 취약할 수 있습니다. Full RELRO보다 보안 수준이 낮습니다.
3. **Stack: No canary found**
- **설명**: **스택 캔리(stack canary)**는 **스택 버퍼 오버플로우 공격을 방어하는 기법**으로, 스택 프레임의 무결성을 검사하여 함수 반환 시 스택이 손상되었는지 확인합니다.
- **No canary found**: 스택 캔리가 활성화되어 있지 않다는 뜻으로, **버퍼 오버플로우에 취약할 가능성**이 큽니다.
4. **NX: NX enabled**
- **설명**: **NX (No-eXecute)**는 **메모리의 특정 영역을 실행할 수 없도록 설정하는 기법**입니다. 예를 들어, 스택 영역이 NX로 설정되면 스택에 있는 코드가 실행되지 않으므로 **ROP(Return Oriented Programming) 공격**에 대한 기본적인 방어가 됩니다.
- **NX enabled**: **NX가 활성화되어 있어**, 스택과 같은 특정 메모리 영역에서 코드 실행이 불가능합니다.
5. **PIE: No PIE (0x8048000)**
- **설명**: **PIE (Position Independent Executable)**는 **메모리 주소가 매번 무작위로 배치되도록 하는 기법**으로, 주소를 예측하기 어려워 공격 난이도가 높아집니다.
- **No PIE**: PIE가 비활성화되어 있어, **프로그램이 항상 동일한 메모리 주소에 로드**됩니다. 이로 인해 **바이너리 공격 시 메모리 주소를 예측**하기가 더 쉬워집니다.
---
### 요약
이 바이너리는 32비트 환경에서 컴파일되었고, **스택 캔리가 비활성화**되어 있으며, **Partial RELRO와 NX**만 활성화되어 있습니다. **PIE가 비활성화**되어 메모리 주소 예측이 가능하므로, **버퍼 오버플로우 및 메모리 예측 공격에 취약**할 수 있습니다.
**Off-by-one**는 **버퍼의 경계**를 정확하게 처리하지 못해 발생하는 **메모리 취약점**의 일종입니다. 이 취약점은 **버퍼의 경계에서 딱 1바이트 초과로 쓰거나 읽는 실수**에서 비롯됩니다.
저번에 경계 관련해서 gpt에게 답변 받은 그거다
### Off-by-one 취약점의 원리
- **버퍼 경계 초과**: 프로그래밍에서 버퍼의 크기를 설정한 후, 버퍼에 데이터를 쓸 때 이 크기보다 1바이트 더 쓰게 되는 상황이 발생할 수 있습니다. 예를 들어, `char buffer[10];`와 같은 10바이트 크기의 배열에 대해 `buffer[10]`을 접근하게 되면, 경계를 넘어가면서 1바이트 초과로 쓰게 됩니다.
- **메모리 손상**: 경계를 넘어서는 접근으로 인해, 다음 위치의 **메모리가 예상치 못하게 손상**될 수 있습니다. 이는 **스택의 반환 주소, 스택 캔리(canary), 중요한 플래그 변수** 등에 영향을 미쳐, 프로그램 흐름을 조작할 수 있는 잠재적인 보안 취약점이 됩니다.
### 예시 코드
다음은 간단한 off-by-one 오류가 있는 예시 코드입니다.
```c
#include <stdio.h>
#include <string.h>
int main() {
char buffer[10];
strcpy(buffer, "ABCDEFGHIJK"); // buffer 크기보다 1바이트 더 입력됨 (11바이트)
printf("%s\n", buffer);
return 0;
}
```
위 코드에서 **`buffer`**는 10바이트 크기이지만, **11바이트**인 `"ABCDEFGHIJK"` 문자열을 복사합니다. 이로 인해 경계를 넘어서는 1바이트(`'K'`)가 초과되어 다음 메모리 공간에 쓰이게 됩니다.
### Off-by-one 취약점이 위험한 이유
1. **스택 오염**: 스택에서 경계를 초과한 데이터가 **반환 주소, 스택 캔리, 플래그 변수**에 영향을 줄 수 있어, 프로그램의 흐름을 조작하는 데 악용될 수 있습니다.
2. **제한된 메모리 조작**: 일반 버퍼 오버플로우에 비해 1바이트만 덮어쓸 수 있어, 제어가 더 어려운 대신 감지하기도 어렵습니다.
3. **악용 가능성**: 특정 상황에서 프로그램의 흐름을 바꾸거나 특정 플래그 값을 조작하는 데 사용할 수 있습니다.
### 방어 방법
- **경계 검사**: 배열 또는 버퍼의 크기를 엄격히 확인하여, **경계를 초과하지 않도록** 해야 합니다.
- **안전한 함수 사용**: `strncpy`, `snprintf`와 같은 안전한 함수들로 경계를 명시적으로 설정하여, 경계를 벗어나는 데이터 쓰기를 방지합니다.
**Off-by-one 취약점**은 작은 실수로 발생하지만, 잘못된 메모리 접근을 통해 **프로그램 보안에 큰 위협**이 될 수 있으므로 주의가 필요합니다.
소스코드 보러가자
#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 read_str(char *ptr, int size)
{
int len;
len = read(0, ptr, size);
printf("%d", len);
ptr[len] = '\0';
}
void get_shell()
{
system("/bin/sh");
}
int main()
{
char name[20];
int age = 1;
initialize();
printf("Name: ");
read_str(name, 20);
printf("Are you baby?");
if (age == 0)
{
get_shell();
}
else
{
printf("Ok, chance: \n");
read(0, name, 20);
}
return 0;
}
이 코드는 `age` 변수의 값을 변경해 `get_shell()` 함수를 실행하려는 목표로 **버퍼 오버플로우 취약점**을 가진 프로그램입니다. 전체적인 흐름과 취약점을 분석해 보겠습니다.
### 코드 분석
1. **초기 설정 - `initialize()` 함수**:
```c
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(30);
}
```
- 이 함수는 버퍼 설정을 비워 버퍼링 없이 입력과 출력을 즉시 처리하도록 설정합니다.
- 또한, `SIGALRM` 신호가 발생할 때 `alarm_handler()` 함수가 실행되도록 설정하고, **30초의 제한 시간을 설정**합니다. 제한 시간 내에 입력이 없으면 프로그램이 종료됩니다.
2. **입력 함수 - `read_str()`**:
```c
void read_str(char *ptr, int size) {
int len;
len = read(0, ptr, size);
printf("%d", len);
ptr[len] = '\0';
}
```
- 이 함수는 **`size` 바이트만큼 표준 입력에서 읽어** `ptr`이 가리키는 메모리 위치에 저장합니다.
- 이때 `ptr[len] = '\0';`을 통해 마지막 위치에 널 문자를 추가해 문자열을 마무리합니다.
- 버퍼의 경계 체크를 하지 않으므로 오버플로우 발생 가능성이 있습니다.
3. **핵심 로직 - `main()` 함수**:
```c
int main() {
char name[20];
int age = 1;
initialize();
printf("Name: ");
read_str(name, 20);
printf("Are you baby?");
if (age == 0) {
get_shell();
} else {
printf("Ok, chance: \n");
read(0, name, 20);
}
return 0;
}
```
- **`name` 배열**은 20바이트로 선언된 **로컬 버퍼**이고, **`age` 변수**는 `1`로 초기화되었습니다.
- `read_str(name, 20);` 함수로 **20바이트까지 입력을 받습니다**.
- 이후 `if (age == 0)` 조건문을 통해 `age`가 `0`인 경우 `get_shell()` 함수를 호출하여 **쉘을 실행**합니다. 하지만 `age`는 `1`로 초기화되어 있고, 프로그램 내에서 직접 변경하는 코드가 없습니다.
- 사용자가 `age` 값을 0으로 변경하는 오버플로우를 유도하면 `get_shell()`을 실행할 수 있습니다.
### 취약점 분석 및 공격 방법
- **버퍼 오버플로우 취약점**: `read_str(name, 20)`에서 `name` 배열에 20바이트를 초과해 입력하게 되면 `age` 변수가 있는 위치까지 덮어쓸 수 있습니다. 이로 인해 `age` 값을 **0으로 변경하여 조건문을 통과**할 수 있습니다.
- **공격 방법**:
- `name` 배열이 20바이트이므로, `name`에 20바이트 이상의 값을 입력하여 `age`의 값을 조작할 수 있습니다.
- 20바이트를 초과한 입력으로 `age`의 값을 `0`으로 덮어씁니다.
### 익스플로잇 예시
1. **입력으로 20바이트 이상의 데이터 전송**:
- 예를 들어, `name`에 20바이트의 패딩과 추가로 `0x00`을 전송하여 `age`를 0으로 만듭니다.
- 입력 예시 (파이썬):
```python
payload = b"A" * 20 + b"\x00" # 20바이트 패딩과 \x00으로 age를 0으로 설정
```
2. **명령 실행**:
- 페이로드가 성공적으로 `age`를 0으로 설정하면, `if (age == 0)` 조건이 참이 되어 `get_shell()` 함수가 호출되고, 쉘이 열립니다.
### 요약
이 프로그램은 `age` 변수를 1바이트 오버플로우하여 0으로 설정해 **쉘을 실행하는 취약점**을 가지고 있습니다. 이를 통해 버퍼 오버플로우 공격을 수행하여 `get_shell()`을 호출할 수 있습니다.
위 gdb main 함수 결과는 main 함수의 name배열과 age변수를 어셈블리로 분석한 것이다. sub sep,0x18을 통해 name 변수는 ebp와 24만큼 떨어져 있고 바로 아래 ebp-0x4에 1을 저장하므로 ebp-0x4가 age변수의 주소 임을 알 수 있다. 따라서 name 배열과 age 변수의 차이는 20바이트이고 read로 name 배열을 20바이트 만큼 채우면 21번째에 '\0'을 추가하므로 age가 0으로 덮어씌워진다. age가 0이면 get_shell()이 실행되므로 쉘을 획득할 수 있다.
출처 ㅣhttps://lemon-soju.tistory.com/29
'Dreamhack > Dreamhack Wargame (Challenge)' 카테고리의 다른 글
[68] IT 비전공자 [dreamhack][wargame.kr] strcmp문제 풀기 (0) | 2024.11.16 |
---|---|
[67] IT 비전공자 [dreamhack][wargame.kr] login filtering문제 풀기 (1) | 2024.11.15 |
[65] IT 비전공자 [dreamhack]cmd_center문제 풀기 (0) | 2024.11.13 |
[64] IT 비전공자 [dreamhack]ssp_000문제 풀기 (1) | 2024.11.12 |
[63] IT 비전공자 [dreamhack]CSRF Advanced문제 풀기 (3) | 2024.11.11 |