Skip to content

Commit

Permalink
Adds mixin and test module
Browse files Browse the repository at this point in the history
  • Loading branch information
cgranleese-r7 committed Feb 7, 2025
1 parent 764fe05 commit 02b2435
Show file tree
Hide file tree
Showing 12 changed files with 393 additions and 26 deletions.
4 changes: 4 additions & 0 deletions lib/msf/core/post/dns.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# -*- coding: binary -*-

module Msf::Post::DNS
end
72 changes: 72 additions & 0 deletions lib/msf/core/post/dns/resolve_host.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# -*- coding: binary -*-

require 'rex/post/meterpreter/extensions/stdapi/constants'

module Msf
class Post
module DNS
###
#
# This module resolves session DNS
#
###
module ResolveHost
# Takes the host name and resolves the IP
#
# @param [String] host
# @param [Integer] family AF_INET for IPV4 and AF_INET6 for IPV6
# @return [Hash] The resolved IPs
def resolve_host(host, family)
if client.respond_to?(:net) && client.commands.include?(Rex::Post::Meterpreter::Extensions::Stdapi::COMMAND_ID_STDAPI_NET_RESOLVE_HOST)
resolved_host = client.net.resolve.resolve_host(host, family)
resolved_host.reject { |k, _v| k == :ip }
else
ips = []
data = cmd_exec("nslookup #{host}")
if data =~ /Name/
# Remove unnecessary data and get the section with the addresses
returned_data = data.split(/Name:/)[1..]
# check each element of the array to see if they are IP
returned_data.each do |entry|
ip_list = entry.gsub(/\r\n\t |\r\n|Aliases:|Addresses:|Address:/, ' ').split(' ') - [host]
filtered_ips = filter_ips(ip_list, family)
ips = filtered_ips unless filtered_ips.empty?
end
# If nslookup responds with "no answer", fall back to resolving via host command
elsif data =~ /No answer/
data = cmd_exec("host #{host}")
if data =~ /has address/
# Remove unnecessary data and get the section with the addresses
returned_data = data.split("\n")[...-1]
# check each element of the array to see if they are IP
ip_list = returned_data.map { |entry| entry.split(' ').last }
filtered_ips = filter_ips(ip_list, family)
ips = filtered_ips unless filtered_ips.empty?
end
end
{ hostname: host, ips: ips }
end
end

# Takes the host and family and returns the IP address if it matches the appropriate family
# Needed to handle request that fallback to nslookup or host, as they return both IPV4 and IPV6.
#
# @param [Array] ips
# @param [Integer] family
# @return [Array] ips
def filter_ips(ips, family)
filtered_ips = []
ips.each do |ip|
if family == AF_INET
filtered_ips << ip if !!(ip =~ Resolv::IPv4::Regex)
elsif family == AF_INET6
filtered_ips << ip if !!(ip =~ Resolv::IPv6::Regex)
end
end

filtered_ips
end
end
end
end
end
55 changes: 29 additions & 26 deletions modules/post/windows/gather/enum_computers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'rex/post/meterpreter/extensions/stdapi/constants'

class MetasploitModule < Msf::Post
include Msf::Post::File
include Msf::Post::Windows::Accounts
include Msf::Post::Windows::Registry
include Msf::Post::DNS::ResolveHost

def initialize(info = {})
super(
Expand Down Expand Up @@ -58,36 +61,19 @@ def run

# Takes the host name and makes use of nslookup to resolve the IP
#
# @param [String] host Hostname
# @param [Object] hostname
# @param [Object] family
# @return [String] ip The resolved IP
def resolve_host(host)
vprint_status("Looking up IP for #{host}")
return host if Rex::Socket.dotted_ip?(host)

ip = []
data = cmd_exec("nslookup #{host}")
if data =~ /Name/
# Remove unnecessary data and get the section with the addresses
returned_data = data.split(/Name:/)[1]
# check each element of the array to see if they are IP
returned_data.gsub(/\r\n\t |\r\n|Aliases:|Addresses:|Address:/, ' ').split(' ').each do |e|
if Rex::Socket.dotted_ip?(e)
ip << e
end
end
end

if ip.blank?
'Not resolvable'
else
ip.join(', ')
end
def gethost(hostname, family)
## get IP for host
vprint_status("Looking up IP for #{hostname}")
resolve_host(hostname, family)
end

def get_domain_computers
computer_list = []
divisor = "-------------------------------------------------------------------------------\r\n"
net_view_response = cmd_exec('net view')
net_view_response = cmd_exec("cmd.exe", "/c net view")
unless net_view_response.include?(divisor)
print_error("The net view command failed with: #{net_view_response}")
return []
Expand All @@ -104,6 +90,7 @@ def get_domain_computers
end

def list_computers(domain, hosts)
meterpreter_dns_resolving_errors = []
tbl = Rex::Text::Table.new(
'Header' => 'List of identified Hosts.',
'Indent' => 1,
Expand All @@ -115,12 +102,28 @@ def list_computers(domain, hosts)
]
)
hosts.each do |hostname|
hostip = resolve_host(hostname)
tbl << [domain, hostname, hostip]
hostipv4 = gethost(hostname, AF_INET)
hostipv6 = gethost(hostname, AF_INET6)

