Skip to content

Commit b0c17fd

Browse files
author
jvazquez-r7
committed
Land rapid7#2002, @jlee-r7's patch for better handling uri resources
2 parents 86ab942 + 1ac1d32 commit b0c17fd

File tree

6 files changed

+156
-42
lines changed

6 files changed

+156
-42
lines changed

lib/msf/core/exploit/http/server.rb

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ def initialize(info = {})
3636
], Exploit::Remote::HttpServer
3737
)
3838

39+
# Used to keep track of resources added to the service manager by
40+
# this module. see #add_resource and #cleanup
41+
@my_resources = []
3942
@service_path = nil
4043
end
4144

@@ -202,6 +205,39 @@ def start_service(opts = {})
202205
add_resource(uopts)
203206
end
204207

208+
# Set {#on_request_uri} to handle the given +uri+ in addition to the one
209+
# specified by the user in URIPATH.
210+
#
211+
# @note This MUST be called from {#primer} so that the service has been set
212+
# up but we have not yet entered the listen/accept loop.
213+
#
214+
# @param uri [String] The resource URI that should be handled by
215+
# {#on_request_uri}.
216+
# @return [void]
217+
def hardcoded_uripath(uri)
218+
proc = Proc.new do |cli, req|
219+
on_request_uri(cli, req)
220+
end
221+
222+
vprint_status("Adding hardcoded uri #{uri}")
223+
begin
224+
add_resource({'Path' => uri, 'Proc' => proc})
225+
rescue RuntimeError => e
226+
print_error("This module requires a hardcoded uri at #{uri}. Can't run while other modules are using it.")
227+
raise e
228+
end
229+
end
230+
231+
# Take care of removing any resources that we created
232+
def cleanup
233+
# Must dup here because remove_resource modifies @my_resources
234+
@my_resources.dup.each do |resource|
235+
remove_resource(resource)
236+
end
237+
238+
super
239+
end
240+
205241
#
206242
# Return a Hash containing a best guess at the actual browser and operating
207243
# system versions, based on the User-Agent header.
@@ -358,9 +394,16 @@ def report_user_agent(address, request, client_opts={})
358394
# NOTE: Calling #add_resource will change the results of subsequent calls
359395
# to #get_resource!
360396
#
397+
# @return (see Rex::Service#add_resource)
361398
def add_resource(opts)
362399
@service_path = opts['Path']
363-
service.add_resource(opts['Path'], opts)
400+
res = service.add_resource(opts['Path'], opts)
401+
402+
# This has to go *after* the call to service.add_resource in case
403+
# the service manager doesn't like it for some reason and raises.
404+
@my_resources.push(opts['Path'])
405+
406+
res
364407
end
365408

366409
#
@@ -455,7 +498,11 @@ def srvhost_addr
455498
# Removes a URI resource.
456499
#
457500
def remove_resource(name)
458-
service.remove_resource(name)
501+
# Guard against removing resources added by other modules
502+
if @my_resources.include?(name)
503+
@my_resources.delete(name)
504+
service.remove_resource(name)
505+
end
459506
end
460507

461508
#

modules/exploits/windows/browser/adobe_flash_mp4_cprt.rb

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -170,18 +170,14 @@ def get_target(agent)
170170
end
171171
end
172172

173+
def primer
174+
# "/test.mp4" is currently hard-coded in the swf file, so we need to add to resource
175+
hardcoded_uripath("/test.mp4")
176+
end
177+
173178
def exploit
174179
@swf = create_swf
175180
super
176-
177-
#
178-
# "/test.mp4" is currently hard-coded in the swf file, so we need to add to resource
179-
#
180-
proc = Proc.new do |cli, req|
181-
self.add_resource({'Path' => "/test.mp4", 'Proc' => proc}) rescue nil
182-
on_request_uri(cli, req)
183-
end
184-
185181
end
186182

187183
def on_request_uri(cli, request)
@@ -275,12 +271,6 @@ def on_request_uri(cli, request)
275271
send_response(cli, html, {'Content-Type'=>'text/html'})
276272
end
277273

278-
def cleanup
279-
print_status("Removing mp4 resource")
280-
remove_resource('/test.mp4') rescue nil
281-
super
282-
end
283-
284274
def create_swf
285275
path = ::File.join( Msf::Config.install_root, "data", "exploits", "CVE-2012-0754.swf" )
286276
fd = ::File.open( path, "rb" )

modules/exploits/windows/browser/adobe_flash_otf_font.rb

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -204,16 +204,15 @@ def on_request_uri(cli, request)
204204

205205
html = html.gsub(/^\t\t/, '')
206206

207-
# we need to handle direct /pay.txt requests
208-
proc = Proc.new do |cli, req|
209-
on_request_uri(cli, req)
210-
end
211-
add_resource({'Path' => "/#{@resource_name}.txt", 'Proc' => proc}) rescue nil
212-
213207
print_status("Sending HTML")
214208
send_response(cli, html, {'Content-Type'=>'text/html'})
215209
end
216210

