# Impacket - Collection of Python classes for working with network protocols. # # Copyright (C) 2023 Fortra. All rights reserved. # # This software is provided under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. # # Tested so far: # (h)MimiBind # (h)MimiCommand # MimiUnBind # import pytest import unittest from tests.dcerpc import DCERPCTests from Cryptodome.Cipher import ARC4 from impacket.dcerpc.v5 import mimilib from impacket.dcerpc.v5.rpcrt import RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY @pytest.mark.remote class MimiKatzTests(DCERPCTests, unittest.TestCase): timeout = 30000 iface_uuid = mimilib.MSRPC_UUID_MIMIKATZ protocol = "ncacn_ip_tcp" string_binding_formatting = DCERPCTests.STRING_BINDING_MAPPER transfer_syntax = DCERPCTests.TRANSFER_SYNTAX_NDR mimikatz_command = "token::whoami" def get_dh_public_key(self): dh = mimilib.MimiDiffeH() blob = mimilib.PUBLICKEYBLOB() blob['y'] = dh.genPublicKey()[::-1] public_key = mimilib.MIMI_PUBLICKEY() public_key['sessionType'] = mimilib.CALG_RC4 public_key['cbPublicKey'] = 144 public_key['pbPublicKey'] = blob.getData() return dh, public_key def get_handle_key(self, dce): # Build handshake request dh, public_key = self.get_dh_public_key() resp = mimilib.hMimiBind(dce, public_key) # Get shared secret and obtain handle blob = mimilib.PUBLICKEYBLOB(b''.join(resp['serverPublicKey']['pbPublicKey'])) key = dh.getSharedSecret(blob['y'][::-1]) pHandle = resp['phMimi'] return pHandle, key[-16:] def test_MimiBind(self): dce, rpc_transport = self.connect() dh, public_key = self.get_dh_public_key() request = mimilib.MimiBind() request['clientPublicKey'] = public_key # Send request and get response resp = dce.request(request) self.assertEqual(resp["ErrorCode"], 0) self.assertEqual(resp["serverPublicKey"]["sessionType"], mimilib.CALG_RC4) # Get shared secret and obtain handle blob = mimilib.PUBLICKEYBLOB(b''.join(resp['serverPublicKey']['pbPublicKey'])) key = dh.getSharedSecret(blob['y'][::-1]) pHandle = resp['phMimi'] self.assertIsInstance(pHandle, bytes) self.assertIsInstance(key, bytes) dce.disconnect() rpc_transport.disconnect() def test_hMimiBind(self): dce, rpc_transport = self.connect() dh, public_key = self.get_dh_public_key() resp = mimilib.hMimiBind(dce, public_key) self.assertEqual(resp["ErrorCode"], 0) self.assertEqual(resp["serverPublicKey"]["sessionType"], mimilib.CALG_RC4) dce.disconnect() rpc_transport.disconnect() def test_MimiCommand(self): dce, rpc_transport = self.connect() pHandle, key = self.get_handle_key(dce) cipher = ARC4.new(key[::-1]) command = cipher.encrypt("{}\x00".format(self.mimikatz_command).encode('utf-16le')) request = mimilib.MimiCommand() request['phMimi'] = pHandle request['szEncCommand'] = len(command) request['encCommand'] = list(command) resp = dce.request(request) self.assertEqual(resp["ErrorCode"], 0) self.assertEqual(len(resp["encResult"]), resp["szEncResult"]) cipherText = b''.join(resp['encResult']) cipher = ARC4.new(key[::-1]) plain = cipher.decrypt(cipherText) dce.disconnect() rpc_transport.disconnect() def test_hMimiCommand(self): dce, rpc_transport = self.connect() pHandle, key = self.get_handle_key(dce) cipher = ARC4.new(key[::-1]) command = cipher.encrypt("{}\x00".format(self.mimikatz_command).encode('utf-16le')) resp = mimilib.hMimiCommand(dce, pHandle, command) self.assertEqual(resp["ErrorCode"], 0) self.assertEqual(len(resp["encResult"]), resp["szEncResult"]) dce.disconnect() rpc_transport.disconnect() def test_MimiUnBind(self): dce, rpc_transport = self.connect() pHandle, key = self.get_handle_key(dce) request = mimilib.MimiUnbind() request['phMimi'] = pHandle resp = dce.request(request) self.assertEqual(resp["ErrorCode"], 0) dce.disconnect() rpc_transport.disconnect() class MimiKatzTestsAuthn(MimiKatzTests): authn = True class MimiKatzTestsIntegrity(MimiKatzTestsAuthn): authn_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY class MimiKatzTestsPrivacy(MimiKatzTestsAuthn): authn_level = RPC_C_AUTHN_LEVEL_PKT_PRIVACY if __name__ == "__main__": unittest.main(verbosity=1)