diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6cbedd5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,128 @@ +# App files +py2kms_server.log* +py3kms_server.log* + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don’t work, or not +# install all needed dependencies. +#Pipfile.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + diff --git a/py2-kms/kmsBase.py b/py2-kms/kmsBase.py index 0c27e64..c3ce92a 100644 --- a/py2-kms/kmsBase.py +++ b/py2-kms/kmsBase.py @@ -19,6 +19,8 @@ try: except ImportError: pass +logger = logging.getLogger('root') + class UUID(Structure): commonHdr = () structure = ( @@ -131,7 +133,7 @@ class kmsBase: skuId TEXT, licenseStatus TEXT, lastRequestTime INTEGER, kmsEpid TEXT, requestCount INTEGER)") except sqlite3.Error, e: - logging.error("Error %s:" % e.args[0]) + logger.error("Error %s:" % e.args[0]) sys.exit(1) finally: @@ -140,8 +142,8 @@ skuId TEXT, licenseStatus TEXT, lastRequestTime INTEGER, kmsEpid TEXT, requestCo con.close() shell_message(nshell = 15) - logging.debug("KMS Request Bytes: \n%s\n" % justify(binascii.b2a_hex(str(kmsRequest)))) - logging.debug("KMS Request: \n%s\n" % justify(kmsRequest.dump(print_to_stdout = False))) + logger.debug("KMS Request Bytes: \n%s\n" % justify(binascii.b2a_hex(str(kmsRequest)))) + logger.debug("KMS Request: \n%s\n" % justify(kmsRequest.dump(print_to_stdout = False))) clientMachineId = kmsRequest['clientMachineId'].get() applicationId = kmsRequest['applicationId'].get() @@ -156,10 +158,10 @@ skuId TEXT, licenseStatus TEXT, lastRequestTime INTEGER, kmsEpid TEXT, requestCo tz = get_localzone() local_dt = tz.localize(requestDatetime) except UnknownTimeZoneError: - logging.warning('Unknown time zone ! Request time not localized.') + logger.warning('Unknown time zone ! Request time not localized.') local_dt = requestDatetime except ImportError: - logging.warning('Module "tzlocal" not available ! Request time not localized.') + logger.warning('Module "tzlocal" not available ! Request time not localized.') local_dt = requestDatetime # Get SkuId, AppId and client threshold. @@ -206,12 +208,12 @@ skuId TEXT, licenseStatus TEXT, lastRequestTime INTEGER, kmsEpid TEXT, requestCo "kmsEpid" : None } - logging.info("Machine Name: %s" % infoDict["machineName"]) - logging.info("Client Machine ID: %s" % infoDict["clientMachineId"]) - logging.info("Application ID: %s" % infoDict["appId"]) - logging.info("SKU ID: %s" % infoDict["skuId"]) - logging.info("License Status: %s" % infoDict["licenseStatus"]) - logging.info("Request Time: %s" % local_dt.strftime('%Y-%m-%d %H:%M:%S %Z (UTC%z)')) + logger.info("Machine Name: %s" % infoDict["machineName"]) + logger.info("Client Machine ID: %s" % infoDict["clientMachineId"]) + logger.info("Application ID: %s" % infoDict["appId"]) + logger.info("SKU ID: %s" % infoDict["skuId"]) + logger.info("License Status: %s" % infoDict["licenseStatus"]) + logger.info("Request Time: %s" % local_dt.strftime('%Y-%m-%d %H:%M:%S %Z (UTC%z)')) if self.config['sqlite'] and self.config['dbSupport']: con = None @@ -247,10 +249,10 @@ clientMachineId=:clientMachineId;", infoDict) clientMachineId=:clientMachineId;", infoDict) except sqlite3.Error, e: - logging.error("Error %s:" % e.args[0]) + logger.error("Error %s:" % e.args[0]) except sqlite3.Error, e: - logging.error("Error %s:" % e.args[0]) + logger.error("Error %s:" % e.args[0]) sys.exit(1) finally: if con: @@ -292,17 +294,17 @@ clientMachineId=:clientMachineId;", infoDict) (str(response["kmsEpid"].decode('utf-16le')), str(kmsRequest['clientMachineId'].get()))) except sqlite3.Error, e: - logging.error("Error %s:" % e.args[0]) + logger.error("Error %s:" % e.args[0]) except sqlite3.Error, e: - logging.error("Error %s:" % e.args[0]) + logger.error("Error %s:" % e.args[0]) sys.exit(1) finally: if con: con.commit() con.close() - logging.info("Server ePID: %s" % response["kmsEpid"].decode('utf-16le').encode('utf-8')) + logger.info("Server ePID: %s" % response["kmsEpid"].decode('utf-16le').encode('utf-8')) return response @@ -314,16 +316,16 @@ def generateKmsResponseData(data, config): currentDate = time.strftime("%a %b %d %H:%M:%S %Y") if version == 4: - logging.info("Received V%d request on %s." % (version, currentDate)) + logger.info("Received V%d request on %s." % (version, currentDate)) messagehandler = kmsRequestV4.kmsRequestV4(data, config) elif version == 5: - logging.info("Received V%d request on %s." % (version, currentDate)) + logger.info("Received V%d request on %s." % (version, currentDate)) messagehandler = kmsRequestV5.kmsRequestV5(data, config) elif version == 6: - logging.info("Received V%d request on %s." % (version, currentDate)) + logger.info("Received V%d request on %s." % (version, currentDate)) messagehandler = kmsRequestV6.kmsRequestV6(data, config) else: - logging.info("Unhandled KMS version V%d." % version) + logger.info("Unhandled KMS version V%d." % version) messagehandler = kmsRequestUnknown.kmsRequestUnknown(data, config) return messagehandler.executeRequestLogic() diff --git a/py2-kms/kmsRequestV4.py b/py2-kms/kmsRequestV4.py index 28981fd..a91e9cb 100644 --- a/py2-kms/kmsRequestV4.py +++ b/py2-kms/kmsRequestV4.py @@ -9,6 +9,8 @@ from structure import Structure from aes import AES from formatText import shell_message, justify +logger = logging.getLogger('root') + # v4 AES Key key = bytearray([0x05, 0x3D, 0x83, 0x07, 0xF9, 0xE5, 0xF0, 0x88, 0xEB, 0x5E, 0xA6, 0x68, 0x6C, 0xF0, 0x37, 0xC7, 0xE4, 0xEF, 0xD2, 0xD6]) @@ -102,8 +104,8 @@ class kmsRequestV4(kmsBase): ## Debug stuff. shell_message(nshell = 16) - logging.debug("KMS V4 Response: \n%s\n" % justify(response.dump(print_to_stdout = False))) - logging.debug("KMS V4 Response Bytes: \n%s\n" % justify(binascii.b2a_hex(str(response)))) + logger.debug("KMS V4 Response: \n%s\n" % justify(response.dump(print_to_stdout = False))) + logger.debug("KMS V4 Response Bytes: \n%s\n" % justify(binascii.b2a_hex(str(response)))) return str(response) @@ -120,7 +122,7 @@ class kmsRequestV4(kmsBase): ## Debug stuff. shell_message(nshell = 10) - logging.debug("Request V4 Data: \n%s\n" % justify(request.dump(print_to_stdout = False))) - logging.debug("Request V4: \n%s\n" % justify(binascii.b2a_hex(str(request)))) + logger.debug("Request V4 Data: \n%s\n" % justify(request.dump(print_to_stdout = False))) + logger.debug("Request V4: \n%s\n" % justify(binascii.b2a_hex(str(request)))) return request diff --git a/py2-kms/kmsRequestV5.py b/py2-kms/kmsRequestV5.py index 824c55b..a6a14eb 100644 --- a/py2-kms/kmsRequestV5.py +++ b/py2-kms/kmsRequestV5.py @@ -10,6 +10,8 @@ from kmsBase import kmsBase from structure import Structure from formatText import justify, shell_message +logger = logging.getLogger('root') + class kmsRequestV5(kmsBase): class RequestV5(Structure): class Message(Structure): @@ -135,8 +137,8 @@ class kmsRequestV5(kmsBase): response['padding'] = bytearray(self.getPadding(bodyLength)) shell_message(nshell = 16) - logging.info("KMS V%d Response: \n%s\n" % (self.ver, justify(response.dump(print_to_stdout = False)))) - logging.info("KMS V%d Structure Bytes: \n%s\n" % (self.ver, justify(binascii.b2a_hex(str(response))))) + logger.info("KMS V%d Response: \n%s\n" % (self.ver, justify(response.dump(print_to_stdout = False)))) + logger.info("KMS V%d Structure Bytes: \n%s\n" % (self.ver, justify(binascii.b2a_hex(str(response))))) return str(response) @@ -166,7 +168,7 @@ class kmsRequestV5(kmsBase): request['message'] = message shell_message(nshell = 10) - logging.info("Request V%d Data: \n%s\n" % (self.ver, justify(request.dump(print_to_stdout = False)))) - logging.info("Request V%d: \n%s\n" % (self.ver, justify(binascii.b2a_hex(str(request))))) + logger.info("Request V%d Data: \n%s\n" % (self.ver, justify(request.dump(print_to_stdout = False)))) + logger.info("Request V%d: \n%s\n" % (self.ver, justify(binascii.b2a_hex(str(request))))) return request diff --git a/py2-kms/rpcBind.py b/py2-kms/rpcBind.py index 42f1a62..cf0e0cb 100644 --- a/py2-kms/rpcBind.py +++ b/py2-kms/rpcBind.py @@ -9,6 +9,8 @@ from dcerpc import MSRPCHeader, MSRPCBindAck from structure import Structure from formatText import shell_message, justify +logger = logging.getLogger('root') + uuidNDR32 = uuid.UUID('8a885d04-1ceb-11c9-9fe8-08002b104860') uuidNDR64 = uuid.UUID('71710533-beba-4937-8319-b5dbef9ccc36') uuidTime = uuid.UUID('6cb71c2c-9812-4540-0300-000000000000') @@ -74,8 +76,8 @@ class handler(rpcBase.rpcBase): def parseRequest(self): request = MSRPCHeader(self.data) shell_message(nshell = 3) - logging.debug("RPC Bind Request Bytes: \n%s\n" % justify(binascii.b2a_hex(self.data))) - logging.debug("RPC Bind Request: \n%s\n%s\n" % (justify(request.dump(print_to_stdout = False)), + logger.debug("RPC Bind Request Bytes: \n%s\n" % justify(binascii.b2a_hex(self.data))) + logger.debug("RPC Bind Request: \n%s\n%s\n" % (justify(request.dump(print_to_stdout = False)), justify(MSRPCBind(request['pduData']).dump(print_to_stdout = False)))) return request @@ -117,8 +119,8 @@ class handler(rpcBase.rpcBase): response['ctx_items'] += str(resp) shell_message(nshell = 4) - logging.debug("RPC Bind Response: \n%s\n" % justify(response.dump(print_to_stdout = False))) - logging.debug("RPC Bind Response Bytes: \n%s\n" % justify(binascii.b2a_hex(str(response)))) + logger.debug("RPC Bind Response: \n%s\n" % justify(response.dump(print_to_stdout = False))) + logger.debug("RPC Bind Response Bytes: \n%s\n" % justify(binascii.b2a_hex(str(response)))) return response @@ -157,9 +159,9 @@ class handler(rpcBase.rpcBase): request['pduData'] = str(bind) shell_message(nshell = 0) - logging.debug("RPC Bind Request: \n%s\n%s\n" % (justify(request.dump(print_to_stdout = False)), + logger.debug("RPC Bind Request: \n%s\n%s\n" % (justify(request.dump(print_to_stdout = False)), justify(MSRPCBind(request['pduData']).dump(print_to_stdout = False)))) - logging.debug("RPC Bind Request Bytes: \n%s\n" % justify(binascii.b2a_hex(str(request)))) + logger.debug("RPC Bind Request Bytes: \n%s\n" % justify(binascii.b2a_hex(str(request)))) return request diff --git a/py2-kms/rpcRequest.py b/py2-kms/rpcRequest.py index 63b2c4a..e7a29dc 100644 --- a/py2-kms/rpcRequest.py +++ b/py2-kms/rpcRequest.py @@ -8,12 +8,14 @@ import kmsBase import rpcBase from formatText import justify, shell_message +logger = logging.getLogger('root') + class handler(rpcBase.rpcBase): def parseRequest(self): request = MSRPCRequestHeader(self.data) shell_message(nshell = 14) - logging.debug("RPC Message Request Bytes: \n%s\n" % justify(binascii.b2a_hex(self.data))) - logging.debug("RPC Message Request: \n%s\n" % justify(request.dump(print_to_stdout = False))) + logger.debug("RPC Message Request Bytes: \n%s\n" % justify(binascii.b2a_hex(self.data))) + logger.debug("RPC Message Request: \n%s\n" % justify(request.dump(print_to_stdout = False))) return request @@ -36,8 +38,8 @@ class handler(rpcBase.rpcBase): response['pduData'] = responseData shell_message(nshell = 17) - logging.debug("RPC Message Response: \n%s\n" % justify(response.dump(print_to_stdout = False))) - logging.debug("RPC Message Response Bytes: \n%s\n" % justify(binascii.b2a_hex(str(response)))) + logger.debug("RPC Message Response: \n%s\n" % justify(response.dump(print_to_stdout = False))) + logger.debug("RPC Message Response Bytes: \n%s\n" % justify(binascii.b2a_hex(str(response)))) return response @@ -54,8 +56,8 @@ class handler(rpcBase.rpcBase): request['pduData'] = str(self.data) shell_message(nshell = 11) - logging.debug("RPC Message Request: \n%s\n" % justify(request.dump(print_to_stdout = False))) - logging.debug("RPC Message Request Bytes: \n%s\n" % justify(binascii.b2a_hex(str(request)))) + logger.debug("RPC Message Request: \n%s\n" % justify(request.dump(print_to_stdout = False))) + logger.debug("RPC Message Request Bytes: \n%s\n" % justify(binascii.b2a_hex(str(request)))) return request diff --git a/py2-kms/server.py b/py2-kms/server.py index 950d830..721a075 100644 --- a/py2-kms/server.py +++ b/py2-kms/server.py @@ -15,9 +15,12 @@ import rpcBind, rpcRequest from dcerpc import MSRPCHeader from rpcBase import rpcBase from formatText import shell_message +from logging.handlers import RotatingFileHandler config = {} +logger = logging.getLogger('root') + # Valid language identifiers to be used in the EPID (see "kms.c" in vlmcsd) ValidLcid = [1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, @@ -39,6 +42,15 @@ ValidLcid = [1025, 1026, 1027, 1028, 1029, 10241, 10249, 10250, 11265, 11273, 11274, 12289, 12297, 12298, 13313, 13321, 13322, 14337, 14346, 15361, 15370, 16385, 16394, 17418, 18442, 19466, 20490] +def createLogger(config): + logger.setLevel(config['loglevel']) + + log_formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s', '%a, %d %b %Y %H:%M:%S') + log_handler = RotatingFileHandler(filename=config['logfile'], mode='a', maxBytes=int(config['logsize']*1024*512), backupCount=1, encoding=None, delay=0) + print int(config['logsize']*1024*512) + log_handler.setFormatter(log_formatter) + + logger.addHandler(log_handler) def main(): parser = argparse.ArgumentParser(description='py2-kms: KMS Server Emulator written in Python2', epilog="version: py2-kms_2018-11-15") @@ -66,12 +78,13 @@ The default is \"364F463A8863D35F\" or type \"random\" to auto generate the HWID help='Use this flag to set a Loglevel. The default is \"ERROR\".', type=str) parser.add_argument("-f", "--logfile", dest="logfile", action="store", default=os.path.dirname(os.path.abspath( __file__ )) + "/py2kms_server.log", help='Use this flag to set an output Logfile. The default is \"pykms_server.log\".', type=str) + parser.add_argument("-S", "--logsize", dest="logsize", action="store", default=0, + help='Use this flag to set a maximum size (in MB) to the output Logfile. Desactivated by default.', type=float) config.update(vars(parser.parse_args())) - logging.basicConfig(level=config['loglevel'], format='%(asctime)s %(levelname)-8s %(message)s', - datefmt='%a, %d %b %Y %H:%M:%S', filename=config['logfile'], filemode='w') - + createLogger(config) + # Random HWID. if config['hwid'] == "random": randomhwid = uuid.uuid4().hex @@ -81,13 +94,13 @@ The default is \"364F463A8863D35F\" or type \"random\" to auto generate the HWID try: config['hwid'] = binascii.a2b_hex(re.sub(r'[^0-9a-fA-F]', '', config['hwid'].strip('0x'))) if len(binascii.b2a_hex(config['hwid'])) < 16: - logging.error("Error: HWID \"%s\" is invalid. Hex string is too short." % binascii.b2a_hex(config['hwid']).upper()) + logger.error("Error: HWID \"%s\" is invalid. Hex string is too short." % binascii.b2a_hex(config['hwid']).upper()) return elif len(binascii.b2a_hex(config['hwid'])) > 16: - logging.error("Error: HWID \"%s\" is invalid. Hex string is too long." % binascii.b2a_hex(config['hwid']).upper()) + logger.error("Error: HWID \"%s\" is invalid. Hex string is too long." % binascii.b2a_hex(config['hwid']).upper()) return except TypeError: - logging.error("Error: HWID \"%s\" is invalid. Odd-length hex string." % binascii.b2a_hex(config['hwid']).upper()) + logger.error("Error: HWID \"%s\" is invalid. Odd-length hex string." % binascii.b2a_hex(config['hwid']).upper()) return # Check LCID. @@ -110,21 +123,21 @@ The default is \"364F463A8863D35F\" or type \"random\" to auto generate the HWID try: import sqlite3 except: - logging.warning("Module \"sqlite3\" is not installed, database support disabled.") + logger.warning("Module \"sqlite3\" is not installed, database support disabled.") config['dbSupport'] = False else: config['dbSupport'] = True server = SocketServer.TCPServer((config['ip'], config['port']), kmsServer) server.timeout = 5 - logging.info("TCP server listening at %s on port %d." % (config['ip'], config['port'])) - logging.info("HWID: %s" % binascii.b2a_hex(config['hwid']).upper()) + logger.info("TCP server listening at %s on port %d." % (config['ip'], config['port'])) + logger.info("HWID: %s" % binascii.b2a_hex(config['hwid']).upper()) server.serve_forever() class kmsServer(SocketServer.BaseRequestHandler): def setup(self): - logging.info("Connection accepted: %s:%d" % (self.client_address[0], self.client_address[1])) + logger.info("Connection accepted: %s:%d" % (self.client_address[0], self.client_address[1])) def handle(self): while True: @@ -133,42 +146,42 @@ class kmsServer(SocketServer.BaseRequestHandler): data = self.request.recv(1024) except socket.error, e: if e.errno == errno.ECONNRESET: - logging.error("Connection reset by peer.") + logger.error("Connection reset by peer.") break else: raise if not data: - logging.warning("No data received !") + logger.warning("No data received !") break # data = bytearray(self.data.strip()) - # logging.debug(binascii.b2a_hex(str(data))) + # logger.debug(binascii.b2a_hex(str(data))) packetType = MSRPCHeader(data)['type'] if packetType == rpcBase.packetType['bindReq']: - logging.info("RPC bind request received.") + logger.info("RPC bind request received.") shell_message(nshell = [-2, 2]) handler = rpcBind.handler(data, config) elif packetType == rpcBase.packetType['request']: - logging.info("Received activation request.") + logger.info("Received activation request.") shell_message(nshell = [-2, 13]) handler = rpcRequest.handler(data, config) else: - logging.error("Error: Invalid RPC request type ", packetType) + logger.error("Error: Invalid RPC request type ", packetType) break res = str(handler.populate()) self.request.send(res) if packetType == rpcBase.packetType['bindReq']: - logging.info("RPC bind acknowledged.") + logger.info("RPC bind acknowledged.") shell_message(nshell = [-3, 5, 6]) elif packetType == rpcBase.packetType['request']: - logging.info("Responded to activation request.") + logger.info("Responded to activation request.") shell_message(nshell = [-3, 18, 19]) break def finish(self): self.request.close() - logging.info("Connection closed: %s:%d" % (self.client_address[0], self.client_address[1])) + logger.info("Connection closed: %s:%d" % (self.client_address[0], self.client_address[1])) if __name__ == "__main__": main() diff --git a/py3-kms/kmsBase.py b/py3-kms/kmsBase.py index 7c002ab..bdc19d8 100644 --- a/py3-kms/kmsBase.py +++ b/py3-kms/kmsBase.py @@ -19,6 +19,8 @@ try: except ImportError: pass +logger = logging.getLogger('root') + class UUID(Structure): commonHdr = () structure = ( @@ -130,7 +132,7 @@ class kmsBase: skuId TEXT, licenseStatus TEXT, lastRequestTime INTEGER, kmsEpid TEXT, requestCount INTEGER)") except sqlite3.Error as e: - logging.error("Error %s:" % e.args[0]) + logger.error("Error %s:" % e.args[0]) sys.exit(1) finally: @@ -140,8 +142,8 @@ skuId TEXT, licenseStatus TEXT, lastRequestTime INTEGER, kmsEpid TEXT, requestCo shell_message(nshell = 15) kmsRequest = byterize(kmsRequest) - logging.debug("KMS Request Bytes: \n%s\n" % justify(binascii.b2a_hex(str(kmsRequest).encode('latin-1')).decode('utf-8'))) - logging.debug("KMS Request: \n%s\n" % justify(kmsRequest.dump(print_to_stdout = False))) + logger.debug("KMS Request Bytes: \n%s\n" % justify(binascii.b2a_hex(str(kmsRequest).encode('latin-1')).decode('utf-8'))) + logger.debug("KMS Request: \n%s\n" % justify(kmsRequest.dump(print_to_stdout = False))) clientMachineId = kmsRequest['clientMachineId'].get() applicationId = kmsRequest['applicationId'].get() @@ -156,10 +158,10 @@ skuId TEXT, licenseStatus TEXT, lastRequestTime INTEGER, kmsEpid TEXT, requestCo tz = get_localzone() local_dt = tz.localize(requestDatetime) except UnknownTimeZoneError: - logging.warning('Unknown time zone ! Request time not localized.') + logger.warning('Unknown time zone ! Request time not localized.') local_dt = requestDatetime except ImportError: - logging.warning('Module "tzlocal" not available ! Request time not localized.') + logger.warning('Module "tzlocal" not available ! Request time not localized.') local_dt = requestDatetime # Get SkuId, AppId and client threshold. @@ -205,12 +207,12 @@ skuId TEXT, licenseStatus TEXT, lastRequestTime INTEGER, kmsEpid TEXT, requestCo } #print infoDict - logging.info("Machine Name: %s" % infoDict["machineName"]) - logging.info("Client Machine ID: %s" % infoDict["clientMachineId"]) - logging.info("Application ID: %s" % infoDict["appId"]) - logging.info("SKU ID: %s" % infoDict["skuId"]) - logging.info("License Status: %s" % infoDict["licenseStatus"]) - logging.info("Request Time: %s" % local_dt.strftime('%Y-%m-%d %H:%M:%S %Z (UTC%z)')) + logger.info("Machine Name: %s" % infoDict["machineName"]) + logger.info("Client Machine ID: %s" % infoDict["clientMachineId"]) + logger.info("Application ID: %s" % infoDict["appId"]) + logger.info("SKU ID: %s" % infoDict["skuId"]) + logger.info("License Status: %s" % infoDict["licenseStatus"]) + logger.info("Request Time: %s" % local_dt.strftime('%Y-%m-%d %H:%M:%S %Z (UTC%z)')) if self.config['sqlite'] and self.config['dbSupport']: con = None @@ -246,10 +248,10 @@ clientMachineId=:clientMachineId;", infoDict) clientMachineId=:clientMachineId;", infoDict) except sqlite3.Error as e: - logging.error("Error %s:" % e.args[0]) + logger.error("Error %s:" % e.args[0]) except sqlite3.Error as e: - logging.error("Error %s:" % e.args[0]) + logger.error("Error %s:" % e.args[0]) sys.exit(1) finally: if con: @@ -290,17 +292,17 @@ clientMachineId=:clientMachineId;", infoDict) (str(response["kmsEpid"].decode('utf-16le')), str(kmsRequest['clientMachineId'].get()))) except sqlite3.Error as e: - logging.error("Error %s:" % e.args[0]) + logger.error("Error %s:" % e.args[0]) except sqlite3.Error as e: - logging.error("Error %s:" % e.args[0]) + logger.error("Error %s:" % e.args[0]) sys.exit(1) finally: if con: con.commit() con.close() - logging.info("Server ePID: %s" % response["kmsEpid"].decode('utf-16le')) + logger.info("Server ePID: %s" % response["kmsEpid"].decode('utf-16le')) return response @@ -312,16 +314,16 @@ def generateKmsResponseData(data, config): currentDate = time.strftime("%a %b %d %H:%M:%S %Y") if version == 4: - logging.info("Received V%d request on %s." % (version, currentDate)) + logger.info("Received V%d request on %s." % (version, currentDate)) messagehandler = kmsRequestV4.kmsRequestV4(data, config) elif version == 5: - logging.info("Received V%d request on %s." % (version, currentDate)) + logger.info("Received V%d request on %s." % (version, currentDate)) messagehandler = kmsRequestV5.kmsRequestV5(data, config) elif version == 6: - logging.info("Received V%d request on %s." % (version, currentDate)) + logger.info("Received V%d request on %s." % (version, currentDate)) messagehandler = kmsRequestV6.kmsRequestV6(data, config) else: - logging.info("Unhandled KMS version V%d." % version) + logger.info("Unhandled KMS version V%d." % version) messagehandler = kmsRequestUnknown.kmsRequestUnknown(data, config) return messagehandler.executeRequestLogic() diff --git a/py3-kms/kmsRequestV4.py b/py3-kms/kmsRequestV4.py index 3bc8370..263822c 100644 --- a/py3-kms/kmsRequestV4.py +++ b/py3-kms/kmsRequestV4.py @@ -9,6 +9,8 @@ from structure import Structure from aes import AES from formatText import shell_message, justify, byterize +logger = logging.getLogger('root') + # v4 AES Key key = bytearray([0x05, 0x3D, 0x83, 0x07, 0xF9, 0xE5, 0xF0, 0x88, 0xEB, 0x5E, 0xA6, 0x68, 0x6C, 0xF0, 0x37, 0xC7, 0xE4, 0xEF, 0xD2, 0xD6]) @@ -103,8 +105,8 @@ class kmsRequestV4(kmsBase): ## Debug stuff. shell_message(nshell = 16) response = byterize(response) - logging.debug("KMS V4 Response: \n%s\n" % justify(response.dump(print_to_stdout = False))) - logging.debug("KMS V4 Response Bytes: \n%s\n" % justify(binascii.b2a_hex(str(response).encode('latin-1')).decode('utf-8'))) + logger.debug("KMS V4 Response: \n%s\n" % justify(response.dump(print_to_stdout = False))) + logger.debug("KMS V4 Response Bytes: \n%s\n" % justify(binascii.b2a_hex(str(response).encode('latin-1')).decode('utf-8'))) return str(response) @@ -122,7 +124,7 @@ class kmsRequestV4(kmsBase): ## Debug stuff. shell_message(nshell = 10) request = byterize(request) - logging.debug("Request V4 Data: \n%s\n" % justify(request.dump(print_to_stdout = False))) - logging.debug("Request V4: \n%s\n" % justify(binascii.b2a_hex(str(request).encode('latin-1')).decode('utf-8'))) + logger.debug("Request V4 Data: \n%s\n" % justify(request.dump(print_to_stdout = False))) + logger.debug("Request V4: \n%s\n" % justify(binascii.b2a_hex(str(request).encode('latin-1')).decode('utf-8'))) return request diff --git a/py3-kms/kmsRequestV5.py b/py3-kms/kmsRequestV5.py index 450e1a5..1f260c0 100644 --- a/py3-kms/kmsRequestV5.py +++ b/py3-kms/kmsRequestV5.py @@ -10,6 +10,8 @@ from kmsBase import kmsBase from structure import Structure from formatText import justify, shell_message, byterize +logger = logging.getLogger('root') + class kmsRequestV5(kmsBase): class RequestV5(Structure): class Message(Structure): @@ -138,8 +140,8 @@ class kmsRequestV5(kmsBase): shell_message(nshell = 16) response = byterize(response) - logging.info("KMS V%d Response: \n%s\n" % (self.ver, justify(response.dump(print_to_stdout = False)))) - logging.info("KMS V%d Structure Bytes: \n%s\n" % (self.ver, justify(binascii.b2a_hex(str(response).encode('latin-1')).decode('utf-8')))) + logger.info("KMS V%d Response: \n%s\n" % (self.ver, justify(response.dump(print_to_stdout = False)))) + logger.info("KMS V%d Structure Bytes: \n%s\n" % (self.ver, justify(binascii.b2a_hex(str(response).encode('latin-1')).decode('utf-8')))) return str(response) @@ -170,7 +172,7 @@ class kmsRequestV5(kmsBase): shell_message(nshell = 10) request = byterize(request) - logging.info("Request V%d Data: \n%s\n" % (self.ver, justify(request.dump(print_to_stdout = False)))) - logging.info("Request V%d: \n%s\n" % (self.ver, justify(binascii.b2a_hex(str(request).encode('latin-1')).decode('utf-8')))) + logger.info("Request V%d Data: \n%s\n" % (self.ver, justify(request.dump(print_to_stdout = False)))) + logger.info("Request V%d: \n%s\n" % (self.ver, justify(binascii.b2a_hex(str(request).encode('latin-1')).decode('utf-8')))) return request diff --git a/py3-kms/rpcBind.py b/py3-kms/rpcBind.py index d30428d..f48c8f1 100644 --- a/py3-kms/rpcBind.py +++ b/py3-kms/rpcBind.py @@ -9,6 +9,8 @@ from dcerpc import MSRPCHeader, MSRPCBindAck from structure import Structure from formatText import shell_message, justify, byterize +logger = logging.getLogger('root') + uuidNDR32 = uuid.UUID('8a885d04-1ceb-11c9-9fe8-08002b104860') uuidNDR64 = uuid.UUID('71710533-beba-4937-8319-b5dbef9ccc36') uuidTime = uuid.UUID('6cb71c2c-9812-4540-0300-000000000000') @@ -75,8 +77,8 @@ class handler(rpcBase.rpcBase): request = MSRPCHeader(self.data) shell_message(nshell = 3) request = byterize(request) - logging.debug("RPC Bind Request Bytes: \n%s\n" % justify(binascii.b2a_hex(self.data).decode('utf-8'))) - logging.debug("RPC Bind Request: \n%s\n%s\n" % (justify(request.dump(print_to_stdout = False)), + logger.debug("RPC Bind Request Bytes: \n%s\n" % justify(binascii.b2a_hex(self.data).decode('utf-8'))) + logger.debug("RPC Bind Request: \n%s\n%s\n" % (justify(request.dump(print_to_stdout = False)), justify(MSRPCBind(request['pduData']).dump(print_to_stdout = False)))) return request @@ -119,8 +121,8 @@ class handler(rpcBase.rpcBase): shell_message(nshell = 4) response = byterize(response) - logging.debug("RPC Bind Response: \n%s\n" % justify(response.dump(print_to_stdout = False))) - logging.debug("RPC Bind Response Bytes: \n%s\n" % justify(binascii.b2a_hex(str(response).encode('latin-1')).decode('utf-8'))) + logger.debug("RPC Bind Response: \n%s\n" % justify(response.dump(print_to_stdout = False))) + logger.debug("RPC Bind Response Bytes: \n%s\n" % justify(binascii.b2a_hex(str(response).encode('latin-1')).decode('utf-8'))) return response @@ -161,9 +163,9 @@ class handler(rpcBase.rpcBase): shell_message(nshell = 0) bind = byterize(bind) request = byterize(request) - logging.debug("RPC Bind Request: \n%s\n%s\n" % (justify(request.dump(print_to_stdout = False)), + logger.debug("RPC Bind Request: \n%s\n%s\n" % (justify(request.dump(print_to_stdout = False)), justify(MSRPCBind(request['pduData']).dump(print_to_stdout = False)))) - logging.debug("RPC Bind Request Bytes: \n%s\n" % justify(binascii.b2a_hex(str(request).encode('latin-1')).decode('utf-8'))) + logger.debug("RPC Bind Request Bytes: \n%s\n" % justify(binascii.b2a_hex(str(request).encode('latin-1')).decode('utf-8'))) return request diff --git a/py3-kms/rpcRequest.py b/py3-kms/rpcRequest.py index 155fc01..2ff7738 100644 --- a/py3-kms/rpcRequest.py +++ b/py3-kms/rpcRequest.py @@ -8,13 +8,15 @@ import kmsBase import rpcBase from formatText import justify, shell_message, byterize +logger = logging.getLogger('root') + class handler(rpcBase.rpcBase): def parseRequest(self): request = MSRPCRequestHeader(self.data) shell_message(nshell = 14) request = byterize(request) - logging.debug("RPC Message Request Bytes: \n%s\n" % justify(binascii.b2a_hex(self.data).decode('utf-8'))) - logging.debug("RPC Message Request: \n%s\n" % justify(request.dump(print_to_stdout = False))) + logger.debug("RPC Message Request Bytes: \n%s\n" % justify(binascii.b2a_hex(self.data).decode('utf-8'))) + logger.debug("RPC Message Request: \n%s\n" % justify(request.dump(print_to_stdout = False))) return request @@ -38,8 +40,8 @@ class handler(rpcBase.rpcBase): shell_message(nshell = 17) response = byterize(response) - logging.debug("RPC Message Response: \n%s\n" % justify(response.dump(print_to_stdout = False))) - logging.debug("RPC Message Response Bytes: \n%s\n" % justify(binascii.b2a_hex(str(response).encode('latin-1')).decode('utf-8'))) + logger.debug("RPC Message Response: \n%s\n" % justify(response.dump(print_to_stdout = False))) + logger.debug("RPC Message Response Bytes: \n%s\n" % justify(binascii.b2a_hex(str(response).encode('latin-1')).decode('utf-8'))) return response @@ -57,8 +59,8 @@ class handler(rpcBase.rpcBase): shell_message(nshell = 11) request = byterize(request) - logging.debug("RPC Message Request: \n%s\n" % justify(request.dump(print_to_stdout = False))) - logging.debug("RPC Message Request Bytes: \n%s\n" % justify(binascii.b2a_hex(str(request).encode('latin-1')).decode('utf-8'))) + logger.debug("RPC Message Request: \n%s\n" % justify(request.dump(print_to_stdout = False))) + logger.debug("RPC Message Request Bytes: \n%s\n" % justify(binascii.b2a_hex(str(request).encode('latin-1')).decode('utf-8'))) return request diff --git a/py3-kms/server.py b/py3-kms/server.py index 629d9ff..7290d48 100644 --- a/py3-kms/server.py +++ b/py3-kms/server.py @@ -15,6 +15,9 @@ import rpcBind, rpcRequest from dcerpc import MSRPCHeader from rpcBase import rpcBase from formatText import shell_message +from logging.handlers import RotatingFileHandler + +logger = logging.getLogger('root') config = {} @@ -39,6 +42,14 @@ ValidLcid = [1025, 1026, 1027, 1028, 1029, 10241, 10249, 10250, 11265, 11273, 11274, 12289, 12297, 12298, 13313, 13321, 13322, 14337, 14346, 15361, 15370, 16385, 16394, 17418, 18442, 19466, 20490] +def createLogger(config): + logger.setLevel(config['loglevel']) + + log_formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s', '%a, %d %b %Y %H:%M:%S') + log_handler = RotatingFileHandler(filename=config['logfile'], mode='a', maxBytes=int(config['logsize']*1024*512), backupCount=1, encoding=None, delay=0) + log_handler.setFormatter(log_formatter) + + logger.addHandler(log_handler) def main(): parser = argparse.ArgumentParser(description='py3-kms: KMS Server Emulator written in Python3', epilog="version: py3-kms_2018-11-15") @@ -66,11 +77,13 @@ The default is \"364F463A8863D35F\" or type \"random\" to auto generate the HWID help='Use this flag to set a Loglevel. The default is \"ERROR\".', type=str) parser.add_argument("-f", "--logfile", dest="logfile", action="store", default=os.path.dirname(os.path.abspath( __file__ )) + "/py3kms_server.log", help='Use this flag to set an output Logfile. The default is \"pykms_server.log\".', type=str) - - config.update(vars(parser.parse_args())) + parser.add_argument("-S", "--logsize", dest="logsize", action="store", default=0, + help='Use this flag to set a maximum size (in MB) to the output Logfile. Desactivated by default.', type=float) + + config.update(vars(parser.parse_args())) + + createLogger(config) - logging.basicConfig(level=config['loglevel'], format='%(asctime)s %(levelname)-8s %(message)s', - datefmt='%a, %d %b %Y %H:%M:%S', filename=config['logfile'], filemode='w') # Random HWID. if config['hwid'] == "random": randomhwid = uuid.uuid4().hex @@ -80,13 +93,13 @@ The default is \"364F463A8863D35F\" or type \"random\" to auto generate the HWID try: config['hwid'] = binascii.a2b_hex(re.sub(r'[^0-9a-fA-F]', '', config['hwid'].strip('0x'))) if len(binascii.b2a_hex(config['hwid'])) < 16: - logging.error("Error: HWID \"%s\" is invalid. Hex string is too short." % binascii.b2a_hex(config['hwid']).decode('utf-8').upper()) + logger.error("Error: HWID \"%s\" is invalid. Hex string is too short." % binascii.b2a_hex(config['hwid']).decode('utf-8').upper()) return elif len(binascii.b2a_hex(config['hwid'])) > 16: - logging.error("Error: HWID \"%s\" is invalid. Hex string is too long." % binascii.b2a_hex(config['hwid']).decode('utf-8').upper()) + logger.error("Error: HWID \"%s\" is invalid. Hex string is too long." % binascii.b2a_hex(config['hwid']).decode('utf-8').upper()) return except TypeError: - logging.error("Error: HWID \"%s\" is invalid. Odd-length hex string." % binascii.b2a_hex(config['hwid']).decode('utf-8').upper()) + logger.error("Error: HWID \"%s\" is invalid. Odd-length hex string." % binascii.b2a_hex(config['hwid']).decode('utf-8').upper()) return # Check LCID. @@ -109,21 +122,21 @@ The default is \"364F463A8863D35F\" or type \"random\" to auto generate the HWID try: import sqlite3 except: - logging.warning("Module \"sqlite3\" is not installed, database support disabled.") + logger.warning("Module \"sqlite3\" is not installed, database support disabled.") config['dbSupport'] = False else: config['dbSupport'] = True server = socketserver.TCPServer((config['ip'], config['port']), kmsServer) server.timeout = 5 - logging.info("TCP server listening at %s on port %d." % (config['ip'], config['port'])) - logging.info("HWID: %s" % binascii.b2a_hex(config['hwid']).decode('utf-8').upper()) + logger.info("TCP server listening at %s on port %d." % (config['ip'], config['port'])) + logger.info("HWID: %s" % binascii.b2a_hex(config['hwid']).decode('utf-8').upper()) server.serve_forever() class kmsServer(socketserver.BaseRequestHandler): def setup(self): - logging.info("Connection accepted: %s:%d" % (self.client_address[0], self.client_address[1])) + logger.info("Connection accepted: %s:%d" % (self.client_address[0], self.client_address[1])) def handle(self): while True: @@ -132,42 +145,42 @@ class kmsServer(socketserver.BaseRequestHandler): self.data = self.request.recv(1024) except socket.error as e: if e.errno == errno.ECONNRESET: - logging.error("Connection reset by peer.") + logger.error("Connection reset by peer.") break else: raise if self.data == '' or not self.data: - logging.warning("No data received !") + logger.warning("No data received !") break # data = bytearray(self.data.strip()) - # logging.debug(binascii.b2a_hex(str(data))) + # logger.debug(binascii.b2a_hex(str(data))) packetType = MSRPCHeader(self.data)['type'] if packetType == rpcBase.packetType['bindReq']: - logging.info("RPC bind request received.") + logger.info("RPC bind request received.") shell_message(nshell = [-2, 2]) handler = rpcBind.handler(self.data, config) elif packetType == rpcBase.packetType['request']: - logging.info("Received activation request.") + logger.info("Received activation request.") shell_message(nshell = [-2, 13]) handler = rpcRequest.handler(self.data, config) else: - logging.error("Error: Invalid RPC request type ", packetType) + logger.error("Error: Invalid RPC request type ", packetType) break res = str(handler.populate()).encode('latin-1') self.request.send(res) if packetType == rpcBase.packetType['bindReq']: - logging.info("RPC bind acknowledged.") + logger.info("RPC bind acknowledged.") shell_message(nshell = [-3, 5, 6]) elif packetType == rpcBase.packetType['request']: - logging.info("Responded to activation request.") + logger.info("Responded to activation request.") shell_message(nshell = [-3, 18, 19]) break def finish(self): self.request.close() - logging.info("Connection closed: %s:%d" % (self.client_address[0], self.client_address[1])) + logger.info("Connection closed: %s:%d" % (self.client_address[0], self.client_address[1])) if __name__ == "__main__": main()