#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
remote-method-guesser
A Java RMI Vulnerability Scanner
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
$ whoami
Tobias Neitzel
• Penetration tester and security
researcher at
• Former physicist in the field of
Lattice QCD
• Interested in RPC technologieslike
Java RMI, .NET Remoting, WCF,
Windows RPC, DCOM, …
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
What I'm Going to Talk About
• Motivation and Etymology
• Java RMI in a Nutshell
• Java RMI Vulnerabilities
• Application Level Attacks
 RMI Codebase Attacks
 Remote Binding (Localhost Bypass - CVE-2019-2684)
 JEP 290 and the Activation System
 JEP 290 Bypasses
 Remote Method Guessing and Method Invocation
 Application Level Deserialization Attacks
… and how to detect them with remote-method-guesser
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Motivation and Etymology
• Project started with the only purpose of guessing
remote methods  remote-method-guesser
• Learned a lot about RMI internals during
implementation. Noticed that several vulnerabilities are
missing tool support.
• Idea: Turn remote-method-guesser into a Java RMI
vulnerability scanner
Fig 1 - nmap scan identifying Java RMI endpoints
#BHUSA @BLACKHATEVENTS
Java RMI in a Nutshell
Tobias Neitzel @qtc_de
#BHUSA @BLACKHATEVENTS
Java RMI in a Nutshell
Tobias Neitzel @qtc_de
Server
#BHUSA @BLACKHATEVENTS
Java RMI in a Nutshell
Tobias Neitzel @qtc_de
Fig 2 – Example RMI implementation
Server
#BHUSA @BLACKHATEVENTS
Java RMI in a Nutshell
Tobias Neitzel @qtc_de
Instance
RemoteMath
new RemoteMath()
Listen: 0.0.0.0:4444
ObjID: 1234567890
Server
Fig 2 – Example RMI implementation
exportObject(instance, 4444)
#BHUSA @BLACKHATEVENTS
Java RMI in a Nutshell
Tobias Neitzel @qtc_de
Client
???
Server
Instance
RemoteMath
Listen: 0.0.0.0:4444
ObjID: 1234567890
#BHUSA @BLACKHATEVENTS
Java RMI in a Nutshell
Tobias Neitzel @qtc_de
magic version protocol opType objid opNum methodHash methodArgs
RMIMessage Structure:
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Server
Client
#BHUSA @BLACKHATEVENTS
Java RMI in a Nutshell
Tobias Neitzel @qtc_de
RMIMessage Structure:
Legacy
(nowadaysalways -1)
Constants
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Server
Client
version protocol opType objid opNum methodHash methodArgs
magic
#BHUSA @BLACKHATEVENTS
Java RMI in a Nutshell
Tobias Neitzel @qtc_de
sha(add(II)I)
(int)1
(int)2
RMIMessage Structure:
Legacy
(nowadaysalways -1)
Constants
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Server
Client
ArgumentTypes: int, int Return Type:int
magic version protocol opType objid opNum methodHash methodArgs
#BHUSA @BLACKHATEVENTS
Java RMI in a Nutshell
Tobias Neitzel @qtc_de
WhyObjIDs?
Instance
RemoteControl
Listen: 0.0.0.0:4444
ObjID: 0987654321
Allowsmultipleremote objects
to listen on the same port
RMIMessage Structure:
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Server
Client
version protocol opType objid opNum methodHash methodArgs
magic
#BHUSA @BLACKHATEVENTS
Java RMI in a Nutshell
Tobias Neitzel @qtc_de
RMIMessage Structure:
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Client Server
version protocol opType objid opNum methodHash methodArgs
magic
#BHUSA @BLACKHATEVENTS
Java RMI in a Nutshell
Tobias Neitzel @qtc_de
Instance
RMIRegistry
Listen: 0.0.0.0:1099
ObjID: 0
RMIMessage Structure:
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Client Server
version protocol opType objid opNum methodHash methodArgs
magic
#BHUSA @BLACKHATEVENTS
Java RMI in a Nutshell
Tobias Neitzel @qtc_de
HashMap<String,RemoteObj>
RMIMessage Structure:
Instance
RMIRegistry
Listen: 0.0.0.0:1099
ObjID: 0
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Client Server
version protocol opType objid opNum methodHash methodArgs
magic
#BHUSA @BLACKHATEVENTS
Java RMI in a Nutshell
Tobias Neitzel @qtc_de
IMath
0.0.0.0:4444:ObjID
math
bind("math", instance)
RMIMessage Structure:
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:1099
ObjID: 0
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Client Server
version protocol opType objid opNum methodHash methodArgs
magic
#BHUSA @BLACKHATEVENTS
Java RMI in a Nutshell
Tobias Neitzel @qtc_de
IMath 0.0.0.0:4444:ObjID
RMIMessage Structure:
IMath
0.0.0.0:4444:ObjID
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:1099
ObjID: 0
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Client Server
bind("math", instance)
math
IMath stub = lookup("math")
version protocol opType objid opNum methodHash methodArgs
magic
#BHUSA @BLACKHATEVENTS
Java RMI in a Nutshell
Tobias Neitzel @qtc_de
stub.add(1,1)
2
Fig 3 – Full RMI call example
RMIMessage Structure:
IMath
0.0.0.0:4444:ObjID
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:1099
ObjID: 0
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Client Server
bind("math", instance)
math
IMath stub = lookup("math")
IMath 0.0.0.0:4444:ObjID
version protocol opType objid opNum methodHash methodArgs
magic
#BHUSA @BLACKHATEVENTS
Java RMI Vulnerabilities
Tobias Neitzel @qtc_de
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Fig 4 – Example run of remote-method-guesser
• Example run of remote-method-guesser
• Docker images of vulnerable example servers can be found here:
https://github.com/qtc-de/remote-method-guesser/packages/414459
#BHUSA @BLACKHATEVENTS
Codebase Attacks
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:1099
ObjID: 0
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Client Server
Java RMI Vulnerabilities
Codebase Attacks
bind("math", instance)
math
IMath stub = lookup("math")
IMath 0.0.0.0:4444:ObjID
IMath
0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:1099
ObjID: 0
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Client Server
Java RMI Vulnerabilities
Codebase Attacks
I don'tknow IMath :(
bind("math", instance)
math
IMath stub = lookup("math")
IMath 0.0.0.0:4444:ObjID
IMath
0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Codebase Attacks
Fig 5 – Server side codebase illustration
Source: https://docs.oracle.com/javase/7/docs/technotes/guides/rmi/codebase.html
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Codebase Attacks
Fig 6 – Codebase detection of remote-method-guesser
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:1099
ObjID: 0
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Client Server
Java RMI Vulnerabilities
Codebase Attacks
SupportedMethods:
INumber add(INumber arg1, INumber arg2)
bind("math", instance)
math IMath
0.0.0.0:4444:ObjID
IMath stub = lookup("math")
IMath 0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:1099
ObjID: 0
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Client Server
Java RMI Vulnerabilities
Codebase Attacks
SupportedMethods:
stub.add( (MyNumber)a, (MyNumber)b)
2
I don'tknow MyNumber :(
bind("math", instance)
math IMath
0.0.0.0:4444:ObjID
SupportedMethods:
INumber add(INumber arg1, INumber arg2)
IMath stub = lookup("math")
IMath 0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Codebase Attacks
Fig 7 – Client side codebase illustration
Source: https://docs.oracle.com/javase/7/docs/technotes/guides/rmi/codebase.html
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Codebase Attacks
• Accepting client specified codebases was default behaviorup to 2011
• Misconfigurationstill possible (useCodebaseOnly=false), but often not
detected (nmap and metasploit modules focus on 2011 endpoints)
• For fully up to date RMI servers you usually need to know the signature
of a valid remote method or to attackfrom localhost (Details:
https://github.com/qtc-de/remote-method-guesser/blob/master/docs/rmg/actions.md#codebase-action )
Fig 7 – Client side codebase illustration
Source: https://docs.oracle.com/javase/7/docs/technotes/guides/rmi/codebase.html
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Codebase Attacks
Fig 8 – useCodebaseOnly detection of remote-method-guesser
• Even with useCodebaseOnly=false, exploitability depends on additionalfactors (SecurityManager)
 Status is Non Default instead of Vulnerable
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Codebase Attacks
Demo
#BHUSA @BLACKHATEVENTS
Localhost Bypass (CVE-2019-2684)
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Localhost Bypass(CVE-2019-2684)
• Reminder on how RMI servers bind objects to the RMI registry
Fig 9 – RMI bind operation
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:1099
ObjID: 0
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Server
bind("math", instance)
math IMath
0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Localhost Bypass(CVE-2019-2684)
• Reminder on how RMI servers bind objects to the RMI registry
• But who is actually allowed to bind?
Fig 9 – RMI bind operation
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Server
Listen: 0.0.0.0:1099
ObjID: 0
bind("math", instance)
math IMath
0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Localhost Bypass(CVE-2019-2684)
• Reminder on how RMI servers bind objects to the RMI registry
• But who is actually allowed to bind?
 localhost is!
• Each user on the same host as the registry can:
• Not a vulnerability, but by design
 Create new bound names
 Modify existing bound names
 Remove bound names
Fig 9 – RMI bind operation
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Server
Listen: 0.0.0.0:1099
ObjID: 0
bind("math", instance)
math IMath
0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Localhost Bypass(CVE-2019-2684)
• CVE-2019-2684let's you bypass the localhost restriction
#BHUSA @BLACKHATEVENTS
• CVE-2019-2684let's you bypass the localhost restriction
• Reminder on the RMI message structure:
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Localhost Bypass(CVE-2019-2684)
RMIMessage Structure:
Legacy
(nowadaysalways -1)
Constants
version protocol opType objid opNum methodHash methodArgs
magic
#BHUSA @BLACKHATEVENTS
• CVE-2019-2684let's you bypass the localhost restriction
• Reminder on the RMI message structure:
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Localhost Bypass(CVE-2019-2684)
Still used for remote objects that use Skeletons, e.g. rmi-registry
Fig 10 – Server side implementation of the bind operation.
Access checks are performed in the skeleton only.
https://github.com/openjdk/jdk/blob/master/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java#L247
RMIMessage Structure:
Legacy
(nowadaysalways -1)
Constants
version protocol opType objid opNum methodHash methodArgs
magic
#BHUSA @BLACKHATEVENTS
• CVE-2019-2684let's you bypass the localhost restriction
• Reminder on the RMI message structure:
• RMI registry can be called using both:The legacy andthe
moderncall technique
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Localhost Bypass(CVE-2019-2684)
Still used for remote objects that use Skeletons, e.g. rmi-registry
Fig 10 – Server side implementation of the bind operation.
Access checks are performed in the skeleton only.
https://github.com/openjdk/jdk/blob/master/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java#L247
RMIMessage Structure:
Legacy
(nowadaysalways -1)
Constants
version protocol opType objid opNum methodHash methodArgs
magic
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Localhost Bypass(CVE-2019-2684)
 Check for legacy call
 Handle legacy call via Skeleton – RMI registry calls are
intended to be handled here
 Continue with modern call (no skeleton – and no
accesscheckfor the RMI Registry :D)
How Java RMI decided when to use a Skeleton up to 2019
Fig 11 – How Java RMI decided when to use Skeletons
https://github.com/openjdk/jdk/blob/65db4f42d021444a7cff0f83a86a407a41b16da5/
src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java#L279
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Localhost Bypass(CVE-2019-2684)
Fig 12 – Localhost bypass detection of remote-method-guesser
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Demo
Localhost Bypass(CVE-2019-2684)
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Localhost Bypass(CVE-2019-2684)
Always use the Skeleton if one exists
Fig 13 – Localhost bypass fix
Localhost Bypass Fix
https://github.com/openjdk/jdk/blob/master/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java#L281
#BHUSA @BLACKHATEVENTS
JEP 290
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
#BHUSA @BLACKHATEVENTS
• Reminder on the RMI message structure:
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
JEP 290
RMIMessage Structure:
magic version protocol opType objid opNum methodHash methodArgs
#BHUSA @BLACKHATEVENTS
• Reminder on the RMI message structure:
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
JEP 290
RMIMessage Structure:
int short byte int
long - int - long - short
Compound:
int long
Serialized Java Objects
magic version protocol opType objid opNum methodHash methodArgs
#BHUSA @BLACKHATEVENTS
• Reminder on the RMI message structure:
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
JEP 290
RMIMessage Structure:
int short byte int
long - int - long - short
Compound:
int long
Fig 14 - How RMI arguments are unmarshaled (before 2020)
read by the RMI server
https://github.com/openjdk/jdk/blob/3789983e89c9de252ef546a1b98a732a7d066650
/src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java#L298
magic version protocol opType objid opNum methodHash methodArgs
Serialized Java Objects
#BHUSA @BLACKHATEVENTS
• Reminder on the RMI message structure:
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
JEP 290
RMIMessage Structure:
int short byte int
long - int - long - short
Compound:
int long
Fig 14 - How RMI arguments are unmarshaled (before 2020)
read by the RMI server
Deserialization Attacks
https://github.com/openjdk/jdk/blob/3789983e89c9de252ef546a1b98a732a7d066650
/src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java#L298
magic version protocol opType objid opNum methodHash methodArgs
Serialized Java Objects
#BHUSA @BLACKHATEVENTS
• Reminder on the RMI message structure:
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
JEP 290
RMIMessage Structure:
int short byte int
long - int - long - short
Compound:
int long
read by the RMI server
Fig 15 - How RMI arguments are unmarshaled (after 2020)
No Deserialization Attacks on Strings after 2020
https://github.com/openjdk/jdk/blob/master/src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java#L302
magic version protocol opType objid opNum methodHash methodArgs
Serialized Java Objects
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
JEP 290
• Deserializationattack surface on default remote objects:
RMI Registry
 publicvoid bind(Stringname, Remoteobj)
 publicvoid rebind(Stringname, Remote obj)
 publicvoid unbind(Stringname)
 publicString[] list()
 publicRemote lookup(Stringname)
DistributedGarbageCollector (DGC – Availableon each RMI endpoint)
 publicLease dirty(ObjID[] ids, longsequenceNum, Leaselease))
 publicvoid clean( ObjID[] ids, long sequenceNum, VMID vmid, boolean strong)
