frohoff/ysoserial · warning · IOException

unknown transport op

Error message

unknown transport op ${op}

What it means

JRMPListener.doMessage reads the first transport operation code from an incoming JRMP stream and switches on it. Any op code that is not one of the known TransportConstants (Call, Ping, PingAck, DGCAck, etc.) throws IOException("unknown transport op " + op). The listener only implements the subset of the JRMP protocol needed for the exploit.

Solutions

  1. Ensure only the intended JRMP exploit client connects to the listener port
  2. Check the printed op value to identify what connected; filter or ignore benign scanners
  3. If a legitimate client is failing, verify its Java/JRMP version compatibility with the supported op subset
  4. Compare the op code against TransportConstants to see which operation is missing and add a case if needed

Example fix

// before
default:
    throw new IOException("unknown transport op " + op);
// after
default:
    System.err.println("ignoring unknown transport op " + op);
    break;
Defensive patterns

Strategy: validation

Validate before calling

// verify you are speaking to the JRMP listener with a supported client
int op = rawStreamFirstByte;
if (op != TransportConstants.SINGLEOP && op != TransportConstants.PING && op != TransportConstants.DGCAck) {
    throw new IllegalArgumentException("unsupported JRMP op " + op);
}

Try / catch

try {
    listener.join();
} catch (IOException e) {
    if (e.getMessage().startsWith("unknown transport op")) {
        // log op value; treat as noise from scanners/probes
    }
}

Prevention

When it happens

Trigger: A client sends a JRMP protocol operation the listener does not implement — either a non-JRMP/garbage stream hitting the port, a JRMP client using ops beyond the supported subset, or a misaligned stream producing a bogus op value.

Common situations: Port scanners, health checks, or other services connecting to the fake JRMP listener port; a JRMP client on an incompatible Java version sending unsupported operations; probing the listener with curl/netcat.

Related errors


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

Appendix: source

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

        int op = in.read();

        switch ( op ) {
        case TransportConstants.Call:
            // service incoming RMI call
            doCall(in, out, payload);
            break;

        case TransportConstants.Ping:
            // send ack for ping
            out.writeByte(TransportConstants.PingAck);
            break;

        case TransportConstants.DGCAck:
            UID u = UID.read(in);
            break;

        default:
            throw new IOException("unknown transport op " + op);
        }

        s.close();
    }


    private void doCall ( DataInputStream in, DataOutputStream out, Object payload ) throws Exception {
        ObjectInputStream ois = new ObjectInputStream(in) {

            @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;
                }

View on GitHub (pinned to 218bcffcaa)