Ermir 是一个邪恶/流氓 RMI 注册表,它利用对调用其标准 RMI 方法(list()/lookup()/bind()/rebind()/unbind())的任何 Java 代码进行不安全反序列化的漏洞。
从 rubygems.org 安装 Ermir:
$ gem install ermir
或克隆仓库并构建 gem:
$ git clone https://github.com/hakivvi/ermir.git
$ rake install
Ermir 是一个 CLI gem,它附带两个 CLI 文件 ermir 和 gadgetmarshal,ermir 是实际的 gem,而后者只是 GadgetMarshaller.java 文件的一个漂亮接口,该文件重写了 Ysoserial 的 gadget 以匹配 MarshalInputStream 的要求,输出应通过管道传递给 ermir 或写入文件,若使用自定义 gadget,请使用 MarshalOutputStream 代替 ObjectOutputStream 将序列化对象写入输出流。
ermir 用法:
➜ ~ ermir
Ermir by @hakivvi * https://github.com/hakivvi/ermir.
信息:
Ermir 是一个流氓/邪恶 RMI 注册表,它利用对调用其标准 RMI 方法的任何 Java 代码进行不安全 Java 反序列化的漏洞。
用法:ermir [选项]
-l, --listen 将 RMI 注册表绑定到此 IP 和端口(默认:0.0.0.0:1099)。
-f, --file 包含要反序列化的 gadget 的文件路径。
-p, --pipe 从标准输入流读取序列化的 gadget。
-v, --version 打印 Ermir 版本。
-h, --help 打印选项帮助。
示例:
$ gadgetmarshal /path/to/ysoserial.jar Groovy1 calc.exe | ermir --listen 127.0.0.1:1099 --pipe
gadgetmarshal 用法:
➜ ~ gadgetmarshal
用法:gadgetmarshal /path/to/ysoserial.jar Gadget1 cmd (可选)/path/to/output/file
java.rmi.registry.Registry 提供了 5 个方法:list()、lookup()、bind()、rebind()、unbind():
public Remote lookup(String name):lookup() 根据名称在注册表中搜索绑定的对象,注册表返回一个 Remote 对象,该对象引用了被查找的远程对象,返回的对象通过 MarshalInputStream.readObject() 读取,它只是 ObjectInputStream 之上的另一层,基本上,在每个类/代理描述符(TC_CLASSDESC/TC_PROXYCLASSDESC)之后,它期望一个 URL,用于加载此类或代理类。这是与 jdk7u21 中修复的相同漏洞。(Ermir 不指定此 URL,因为只有旧版 Java 才易受攻击,而是写入 null)。由于 Ysoserial 的 gadget 使用 ObjectOutputStream 进行序列化,Ermir 使用 gadgetmarshal(它是 GadgetMarshaller.java 的包装器)来序列化指定的 gadget 以匹配 MarshalInputStream 的要求。


欢迎在 GitHub 上 https://github.com/hakivvi/ermir 提交错误报告和拉取请求。本项目旨在成为一个安全、欢迎协作的空间,贡献者应遵守行为准则。
此 gem 根据 MIT 许可证 以开源形式提供。
所有参与 Ermir 项目代码库、问题跟踪器、聊天室和邮件列表的互动者都应遵守行为准则。
public String[] list():list() 向注册表询问所有绑定的对象名称,而 String 类型不能替换为恶意 gadget,因为它不像普通对象,并且不是通过 readObject() 读取,而是通过 readUTF() 读取,但由于 list() 返回 String[],这是一个实际的对象,并且通过 readObject() 读取,Ermir 将 gadget 发送代替此 String[] 类型。

public void bind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2):bind() 将对象绑定到注册表中的一个名称,在 bind() 的情况下,返回类型是 void 且没有返回值,但如果注册表在 RMI 返回数据包中指定此返回是异常返回,则客户端/服务端客户端将调用 readObject(),尽管返回类型是 void,这就是注册表向其客户端发送异常的方式(通常是 java.lang.ClassNotFoundException),Ermir 将再次发送序列化的 gadget 代替合法的异常对象。

public void rebind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2):rebind() 用提供的远程引用替换传递名称的绑定,同样返回 void,Ermir 像 bind() 一样返回一个异常。
public void unbind(java.lang.String $param_String_1):unbind() 在 RMI 注册表中按名称解除远程对象的绑定,此方法也返回 void。