Created
December 23, 2022 15:14
-
-
Save tahaconfiant/d6d8746e56cbf0458358ed304a5118ac to your computer and use it in GitHub Desktop.
command line script to decrypt OSX/Shlayer.F C2 configuration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# author : [email protected] aka lordx64 | |
# OSX/Shlayer.F C2 config extracting from DMG files | |
# copyright 2022 - All rights reserved | |
# compatible python 3.8 | |
# Note on installation on mac: | |
# brew install gmp | |
# then: env "CFLAGS=-I/usr/local/include -L/usr/local/lib" pip3 install pycrypto | |
from Crypto.Cipher import AES | |
import argparse | |
import sys | |
import os | |
import re | |
parser = argparse.ArgumentParser(description='shlayer configuration extractor') | |
parser.add_argument('--file','-f', action="store", metavar=('FILE'), help='get the configuration from a specific file') | |
parser.add_argument('--directory', '-d', action="store", metavar=('DIRECTORY'), help='dump the configuration from all the files present in a directory') | |
args = parser.parse_args() | |
if len(sys.argv)==1: | |
parser.print_help(sys.stderr) | |
sys.exit(-1) | |
class Cryptor(): | |
# function pkcs7padding taken from: https://stackoverflow.com/questions/43199123/encrypting-with-aes-256-and-pkcs7-padding | |
def pkcs7padding(self, data, block_size=16): | |
if type(data) != bytearray and type(data) != bytes: | |
raise TypeError("Only support bytearray/bytes !") | |
pl = block_size - (len(data) % block_size) | |
return data + bytearray([pl for i in range(pl)]) | |
def decrypt(self, data, iv, key): | |
mode = AES.MODE_CBC | |
cipher = AES.new(key, mode, iv) | |
decoded = cipher.decrypt(self.pkcs7padding(data)) | |
return decoded | |
def absoluteFilePaths(directory): | |
for dirpath,_,filenames in os.walk(directory): | |
for f in filenames: | |
yield os.path.abspath(os.path.join(dirpath, f)) | |
def decrypt_config_from_file(inputfile, iponly=False): | |
#print("decrypting from {}".format(os.path.basename(inputfile))) | |
with open(inputfile, 'rb') as f: | |
s = f.read() | |
if len(s) != 0 : # check if its an empty file | |
found_index_end = s.find(b'\x6b\x6f\x6c\x79') # koly header | |
found_index_start = s.find(b'\x3c\x2f\x70\x6c\x69\x73\x74\x3e') + 8 + 1 # </plist> + \x0a | |
key_size = 0x20 | |
iv_size = 0x10 | |
data_size = (found_index_end-(found_index_start+key_size+iv_size)) | |
key = s[found_index_start:found_index_start+key_size] | |
iv = s[found_index_start+key_size:found_index_start+key_size+iv_size] | |
data = s[found_index_start+key_size+iv_size:found_index_end] | |
cryptor = Cryptor() | |
decoded = cryptor.decrypt(data, iv, key).decode("utf-8", errors='ignore') | |
return decoded | |
else: | |
print("file {} is empty".format(inputfile)) | |
def decrypt_config_from_directory(dir, args): | |
res = set() | |
dir_path = os.path.abspath(dir) | |
files = absoluteFilePaths(dir_path) | |
for f in files: | |
buffer = decrypt_config_from_file(f) | |
print(buffer) | |
def main(argv): | |
if argv.file is not None: | |
res=decrypt_config_from_file(argv.file) | |
print(res) | |
if argv.directory is not None: | |
decrypt_config_from_directory(argv.directory, argv) | |
if __name__ == '__main__': | |
main(args) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment