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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
local rmi = require "rmi"
local shortport = require "shortport"
local string = require "string"
local stdnse = require "stdnse"
local vulns = require "vulns"
description = [[
Tests whether Java rmiregistry allows class loading. The default
configuration of rmiregistry allows loading classes from remote URLs,
which can lead to remote code execution. The vendor (Oracle/Sun)
classifies this as a design feature.
Based on original Metasploit module by mihi.
References:
* https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/multi/misc/java_rmi_server.rb
]];
---
-- @usage
-- nmap --script=rmi-vuln-classloader -p 1099 <target>
--
-- @output
-- PORT STATE SERVICE
-- 1099/tcp open rmiregistry
-- | rmi-vuln-classloader:
-- | VULNERABLE:
-- | RMI registry default configuration remote code execution vulnerability
-- | State: VULNERABLE
-- | Description:
-- | Default configuration of RMI registry allows loading classes from remote URLs which can lead to remote code executeion.
-- |
-- | References:
-- |_ https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/multi/misc/java_rmi_server.rb
author = "Aleksandar Nikolic";
license = "Same as Nmap--See https://nmap.org/book/man-legal.html";
categories = {
"intrusive",
"vuln"
};
portrule = shortport.port_or_service({1098, 1099, 1090, 8901, 8902, 8903}, {"java-rmi", "rmiregistry"})
action = function (host, port)
local registry = rmi.Registry:new(host, port);
registry:_handshake();
local rmiArgs = rmi.Arguments:new();
local argsRaw = "75" .. --TC_ARRAY
"72" .. -- TC_CLASSDESC
"0018" .. -- string len
"5B4C6A6176612E726D692E7365727665722E4F626A49443B" .. -- class name "[Ljava.rmi.server.ObjID;"
"871300B8D02C647E" .. -- serial id
"02" .. -- FLAGS (serializable)
"0000" .. -- FIELD COUNT
"70787000000000" .. --TC_NULL TC_BLOCKEND TC_NULL
"77080000000000000000" .. -- TC_BLOCKDATA
"73" .. -- TC_OBJECT
"72" .. -- TC_CLASSDESC
"0005" .. -- string len
"64756D6D79" .. -- class name "dummy"
"A16544BA26F9C2F4" .. -- serial id
"02" .. -- FLAGS (serializable)
"0000" .. -- FIELD COUNT
"74" .. -- TC_STRING
"0010" .. -- string len
"66696C653A2E2F64756D6D792E6A6172" .. -- annotation "file:./dummy.jar"
"78" .. -- TC_ENDBLOCKDATA
"70" .. -- TC_NULL
"7701000A"; -- TC_BLOCKDATA
local rmi_vuln = {
title = "RMI registry default configuration remote code execution vulnerability",
description = [[
Default configuration of RMI registry allows loading classes from remote URLs which can lead to remote code execution.
]],
references = {
'https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/multi/misc/java_rmi_server.rb',
},
exploit_results = {},
};
local report = vulns.Report:new(SCRIPT_NAME, host, port);
rmi_vuln.state = vulns.STATE.NOT_VULN;
rmiArgs:addRaw(stdnse.fromhex( argsRaw));
-- reference: java/rmi/dgc/DGCImpl_Stub.java and java/rmi/dgc/DGCImpl_Skel.java
-- we are calling DGC's (its objectId is 2) method with opnum 0
-- DCG's hashcode is f6b6898d8bf28643 hex or -669196253586618813 dec
local status, j_array = registry.out:writeMethodCall(registry.out, 2, "f6b6898d8bf28643", 0, rmiArgs);
local status, retByte = registry.out.dis:readByte();
if not status then
return false, "No return data received from server";
end
if 0x51 ~= retByte then
-- 0x51 : Returndata
return false, "No return data received from server";
end
-- Need to make sure we get a good chunk of data. It's going to be a java
-- stack trace. But if we don't get enough, I guess we can check with
-- whatever we get.
registry.out.dis:canRead(256)
local data = registry.out.dis.bReader.readBuffer;
if string.find(data, "RMI class loader disabled") == nil then
rmi_vuln.state = vulns.STATE.VULN;
return report:make_output(rmi_vuln);
end
return report:make_output(rmi_vuln);
end;
|