* 本文作者:Ka1ier,本文属FreeBuf原创奖励计划,未经许可禁止转载
blueCMS介绍
个人认为,作为一个要入门代码审计的人,审计流程应该从简单到困难,逐步提升。因此我建议大家的审计流程为——DVWA——blueCMS——其他小众CMS——框架。同时做总结,搞清楚漏洞原理。好,进入正文!
blueCMS是一款小众的CMS,在2012年左右的时候,就有人发布其相关漏洞。但是,我个人感觉用blueCMS进行新手实战代码审计入门,是一个非常不错的选择。而我在进行blueCMS审计之前,网上也搜索了blueCMS的审计文章。那些文章可能都是你转过来,我转过去的,一般都是文章中只提到了两个漏洞,一个是位于根目录下的ad_js.php文件中,存在sql注入。
另一个就是,在common.fun.php中,自定义函数getip()可以伪造IP地址,造成注入。
而我,作为一个新手,很清楚新手在初学代码审计的时候,会遇到什么样的困惑,因此,决定花一些时间,认真记录下自己实战过程中的所见所闻所想,以及解决思路的方法。争取给新手一个非常全面的借鉴过程。
环境准备
BlueCMS v1.6 sp1
phpstudy php5.4.45+apache+mysql
操作系统 WIN7 64位 专业版
BlueCMS资源在i春秋上有一篇文章,上面有下载地址。其他的文章中出现的工具自己完全可以独立解决。因此文章中不再详述这部分内容。若不会搭建本地网站环境,百度一下即可。
开始实战!
代码审计有好几种办法,有人习惯于追踪数据流,有人习惯追踪危险函数,然后回溯。有人喜欢按功能点来进行审计。当然也有人直接通读全文。
我作为一个新手,按道理讲最好通读全文,熟悉架构。但是,我发现我的性格和习惯,更偏向于追踪数据流。俗话说,适合自己的才是最好的。因此,作为新手,读者应当结合自己的习惯,去进行代码审计。
我之所以选择追踪数据流,一方面是个人习惯,另一方面是因为余弦大佬曾经说过,web安全重点就三个词——“输入”,“输出”,“数据流”。
虽然我是追踪数据流,但是基本的网站结构该看还是要看的。因此,我做的第一件事,就是简单浏览网站目录结构。
实际上,很多情况下,根据命名,就可以猜出来这部分的文件具体是干嘛的了。比如admin文件夹,那么里面的文件肯定是和管理员的操作有关。include文件夹,里面肯定包含了一些常用的函数文件。
简单看完目录后,我会看主页的index.php,在看这个文件的同时,我还会打开它的网页,做到一边看代码,一边看网页的效果。这种方法可以让我们这些对代码不熟悉的新手脑海中可以构建相应的情景图。以后即使做渗透,也不会手足无措。
接着,我会打开主页index.php,“装模作样”的浏览一番。实际上,我也就是看看里面的注释罢了。。。。。因为在Index.php里面,往往不需要获取用户输入。之所以看它,是想知道在这个主页上,会引用哪些操作文件,一个网站的大概样子是啥样子。
比如说blueCMS中,根据主页,我就猜测,如果将一些xss语句存到数据库,那么他主页显示的时候,是不是就会有存储型xss呢?另外,主页还引入了一些文件,但是,我个人是没有去看的。个人习惯吧,尽管那本《代码审计:企业级web安全》中,建议大家是看看常用函数库文件,看看配置文件的。不过,我本人更喜欢在用到相关函数、相关配置的时候再去查看。
接下来,有两种审计思路,一种是通过点击网页,看网页如何跳转,来追踪审计。比如下面这幅图:
我一旦点击主页上的登录按钮,那么我就会跳转到user.php中,执行act=index_login的操作。那么这时候,你就可以打开相关的文件,查看该操作是如何进行的即可。
可以看到,先是获取了用户的输入,然后有的地方过滤了,有的地方没有。实际上,这里咋一看是好像存在漏洞,但是,当你仔细看的时候,就会发现UC_API,并且引用了client.php中的函数。可以这么说,由于我没有网站开发能力,导致我在看client.php中的一些函数时,是看不懂的。就比如下面这个,即使我知道是将那些参数全都传入UC_API_FUNC中,可是依旧不清楚返回值是什么类型。
"当你遇到问题的时候,就是你成长的契机"我非常喜欢这句话。同理,我们都是新手,初学代码审计,肯定很多东西看不懂。怎么办?这个问题会将一大批想学代码审计又没有开发背景的人刷下去。我们唯有硬啃,把这硬骨头啃碎了,才能继续下去,否则代码会读的昏昏沉沉。于是我通过搜索引擎查阅UC_API_FUNC知道,这个玩意儿是判断用户提交信息是否正确,然后返回正确情况下的uid。知道这个,目前来说,就够了。没必要再深入了。
我这里举这个例子,就是想让新手知道,初学代码审计,会有大批代码看不懂。死磕下去,才会看懂越来越多的代码。也为了以后审计逻辑漏洞打下基础。但是,也不能盲目死磕一个不会的点,这个度只能自己把握。
另外,由于我是追踪数据流的,所以我个人还有另外一种审计思路,就是不看网页,也不必刻意搞懂网站的整体架构。就一句话“我只关心用户输入”。
这种方法说的直白点,我就利用正则匹配,每个网页里面我都找到用户能控制的变量,一个一个的排查。优点就是不会像上面那种方法那样,漏掉一些页面。缺点就是,理清这个网站的结构有点麻烦。因为是追踪用户输入么,所以各种页面都要打开,很麻烦。
比如,在根目录下,我就看到了这些PHP文件,那么就挨个进去查有没有用户输入,没有就跳过。有就继续跟读。
恩,很巧,第一个就是那个网上流传很多的ad_js.php。那就先进去看看吧。先声明一下,我没抄袭别人啊,这篇文章就是自己原创的。(这个地方漏洞和利用方法很多人已经知道了,我只是凑巧就顺便写一下,写的全面一点。文章后面会有一些自己挖到了漏洞分享。)
虽说这里有过滤,但是他这过滤的是string型注入,而上面的sql语句压根不需要闭合。所以这里的过滤根本没用。就造成了int型注入。
简单验证一下,union select 1,2,3,4,5,6,7,发现到7的时候没报错。那么就可以在7这个位置构造语句。不过,不知道是不是我的这套blueCMS有问题,虽然存在注入,可是页面始终显示空白。估计应该是这套cms有地方没写好吧。具体的读者可以看别人的这方面文章,他们都在文章中详细写了这个漏洞。文章链接在我这篇文章快要结束的时候会提供。
按照这种找用户输入的方法,以此类推,继续下一个文件查看。
像上面这个文件,明显进行了过滤,用的还是白名单思想。这种情况,我们代码审计就可以节约时间了,这个文件也就这两个地方有输入,还对输入进行了非常好的过滤,inval()只获取变量的整数值。那么就可以直接跳过这个文件,不往下继续看了。节约时间成本。
又遇到了一种情况是什么呢?就是上面这幅图,明明$act没有过滤,是个可控变量,可是在这个文件中,并没有用到这个可控变量。那么,这就说明了两种情况,第一,这个文件在其他地方被引用。第二,程序员纯粹写着玩的。。。当然,我相信第一种情况是更有可能的。于是,我们可以这时候搜索一下看看到底哪些文件引用了这个文件。
在搜索之前,由于我记忆力不好,做了其他事情就会忘了之前要干嘛,因此,我还记录了笔记。我也建议新手审计的时候做标注,做笔记,否则除非你是有天赋的人,像我这样的普通人,真的会逻辑混乱,忘了前一个文件看到哪里。为什么要去找那个文件。我是谁?我为什么要打开这个文件?(或许我是提前进入老年痴呆了?手动滑稽)
于是乎,作为新手的我就在笔记上记录下这么一句话:
图片中你可能还会看到我写的其他记录,那是我之前审计这个cms时候写的。我就想告诉新手,这样可以让我们新手的思路更清晰一点。思维是要慢慢锻炼的,万事开头难。难归难,但是我们要掌握解决问题的方法。这或许也是一种黑客思维。
经过追踪发现,凡是涉及到category.php文件的相关文件,哪怕是html文件,无一例外的全都对name=act进行了赋值,这就导致了该文件中$act变量与xss是无缘了。
大家可以看到,基本上都是下图这种情况,提前在html页面中将name=act赋值,然后服务器端再获取,也是白名单思想。
而唯一的一个php文件引用了category.php,却还不涉及到$act变量。
于是乎,category.php中的那个可控变量也没啥用了。。。
这里再补充一下,虽然按照cms的逻辑来看,是没什么用了。但是,我要没记错的话,有种漏洞叫基于dom的XSS,是可以修改html元素的。那么,既然这套cms这个地方没有对页面的name=act进行过滤,那么假如,有基于dom的xss,攻击者随意修改了name=act的值,构造攻击语句,是不是就无法防御了呢?换句话说,利用其他漏洞来打出组合拳,那这个没过滤还是很危险的。无奈我知识储备有限,无法验证我的思路。故先在文章中写下来。等深入研究了XSS再做实践。
按照这样的思路,可以继续下一处追踪。
不过,如果你看到现在,还没发现我文章的问题,那么恭喜你,要么你没有审计过这套cms,要么你和我一样是新手。我前面写那么多,看似没过滤的变量,实际上往往在引用文件的地方就进行了过滤。
比如下面这幅图:
是不是觉得这里的$act也没过滤?然而事实却是在引入的common.inc.php中,早就进行了过滤。早就对$_GET,$_POST , $_REQUIREST ,$_COOKIES进行了过滤。但是,似乎还漏了一个$_SERVER。这个或许就会导致IP注入或XSS,前提是如果开发者将用户IP写入数据库或展现出来的话。
这里提出来是因为作为新手的我居然也忽略了过滤文件。。。都说过滤文件很重要,很重要,但是我实战中还是忽略了,还好反应过来。否则挖到一个漏洞,想复现就会遇到过滤问题。才会想到是否被过滤了,才会再回去查找,很麻烦。
而至于这里的过滤函数么,实际上就是判断传进来的数据是不是数组,要是数组,则遍历数组的每个值进行addslashes过滤,不是数组,则直接用addslashes进行过滤。虽然引用了过滤文件,但是明显是有可能突破的。假如开发者在某处执行sql语句的时候,拼接变量没有加单引号,那么int型注入就可以突破这种过滤。
其他的我这里就不一一叙述了。简单来说,我喜欢追踪数据流,虽然挖掘漏洞的速度没有那些按功能点审计,按危险函数回溯的方法快,而且对于自定义封装的函数来说,我容易忽略这类漏洞,比如这里的getip()明显有未过滤的情况,我却忽略了,但是,我喜欢,不是么?就好像读者们为什么喜欢学黑客呢?不就是因为喜欢么?
最后,分享一下我挖到的漏洞。由于blueCMS是我代码审计第一战,有不完善的地方,或错误的地方,也欢迎大神指出来。别喷我就是了。。。
漏洞分享
1.网站根目录下文件读取漏洞
在用户进行登录操作的时候,$from变量可控。奇怪的是,这里还进行了base64解码。showmsg函数功能如下:
当我看到这个assign的时候,我就有预感,这个可控变量还会在前端出现的。果不其然。我去登录页面进行登录,抓包。
我先构造了from参数的值为网站根目录下的另一个网站DVWA的登录主页,然后发包
在返回包中,可以看到经过我base64编码的值,成功解码,并且路径也成功的变成了网站根目录下的DVWA
再去看一下浏览器,成功读取到了DVWA的页面
再附上一张我自己电脑上的路径图片。
而我用这个漏洞,只能读取phpinfo页面。。。其他的文件读取的话(比如管理员界面),由于有session限制,没有权限读取。。。就会又跳转到管理员登录界面。
或许这个漏洞在大神眼中还可以有其他的利用姿势吧。。。
2.注册页面存在反射型XSS
这个反射型XSS黑盒测试是测不出来的。因为默认html中的name=from这个from的value是不提交的。从下面的代码中可以明显看到(部分我分析过的无用代码被我省略),程序的逻辑是在进入user.php中的时候,几乎是同时获取$act和$from的值,然后判断$act的值,来进行相应的操作。但是当$act的值为’reg‘,也就是注册的时候,他会将$from的值渲染到浏览器上。这也就导致了反射型XSS。
于是,我开始构造弹窗。虽然,在user.php中,一开始就引入了过滤操作,但是,只是用addslashes进行深度过滤罢了。要知道,在XSS中,转义字符的效果并不明显。
话说回来,我这个弹窗构造了一些时间,可能是因为我对XSS的研究不深入导致的吧。另外,以我目前的水平来看,这个XSS是黑盒测试测不出来的漏洞,为什么这么说呢?因为我理解的黑盒测试是从看到的参数中进行各种测试,而这个from默认在你访问注册操作的时候,是不提交的。from早就在访问user.php的时候提交了,提交的还是空值。必须要同时满足两个条件:1.访问user.php的时候,就已经提交了恶意请求。2.并且要与此同时访问注册页面。如果这两个页面无法同时满足,那么这个XSS就无法形成。
3.注册页面存在文件读取漏洞(原理同第一个漏洞一样)
在审计注册操作的同时,又偶然发现了一个文件读取漏洞,网站根目录下的文件还是可以任意读取,不过还是那个问题,就是有的页面判断session,你能有权限读取那个页面,但是无权利访问。有的网页能读取,但是无法渲染。。。这个洞有点鸡肋。
具体如何复现,参考我提供的第一个文件读取漏洞。一样的原理,一样的方法。只是出现的位置不同罢了。都是由于一个可控变量$from引起的。
4、编辑资料处出现存储型XSS
首先这个漏洞我们可以很清晰的找到输入出,但是输出在哪目前根据代码是看不出来的。依据尝试,个人资料处一般都可以看到自己的email地址,所以推断这个存储型XSS肯定有输出点。打开网页稍微浏览一下就找到了输出点。
只需要在编辑个人资料的地方,将email地址中填入最基本的<script>alert(1)</script>,便可以提交存储到服务器的数据库中。之前我在审计关于email这一栏的时候,他里面还用正则匹配做了过滤。可是到了后台这里,却没有再用正则匹配进行过滤,或许是因为程序员太累了吧。。。这就造成了存储型XSS漏洞。
这还没什么,关键是上面的代码仔细看的话,会发现大都没过滤,那么就可以用各种姿势的存储型XSS往里面插入。
msn也可以插入"><img src='' onerror=alert(1)>,插入之后,在点击编辑资料,那么就会直接出现弹窗。下图是我关闭弹窗之后的样子。生成的代码看我F12.
其他几个变量就不一个一个插入了。原理都是一样的。存储型XSS在这个页面泛滥。
5、ip地址伪造漏洞,还可以注入
这个漏洞,实际上其他文章里面都写了。。。我不知道自己再写一遍还算不算原创。。。我就说一下自己挖到这个洞的经历吧。我就是地毯式搜索用户输入,每个文件都看。一般在常用函数里面用户输入比较少,但是也存在这个可能性。结果一查看,还真找到了一个。
为了验证这个漏洞是否只是伪造IP,还是说又存在注入,就再去追踪这个函数。
结果第一个就发现可以伪造IP,但是这个还只是伪造IP
我看过的那篇文章中,利用这个点进行了注入,获取到了管理员信息。
原理我就简单说一下吧,毕竟这个洞别人都挖好了,还利用的很漂亮,以我的sql水准,在写这篇文章的时候,还想不到这样也能利用。不过技巧是学到了。
原理就是,既然getip()是可控的,那么只要在getip()处的输入为:
1','1'),('','6','2','1','6',(select concat(admin_name,':',pwd) from blue_admin),'1','1
那么1','1')就是完成第一次插入,后面的则是完成第二次插入。至于回显的位置,只能自己判断了。因为我的blueCMS有问题,很多功能无法实现,故这里没办法演示。
那篇文章地址我已经提供,感兴趣的可以去看看。
总结:
作为一个代码审计的新手,这虽然是我的第一次实战,但是,当我靠自己实力挖到第一个洞的时候(尽管不是高危0day,只是小漏洞),内心的喜悦是难以言表的。而我相信,代码审计,只要你有耐心,细心,恒心,你肯定能成为一个合格的代码审计人员。另外,freebuf作为一个高大上的平台,高水众多,但是新手应该也不会少。所以,我希望我的这篇文章能对和我一样刚入门代码审计的新手、或想入门PHP代码审计的人,有一定的帮助。欢迎讨论。
* 本文作者:Ka1ier,本文属FreeBuf原创奖励计划,未经许可禁止转载