frohoff/ysoserial · error · MarshalException

unable to read objID

Error message

unable to read objID

What it means

In JRMPListener.doCall, the listener reads the ObjID from the ObjectInputStream; if reading throws an IOException it rethrows as java.rmi.MarshalException("unable to read objID", e). This means the JRMP call stream was truncated or malformed at the very first field of the call message.

Solutions

  1. Verify the connecting client actually speaks Java RMI/JRMP
  2. Inspect the wrapped cause (e.getCause()) to distinguish EOF from corrupt data
  3. Ensure the client sends the complete call message (ObjID + method + hash)
  4. Retry if the network may have truncated the stream
Defensive patterns

Strategy: try-catch

Validate before calling

// confirm the peer speaks JRMP before treating it as a call stream
// e.g. verify the transport op byte matches TransportConstants.Call

Try / catch

try {
    listenerSession();
} catch (MarshalException e) {
    if (e.getMessage().equals("unable to read objID")) {
        // log cause; likely non-JRMP client or truncated stream
    }
}

Prevention

When it happens

Trigger: The incoming stream does not contain a well-formed ObjID at the point doCall expects it — stream ends early, bytes are corrupt, or the sender is not speaking the JRMP call protocol at all.

Common situations: Non-JRMP clients (probes, HTTP requests) hitting the listener port; a truncated packet due to network issues; a client with an incompatible protocol version sending a different framing.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


AI-assisted analysis of frohoff/ysoserial@218bcffcaa (2026-09-12). Data as JSON: /api/errors/7cb1dee3df2af1a7. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/ysoserial/exploit/JRMPListener.java:265

            @Override
            protected Class<?> resolveClass ( ObjectStreamClass desc ) throws IOException, ClassNotFoundException {
                if ( "[Ljava.rmi.server.ObjID;".equals(desc.getName())) {
                    return ObjID[].class;
                } else if ("java.rmi.server.ObjID".equals(desc.getName())) {
                    return ObjID.class;
                } else if ( "java.rmi.server.UID".equals(desc.getName())) {
                    return UID.class;
                }
                throw new IOException("Not allowed to read object");
            }
        };

        ObjID read;
        try {
            read = ObjID.read(ois);
        }
        catch ( java.io.IOException e ) {
            throw new MarshalException("unable to read objID", e);
        }


        if ( read.hashCode() == 2 ) {
            ois.readInt(); // method
            ois.readLong(); // hash
            System.err.println("Is DGC call for " + Arrays.toString((ObjID[])ois.readObject()));
        }

        System.err.println("Sending return with payload for obj " + read);

        out.writeByte(TransportConstants.Return);// transport op
        ObjectOutputStream oos = new JRMPClient.MarshalOutputStream(out, this.classpathUrl);

        oos.writeByte(TransportConstants.ExceptionalReturn);
        new UID().write(oos);

        BadAttributeValueExpException ex = new BadAttributeValueExpException(null);

View on GitHub (pinned to 218bcffcaa)