Vulnerability 3: Plaintext Transport (CWE-319)
OWASP A02:2021 — Cryptographic Failures
Severity: High — Credential Theft, Data Exposure
What Is the Vulnerability?
Plain Java RMI uses unencrypted TCP sockets. Every byte that goes over the network — session tokens, passwords, file contents — travels in cleartext. Anyone with access to the network path can:
- Eavesdrop: Capture credentials and file data passively
- Man-in-the-Middle: Intercept and modify requests/directories in transit
- Replay: Record and replay entire RMI calls
This is especially dangerous on shared networks (public WiFi, university networks, co-working spaces) where any device on the same subnet can sniff traffic.
Vulnerable Code
File: vulnerable/src/server/ReplicaNode.java
// VULNERABILITY 3: Plain TCP sockets — no TLS/SSL configured.
// All RMI traffic including passwords and file data flows in cleartext.
// An attacker running tcpdump on the same network can read everything.
public ReplicaNode(int nodeId, int port) throws RemoteException {
super(0); // NO SslRMIServerSocketFactory — plain TCP!
// ...
}
public static void main(String[] args) {
// Plain registry — no SSL socket factories
Registry registry = LocateRegistry.createRegistry(port);
// ...
}
Attack Demo
Eavesdropping with tcpdump
# Terminal 1 — Start vulnerable stack
cd vulnerable
start_node.bat 1
start_node.bat 2
start_node.bat 3
# Terminal 2 — Start tcpdump to capture RMI traffic
sudo tcpdump -i lo -A 'tcp port 5001' 2>/dev/null | strings | grep -E "token|password|username"
# Terminal 3 — Connect a client and log in
start_client.bat
# (register with username=testuser, password=secret123)
What the attacker sees in Terminal 2:
username: testuser
password: secret123
token: 550e8400-e29b-41d4-a716-446655440000
All three pieces of sensitive data appear in plaintext. The attacker now has:
- The username
- The password (can log in as the victim)
- The session token (can hijack the existing session)
Attacker3_Eavesdrop — Built-in Demo
cd vulnerable
# Start the proxy (listens on 5101, forwards to 5001)
java -cp out attacker.Attacker3_Eavesdrop
# In another terminal, connect through the proxy
start_client.bat 5101
# All traffic appears in the proxy's terminal
The Fix
File: secured/src/server/ReplicaNode.java
Step 1 — Load Certificates
// FIX 3: Load keystore (our identity) and truststore (who we trust)
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("certs/node" + nodeId + ".jks"), "changeit".toCharArray());
KeyStore ts = KeyStore.getInstance("JKS");
ts.load(new FileInputStream("certs/truststore.jks"), "changeit".toCharArray());
Step 2 — Build SSL Context
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "changeit".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ts);
SSLContext sslCtx = SSLContext.getInstance("TLS");
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
Step 3 — Create SSL Socket Factories
SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory();
// true = require client certificate (mutual TLS)
SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory(null, null, true);
Step 4 — Export with mTLS
// The constructor passes the SSL factory to UnicastRemoteObject
public ReplicaNode(int nodeId, int port) throws RemoteException {
super(0, csf, ssf); // <-- SSL socket factories
// ...
}
// The registry uses SSL factories
Registry registry = LocateRegistry.createRegistry(port, csf, ssf);
Step 5 — Client Side
// Client also configures TLS
System.setProperty("javax.net.ssl.keyStore", "certs/client.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "changeit");
System.setProperty("javax.net.ssl.trustStore", "certs/truststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
// Connect over mTLS
Registry registry = LocateRegistry.getRegistry("localhost", 6001, new SslRMIClientSocketFactory());
Verification
After applying the fix, run the same tcpdump:
# With the secured version running:
sudo tcpdump -i lo -A 'tcp port 6001' 2>/dev/null
Output: Only encrypted bytes — no readable credentials, tokens, or file data.
Why This Vulnerability Is Dangerous
| Property | Impact |
|---|---|
| Exploitability | Trivial — tcpdump is installed on every Linux system |
| Impact | Full credential theft — attacker gets username, password, session token |
| Prerequisites | Network access (same subnet as victim, or on the network path) |
| Passive vs Active | Passive eavesdropping — no packets sent, impossible to detect |
| Detection | Impossible — the attacker only listens, never transmits |
On a university campus network, a single compromised machine running tcpdump could capture credentials from every student using the vulnerable system.