if hostipv4[:ips].empty?
meterpreter_dns_resolving_errors << "IPV4: #{hostname} could not be resolved"
else
tbl << [domain, hostname, hostipv4[:ips].join(',')]
end

if hostipv6[:ips].empty?
meterpreter_dns_resolving_errors << "IPV6: #{hostname} could not be resolved" if hostipv6[:ips].empty?
else
tbl << [domain, hostname, hostipv6[:ips].join(',')] unless hostipv6[:ips].nil?
end
end

print_line("\n#{tbl}\n")

meterpreter_dns_resolving_errors.each do | error |
print_warning(error)
end

report_note(
host: session,
type: 'domain.hosts',
Expand Down
32 changes: 32 additions & 0 deletions spec/support/acceptance/command_shell/cmd.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,38 @@ module Acceptance::Session
}
],
module_tests: [
{
name: 'post/test/resolve_host',
platforms: [
[
:linux,
{
skip: true,
reason: 'Payload not compiled for platform'
}
],
[
:osx,
{
skip: true,
reason: 'Payload not compiled for platform'
}
],
:windows
],
skipped: false,
lines: {
linux: {
known_failures: []
},
osx: {
known_failures: []
},
windows: {
known_failures: []
}
}
},
{
name: 'post/test/cmd_exec',
platforms: [
Expand Down
26 changes: 26 additions & 0 deletions spec/support/acceptance/command_shell/linux.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,32 @@ module Acceptance::Session
}
}
},
{
name: "post/test/resolve_host",
platforms: [
:linux,
:osx,
[
:windows,
{
skip: true,
reason: "Payload not compiled for platform"
}
]
],
skipped: false,
lines: {
linux: {
known_failures: []
},
osx: {
known_failures: []
},
windows: {
known_failures: []
}
}
},
{
name: "post/test/cmd_exec",
platforms: [
Expand Down
32 changes: 32 additions & 0 deletions spec/support/acceptance/command_shell/powershell.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,38 @@ module Acceptance::Session
}
],
module_tests: [
{
name: 'post/test/resolve_host',
platforms: [
[
:linux,
{
skip: true,
reason: 'Payload not compiled for platform'
}
],
[
:osx,
{
skip: true,
reason: 'Payload not compiled for platform'
}
],
:windows
],
skipped: false,
lines: {
linux: {
known_failures: []
},
osx: {
known_failures: []
},
windows: {
known_failures: []
}
}
},
{
name: 'post/test/cmd_exec',
platforms: [
Expand Down
16 changes: 16 additions & 0 deletions spec/support/acceptance/session/java.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,22 @@ module Acceptance::Session
}
}
},
{
name: "post/test/resolve_host",
platforms: [:linux, :osx, :windows],
skipped: false,
lines: {
linux: {
known_failures: []
},
osx: {
known_failures: []
},
windows: {
known_failures: []
}
}
},
{
name: "post/test/cmd_exec",
platforms: [:linux, :osx, :windows],
Expand Down
27 changes: 27 additions & 0 deletions spec/support/acceptance/session/mettle.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

module Acceptance::Session
METTLE_METERPRETER = {
payloads: [
Expand Down Expand Up @@ -69,6 +70,32 @@ module Acceptance::Session
}
}
},
{
name: "post/test/resolve_host",
platforms: [
:linux,
:osx,
[
:windows,
{
skip: true,
reason: "Payload not compiled for platform"
}
]
],
skipped: false,
lines: {
linux: {
known_failures: []
},
osx: {
known_failures: []
},
windows: {
known_failures: []
}
}
},
{
name: "post/test/cmd_exec",
platforms: [
Expand Down
17 changes: 17 additions & 0 deletions spec/support/acceptance/session/php.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,23 @@ module Acceptance::Session
}
}
},
{
name: "post/test/resolve_host",
platforms: [:linux, :osx, :windows],
skipped: false,
lines: {
linux: {
known_failures: []
},
osx: {
known_failures: []
},
windows: {
known_failures: [
]
}
}
},
{
name: "post/test/cmd_exec",
platforms: [:linux, :osx, :windows],
Expand Down
16 changes: 16 additions & 0 deletions spec/support/acceptance/session/python.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,22 @@ module Acceptance::Session
}
}
},
{
name: "post/test/resolve_host",
platforms: [:linux, :osx, :windows],
skipped: false,
lines: {
linux: {
known_failures: []
},
osx: {
known_failures: []
},
windows: {
known_failures: []
}
}
},
{
name: "post/test/cmd_exec",
platforms: [:linux, :osx, :windows],
Expand Down
Loading

0 comments on commit 02b2435

Please sign in to comment.