RMI Activator(ActivationSystem – Legacy Component)
 publicMarshalledObject activate(ActivationID id, boolean force)
Usable for deserialization attacks
Usable for deserialization attacks before 2020
Only callable from localhost
Callable from everywhere
Argument Legend Method Legend
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
JEP 290
• JEP 290 introduced deserializationfilters for the RMI Registry andthe DGC(not for the ActivationSystem)
• Corresponding remote-method-guesser enumeration:
Fig 16 – JEP290 and Activation System enumeration of remote-method-guesser
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Demo
JEP 290
#BHUSA @BLACKHATEVENTS
JEP 290 Bypasses
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
• The RMI Registry andthe DGCallow certain classes to get deserialized
 Filter bypasses are possible
Java RMI Vulnerabilities
JEP 290 Bypasses
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
JEP 290 Bypasses
• The RMI Registry andthe DGCallow certain classes to get deserialized
 Filter bypasses are possible
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:1099
ObjID: 0
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Server
Client
bind("math", instance)
math IMath
0.0.0.0:4444:ObjID
IMath stub = lookup("math")
IMath 0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
JEP 290 Bypasses
lookup(ysoserial.Payload)
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Server
Client
• The RMI Registry andthe DGCallow certain classes to get deserialized
 Filter bypasses are possible
