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
- Ensure only the intended JRMP exploit client connects to the listener port
- Check the printed op value to identify what connected; filter or ignore benign scanners
- If a legitimate client is failing, verify its Java/JRMP version compatibility with the supported op subset
- 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
- Dedicate the listener port to the exploit client only
- Ignore/log port-scan noise instead of crashing
- Keep the client's JRMP/Java version aligned with the ops the listener implements
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
- unable to read objID
- Not allowed to read object
- Failed to get object id
- Failed to get object id, separator
- mismatched columns
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)