Skip to content

Commit f4977bf

Browse files
author
Brent Cook
committed
Land rapid7#5006 @jlee-r7 adds meterpreter specs
2 parents 46dca23 + dfaf1b3 commit f4977bf

File tree

2 files changed

+164
-4
lines changed

2 files changed

+164
-4
lines changed

lib/msf/base/sessions/meterpreter.rb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,9 @@ def load_session_info()
323323
nhost = find_internet_connected_address
324324

325325
original_session_host = self.session_host
326-
# If we found a better IP address for this session, change it up
327-
# only handle cases where the DB is not connected here
328-
if !(framework.db && framework.db.active)
326+
# If we found a better IP address for this session, change it
327+
# up. Only handle cases where the DB is not connected here
328+
if nhost && !(framework.db && framework.db.active)
329329
self.session_host = nhost
330330
end
331331

@@ -461,6 +461,8 @@ def create(param)
461461
# @see Rex::Post::Meterpreter::Extensions::Stdapi::Net::Config#get_routes
462462
# @return [String] The address from which this host reaches the
463463
# internet, as ASCII. e.g.: "192.168.100.156"
464+
# @return [nil] If there is an interface with an address that matches
465+
# {#session_host}
464466
def find_internet_connected_address
465467

466468
ifaces = self.net.config.get_interfaces().flatten rescue []
@@ -497,7 +499,9 @@ def find_internet_connected_address
497499
end
498500