Listen: 0.0.0.0:1099
ObjID: 0
bind("math", instance)
math
Exception
IMath
0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
JEP 290 Bypasses
Protected
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Server
Client
• The RMI Registry andthe DGCallow certain classes to get deserialized
 Filter bypasses are possible
Listen: 0.0.0.0:1099
ObjID: 0
bind("math", instance)
math
lookup(ysoserial.Payload)
Filtered!
IMath
0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Exception
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
JEP 290 Bypasses
Protected
JRMP Request
ysoserial.payload
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Server
Client
• The RMI Registry andthe DGCallow certain classes to get deserialized
 Filter bypasses are possible
Fig 17 - Outbound JRMP Bypass Schema
Listen: 0.0.0.0:1099
ObjID: 0
bind("math", instance)
math
lookup(bypass.Payload)
IMath
0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
JEP 290 Bypasses
• The RMI Registry andthe DGCallow certain classes to get deserialized
 Filter bypasses are possible
• JEP290 bypass enumeration – Uses the most recent bypass technique (discovered by @_tint0 in 2019):
Fig 18 – JEP290 bypass enumeration of remote-method-guesser
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
Demo
JEP 290 Bypasses
#BHUSA @BLACKHATEVENTS
Application Level
Attacks
Tobias Neitzel @qtc_de
Remote Method Guessing
#BHUSA @BLACKHATEVENTS
Remote Method Guessing
Tobias Neitzel @qtc_de
int add(intarg1, int arg2)
SupportedMethods:
• Reminder: Typical RMI call example
stub.add(1,1)
2
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:1099
ObjID: 0
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Client Server
bind("math", instance)
math IMath
0.0.0.0:4444:ObjID
IMath stub = lookup("math")
IMath 0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Remote Method Guessing
Tobias Neitzel @qtc_de
• Reminder: Typical RMI call example
• During blackbox assessments, you don’t know supported methods
???
SupportedMethods:
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Client Server
bind("math", instance)
math
int add(intarg1, int arg2)
Listen: 0.0.0.0:1099
ObjID: 0
IMath
0.0.0.0:4444:ObjID
IMath stub = lookup("math")
IMath 0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Remote Method Guessing
Tobias Neitzel @qtc_de
• Reminder: Typical RMI call example
• During blackbox assessments, you don’t know supported methods
• You may miss dangerous remote methods ???
int add(intarg1, int arg2)
String exec(String cmd)
SupportedMethods:
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Client Server
bind("math", instance)
math
Listen: 0.0.0.0:1099
ObjID: 0
IMath
0.0.0.0:4444:ObjID
IMath stub = lookup("math")
IMath 0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Remote Method Guessing
Tobias Neitzel @qtc_de
Fig 19 – Method Guessing Schema
• Reminder: Typical RMI call example
• During blackbox assessments, you don’t know supported methods
• You may miss dangerous remote methods
• Method Guessing:
stub.exec(canary)
SupportedMethods:
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Client Server
Exception
exists not exists
bind("math", instance)
math
Listen: 0.0.0.0:1099
ObjID: 0
int add(intarg1, int arg2)
String exec(String cmd)
IMath
0.0.0.0:4444:ObjID
IMath stub = lookup("math")
IMath 0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Fig 20 – Method guessing run of remote-method-guesser
https://github.com/qtc-de/remote-method-guesser/blob/master/docs/rmg/method-guessing.md
Remote Method Guessing
#BHUSA @BLACKHATEVENTS
• You may want to call methods in a regular way (e.g. String exec(String cmd) )
• remote-method-guessercando that:
• Server responses are ignored by default. Plugins can be used to process them:
https://github.com/qtc-de/remote-method-guesser/blob/master/docs/rmg/plugin-system.md
Tobias Neitzel @qtc_de
Fig 21 – Calling a method with remote-method-guesser
Remote Method Guessing
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Demo
Remote Method Guessing
#BHUSA @BLACKHATEVENTS
Application Level
Attacks
Tobias Neitzel @qtc_de
Application Level Deserialization
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
JEP 290 Bypasses
Protected
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Server
Client
• The RMI Registry andthe DGCare protected by deserialization filters
• Applicationlevel method calls aren't!
bind("math", instance)
math
Listen: 0.0.0.0:1099
ObjID: 0
IMath
0.0.0.0:4444:ObjID
IMath stub = lookup("math")
IMath 0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
JEP 290 Bypasses
Protected
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Server
Client
• The RMI Registry andthe DGCare protected by deserialization filters
• Applicationlevel method calls aren't!
stub.add(1,1)
2
bind("math", instance)
math
Listen: 0.0.0.0:1099
ObjID: 0
IMath
0.0.0.0:4444:ObjID
IMath stub = lookup("math")
IMath 0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Java RMI Vulnerabilities
JEP 290 Bypasses
Protected
HashMap<String,RemoteObj>
Instance
RMIRegistry
Listen: 0.0.0.0:4444
ObjID: 1234567890
Instance
RemoteMath
Server
Client
• The RMI Registry andthe DGCare protected by deserialization filters
• Applicationlevel method calls aren't!
• Attack requires non primitive argument types
2
int[] addMap(Map<int, int>arg)
SupportedMethods:
stub.addMap(ysoserial.payload)
Fig 22– Application Level Deserialization Schema
bind("math", instance)
math
Listen: 0.0.0.0:1099
ObjID: 0
IMath
0.0.0.0:4444:ObjID
IMath stub = lookup("math")
IMath 0.0.0.0:4444:ObjID
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Fig 23 – Exploiting application level deserialization with remote-method-guesser
Application Level Deserialization
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
Demo
Application Level Deserialization
#BHUSA @BLACKHATEVENTS
Thank You for Your Attention!
Tobias Neitzel @qtc_de
• https://github.com/qtc-de/remote-method-guesser [Tool itself]
• https://github.com/qtc-de/remote-method-guesser/packages/414459 [Example Server]
• https://github.com/qtc-de/remote-method-guesser/tree/master/docs [Documentation]
• https://mogwailabs.de/de/blog/2019/03/attacking-java-rmi-services-after-jep-290/ [JEP290 and Application Level Deserialization]
• https://mogwailabs.de/de/blog/2020/02/an-trinhs-rmi-registry-bypass/ [JEP290 Bypasses]
• https://i.blackhat.com/eu-19/Wednesday/eu-19-An-Far-Sides-Of-Java-Remote-Protocols.pdf [RMI Attack Surface Overview]
• https://github.com/openjdk/jdk/tree/master/src/java.rmi/share/classes [Java RMI Source Code]
• https://docs.oracle.com/javase/7/docs/technotes/guides/rmi/codebase.html [Remote Class Loading]
• https://labs.bishopfox.com/tech-blog/rmiscout [Method Guessing]
• https://github.com/qtc-de/remote-method-guesser/blob/master/docs/rmg/method-guessing.md [Method Guessing]
remote-method-guesser:
Java RMI:
#BHUSA @BLACKHATEVENTS
Tobias Neitzel @qtc_de
RMI Attack Surface - MindMap
Fig 24 – Attack Surface on Java RMI Endpoints

