There are many malicious scripts available on the Internet. Github has plenty of info stealers and RATs made available “for testing or research purposes”. Here is one that I found recently: Trap-Stealer[1]. Often those scripts are pretty well obfuscated to pass through security controls and make Security Analysts’ life harder. Let’s review a practical example.
Today, I won’t review the info stealer capabilities because they are common but let’s check the obfuscation techniques. The file was dropped as a fake JPEG image: C:UsersuserAppDataLocalapxpvddh.jpeg. It has a low score on VT: 3/63[2].
First, the code is “flooded” with classes that do nothing:
class TtV4adTuzK: def __init__(self): self.data = True def get_data(self): return self.data class nxTJRP4oBo: def __init__(self): self.data = True def get_data(self): return self.data class cLaiqjSQel: def __init__(self): self.data = True def get_data(self): return self.data
Or useless variables:
J4BL2VTnoS = 95994844 Q5eKoFfYgd = 79322716 ME2ZgJpLA0 = 84016443 m4tvU1GFfJ = 31572061 EacvCg0xlz = 58092955 TRwCJhKsQb = 88130587
Dependencies with some Python modules are resolved:
requirements = [ ["requests", "requests"], ["Cryptodome.Cipher", "pycryptodomex" if not 'PythonSoftwareFoundation' in executable else 'pycryptodome'] ] for modl in requirements: try: import_module(module[0]) except: subprocess.Popen(executable + " -m pip install " +modl[1], shell=True) time.sleep(3)
The interesting code starts here:
f2KQN4bukRZMWSZicAmmYUWycFs6d0m5AqoEhG(base64.b64decode(S3ZpuwXgombrIYkwUNwRUJmSFtqLNOGKAHETR1))
A huge chunk of Base64 data is decoded and passed to f2KQN4bukRZMWSZicAmmYUWycFs6d0m5AqoEhG, an alias for exe()!
Once decoded, a second script obfuscated with the same techniques is disclosed. It contains another Base64 chunk of data. This time, the decoded data is encrypted.
Here a funny technique is used to decrypt the next payload. An array of encryption keys is provided and all of them are tested until the decryption succeeds:
s = [b'Co-7hDMhMh7UtUQ29kT0J7krqsTXPUAFXA7RtpcU6xY=', b'cbkSAtHBbB-1QGa6bhIz_faB_iLXMnoQ2DnoXOGCxLo=', b'0d5ykqArsb7Gkb3ZJtjr5-nzIF-2bOYgKtwAyny8B8k=', b'ztG6jHYX0PPlTa_yMzrrxLelrKf79hovRQADx5sioXo=', b'JT0JyIIHm3LfeAuit0xf-vej3m37Qhxvnwc3flWQ3ew=', b'0lSaIjRa6nePT6QiGIoPpVrw8EMHDCT_I7T6JwCk0Cc=', b'KhJzINwra-Dv78aZpTZeqClzc484KhtXEO8fvmV38nY=', b'cRReHk0vv3NlLplRTBxly-B5LamTR4s-7UwaGl-iuak=', b'NWXrr-8oMnHPP9q46JheOjH46abeH9_kHUcUjhxRbsE=', b'4Vu6YVdZGOSclihs4ukSRppyV1M62QFqwp7ZU6y3RBs=', b'M1qQk8eFmk_tigtJgYhOFQVb6pxA4YAfzXAbzx-0BhA=', b'0KjwnWf-Bqri4ae4UVy3pBUCCcAWiFbgWjkWmd7zsdI=', b'WBkyoZfIwgzunYz9je8_-lBeotQ2ntjx59kVuscHboQ=', b'usQcLUBWrVM7dENg0A6ge15mHK9RtB4RV6MB4hbD70o='] for key in s: try: decrypted_code = wqSJRHIzn7T3FiBgqfmquhhSEyCwLpRRMcdtF3(key.decode("utf-8")).decrypt(encrypted_code) break except Exception as e: pass
Finally, the decrypted code is decompressed and executed:
decompressed_code = zlib.decompress(decrypted_code).decode('utf-8') f2KQN4bukRZMWSZicAmmYUWycFs6d0m5AqoEhG(decompressed_code)
You may wonder how these obfuscation techniques are implemented by the attacker. They have tools for this! In the context of Trap-Stealer, the obfuscation tool is even part of the repository[3]. Here is how it works:
remnux@remnux:/MalwareZoo/20241125/Trap-Stealer$ mkdir build remnux@remnux:/MalwareZoo/20241125/Trap-Stealer$ cat <<__END__ >build/temp.py print("This is a super malicious Python script! }:->") __END__ remnux@remnux:/MalwareZoo/20241125/Trap-Stealer$ python3 ./obfucator.py my_super_cool_infostealer INFO:root:The code has been encrypted, Filename: ./build/my_super_cool_infostealer.py remnux@remnux:/MalwareZoo/20241125/Trap-Stealer$ head build/my_super_cool_infostealer.py from sys import executable, stderr ueupD5ALo7 = 33628666 VKkflw4g74 = 98340683 XRPK2HJT5b = 80807402 fhaj93exmX = 5089192 class fMVSRbmSTG: def __init__(self): self.data = True remnux@remnux:/MalwareZoo/20241125/Trap-Stealer$ python3 build/my_super_cool_infostealer.py [...pip stuff removed ...] This is a super malicious Python script! }:->
Note that the obfuscated file is pretty big compared to the “clear text” version: 37 bytes for “temp.py” and 20087 bytes for “my_super_cool_infostealer.py”. Obfuscation has a cost! 🙂
[1] https://github.com/TheCuteOwl/Trap-Stealer/tree/main
[2] https://www.virustotal.com/gui/file/85a0342027420025c477f3f6ab68376aa1608a447d1fb24920ac36b7cf7fd59d/detection
[3] https://github.com/TheCuteOwl/Trap-Stealer/blob/main/obfuscator.py
Xavier Mertens (@xme)
Xameco
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.