CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

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