Skip to content

Instantly share code, notes, and snippets.

@tahaconfiant
Created December 23, 2022 15:14
Show Gist options
  • Save tahaconfiant/d6d8746e56cbf0458358ed304a5118ac to your computer and use it in GitHub Desktop.
Save tahaconfiant/d6d8746e56cbf0458358ed304a5118ac to your computer and use it in GitHub Desktop.
command line script to decrypt OSX/Shlayer.F C2 configuration
# author : taha@confiant.com 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