Skip to content

Commit c85913f

Browse files
committed
Land rapid7#5983, @jhart-r7's SOAP PortMapping UPnP auxiliary module
2 parents cb4e609 + f6f3efe commit c85913f

File tree

1 file changed

+140
-0
lines changed

1 file changed

+140
-0
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
##
2+
# encoding: utf-8
3+
# This module requires Metasploit: http://metasploit.com/download
4+
# Current source: https://github.com/rapid7/metasploit-framework
5+
##
6+
7+
require 'msf/core'
8+
require 'nokogiri'
9+
10+
class Metasploit3 < Msf::Auxiliary
11+
include Msf::Exploit::Remote::HttpClient
12+
13+
def initialize
14+
super(
15+
'Name' => 'UPnP IGD SOAP Port Mapping Utility',
16+
'Description' => %q{
17+
Manage port mappings on UPnP IGD-capable device using the AddPortMapping and
18+
DeletePortMapping SOAP requests
19+
},
20+
'Author' =>
21+
[
22+
'St0rn <fabien[at]anbu-pentest.com>', # initial module
23+
'Jon Hart <jon_hart[at]rapid7.com>' # module cleanup and refactoring
24+
],
25+
'License' => MSF_LICENSE,
26+
'References' => [['URL', 'http://www.upnp-hacks.org/igd.html']],
27+
'DefaultAction' => 'ADD',
28+
'Actions' =>
29+
[
30+
[ 'ADD',
31+
{
32+
'Description' => 'Use the AddPortMapping SOAP command to open and forward a port',
33+
'SOAP_ACTION' => 'AddPortMapping'
34+
}
35+
],
36+
[ 'DELETE',
37+
{
38+
'Description' => 'Use the DeletePortMapping SOAP command to remove a port forwarding',
39+
'SOAP_ACTION' => 'DeletePortMapping'
40+
}
41+
]
42+
],
43+
)
44+
45+
register_options(
46+
[
47+
OptString.new('TARGETURI', [true, 'UPnP control URL', '/' ]),
48+
OptAddress.new('INTERNAL_CLIENT', [false, 'Internal client hostname/IP']),
49+
OptAddress.new('EXTERNAL_CLIENT', [false, 'External client hostname/IP']),
50+
OptEnum.new('PROTOCOL', [true, 'Transport level protocol to map', 'TCP', %w(TCP UDP)]),
51+
OptInt.new('INTERNAL_PORT', [false, 'Internal port']),
52+
OptInt.new('EXTERNAL_PORT', [true, 'External port']),
53+
OptInt.new('LEASE_DURATION', [false, 'Lease time for mapping, in seconds', 3600])
54+
],
55+
self.class
56+
)
57+
end
58+
59+
def internal_port
60+
@internal_port ||= datastore['INTERNAL_PORT']
61+
end
62+
63+
def internal_client
64+
@internal_client ||= datastore['INTERNAL_CLIENT']
65+
end
66+
67+
def external_port
68+
@external_port ||= datastore['EXTERNAL_PORT']
69+
end
70+
71+
def external_client
72+
@external_client ||= datastore['EXTERNAL_CLIENT']
73+
end
74+
75+
def lease_duration
76+
@lease_duration ||= datastore['LEASE_DURATION']
77+
end
78+
79+
def protocol
80+
@protocol ||= datastore['PROTOCOL']
81+
end
82+
83+
def soap_action
84+
@soap_action ||= action.opts['SOAP_ACTION']
85+
end
86+
87+
def build_soap
88+
builder = ::Nokogiri::XML::Builder.new do |xml|
89+
xml['SOAP-ENV'].Envelope('xmlns:SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope', 'SOAP-ENV:encodingStyle' => 'http://schemas.xmlsoap.org/soap/encoding/') do
90+
xml['SOAP-ENV'].Body do
91+
xml['m'].send(soap_action, 'xmlns:m' => 'urn:schemas-upnp-org:service:WANIPConnection:1') do
92+
case action.name
93+
when 'ADD'
94+
xml.NewPortMappingDescription(Rex::Text.rand_text_alpha(8)) { xml.parent.namespace = nil }
95+
xml.NewLeaseDuration(lease_duration) { xml.parent.namespace = nil }
96+
xml.NewInternalClient(internal_client) { xml.parent.namespace = nil }
97+
xml.NewEnabled(1) { xml.parent.namespace = nil }
98+
xml.NewExternalPort(external_port) { xml.parent.namespace = nil }
99+
xml.NewRemoteHost(external_client) { xml.parent.namespace = nil }
100+
xml.NewProtocol(protocol) { xml.parent.namespace = nil }
101+
xml.NewInternalPort(internal_port) { xml.parent.namespace = nil }
102+
when 'DELETE'
103+
xml.NewExternalPort(external_port) { xml.parent.namespace = nil }
104+
xml.NewRemoteHost(external_client) { xml.parent.namespace = nil }
105+
xml.NewProtocol(protocol) { xml.parent.namespace = nil }
106+
end
107+
end
108+
end
109+
end
110+
end
111+
builder.to_xml
112+
end
113+
114+
def run
115+
res = send_request_cgi(
116+
'uri' => normalize_uri(target_uri.path),
117+
'method' => 'POST',
118+
'content-type' => 'text/xml;charset="utf-8"',
119+
'data' => build_soap,
120+
'headers' => {
121+
'SoapAction' => "urn:schemas-upnp-org:service:WANIPConnection:1##{soap_action}"
122+
}
123+
)
124+
125+
external_map = "#{external_client ? external_client : 'any'}:#{external_port}/#{protocol}"
126+
internal_map = "#{internal_client ? internal_client : 'any'}:#{internal_port}/#{protocol}"
127+
map = "#{external_map} -> #{internal_map}"
128+
129+
if res
130+
if res.code == 200
131+
print_good("#{peer} #{map} #{action.name} succeeded")
132+
else
133+
print_error("#{peer} #{map} #{action.name} failed with response code #{res.code}")
134+
vprint_status("#{res.body}")
135+
end
136+
else
137+
print_error("#{peer} no response for #{map} #{action.name}")
138+
end
139+
end
140+
end

0 commit comments

Comments
 (0)