Ermir is an Evil/Rogue RMI Registry, it exploits unsecure deserialization on any Java code calling standard RMI methods on it (list()
/lookup()
/bind()
/rebind()
/unbind()
).
- Ruby v3 or newer.
Installation
Install Ermir from rubygems.org:
or clone the repo and build the gem:
$ git clone https://github.com/hakivvi/ermir.git
$ rake install
Usage
Ermir is a cli gem, it comes with 2 cli files ermir
and gadgetmarshal
, ermir
is the actual gem and the latter is just a pretty interface to GadgetMarshaller.java file which rewrites the gadgets of Ysoserial to match MarshalInputStream
requirements, the output should be then piped into ermir
or a file, in case of custom gadgets use MarshalOutputStream
instead of ObjectOutputStream
to write your serialized object to the output stream.
ermir
usage:
RMI Registry which exploits unsecure Java deserialization on any Java code calling standard RMI methods on it. Usage: ermir [options] -l, --listen bind the RMI Registry to this ip and port (default: 0.0.0.0:1099). -f, --file path to file containing the gadget to be deserialized. -p, --pipe read the serialized gadget from the standard input stream. -v, --version print Ermir version. -h, --help print options help. Example: $ gadgetmarshal /path/to/ysoserial.jar Groovy1 calc.exe | ermir --listen 127.0.0.1:1099 --pipe" dir="auto">
➜ ~ ermir
Ermir by @hakivvi * https://github.com/hakivvi/ermir.
Info:
Ermir is a Rogue/Evil RMI Registry which exploits unsecure Java deserialization on any Java code calling standard RMI methods on it.
Usage: ermir [options]
-l, --listen bind the RMI Registry to this ip and port (default: 0.0.0.0:1099).
-f, --file path to file containing the gadget to be deserialized.
-p, --pipe read the serialized gadget from the standard input stream.
-v, --version print Ermir version.
-h, --help print options help.
Example:
$ gadgetmarshal /path/to/ysoserial.jar Groovy1 calc.exe | ermir --listen 127.0.0.1:1099 --pipe
gadgetmarshal
usage:
➜ ~ gadgetmarshal
Usage: gadgetmarshal /path/to/ysoserial.jar Gadget1 cmd (optional)/path/to/output/file
How does it work?
java.rmi.registry.Registry
offers 5 methods: list()
, lookup()
, bind()
, rebind()
, unbind()
:
-
public Remote lookup(String name)
: lookup() searches for a bound object in the registry by its name, the registry returns aRemote
object which references the remote object that was looked up, the returned object is read usingMarshalInputStream.readObject()
which is just another layer on top ofObjectInputStream
, basically it excpects after each class/proxy descriptor (TC_CLASSDESC
/TC_PROXYCLASSDESC
) an URL that will be used to load this class or proxy class. this is the same wild bug that was fixed in jdk7u21. (Ermir does not specify this URL as only old Java version are vulnerable, instead it just write null). as Ysoserial gadgets are being serialized usingObjectOutputStream
, Ermir usesgadgetmarshal
-a wrapper around GadgetMarshaller.java- to serialize the specified gagdet to matchMarshalInputStream
requirements. -
public String[] list()
: list() asks the registry for all the bound objects names, whileString
type cannot be subsitued with a malicious gadget as it is not like any ordinary object and it is not read usingreadObject()
but ratherreadUTF()
, however aslist()
returnsString[]
which is an actual object and it is read usingreadObject()
, Ermir sends the gadget instead of thisString[]
type. -
public void bind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2)
: bind() binds an object to a name on the registry, in bind() case the return type isvoid
and there is nothing being returned, however if the registry specifies in the RMI return data packet that this return is an execptional return, the client/server client will callreadObject()
despite the return type isvoid
, this is how the regitry sends exceptions to its client (usuallyjava.lang.ClassNotFoundException
), once again Ermir will deliver the serialized gadget instead of a legitimate Exception object. -
public void rebind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2)
: rebind() replaces the binding of the passed name with the supplied remote reference, also returnsvoid
, Ermir returns an exception just like bind(). -
public void unbind(java.lang.String $param_String_1)
: unbind() unbinds a remote object by name in the RMI registry, this one also returnsvoid
.
PoC
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/hakivvi/ermir. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
License
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting in the Ermir project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.