今天选择了一个比较小的CMS---消息果吐槽,尝试审计一下:
源码地址:https://7alk.com/index.php
首先下载并且在虚拟机安装网站:
安装之后是这样的,先熟悉一下功能:主要功能有留言和评论留言、以及管理员登录对留言进行处理(回复、删除、隐藏),咳!!比较简单,刚开始学习还是先找简单点的练手吧。看到这个留言功能,我就先在心里多念叨了一下XSS。
然后来看一下文件目录,这里需要提示的是:一般我们应该先安装完网站再把网站文件在sublime或者审计应用中打开,因为网站在安装的过程中可能会生成新的文件。这是一个小经验吧。
好吧,就这么大,其中
index.php属于前端显示+入口文件
Page.php 主要是对于留言页码的控制
Cfg.php 主要是基础配置如数据库路径、session赋值、基本路径
App.php 主要存放各种自定义的函数
Mail.php 主要是对于留言者邮箱的处理,支持邮件的发送,但是我安装测试的时候并没有发送邮件这一功能
Ajax.php 主要的控制文件,接受index主页的参数传入,根据传入的get或是post参数的不同进行不同的处理
db文件是空的 应该和数据库有关,但是是空的我就不知道怎么回事了
Style 主要是样式,美化的,不用多看
我感觉审计CMS有一个问题比较难受:就是经常无法将代码和网站的实际位置功能对应起来,就是代码找到了可能有问题的地方,但是实际想去测试却找不到在那个功能点,或者请求哪个网站页面。对此我的办法就是使用burp抓包。
我们从主页index.php发送一条留言请求:
发现第一个请求文件是ajax.php,然后从这个入口文件开始通读:
<?php require_once 'app.php'; $c = isset($_GET['act'])?$_GET['act']:''; //c = act 未过滤 $t = isset($_POST['text'])?$_POST['text']:''; //t == text 未过滤 $p = isset($_GET['p'])?intval($_GET['p']):1; //intval()这个函数是将参数转化为整型的,有这个函数过滤,这个参数一般就不能进行SQL注入了 后来我查了一下这个参数的绕过,但是比较繁琐会有%00截断,但是绕过无关SQL注入 $id = isset($_GET['id'])?intval($_GET['id']):0; $db = new DbHelpClass(); switch ($c) { case "login": $pass = $_POST['pass']; //尝试伪造管理员登录?act=login&pass=md5(KEY.$pass) if($config['pass'] == md5(KEY.$pass)){ //$config这个值是可以从数据取得 应该是个固定值 此处应该管理员验证是将post获取的值与数据库取出的值比较,暂时没想到什么利用方法 $_SESSION[KEY.'admin'] = 1; logmsg(1,'登录成功'); }else{ logmsg(0,'登录失败'); } break;
下面是各种case情形:获取的act参数的值 /app/class/ajax.php?act=logout退出/login登录/vcode验证码/new最新留言/add留言加到数据库/locker隐藏评论/top置顶评论/del删除/mail回复留言
一般我会粗略的读一读这些代码,将可能的地方注释标记,主要侧重点在是否对于参数有过滤、危险函数、数据库操作、身份验证等等
ajax.php开头包含了app.php,翻翻看看全是自定义的一些函数:
function get_config() //要是没有config值,从数据库取出一个默认的config赋值 function hide() //判断是否为管理员 function ckadm() //不是管理员 返回未登录消息 function logmsg() //服务器返回消息和状态码的函数 function view_ip() //获取管理员邮箱+ip地址 function view_content() //管理员登录审核留言 function get_ip() //从请求头中获取ip地址 function get_captch() //这个函数应该和验证码相关 function timeago() //这个是留言计时的 function arr_sql($tab, $run, $arr) //往数据库的$tab表中插入或者更新消息 (特别关注可能存在的注入) class DbHelpClass //初始化的一个数据库连接操作 function total($sql,$params=array())//求总记录数目 function runsql($sql, $params = array()) //数据库中添加留言 PDO方式 function getdata($sql, $params = array()) //读取数据库留言 PDO方式
一开始我有一个困惑是$config,这个参数是如何赋值的,因为我观察上面的代码,找了一会才发现,它是从数据库取到的,但是取得过程我们无法控制,也不能传入参数
function get_config() //要是没有config值,从数据库取出一个赋值 { $db = new DbHelpClass(); if (empty($_SESSION[KEY . 'config'])) { $rs = $db->getdata("select * from `config` where id=1"); $config = $rs[0]; $_SESSION[KEY . 'config'] = $rs[0]; } else { $config = $_SESSION[KEY . 'config']; } return $config; }
我想去数据库里执行 select * from `config` where id=1 看看config的值是什么格式,但是我用PHPmyadmin打开竟然没有找到数据库,这就神了。。。但是我的留言确实可以持续显示
接着ajax.php往下走:
case "new": //?act=new&r= $list = $db->getdata("select * from `content` order by top desc,lastime desc limit 0,$id"); //乍一看可能存在limit注入,但是想到上面intval($_GET['id'])的过滤,此处就无法利用了
下面这个地方尝试绕过XSS,但是没成功:
case "add": //?act=add&author=xss $arr['content'] = strip_tags(trim($_POST['content'])); //strip_tags()剥离HTML标签 $vcode = strtolower(trim($_POST['vcode'])); if($config['captch'] == 1 and $vcode != $_SESSION[KEY . 'captch'] and ADMIN==0){ logmsg(0,'验证码错误!'); } $arr['author'] = ADMIN?$config['author']:mb_substr(strip_tags(trim($_POST['author'])),0,20,'utf-8'); if(empty($arr['author'])){$arr['author'] ='匿名网友';} $arr['mail'] = strip_tags(trim($_POST['mail'])); //strip_tags()函数剥除HTML标签 而且邮箱这个地方有长度限制 if(!empty($arr['mail']) && filter_var($arr['mail'], FILTER_VALIDATE_EMAIL)==false){ logmsg(0,'Email格式错误!'); } $arr['ip'] = get_ip(); //ip是从请求头部分获取的 $arr['lock'] = ADMIN?0:$config['lock']; //ip在前端没有找到回显的地方 $arr['parent'] = $id; $arr['aid'] = ADMIN; $sql = arr_sql('content','insert',$arr); //content表中插入内容 setcookie('pname',$arr['author'],time()+3600*24*30,'/'); setcookie('pmail',$arr['mail'],time()+3600*24*30,'/'); $b = $db->runsql($sql,$arr); $_SESSION[KEY.'add'] = $arr; //$_SESSION[KEY.'mail'] = $arr['mail']; if($arr['parent']>0){$db->runsql("update `content` set lastime=:lastime where id=:id",array('lastime'=>date('Y-m-d H:i:s'),'id'=>$id));} //$id经过了intval()过滤 绝了 logmsg($b,$arr); break;
后面一堆数据库找不到我就很难受,总的来说这次审计做的不太成功,但是确实学到了不少经验,比如拿到一个CMS,如何着手一步步来,怎么使用审计工具查各种参数和函数,各种函数的功能怎么去记忆(好记性不如烂笔头,在自定义函数旁边做注释是个不错的选择),PHP封装好的各种函数(看到陌生的就去菜鸟教程查,一定不能懒,一个地方看不懂,后面流程就会越来越乱,最后就不知道他的函数在做什么了,脑子就会开始烦躁。。。),