java.rmi.security.server-dangerous-object-deserialization.server-dangerous-object-deserialization

Verifed by r2c
Community Favorite
profile photo of semgrepsemgrep
Author
98,168
Download Count*

Using an arbitrary object ('$PARAMTYPE $PARAM') with Java RMI is an insecure deserialization vulnerability. This object can be manipulated by a malicious actor allowing them to execute code on your system. Instead, use an integer ID to look up your object, or consider alternative serialization schemes such as JSON.

Run Locally

Run in CI

Defintion

rules:
  - id: server-dangerous-object-deserialization
    severity: ERROR
    metadata:
      cwe:
        - "CWE-502: Deserialization of Untrusted Data"
      owasp:
        - A08:2017 - Insecure Deserialization
        - A08:2021 - Software and Data Integrity Failures
      references:
        - https://frohoff.github.io/appseccali-marshalling-pickles/
        - https://book.hacktricks.xyz/network-services-pentesting/1099-pentesting-java-rmi
        - https://youtu.be/t_aw1mDNhzI
        - https://github.com/qtc-de/remote-method-guesser
        - https://github.com/openjdk/jdk/blob/master/src/java.rmi/share/classes/sun/rmi/server/UnicastRef.java#L303C4-L331
      category: security
      technology:
        - rmi
      cwe2022-top25: true
      cwe2021-top25: true
      subcategory:
        - audit
      likelihood: LOW
      impact: HIGH
      confidence: LOW
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - "Insecure Deserialization "
    message: Using an arbitrary object ('$PARAMTYPE $PARAM') with Java RMI is an
      insecure deserialization vulnerability. This object can be manipulated by
      a malicious actor allowing them to execute code on your system. Instead,
      use an integer ID to look up your object, or consider alternative
      serialization schemes such as JSON.
    languages:
      - java
    patterns:
      - pattern: |
          interface $INTERFACE extends Remote {
            $RETURNTYPE $METHOD($PARAMTYPE $PARAM) throws RemoteException;
          }
      - metavariable-pattern:
          metavariable: $PARAMTYPE
          language: generic
          patterns:
            - pattern-not: String
            - pattern-not: java.lang.String
            - pattern-not: boolean
            - pattern-not: Boolean
            - pattern-not: java.lang.Boolean
            - pattern-not: byte
            - pattern-not: Byte
            - pattern-not: java.lang.Byte
            - pattern-not: char
            - pattern-not: Character
            - pattern-not: java.lang.Character
            - pattern-not: double
            - pattern-not: Double
            - pattern-not: java.lang.Double
            - pattern-not: float
            - pattern-not: Float
            - pattern-not: java.lang.Float
            - pattern-not: int
            - pattern-not: Integer
            - pattern-not: java.lang.Integer
            - pattern-not: long
            - pattern-not: Long
            - pattern-not: java.lang.Long
            - pattern-not: short
            - pattern-not: Short
            - pattern-not: java.lang.Short

Examples

server-dangerous-object-deserialization.java

// cf. https://mogwailabs.de/blog/2019/03/attacking-java-rmi-services-after-jep-290/

package de.mogwailabs.BSidesRMIService;

import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;

import java.rmi.Remote;
import java.rmi.RemoteException;

// ruleid:server-dangerous-object-deserialization
public interface IBSidesService extends Remote {
   boolean registerTicket(String ticketID) throws RemoteException;
   void vistTalk(String talkID) throws RemoteException;
   void poke(Object attende) throws RemoteException;
}

// ruleid:server-dangerous-object-deserialization
public interface IBSidesService extends Remote {
   boolean registerTicket(String ticketID) throws RemoteException;
   void vistTalk(String talkID) throws RemoteException;
   void poke(StringBuilder attende) throws RemoteException;
}

// ok:server-dangerous-object-deserialization
public interface IBSidesServiceOK extends Remote {
   boolean registerTicket(String ticketID) throws RemoteException;
   void vistTalk(String talkID) throws RemoteException;
   void poke(int attende) throws RemoteException;
}

// ok:server-dangerous-object-deserialization
public interface IBSidesServiceOK extends Remote {
   boolean registerTicket(String ticketID) throws RemoteException;
   void vistTalk(String talkID) throws RemoteException;
   void poke(Integer attende) throws RemoteException;
}

public class BSidesServer {
    public static void main(String[] args) {
        try {
            // Create new RMI registry to which we can register
            LocateRegistry.createRegistry(1099);

            // Make our BSides Server object
            // available under the name "bsides"
            Naming.bind("bsides", new BSidesServiceServerImpl());
            System.out.println("BSides RMI server is ready");

        } catch (Exception e) {
            // In case of an error, print the stacktrace
            // and bail out
            e.printStackTrace();
        }
    }
}