499501
if !nhost
500-
# Find the first non-loopback address
502+
# No internal address matches what we see externally and no
503+
# interface has a default route. Fall back to the first
504+
# non-loopback address
501505
non_loopback = ifaces.find { |i| i.ip != "127.0.0.1" && i.ip != "::1" }
502506
if non_loopback
503507
nhost = non_loopback.ip
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
require 'spec_helper'
2+
require 'msf/base/sessions/meterpreter'
3+
require 'rex/post/meterpreter/extensions/stdapi/net/interface'
4+
require 'rex/post/meterpreter/extensions/stdapi/net/route'
5+
6+
describe Msf::Sessions::Meterpreter do
7+
before do
8+
allow_any_instance_of(Rex::Post::Meterpreter::PacketDispatcher).to receive(:monitor_socket)
9+
end
10+
11+
subject(:meterpreter) { described_class.new(StringIO.new(""), skip_ssl: true) }
12+
13+
let(:v6_gateway) { "2607:f8b0:4004:0802::1014" }
14+
let(:v4_gateway) { "192.168.3.1" }
15+
16+
let(:v6_linklocal) { "fe80::d6c9:efff:fe53:53ff" }
17+
18+
let(:routes) do
19+
[
20+
Rex::Post::Meterpreter::Extensions::Stdapi::Net::Route.new(
21+
IPAddr.new("0.0.0.0").hton, # Subnet
22+
IPAddr.new("0.0.0.0").hton, # Netmask
23+
IPAddr.new("192.168.3.1").hton # Gateway
24+
),
25+
Rex::Post::Meterpreter::Extensions::Stdapi::Net::Route.new(
26+
IPAddr.new("::").hton, # Subnet
27+
IPAddr.new("::").hton, # Netmask
28+
IPAddr.new(v6_gateway).hton # Gateway
29+
)
30+
]
31+
end
32+
33+
describe "#find_internet_connected_address" do
34+
35+
subject(:connected_address) do
36+
m = described_class.new(StringIO.new(""), skip_ssl: true)
37+
m.stub_chain(:net, :config, :get_interfaces).and_return(interfaces)
38+
m.stub_chain(:net, :config, :get_routes).and_return(routes)
39+
m.session_host = session_host
40+
41+
m.send(:find_internet_connected_address)
42+
end
43+
44+
let(:interfaces) do
45+
ifaces = []
46+
interface_config.each_with_index { |iface_hash, idx|
47+
ifaces << Rex::Post::Meterpreter::Extensions::Stdapi::Net::Interface.new(
48+
index: idx,
49+
mac_addr: "00:11:22:33:44:%02x"%idx,
50+
mac_name: "eth0",
51+
mtu: 1500,
52+
flags: 0,
53+
addrs: iface_hash[:ips],
54+
netmasks: iface_hash[:masks],
55+
scopes: [ "" ]
56+
)
57+
}
58+
59+
ifaces
60+
end
61+
62+
let(:session_host) { "99.99.99.99" }
63+
64+
context "with an address that matches #session_host" do
65+
let(:interface_config) do
66+
[
67+
{ ips: [ "192.168.10.1" ], masks: [ "255.255.255.0" ], },
68+
{ ips: [ "192.168.11.1" ], masks: [ "255.255.255.0" ], },
69+
{ ips: [ "192.168.12.1" ], masks: [ "255.255.255.0" ], },
70+
{ ips: [ session_host ], masks: [ "255.255.255.0" ], },
71+
{ ips: [ "192.168.14.1" ], masks: [ "255.255.255.0" ], },
72+
{ ips: [ "192.168.16.1" ], masks: [ "255.255.255.0" ], },
73+
]
74+
end
75+
it "returns nil" do
76+
expect(connected_address).to be_nil
77+
end
78+
end
79+
80+
# All the rest of these assume session_host does not match any
81+
# interface's addresses
82+
83+
context "one interface with one IPv4 address" do
84+
let(:interface_config) do
85+
[ { ips: [ "10.2.3.4" ], masks: [ "255.255.255.0" ], } ]
86+
end
87+
it "returns that address" do
88+
expect(connected_address).to eq("10.2.3.4")
89+
end
90+
end
91+
92+
context "one interface with one IPv6 address" do
93+
let(:interface_config) do
94+
[
95+
{ ips: [ v6_linklocal ], masks: [ "ffff:ffff:ffff:ffff::" ], },
96+
]
97+
end
98+
it "returns that address" do
99+
expect(connected_address).to eq(v6_linklocal)
100+
end
101+
end
102+
103+
context "one interface with mixed IP versions" do
104+
context "first is correct" do
105+
let(:interface_config) do
106+
[
107+
{ ips: [ "192.168.3.4" ], masks: [ "255.255.255.0" ], },
108+
{ ips: [ v6_linklocal ], masks: [ "ffff:ffff:ffff:ffff::" ], },
109+
]
110+
end
111+
it "returns first address" do
112+
expect(connected_address).to eq("192.168.3.4")
113+
end
114+
end
115+
context "second address is correct" do
116+
let(:interface_config) do
117+
[
118+
{ ips: [ v6_linklocal ], masks: [ "ffff:ffff:ffff:ffff::" ], },
119+
{ ips: [ "192.168.3.4" ], masks: [ "255.255.255.0" ], },
120+
]
121+
end
122+
it "returns second address" do
123+
expect(connected_address).to eq("192.168.3.4")
124+
end
125+
end
126+
end
127+
128+
context "one interface with multiple IPv4 addresses" do
129+
context "first address is correct" do
130+
let(:interface_config) do
131+
[ {
132+
ips: ["192.168.3.4", "10.2.3.4"],
133+
masks: [ "255.255.255.0", "255.0.0.0"],
134+
} ]
135+
end
136+
it "returns first address" do
137+
expect(connected_address).to eq("192.168.3.4")
138+
end
139+
end
140+
context "second address is correct" do
141+
let(:interface_config) do
142+
[ {
143+
ips: [ "10.2.3.4", "192.168.3.4" ],
144+
masks: [ "255.0.0.0", "255.255.255.0" ],
145+
} ]
146+
end
147+
it "returns second address" do
148+
expect(connected_address).to eq("192.168.3.4")
149+
end
150+
end
151+
end
152+
153+
end
154+
155+
end
156+

0 commit comments

Comments
 (0)