remote-method-guesser - BHUSA2021 Arsenal

  • 1.
  • 2.
    remote-method-guesser A Java RMIVulnerability Scanner #BHUSA @BLACKHATEVENTS Tobias Neitzel @qtc_de
  • 3.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de $ whoami Tobias Neitzel • Penetration tester and security researcher at • Former physicist in the field of Lattice QCD • Interested in RPC technologieslike Java RMI, .NET Remoting, WCF, Windows RPC, DCOM, …
  • 4.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de What I'm Going to Talk About • Motivation and Etymology • Java RMI in a Nutshell • Java RMI Vulnerabilities • Application Level Attacks  RMI Codebase Attacks  Remote Binding (Localhost Bypass - CVE-2019-2684)  JEP 290 and the Activation System  JEP 290 Bypasses  Remote Method Guessing and Method Invocation  Application Level Deserialization Attacks … and how to detect them with remote-method-guesser
  • 5.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Motivation and Etymology • Project started with the only purpose of guessing remote methods  remote-method-guesser • Learned a lot about RMI internals during implementation. Noticed that several vulnerabilities are missing tool support. • Idea: Turn remote-method-guesser into a Java RMI vulnerability scanner Fig 1 - nmap scan identifying Java RMI endpoints
  • 6.
    #BHUSA @BLACKHATEVENTS Java RMIin a Nutshell Tobias Neitzel @qtc_de
  • 7.
    #BHUSA @BLACKHATEVENTS Java RMIin a Nutshell Tobias Neitzel @qtc_de Server
  • 8.
    #BHUSA @BLACKHATEVENTS Java RMIin a Nutshell Tobias Neitzel @qtc_de Fig 2 – Example RMI implementation Server
  • 9.
    #BHUSA @BLACKHATEVENTS Java RMIin a Nutshell Tobias Neitzel @qtc_de Instance RemoteMath new RemoteMath() Listen: 0.0.0.0:4444 ObjID: 1234567890 Server Fig 2 – Example RMI implementation exportObject(instance, 4444)
  • 10.
    #BHUSA @BLACKHATEVENTS Java RMIin a Nutshell Tobias Neitzel @qtc_de Client ??? Server Instance RemoteMath Listen: 0.0.0.0:4444 ObjID: 1234567890
  • 11.
    #BHUSA @BLACKHATEVENTS Java RMIin a Nutshell Tobias Neitzel @qtc_de magic version protocol opType objid opNum methodHash methodArgs RMIMessage Structure: Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Server Client
  • 12.
    #BHUSA @BLACKHATEVENTS Java RMIin a Nutshell Tobias Neitzel @qtc_de RMIMessage Structure: Legacy (nowadaysalways -1) Constants Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Server Client version protocol opType objid opNum methodHash methodArgs magic
  • 13.
    #BHUSA @BLACKHATEVENTS Java RMIin a Nutshell Tobias Neitzel @qtc_de sha(add(II)I) (int)1 (int)2 RMIMessage Structure: Legacy (nowadaysalways -1) Constants Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Server Client ArgumentTypes: int, int Return Type:int magic version protocol opType objid opNum methodHash methodArgs
  • 14.
    #BHUSA @BLACKHATEVENTS Java RMIin a Nutshell Tobias Neitzel @qtc_de WhyObjIDs? Instance RemoteControl Listen: 0.0.0.0:4444 ObjID: 0987654321 Allowsmultipleremote objects to listen on the same port RMIMessage Structure: Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Server Client version protocol opType objid opNum methodHash methodArgs magic
  • 15.
    #BHUSA @BLACKHATEVENTS Java RMIin a Nutshell Tobias Neitzel @qtc_de RMIMessage Structure: Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Client Server version protocol opType objid opNum methodHash methodArgs magic
  • 16.
    #BHUSA @BLACKHATEVENTS Java RMIin a Nutshell Tobias Neitzel @qtc_de Instance RMIRegistry Listen: 0.0.0.0:1099 ObjID: 0 RMIMessage Structure: Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Client Server version protocol opType objid opNum methodHash methodArgs magic
  • 17.
    #BHUSA @BLACKHATEVENTS Java RMIin a Nutshell Tobias Neitzel @qtc_de HashMap<String,RemoteObj> RMIMessage Structure: Instance RMIRegistry Listen: 0.0.0.0:1099 ObjID: 0 Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Client Server version protocol opType objid opNum methodHash methodArgs magic
  • 18.
    #BHUSA @BLACKHATEVENTS Java RMIin a Nutshell Tobias Neitzel @qtc_de IMath 0.0.0.0:4444:ObjID math bind("math", instance) RMIMessage Structure: HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:1099 ObjID: 0 Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Client Server version protocol opType objid opNum methodHash methodArgs magic
  • 19.
    #BHUSA @BLACKHATEVENTS Java RMIin a Nutshell Tobias Neitzel @qtc_de IMath 0.0.0.0:4444:ObjID RMIMessage Structure: IMath 0.0.0.0:4444:ObjID HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:1099 ObjID: 0 Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Client Server bind("math", instance) math IMath stub = lookup("math") version protocol opType objid opNum methodHash methodArgs magic
  • 20.
    #BHUSA @BLACKHATEVENTS Java RMIin a Nutshell Tobias Neitzel @qtc_de stub.add(1,1) 2 Fig 3 – Full RMI call example RMIMessage Structure: IMath 0.0.0.0:4444:ObjID HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:1099 ObjID: 0 Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Client Server bind("math", instance) math IMath stub = lookup("math") IMath 0.0.0.0:4444:ObjID version protocol opType objid opNum methodHash methodArgs magic
  • 21.
    #BHUSA @BLACKHATEVENTS Java RMIVulnerabilities Tobias Neitzel @qtc_de
  • 22.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities Fig 4 – Example run of remote-method-guesser • Example run of remote-method-guesser • Docker images of vulnerable example servers can be found here: https://github.com/qtc-de/remote-method-guesser/packages/414459
  • 23.
    #BHUSA @BLACKHATEVENTS Codebase Attacks TobiasNeitzel @qtc_de Java RMI Vulnerabilities
  • 24.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:1099 ObjID: 0 Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Client Server Java RMI Vulnerabilities Codebase Attacks bind("math", instance) math IMath stub = lookup("math") IMath 0.0.0.0:4444:ObjID IMath 0.0.0.0:4444:ObjID
  • 25.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:1099 ObjID: 0 Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Client Server Java RMI Vulnerabilities Codebase Attacks I don'tknow IMath :( bind("math", instance) math IMath stub = lookup("math") IMath 0.0.0.0:4444:ObjID IMath 0.0.0.0:4444:ObjID
  • 26.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities Codebase Attacks Fig 5 – Server side codebase illustration Source: https://docs.oracle.com/javase/7/docs/technotes/guides/rmi/codebase.html
  • 27.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities Codebase Attacks Fig 6 – Codebase detection of remote-method-guesser
  • 28.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:1099 ObjID: 0 Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Client Server Java RMI Vulnerabilities Codebase Attacks SupportedMethods: INumber add(INumber arg1, INumber arg2) bind("math", instance) math IMath 0.0.0.0:4444:ObjID IMath stub = lookup("math") IMath 0.0.0.0:4444:ObjID
  • 29.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:1099 ObjID: 0 Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Client Server Java RMI Vulnerabilities Codebase Attacks SupportedMethods: stub.add( (MyNumber)a, (MyNumber)b) 2 I don'tknow MyNumber :( bind("math", instance) math IMath 0.0.0.0:4444:ObjID SupportedMethods: INumber add(INumber arg1, INumber arg2) IMath stub = lookup("math") IMath 0.0.0.0:4444:ObjID
  • 30.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities Codebase Attacks Fig 7 – Client side codebase illustration Source: https://docs.oracle.com/javase/7/docs/technotes/guides/rmi/codebase.html
  • 31.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities Codebase Attacks • Accepting client specified codebases was default behaviorup to 2011 • Misconfigurationstill possible (useCodebaseOnly=false), but often not detected (nmap and metasploit modules focus on 2011 endpoints) • For fully up to date RMI servers you usually need to know the signature of a valid remote method or to attackfrom localhost (Details: https://github.com/qtc-de/remote-method-guesser/blob/master/docs/rmg/actions.md#codebase-action ) Fig 7 – Client side codebase illustration Source: https://docs.oracle.com/javase/7/docs/technotes/guides/rmi/codebase.html
  • 32.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities Codebase Attacks Fig 8 – useCodebaseOnly detection of remote-method-guesser • Even with useCodebaseOnly=false, exploitability depends on additionalfactors (SecurityManager)  Status is Non Default instead of Vulnerable
  • 33.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities Codebase Attacks Demo
  • 34.
    #BHUSA @BLACKHATEVENTS Localhost Bypass(CVE-2019-2684) Tobias Neitzel @qtc_de Java RMI Vulnerabilities
  • 35.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities Localhost Bypass(CVE-2019-2684) • Reminder on how RMI servers bind objects to the RMI registry Fig 9 – RMI bind operation HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:1099 ObjID: 0 Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Server bind("math", instance) math IMath 0.0.0.0:4444:ObjID
  • 36.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities Localhost Bypass(CVE-2019-2684) • Reminder on how RMI servers bind objects to the RMI registry • But who is actually allowed to bind? Fig 9 – RMI bind operation HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Server Listen: 0.0.0.0:1099 ObjID: 0 bind("math", instance) math IMath 0.0.0.0:4444:ObjID
  • 37.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities Localhost Bypass(CVE-2019-2684) • Reminder on how RMI servers bind objects to the RMI registry • But who is actually allowed to bind?  localhost is! • Each user on the same host as the registry can: • Not a vulnerability, but by design  Create new bound names  Modify existing bound names  Remove bound names Fig 9 – RMI bind operation HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Server Listen: 0.0.0.0:1099 ObjID: 0 bind("math", instance) math IMath 0.0.0.0:4444:ObjID
  • 38.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities Localhost Bypass(CVE-2019-2684) • CVE-2019-2684let's you bypass the localhost restriction
  • 39.
    #BHUSA @BLACKHATEVENTS • CVE-2019-2684let'syou bypass the localhost restriction • Reminder on the RMI message structure: Tobias Neitzel @qtc_de Java RMI Vulnerabilities Localhost Bypass(CVE-2019-2684) RMIMessage Structure: Legacy (nowadaysalways -1) Constants version protocol opType objid opNum methodHash methodArgs magic
  • 40.
    #BHUSA @BLACKHATEVENTS • CVE-2019-2684let'syou bypass the localhost restriction • Reminder on the RMI message structure: Tobias Neitzel @qtc_de Java RMI Vulnerabilities Localhost Bypass(CVE-2019-2684) Still used for remote objects that use Skeletons, e.g. rmi-registry Fig 10 – Server side implementation of the bind operation. Access checks are performed in the skeleton only. https://github.com/openjdk/jdk/blob/master/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java#L247 RMIMessage Structure: Legacy (nowadaysalways -1) Constants version protocol opType objid opNum methodHash methodArgs magic
  • 41.
    #BHUSA @BLACKHATEVENTS • CVE-2019-2684let'syou bypass the localhost restriction • Reminder on the RMI message structure: • RMI registry can be called using both:The legacy andthe moderncall technique Tobias Neitzel @qtc_de Java RMI Vulnerabilities Localhost Bypass(CVE-2019-2684) Still used for remote objects that use Skeletons, e.g. rmi-registry Fig 10 – Server side implementation of the bind operation. Access checks are performed in the skeleton only. https://github.com/openjdk/jdk/blob/master/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java#L247 RMIMessage Structure: Legacy (nowadaysalways -1) Constants version protocol opType objid opNum methodHash methodArgs magic
  • 42.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities Localhost Bypass(CVE-2019-2684)  Check for legacy call  Handle legacy call via Skeleton – RMI registry calls are intended to be handled here  Continue with modern call (no skeleton – and no accesscheckfor the RMI Registry :D) How Java RMI decided when to use a Skeleton up to 2019 Fig 11 – How Java RMI decided when to use Skeletons https://github.com/openjdk/jdk/blob/65db4f42d021444a7cff0f83a86a407a41b16da5/ src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java#L279
  • 43.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities Localhost Bypass(CVE-2019-2684) Fig 12 – Localhost bypass detection of remote-method-guesser
  • 44.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities Demo Localhost Bypass(CVE-2019-2684)
  • 45.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities Localhost Bypass(CVE-2019-2684) Always use the Skeleton if one exists Fig 13 – Localhost bypass fix Localhost Bypass Fix https://github.com/openjdk/jdk/blob/master/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java#L281
  • 46.
    #BHUSA @BLACKHATEVENTS JEP 290 TobiasNeitzel @qtc_de Java RMI Vulnerabilities
  • 47.
    #BHUSA @BLACKHATEVENTS • Reminderon the RMI message structure: Tobias Neitzel @qtc_de Java RMI Vulnerabilities JEP 290 RMIMessage Structure: magic version protocol opType objid opNum methodHash methodArgs
  • 48.
    #BHUSA @BLACKHATEVENTS • Reminderon the RMI message structure: Tobias Neitzel @qtc_de Java RMI Vulnerabilities JEP 290 RMIMessage Structure: int short byte int long - int - long - short Compound: int long Serialized Java Objects magic version protocol opType objid opNum methodHash methodArgs
  • 49.
    #BHUSA @BLACKHATEVENTS • Reminderon the RMI message structure: Tobias Neitzel @qtc_de Java RMI Vulnerabilities JEP 290 RMIMessage Structure: int short byte int long - int - long - short Compound: int long Fig 14 - How RMI arguments are unmarshaled (before 2020) read by the RMI server https://github.com/openjdk/jdk/blob/3789983e89c9de252ef546a1b98a732a7d066650 /src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java#L298 magic version protocol opType objid opNum methodHash methodArgs Serialized Java Objects
  • 50.
    #BHUSA @BLACKHATEVENTS • Reminderon the RMI message structure: Tobias Neitzel @qtc_de Java RMI Vulnerabilities JEP 290 RMIMessage Structure: int short byte int long - int - long - short Compound: int long Fig 14 - How RMI arguments are unmarshaled (before 2020) read by the RMI server Deserialization Attacks https://github.com/openjdk/jdk/blob/3789983e89c9de252ef546a1b98a732a7d066650 /src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java#L298 magic version protocol opType objid opNum methodHash methodArgs Serialized Java Objects
  • 51.
    #BHUSA @BLACKHATEVENTS • Reminderon the RMI message structure: Tobias Neitzel @qtc_de Java RMI Vulnerabilities JEP 290 RMIMessage Structure: int short byte int long - int - long - short Compound: int long read by the RMI server Fig 15 - How RMI arguments are unmarshaled (after 2020) No Deserialization Attacks on Strings after 2020 https://github.com/openjdk/jdk/blob/master/src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java#L302 magic version protocol opType objid opNum methodHash methodArgs Serialized Java Objects
  • 52.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities JEP 290 • Deserializationattack surface on default remote objects: RMI Registry  publicvoid bind(Stringname, Remoteobj)  publicvoid rebind(Stringname, Remote obj)  publicvoid unbind(Stringname)  publicString[] list()  publicRemote lookup(Stringname) DistributedGarbageCollector (DGC – Availableon each RMI endpoint)  publicLease dirty(ObjID[] ids, longsequenceNum, Leaselease))  publicvoid clean( ObjID[] ids, long sequenceNum, VMID vmid, boolean strong) RMI Activator(ActivationSystem – Legacy Component)  publicMarshalledObject activate(ActivationID id, boolean force) Usable for deserialization attacks Usable for deserialization attacks before 2020 Only callable from localhost Callable from everywhere Argument Legend Method Legend
  • 53.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities JEP 290 • JEP 290 introduced deserializationfilters for the RMI Registry andthe DGC(not for the ActivationSystem) • Corresponding remote-method-guesser enumeration: Fig 16 – JEP290 and Activation System enumeration of remote-method-guesser
  • 54.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities Demo JEP 290
  • 55.
    #BHUSA @BLACKHATEVENTS JEP 290Bypasses Tobias Neitzel @qtc_de Java RMI Vulnerabilities
  • 56.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de • The RMI Registry andthe DGCallow certain classes to get deserialized  Filter bypasses are possible Java RMI Vulnerabilities JEP 290 Bypasses
  • 57.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities JEP 290 Bypasses • The RMI Registry andthe DGCallow certain classes to get deserialized  Filter bypasses are possible HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:1099 ObjID: 0 Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Server Client bind("math", instance) math IMath 0.0.0.0:4444:ObjID IMath stub = lookup("math") IMath 0.0.0.0:4444:ObjID
  • 58.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities JEP 290 Bypasses lookup(ysoserial.Payload) HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Server Client • The RMI Registry andthe DGCallow certain classes to get deserialized  Filter bypasses are possible Listen: 0.0.0.0:1099 ObjID: 0 bind("math", instance) math Exception IMath 0.0.0.0:4444:ObjID
  • 59.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities JEP 290 Bypasses Protected HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Server Client • The RMI Registry andthe DGCallow certain classes to get deserialized  Filter bypasses are possible Listen: 0.0.0.0:1099 ObjID: 0 bind("math", instance) math lookup(ysoserial.Payload) Filtered! IMath 0.0.0.0:4444:ObjID
  • 60.
    #BHUSA @BLACKHATEVENTS Exception Tobias Neitzel@qtc_de Java RMI Vulnerabilities JEP 290 Bypasses Protected JRMP Request ysoserial.payload HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Server Client • The RMI Registry andthe DGCallow certain classes to get deserialized  Filter bypasses are possible Fig 17 - Outbound JRMP Bypass Schema Listen: 0.0.0.0:1099 ObjID: 0 bind("math", instance) math lookup(bypass.Payload) IMath 0.0.0.0:4444:ObjID
  • 61.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities JEP 290 Bypasses • The RMI Registry andthe DGCallow certain classes to get deserialized  Filter bypasses are possible • JEP290 bypass enumeration – Uses the most recent bypass technique (discovered by @_tint0 in 2019): Fig 18 – JEP290 bypass enumeration of remote-method-guesser
  • 62.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities Demo JEP 290 Bypasses
  • 63.
    #BHUSA @BLACKHATEVENTS Application Level Attacks TobiasNeitzel @qtc_de Remote Method Guessing
  • 64.
    #BHUSA @BLACKHATEVENTS Remote MethodGuessing Tobias Neitzel @qtc_de int add(intarg1, int arg2) SupportedMethods: • Reminder: Typical RMI call example stub.add(1,1) 2 HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:1099 ObjID: 0 Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Client Server bind("math", instance) math IMath 0.0.0.0:4444:ObjID IMath stub = lookup("math") IMath 0.0.0.0:4444:ObjID
  • 65.
    #BHUSA @BLACKHATEVENTS Remote MethodGuessing Tobias Neitzel @qtc_de • Reminder: Typical RMI call example • During blackbox assessments, you don’t know supported methods ??? SupportedMethods: HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Client Server bind("math", instance) math int add(intarg1, int arg2) Listen: 0.0.0.0:1099 ObjID: 0 IMath 0.0.0.0:4444:ObjID IMath stub = lookup("math") IMath 0.0.0.0:4444:ObjID
  • 66.
    #BHUSA @BLACKHATEVENTS Remote MethodGuessing Tobias Neitzel @qtc_de • Reminder: Typical RMI call example • During blackbox assessments, you don’t know supported methods • You may miss dangerous remote methods ??? int add(intarg1, int arg2) String exec(String cmd) SupportedMethods: HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Client Server bind("math", instance) math Listen: 0.0.0.0:1099 ObjID: 0 IMath 0.0.0.0:4444:ObjID IMath stub = lookup("math") IMath 0.0.0.0:4444:ObjID
  • 67.
    #BHUSA @BLACKHATEVENTS Remote MethodGuessing Tobias Neitzel @qtc_de Fig 19 – Method Guessing Schema • Reminder: Typical RMI call example • During blackbox assessments, you don’t know supported methods • You may miss dangerous remote methods • Method Guessing: stub.exec(canary) SupportedMethods: HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Client Server Exception exists not exists bind("math", instance) math Listen: 0.0.0.0:1099 ObjID: 0 int add(intarg1, int arg2) String exec(String cmd) IMath 0.0.0.0:4444:ObjID IMath stub = lookup("math") IMath 0.0.0.0:4444:ObjID
  • 68.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Fig 20 – Method guessing run of remote-method-guesser https://github.com/qtc-de/remote-method-guesser/blob/master/docs/rmg/method-guessing.md Remote Method Guessing
  • 69.
    #BHUSA @BLACKHATEVENTS • Youmay want to call methods in a regular way (e.g. String exec(String cmd) ) • remote-method-guessercando that: • Server responses are ignored by default. Plugins can be used to process them: https://github.com/qtc-de/remote-method-guesser/blob/master/docs/rmg/plugin-system.md Tobias Neitzel @qtc_de Fig 21 – Calling a method with remote-method-guesser Remote Method Guessing
  • 70.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Demo Remote Method Guessing
  • 71.
    #BHUSA @BLACKHATEVENTS Application Level Attacks TobiasNeitzel @qtc_de Application Level Deserialization
  • 72.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities JEP 290 Bypasses Protected HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Server Client • The RMI Registry andthe DGCare protected by deserialization filters • Applicationlevel method calls aren't! bind("math", instance) math Listen: 0.0.0.0:1099 ObjID: 0 IMath 0.0.0.0:4444:ObjID IMath stub = lookup("math") IMath 0.0.0.0:4444:ObjID
  • 73.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities JEP 290 Bypasses Protected HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Server Client • The RMI Registry andthe DGCare protected by deserialization filters • Applicationlevel method calls aren't! stub.add(1,1) 2 bind("math", instance) math Listen: 0.0.0.0:1099 ObjID: 0 IMath 0.0.0.0:4444:ObjID IMath stub = lookup("math") IMath 0.0.0.0:4444:ObjID
  • 74.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Java RMI Vulnerabilities JEP 290 Bypasses Protected HashMap<String,RemoteObj> Instance RMIRegistry Listen: 0.0.0.0:4444 ObjID: 1234567890 Instance RemoteMath Server Client • The RMI Registry andthe DGCare protected by deserialization filters • Applicationlevel method calls aren't! • Attack requires non primitive argument types 2 int[] addMap(Map<int, int>arg) SupportedMethods: stub.addMap(ysoserial.payload) Fig 22– Application Level Deserialization Schema bind("math", instance) math Listen: 0.0.0.0:1099 ObjID: 0 IMath 0.0.0.0:4444:ObjID IMath stub = lookup("math") IMath 0.0.0.0:4444:ObjID
  • 75.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Fig 23 – Exploiting application level deserialization with remote-method-guesser Application Level Deserialization
  • 76.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de Demo Application Level Deserialization
  • 77.
    #BHUSA @BLACKHATEVENTS Thank Youfor Your Attention! Tobias Neitzel @qtc_de • https://github.com/qtc-de/remote-method-guesser [Tool itself] • https://github.com/qtc-de/remote-method-guesser/packages/414459 [Example Server] • https://github.com/qtc-de/remote-method-guesser/tree/master/docs [Documentation] • https://mogwailabs.de/de/blog/2019/03/attacking-java-rmi-services-after-jep-290/ [JEP290 and Application Level Deserialization] • https://mogwailabs.de/de/blog/2020/02/an-trinhs-rmi-registry-bypass/ [JEP290 Bypasses] • https://i.blackhat.com/eu-19/Wednesday/eu-19-An-Far-Sides-Of-Java-Remote-Protocols.pdf [RMI Attack Surface Overview] • https://github.com/openjdk/jdk/tree/master/src/java.rmi/share/classes [Java RMI Source Code] • https://docs.oracle.com/javase/7/docs/technotes/guides/rmi/codebase.html [Remote Class Loading] • https://labs.bishopfox.com/tech-blog/rmiscout [Method Guessing] • https://github.com/qtc-de/remote-method-guesser/blob/master/docs/rmg/method-guessing.md [Method Guessing] remote-method-guesser: Java RMI:
  • 78.
    #BHUSA @BLACKHATEVENTS Tobias Neitzel@qtc_de RMI Attack Surface - MindMap Fig 24 – Attack Surface on Java RMI Endpoints