211+
def primer
212+
# we need to handle direct /pay.txt requests
213+
hardcoded_uripath("/#{@resource_name}.txt")
214+
end
215+
217216
def exploit
218217
@swf = create_swf
219218
@resource_name = Rex::Text.rand_text_alpha(5)
@@ -235,10 +234,4 @@ def create_swf
235234
return swf
236235
end
237236

238-
def cleanup
239-
vprint_status("Removing txt resource")
240-
remove_resource("/#{@resource_name}.txt") rescue nil
241-
super
242-
end
243-
244237
end

modules/exploits/windows/browser/citrix_gateway_actx.rb

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ def initialize(info = {})
6060
'DefaultTarget' => 0))
6161
end
6262

63+
def primer
64+
hardcoded_uripath("/epaq")
65+
end
66+
6367
def exploit
6468
@ocx = ::File.read(::File.join(Msf::Config.install_root, 'data', 'exploits', 'CVE-2011-2882', 'nsepa.ocx'))
6569
super
@@ -184,12 +188,6 @@ def on_request_uri(cli, request)
184188

185189
html = html.gsub(/^\t\t/, '')
186190

187-
# we need to handle direct /epaq requests
188-
proc = Proc.new do |cli, req|
189-
on_request_uri(cli, req)
190-
end
191-
192-
add_resource({'Path' => "/epaq", 'Proc' => proc}) rescue nil
193191
print_status("Sending #{self.name} HTML")
194192
send_response(cli, html, { 'Content-Type' => 'text/html' })
195193
end

modules/exploits/windows/browser/honeywell_hscremotedeploy_exec.rb

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ def initialize(info={})
5555
'DefaultTarget' => 0))
5656
end
5757

58+
def primer
59+
hardcoded_uripath("/SystemDisplays/RemoteInstallWelcome.hta")
60+
end
61+
5862
def exploit
5963
@var_exename = rand_text_alpha(5 + rand(5)) + ".exe"
6064
@dropped_files = [
@@ -198,13 +202,6 @@ def on_request_uri(cli, request)
198202
</html>
199203
EOS
200204

201-
# we need to handle direct /SystemDisplays/RemoteInstallWelcome.hta requests
202-
proc = Proc.new do |cli, req|
203-
on_request_uri(cli, req)
204-
end
205-
206-
add_resource({'Path' => "/SystemDisplays/RemoteInstallWelcome.hta", 'Proc' => proc}) rescue nil
207-
208205
print_status("Sending html")
209206
send_response(cli, html, {'Content-Type'=>'text/html'})
210207

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
2+
# -*- coding:binary -*-
3+
require 'spec_helper'
4+
5+
require 'msf/core'
6+
require 'msf/core/exploit/http/server'
7+
8+
describe Msf::Exploit::Remote::HttpServer do
9+
subject(:server_module) do
10+
mod = Msf::Exploit.allocate
11+
mod.extend described_class
12+
mod.send(:initialize, {})
13+
14+
mod
15+
end
16+
17+
let(:mock_service) do
18+
mock_service = mock("service")
19+
mock_service.stub(:server_name=)
20+
mock_service.stub(:add_resource)
21+
22+
mock_service
23+
end
24+
25+
before do
26+
Rex::ServiceManager.stub(:start => mock_service)
27+
end
28+
29+
describe "#add_resource" do
30+
it "should call the ServiceManager's add_resource" do
31+
server_module.start_service
32+
33+
mock_service.should_receive(:add_resource)
34+
server_module.add_resource('Path' => 'foo')
35+
end
36+
37+
it "should re-raise if the resource has already been added" do
38+
server_module.start_service
39+
40+
mock_service.should_receive(:add_resource).ordered
41+
mock_service.should_receive(:add_resource).ordered.and_raise(RuntimeError)
42+
43+
server_module.add_resource('Path' => 'foo')
44+
45+
expect { server_module.add_resource('Path' => 'foo') }.to raise_error
46+
end
47+
48+
end
49+
50+
describe "#cleanup" do
51+
it "should not remove resources if none were successfully added" do
52+
server_module.should_not_receive(:remove_resource)
53+
server_module.cleanup
54+
end
55+
56+
it "should remove successfully-added resources" do
57+
# setup
58+
server_module.start_service
59+
resources = [ 'a', 'b', 'c' ]
60+
resources.each { |r| server_module.add_resource('Path' => r) }
61+
62+
# The service will add one resource as part of #start_service, so
63+
# add that to the number that we added manually
64+
server_module.should_receive(:remove_resource).exactly(resources.count + 1).times
65+
server_module.cleanup
66+
end
67+
68+
end
69+
70+
describe "#hardcoded_uripath" do
71+
it "should call the ServiceManager's add_resource" do
72+
server_module.start_service
73+
74+
mock_service.should_receive(:add_resource)
75+
server_module.hardcoded_uripath('foo')
76+
end
77+
78+
it "should re-raise if the resource has already been added" do
79+
server_module.start_service
80+
81+
mock_service.should_receive(:add_resource).ordered.and_raise(RuntimeError)
82+
83+
expect { server_module.hardcoded_uripath('foo') }.to raise_error
84+
end
85+
end
86+
87+
end
88+
89+

0 commit comments

Comments
 (0)