Skip to content

Instantly share code, notes, and snippets.

@lbpierre
Created July 12, 2023 13:17
Show Gist options
  • Save lbpierre/ad699298e09110727a959a0b0ba54d63 to your computer and use it in GitHub Desktop.
Save lbpierre/ad699298e09110727a959a0b0ba54d63 to your computer and use it in GitHub Desktop.
CustomerLoader AES key and C2 URL extraction
import sys, struct, clr
clr.AddReference("System.Memory")
from System.Reflection import Assembly, MethodInfo, BindingFlags
from System import Type
import string
import hashlib
from base64 import b64decode
from itertools import combinations
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
DNLIB_PATH = '/home/jovyan/work/utils/dnlib.dll'
clr.AddReference(DNLIB_PATH)
import dnlib
from dnlib.DotNet import *
from dnlib.DotNet.Emit import OpCodes
def decrypt(key: str, data: str) -> bytes:
"""decrypt CustomerLoader encrypted data"""
cleartext = b""
try:
cipher = Cipher(algorithms.AES(key), modes.ECB())
decryptor = cipher.decryptor()
cleartext = decryptor.update(data)
unpadder = padding.PKCS7(128).unpadder()
block = unpadder.update(cleartext)
end = unpadder.finalize()
cleartext = block + end
except Exception:
pass
return cleartext
def extract_base64_strings(PE_PATH: str) -> list:
""" """
base64_set = string.ascii_letters + string.digits + "+/="
def is_base64(data: str) -> bool:
return True if all(map(lambda x: x in base64_set, data)) else False
datas = []
module = dnlib.DotNet.ModuleDefMD.Load(PE_PATH)
for mtype in module.GetTypes():
for method in mtype.Methods:
for ptr in range(100):
try:
if method.Body.Instructions[ptr].OpCode.Name == "ldstr":
data = method.Body.Instructions[ptr].Operand
if is_base64(data) and data and len(data) > 16:
datas.append(data)
except Exception:
pass
return datas
def search_key_and_c2(strings: list) -> tuple:
"""As CustomerLoader does not embedded too much base64 strings,
this function generate all combinaison of pair of strings to attempts
decrypting strings until one starts by http:// or https:// meaning
the decryption works successfuly.
Nb: clearly note the clever approach..."""
for x, y in combinations(strings, 2):
try:
b64decode(x)
b64decode(y)
except Exception:
continue
data = decrypt(b64decode(x), b64decode(y))
if data.startswith(b"http://") or data.startswith(b"https://"):
print(f"found AES key: `{x}` {data}")
key = x
c2 = data
return key, c2
data = decrypt(b64decode(y), b64decode(x))
if data.startswith(b"http://") or data.startswith(b"https://"):
print(f"found AES key: `{y}` {data}")
key = y
c2 = data
return key, c2
return None, None
if __name__ == "__main__":
import sys
strings = extract_base64_strings(sys.argv[1])
key, c2 = search_key_and_c2(strings)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment