diff --git a/IX. TCC/python/CrimsonUroboros.py b/IX. TCC/python/CrimsonUroboros.py index 5bb7fbf..7cf2b62 100755 --- a/IX. TCC/python/CrimsonUroboros.py +++ b/IX. TCC/python/CrimsonUroboros.py @@ -16,6 +16,7 @@ import struct import threading import time import xattr +import sqlite3 ### --- APP BUNDLE EXTENSION --- ### class SnakeHatchery: @@ -3121,16 +3122,278 @@ class TCCProcessor: pass def process(self, args): - if args.test: # - snake_instance.test() + + if args.tcc: + snake_instance.printPermissions() + + if args.tcc_fda: + snake_instance.printFDAStatus() + + if args.tcc_automation: + snake_instance.printTCCAutomation() + + if args.tcc_sysadmin: + snake_instance.printSysAdminFilesStatus() + + if args.tcc_desktop: + snake_instance.printDesktopAccessStatus() + + if args.tcc_documents: + snake_instance.printDocumentsAccessStatus() + + if args.tcc_downloads: + snake_instance.printDownloadsAccessStatus() + + if args.tcc_photos: + snake_instance.printPhotosAccessStatus() + + if args.tcc_contacts: + snake_instance.printContactsAccessStatus() + + if args.tcc_calendar: + snake_instance.printCalendarAccessStatus() + + if args.tcc_camera: + snake_instance.printCameraAccessStatus() + + if args.tcc_microphone: + snake_instance.printMicrophoneAccessStatus() + + if args.tcc_location: + snake_instance.printLocationAccessStatus() + + if args.tcc_recording: + snake_instance.printScreenRecordingAccessStatus() + + if args.tcc_accessibility: + snake_instance.printAccessibilityAccessStatus() + + if args.tcc_icloud: + snake_instance.printICloudAccessStatus() class SnakeIX(SnakeVIII): def __init__(self, binaries, file_path): super().__init__(binaries, file_path) + # Paths for TCC databases and location plist + self.TCC_DB_PATHS = [ + "/Library/Application Support/com.apple.TCC/TCC.db", + os.path.expanduser("~/Library/Application Support/com.apple.TCC/TCC.db") + ] + self.LOCATION_PLIST_PATH = "/var/db/locationd/clients.plist" - def test(self): - ''' test ''' - print('test') + def prepareDataForTCCQuery(self): + ''' Prepare binary path and bundle ID for TCC queries. ''' + binary_path = os.path.abspath(self.file_path).lower() + bundle_id = bundle_processor.getBundleId().lower() if bundle_processor else None + return binary_path, bundle_id + + def getPermissionsFromDB(self, db_path, binary_path, bundle_id): + ''' Retrieve all permissions from a given TCC database for the binary. ''' + permissions = [] + try: + conn = sqlite3.connect(db_path) + conn.create_function("lower", 1, lambda x: x.lower()) + cursor = conn.cursor() + cursor.execute(''' + SELECT * FROM access + WHERE lower(client) IN (lower(?), lower(?)); + ''', (binary_path, bundle_id or binary_path)) + columns = [col[0] for col in cursor.description] + permissions = [dict(zip(columns, row)) for row in cursor.fetchall()] + except sqlite3.Error as e: + print(f"Error accessing {db_path}: {e}") + finally: + if 'conn' in locals() and conn: + conn.close() + return permissions + + def getPermissions(self, binary_path, bundle_id): + ''' Retrieve all permissions from all TCC databases. ''' + permissions = {} + for db_path in self.TCC_DB_PATHS: + if self.checkIfPathExists(db_path): + db_permissions = self.getPermissionsFromDB(db_path, binary_path, bundle_id) + for permission in db_permissions: + service = permission.get('service') + if service not in permissions: + permissions[service] = permission.get('auth_value') + return permissions + + def getLocationPermission(self, binary_path, bundle_id): + ''' Check location services permission for the given binary from the plist. ''' + if not os.path.exists(self.LOCATION_PLIST_PATH): + print(f"Error accessing {self.LOCATION_PLIST_PATH}: File not found or inaccessible from current user (run as root)") + return {} + + with open(self.LOCATION_PLIST_PATH, 'rb') as plist_file: + plist_data = plistlib.load(plist_file) + for key, value in plist_data.items(): + if isinstance(value, dict): + executable_match = 'Executable' in value and binary_path.lower() in value['Executable'].lower() + bundle_match = bundle_id and 'BundleId' in value and bundle_id.lower() in value['BundleId'].lower() + if executable_match or bundle_match: + return {'Location Services': 2 if value.get('Authorized', 0) == 1 else 0} + return {} + + def parseTCCPermissions(self, location_check=False): + ''' Consolidate permissions from TCC databases and location plist. ''' + binary_path, bundle_id = self.prepareDataForTCCQuery() + permissions = self.getPermissions(binary_path, bundle_id) + + if location_check: + permissions.update(self.getLocationPermission(binary_path, bundle_id)) + + return permissions + + def printPermissions(self): + ''' Print permissions from TCC databases and location plist in a readable format. ''' + results = self.parseTCCPermissions(True) + for service in sorted(results.keys()): + auth_value = results[service] + status = self.getAuthValueStatus(auth_value) + print(f"{service}: {status} ({auth_value})") + + def getAuthValueStatus(self, auth_value): + ''' Get human-readable status for a given auth value. ''' + return { + 0: "No Access", + 1: "Unknown", + 2: "Access Granted", + 3: "Limited" + }.get(auth_value, "Unknown Status") + + def checkFDA(self): + ''' Check if the binary has Full Disk Access (FDA) by looking for specific permissions. ''' + return self.parseTCCPermissions().get('kTCCServiceSystemPolicyAllFiles') == 2 + + def printFDAStatus(self): + ''' Print the Full Disk Access (FDA) status. ''' + print(f"FDA: {'True' if self.checkFDA() else 'False'}") + + def getAppleEventsPermissions(self, binary_path, bundle_id): + ''' Retrieve permissions related to "kTCCServiceAppleEvents". ''' + permissions = [] + for db_path in self.TCC_DB_PATHS: + if self.checkIfPathExists(db_path): + db_permissions = self.getPermissionsFromDB(db_path, binary_path, bundle_id) + permissions.extend([ + { + 'service': perm['service'], + 'auth_value': perm['auth_value'], + 'indirect_object_identifier': perm['indirect_object_identifier'] + } + for perm in db_permissions if perm['service'] == "kTCCServiceAppleEvents" + ]) + return permissions + + def printTCCAutomation(self): + ''' Print automation access details for "kTCCServiceAppleEvents". ''' + binary_path, bundle_id = self.prepareDataForTCCQuery() + apple_events_permissions = self.getAppleEventsPermissions(binary_path, bundle_id) + + if not apple_events_permissions: + print("TCC Automation: False") + else: + print("TCC Automation: True") + for permission in apple_events_permissions: + status = self.getAuthValueStatus(permission['auth_value']) + print(f"Target: {permission['indirect_object_identifier']}, Status: {status} ({permission['auth_value']})") + + def checkSysAdminFilesAccess(self): + ''' Check if the binary has System Policy SysAdmin Files access by looking for specific permissions. ''' + return self.parseTCCPermissions().get('kTCCServiceSystemPolicySysAdminFiles') == 2 + + def printSysAdminFilesStatus(self): + ''' Print the System Policy SysAdmin Files access status. ''' + print(f"SysAdmin Files Access: {'True' if self.checkSysAdminFilesAccess() else 'False'}") + + def checkDesktopAccess(self): + ''' Check if the binary has Desktop Folder access by looking for specific permissions. ''' + return self.parseTCCPermissions().get('kTCCServiceSystemPolicyDesktopFolder') == 2 + + def printDesktopAccessStatus(self): + ''' Print the Desktop Folder access status. ''' + print(f"Desktop Folder Access: {'True' if self.checkDesktopAccess() else 'False'}") + + def checkDocumentsAccess(self): + ''' Check if the binary has Documents Folder access by looking for specific permissions. ''' + return self.parseTCCPermissions().get('kTCCServiceSystemPolicyDocumentsFolder') == 2 + + def printDocumentsAccessStatus(self): + ''' Print the Documents Folder access status. ''' + print(f"Documents Folder Access: {'True' if self.checkDocumentsAccess() else 'False'}") + + def checkDownloadsAccess(self): + ''' Check if the binary has Downloads Folder access by looking for specific permissions. ''' + return self.parseTCCPermissions().get('kTCCServiceSystemPolicyDownloadsFolder') == 2 + + def printDownloadsAccessStatus(self): + ''' Print the Downloads Folder access status. ''' + print(f"Downloads Folder Access: {'True' if self.checkDownloadsAccess() else 'False'}") + + def checkPhotosAccess(self): + ''' Check if the binary has Photos Library access by looking for specific permissions. ''' + return self.parseTCCPermissions().get('kTCCServicePhotos') == 2 + + def printPhotosAccessStatus(self): + ''' Print the Photos Library access status. ''' + print(f"Photos Library Access: {'True' if self.checkPhotosAccess() else 'False'}") + + def checkContactsAccess(self): + ''' Check if the binary has Contacts access by looking for specific permissions. ''' + return self.parseTCCPermissions().get('kTCCServiceAddressBook') == 2 + + def printContactsAccessStatus(self): + ''' Print the Contacts access status. ''' + print(f"Contacts Access: {'True' if self.checkContactsAccess() else 'False'}") + + def checkCalendarAccess(self): + ''' Check if the binary has Calendar access by looking for specific permissions. ''' + return self.parseTCCPermissions().get('kTCCServiceCalendar') == 2 + + def printCalendarAccessStatus(self): + ''' Print the Calendar access status. ''' + print(f"Calendar Access: {'True' if self.checkCalendarAccess() else 'False'}") + + def checkCameraAccess(self): + ''' Check if the binary has Camera access by looking for specific permissions. ''' + return self.parseTCCPermissions().get('kTCCServiceCamera') == 2 + + def printCameraAccessStatus(self): + ''' Print the Camera access status. ''' + print(f"Camera Access: {'True' if self.checkCameraAccess() else 'False'}") + + def checkMicrophoneAccess(self): + ''' Check if the binary has Microphone access by looking for specific permissions. ''' + return self.parseTCCPermissions().get('kTCCServiceMicrophone') == 2 + + def printMicrophoneAccessStatus(self): + ''' Print the Microphone access status. ''' + print(f"Microphone Access: {'True' if self.checkMicrophoneAccess() else 'False'}") + + def checkScreenRecordingAccess(self): + ''' Check if the binary has Screen Recording access by looking for specific permissions. ''' + return self.parseTCCPermissions().get('kTCCServiceScreenCapture') == 2 + + def printScreenRecordingAccessStatus(self): + ''' Print the Screen Recording access status. ''' + print(f"Screen Recording Access: {'True' if self.checkScreenRecordingAccess() else 'False'}") + + def checkAccessibilityAccess(self): + ''' Check if the binary has Accessibility access by looking for specific permissions. ''' + return self.parseTCCPermissions().get('kTCCServiceAccessibility') == 2 + + def printAccessibilityAccessStatus(self): + ''' Print the Accessibility access status. ''' + print(f"Accessibility Access: {'True' if self.checkAccessibilityAccess() else 'False'}") + + def checkICloudAccess(self): + ''' Check if the binary has iCloud (Ubiquity) access by looking for specific permissions. ''' + return self.parseTCCPermissions().get('kTCCServiceUbiquity') == 2 + + def printICloudAccessStatus(self): + ''' Print the iCloud (Ubiquity) access status. ''' + print(f"iCloud Access: {'True' if self.checkICloudAccess() else 'False'}") ### --- ARGUMENT PARSER --- ### @@ -3299,7 +3562,22 @@ class ArgumentParser: def addTCCArgs(self): tcc_group = self.parser.add_argument_group('TCC ARGS') - tcc_group.add_argument('--test', action='store_true', help="test") + tcc_group.add_argument('--tcc', action='store_true', help="Print TCC permissions of the binary") + tcc_group.add_argument('--tcc_fda', action='store_true', help="Check Full Disk Access (FDA) TCC permission for the binary") + tcc_group.add_argument('--tcc_automation', action='store_true', help="Check Automation TCC permission for the binary") + tcc_group.add_argument('--tcc_sysadmin', action='store_true', help="Check System Policy SysAdmin Files TCC permission for the binary") + tcc_group.add_argument('--tcc_desktop', action='store_true', help="Check Desktop Folder TCC permission for the binary") + tcc_group.add_argument('--tcc_documents', action='store_true', help="Check Documents Folder TCC permission for the binary") + tcc_group.add_argument('--tcc_downloads', action='store_true', help="Check Downloads Folder TCC permission for the binary") + tcc_group.add_argument('--tcc_photos', action='store_true', help="Check Photos Library TCC permission for the binary") + tcc_group.add_argument('--tcc_contacts', action='store_true', help="Check Contacts TCC permission for the binary") + tcc_group.add_argument('--tcc_calendar', action='store_true', help="Check Calendar TCC permission for the binary") + tcc_group.add_argument('--tcc_camera', action='store_true', help="Check Camera TCC permission for the binary") + tcc_group.add_argument('--tcc_microphone', action='store_true', help="Check Microphone TCC permission for the binary") + tcc_group.add_argument('--tcc_location', action='store_true', help="Check Location Services TCC permission for the binary") + tcc_group.add_argument('--tcc_recording', action='store_true', help="Check Screen Recording TCC permission for the binary") + tcc_group.add_argument('--tcc_accessibility', action='store_true', help="Check Accessibility TCC permission for the binary") + tcc_group.add_argument('--tcc_icloud', action='store_true', help="Check iCloud (Ubiquity) TCC permission for the binary") def parseArgs(self): args = self.parser.parse_args() diff --git a/README.md b/README.md index 834a740..f15a2a4 100644 --- a/README.md +++ b/README.md @@ -56,37 +56,68 @@ The table of contents showing links to all articles is below: Core program resulting from the Snake&Apple article series for binary analysis. You may find older versions of this script in each article directory in this repository. * Usage ```console -usage: CrimsonUroboros [-h] [-p PATH] [-b BUNDLE] [--bundle_structure] [--bundle_info] - [--bundle_info_syntax_check] [--bundle_frameworks] [--bundle_plugins] [--bundle_id] - [--file_type] [--header_flags] [--endian] [--header] [--load_commands] [--has_cmd LC_MAIN] - [--segments] [--has_segment __SEGMENT] [--sections] [--has_section __SEGMENT,__section] - [--symbols] [--imports] [--exports] [--imported_symbols] [--chained_fixups] - [--exports_trie] [--uuid] [--main] [--encryption_info [(optional) save_path.bytes]] - [--strings_section] [--all_strings] [--save_strings all_strings.txt] [--info] - [--dump_data [offset,size,output_path]] [--calc_offset vm_offset] [--constructors] - [--dump_section __SEGMENT,__section] [--dump_binary output_path] [--verify_signature] - [--cd_info] [--cd_requirements] [--entitlements [human|xml|var]] - [--extract_cms cms_signature.der] [--extract_certificates certificate_name] - [--remove_sig unsigned_binary] [--sign_binary [adhoc|identity]] [--cs_offset] [--cs_flags] - [--verify_bundle_signature] [--remove_sig_from_bundle] [--has_pie] [--has_arc] - [--is_stripped] [--has_canary] [--has_nx_stack] [--has_nx_heap] [--has_xn] [--is_notarized] - [--is_encrypted] [--is_restricted] [--is_hr] [--is_as] [--is_fort] [--has_rpath] [--has_lv] - [--checksec] [--dylibs] [--rpaths] [--rpaths_u] [--dylibs_paths] [--dylibs_paths_u] - [--broken_relative_paths] [--dylibtree [cache_path,output_path,is_extracted]] [--dylib_id] - [--reexport_paths] [--hijack_sec] [--dylib_hijacking [(optional) cache_path]] - [--dylib_hijacking_a [cache_path]] [--prepare_dylib [(optional) target_dylib_name]] - [--is_built_for_sim] [--get_dyld_env] [--compiled_with_dyld_env] [--has_interposing] - [--interposing_symbols] [--dump_prelink_info [(optional) out_name]] - [--dump_prelink_text [(optional) out_name]] [--dump_prelink_kext [kext_name]] - [--kext_prelinkinfo [kext_name]] [--kmod_info kext_name] [--kext_entry kext_name] - [--kext_exit kext_name] [--mig] [--has_suid] [--has_sgid] [--has_sticky] - [--injectable_dyld] [--test_insert_dylib] [--test_prune_dyld] [--test_dyld_print_to_file] - [--test_dyld_SLC] [--xattr] [--xattr_value xattr_name] [--xattr_all] [--has_quarantine] - [--remove_quarantine] [--add_quarantine] [--sandbox_container_path] - [--sandbox_container_metadata] [--sandbox_redirectable_paths] [--sandbox_parameters] - [--sandbox_entitlements] [--sandbox_build_uuid] [--sandbox_redirected_paths] - [--sandbox_system_images] [--sandbox_system_profiles] [--sandbox_content_protection] - [--sandbox_profile_data] [--dump_kext kext_name] [--extract_sandbox_operations] +usage: CrimsonUroboros [-h] [-p PATH] [-b BUNDLE] [--bundle_structure] + [--bundle_info] [--bundle_info_syntax_check] + [--bundle_frameworks] [--bundle_plugins] [--bundle_id] + [--file_type] [--header_flags] [--endian] [--header] + [--load_commands] [--has_cmd LC_MAIN] [--segments] + [--has_segment __SEGMENT] [--sections] + [--has_section __SEGMENT,__section] [--symbols] + [--imports] [--exports] [--imported_symbols] + [--chained_fixups] [--exports_trie] [--uuid] [--main] + [--encryption_info [(optional) save_path.bytes]] + [--strings_section] [--all_strings] + [--save_strings all_strings.txt] [--info] + [--dump_data [offset,size,output_path]] + [--calc_offset vm_offset] [--constructors] + [--dump_section __SEGMENT,__section] + [--dump_binary output_path] [--verify_signature] + [--cd_info] [--cd_requirements] + [--entitlements [human|xml|var]] + [--extract_cms cms_signature.der] + [--extract_certificates certificate_name] + [--remove_sig unsigned_binary] + [--sign_binary [adhoc|identity]] [--cs_offset] + [--cs_flags] [--verify_bundle_signature] + [--remove_sig_from_bundle] [--has_pie] [--has_arc] + [--is_stripped] [--has_canary] [--has_nx_stack] + [--has_nx_heap] [--has_xn] [--is_notarized] + [--is_encrypted] [--is_restricted] [--is_hr] [--is_as] + [--is_fort] [--has_rpath] [--has_lv] [--checksec] + [--dylibs] [--rpaths] [--rpaths_u] [--dylibs_paths] + [--dylibs_paths_u] [--broken_relative_paths] + [--dylibtree [cache_path,output_path,is_extracted]] + [--dylib_id] [--reexport_paths] [--hijack_sec] + [--dylib_hijacking [(optional) cache_path]] + [--dylib_hijacking_a [cache_path]] + [--prepare_dylib [(optional) target_dylib_name]] + [--is_built_for_sim] [--get_dyld_env] + [--compiled_with_dyld_env] [--has_interposing] + [--interposing_symbols] + [--dump_prelink_info [(optional) out_name]] + [--dump_prelink_text [(optional) out_name]] + [--dump_prelink_kext [kext_name]] + [--kext_prelinkinfo [kext_name]] + [--kmod_info kext_name] [--kext_entry kext_name] + [--kext_exit kext_name] [--mig] [--has_suid] + [--has_sgid] [--has_sticky] [--injectable_dyld] + [--test_insert_dylib] [--test_prune_dyld] + [--test_dyld_print_to_file] [--test_dyld_SLC] [--xattr] + [--xattr_value xattr_name] [--xattr_all] + [--has_quarantine] [--remove_quarantine] + [--add_quarantine] [--sandbox_container_path] + [--sandbox_container_metadata] + [--sandbox_redirectable_paths] [--sandbox_parameters] + [--sandbox_entitlements] [--sandbox_build_uuid] + [--sandbox_redirected_paths] [--sandbox_system_images] + [--sandbox_system_profiles] + [--sandbox_content_protection] [--sandbox_profile_data] + [--dump_kext kext_name] [--extract_sandbox_operations] + [--tcc] [--tcc_fda] [--tcc_automation] [--tcc_sysadmin] + [--tcc_desktop] [--tcc_documents] [--tcc_downloads] + [--tcc_photos] [--tcc_contacts] [--tcc_calendar] + [--tcc_camera] [--tcc_microphone] [--tcc_location] + [--tcc_recording] [--tcc_accessibility] [--tcc_icloud] Mach-O files parser for binary analysis @@ -94,19 +125,21 @@ options: -h, --help show this help message and exit GENERAL ARGS: - -p PATH, --path PATH Path to the Mach-O file - -b BUNDLE, --bundle BUNDLE - Path to the App Bundle (can be used with -p to change path of binary which is by default - set to: /target.app/Contents/MacOS/target) + -p, --path PATH Path to the Mach-O file + -b, --bundle BUNDLE Path to the App Bundle (can be used with -p to change + path of binary which is by default set to: + /target.app/Contents/MacOS/target) BUNDLE ARGS: --bundle_structure Print the structure of the app bundle - --bundle_info Print the Info.plist content of the app bundle (JSON format) + --bundle_info Print the Info.plist content of the app bundle (JSON + format) --bundle_info_syntax_check Check if bundle info syntax is valid --bundle_frameworks Print the list of frameworks in the bundle --bundle_plugins Print the list of plugins in the bundle - --bundle_id Print the CFBundleIdentifier value from the Info.plist file if it exists + --bundle_id Print the CFBundleIdentifier value from the Info.plist + file if it exists MACH-O ARGS: --file_type Print binary file type @@ -124,147 +157,192 @@ MACH-O ARGS: --symbols Print all binary symbols --imports Print imported symbols --exports Print exported symbols - --imported_symbols Print symbols imported from external libraries with dylib names + --imported_symbols Print symbols imported from external libraries with + dylib names --chained_fixups Print Chained Fixups information --exports_trie Print Export Trie information --uuid Print UUID --main Print entry point and stack size --encryption_info [(optional) save_path.bytes] - Print encryption info if any. Optionally specify an output path to dump the encrypted data - (if cryptid=0, data will be in plain text) + Print encryption info if any. Optionally specify an + output path to dump the encrypted data (if cryptid=0, + data will be in plain text) --strings_section Print strings from __cstring section --all_strings Print strings from all sections --save_strings all_strings.txt - Parse all sections, detect strings, and save them to a file - --info Print header, load commands, segments, sections, symbols, and strings + Parse all sections, detect strings, and save them to a + file + --info Print header, load commands, segments, sections, + symbols, and strings --dump_data [offset,size,output_path] - Dump {size} bytes starting from {offset} to a given {filename} (e.g. - '0x1234,0x1000,out.bin') + Dump {size} bytes starting from {offset} to a given + {filename} (e.g. '0x1234,0x1000,out.bin') --calc_offset vm_offset - Calculate the real address (file on disk) of the given Virtual Memory {vm_offset} (e.g. - 0xfffffe000748f580) + Calculate the real address (file on disk) of the given + Virtual Memory {vm_offset} (e.g. 0xfffffe000748f580) --constructors Print binary constructors --dump_section __SEGMENT,__section - Dump '__SEGMENT,__section' to standard output as a raw bytes + Dump '__SEGMENT,__section' to standard output as a raw + bytes --dump_binary output_path Dump arm64 binary to a given file CODE SIGNING ARGS: - --verify_signature Code Signature verification (if the contents of the binary have been modified) + --verify_signature Code Signature verification (if the contents of the + binary have been modified) --cd_info Print Code Signature information --cd_requirements Print Code Signature Requirements --entitlements [human|xml|var] - Print Entitlements in a human-readable, XML, or DER format (default: human) + Print Entitlements in a human-readable, XML, or DER + format (default: human) --extract_cms cms_signature.der - Extract CMS Signature from the Code Signature and save it to a given file + Extract CMS Signature from the Code Signature and save + it to a given file --extract_certificates certificate_name - Extract Certificates and save them to a given file. To each filename will be added an - index at the end: _0 for signing, _1 for intermediate, and _2 for root CA certificate + Extract Certificates and save them to a given file. To + each filename will be added an index at the end: _0 + for signing, _1 for intermediate, and _2 for root CA + certificate --remove_sig unsigned_binary Save the new file on a disk with removed signature --sign_binary [adhoc|identity] - Sign binary using specified identity - use : 'security find-identity -v -p codesigning' to - get the identity (default: adhoc) + Sign binary using specified identity - use : 'security + find-identity -v -p codesigning' to get the identity + (default: adhoc) --cs_offset Print Code Signature file offset --cs_flags Print Code Signature flags --verify_bundle_signature - Code Signature verification (if the contents of the bundle have been modified) + Code Signature verification (if the contents of the + bundle have been modified) --remove_sig_from_bundle Remove Code Signature from the bundle CHECKSEC ARGS: --has_pie Check if Position-Independent Executable (PIE) is set - --has_arc Check if Automatic Reference Counting (ARC) is in use (can be false positive) + --has_arc Check if Automatic Reference Counting (ARC) is in use + (can be false positive) --is_stripped Check if binary is stripped - --has_canary Check if Stack Canary is in use (can be false positive) + --has_canary Check if Stack Canary is in use (can be false + positive) --has_nx_stack Check if stack is non-executable (NX stack) --has_nx_heap Check if heap is non-executable (NX heap) - --has_xn Check if binary is protected by eXecute Never (XN) ARM protection - --is_notarized Check if the application is notarized and can pass the Gatekeeper verification - --is_encrypted Check if the application is encrypted (has LC_ENCRYPTION_INFO(_64) and cryptid set to 1) - --is_restricted Check if binary has __RESTRICT segment or CS_RESTRICT flag set + --has_xn Check if binary is protected by eXecute Never (XN) ARM + protection + --is_notarized Check if the application is notarized and can pass the + Gatekeeper verification + --is_encrypted Check if the application is encrypted (has + LC_ENCRYPTION_INFO(_64) and cryptid set to 1) + --is_restricted Check if binary has __RESTRICT segment or CS_RESTRICT + flag set --is_hr Check if the Hardened Runtime is in use --is_as Check if the App Sandbox is in use --is_fort Check if the binary is fortified --has_rpath Check if the binary utilise any @rpath variables - --has_lv Check if the binary has Library Validation (protection against Dylib Hijacking) + --has_lv Check if the binary has Library Validation (protection + against Dylib Hijacking) --checksec Run all checksec module options on the binary DYLIBS ARGS: - --dylibs Print shared libraries used by specified binary with compatibility and the current version - (loading paths unresolved, like @rpath/example.dylib) - --rpaths Print all paths (resolved) that @rpath can be resolved to - --rpaths_u Print all paths (unresolved) that @rpath can be resolved to - --dylibs_paths Print absolute dylib loading paths (resolved @rpath|@executable_path|@loader_path) in - order they are searched for + --dylibs Print shared libraries used by specified binary with + compatibility and the current version (loading paths + unresolved, like @rpath/example.dylib) + --rpaths Print all paths (resolved) that @rpath can be resolved + to + --rpaths_u Print all paths (unresolved) that @rpath can be + resolved to + --dylibs_paths Print absolute dylib loading paths (resolved + @rpath|@executable_path|@loader_path) in order they + are searched for --dylibs_paths_u Print unresolved dylib loading paths. --broken_relative_paths - Print 'broken' relative paths from the binary (cases where the dylib source is specified - for an executable directory without @executable_path) + Print 'broken' relative paths from the binary (cases + where the dylib source is specified for an executable + directory without @executable_path) --dylibtree [cache_path,output_path,is_extracted] - Print the dynamic dependencies of a Mach-O binary recursively. You can specify the Dyld - Shared Cache path in the first argument, the output directory as the 2nd argument, and if - you have already extracted DSC in the 3rd argument (0 or 1). The output_path will be used - as a base for dylibtree. For example, to not extract DSC, use: --dylibs ",,1", or to - extract from default to default use just --dylibs or --dylibs ",,0" which will extract DSC - to extracted_dyld_share_cache/ in the current directory + Print the dynamic dependencies of a Mach-O binary + recursively. You can specify the Dyld Shared Cache + path in the first argument, the output directory as + the 2nd argument, and if you have already extracted + DSC in the 3rd argument (0 or 1). The output_path will + be used as a base for dylibtree. For example, to not + extract DSC, use: --dylibs ",,1", or to extract from + default to default use just --dylibs or --dylibs ",,0" + which will extract DSC to extracted_dyld_share_cache/ + in the current directory --dylib_id Print path from LC_ID_DYLIB --reexport_paths Print paths from LC_REEXPORT_DLIB --hijack_sec Check if binary is protected against Dylib Hijacking --dylib_hijacking [(optional) cache_path] - Check for possible Direct and Indirect Dylib Hijacking loading paths. The output is - printed to console and saved in JSON format to /tmp/dylib_hijacking_log.json(append mode). + Check for possible Direct and Indirect Dylib Hijacking + loading paths. The output is printed to console and + saved in JSON format to + /tmp/dylib_hijacking_log.json(append mode). Optionally, specify the path to the Dyld Shared Cache --dylib_hijacking_a [cache_path] - Like --dylib_hijacking, but shows only possible vectors (without protected binaries) + Like --dylib_hijacking, but shows only possible + vectors (without protected binaries) --prepare_dylib [(optional) target_dylib_name] - Compile rogue dylib. Optionally, specify target_dylib_path, it will search for the - imported symbols from it in the dylib specified in the --path argument and automatically - add it to the source code of the rogue lib. Example: --path lib1.dylib --prepare_dylib - /path/to/lib2.dylib + Compile rogue dylib. Optionally, specify + target_dylib_path, it will search for the imported + symbols from it in the dylib specified in the --path + argument and automatically add it to the source code + of the rogue lib. Example: --path lib1.dylib + --prepare_dylib /path/to/lib2.dylib DYLD ARGS: --is_built_for_sim Check if binary is built for simulator platform. - --get_dyld_env Extract Dyld environment variables from the loader binary. + --get_dyld_env Extract Dyld environment variables from the loader + binary. --compiled_with_dyld_env - Check if binary was compiled with -dyld_env flag and print the environment variables and - its values. + Check if binary was compiled with -dyld_env flag and + print the environment variables and its values. --has_interposing Check if binary has interposing sections. --interposing_symbols Print interposing symbols if any. AMFI ARGS: --dump_prelink_info [(optional) out_name] - Dump "__PRELINK_INFO,__info" to a given file (default: "PRELINK_info.txt") + Dump "__PRELINK_INFO,__info" to a given file (default: + "PRELINK_info.txt") --dump_prelink_text [(optional) out_name] - Dump "__PRELINK_TEXT,__text" to a given file (default: "PRELINK_text.txt") + Dump "__PRELINK_TEXT,__text" to a given file (default: + "PRELINK_text.txt") --dump_prelink_kext [kext_name] - Dump prelinked KEXT {kext_name} from decompressed Kernel Cache PRELINK_TEXT segment to a - file named: prelinked_{kext_name}.bin + Dump prelinked KEXT {kext_name} from decompressed + Kernel Cache PRELINK_TEXT segment to a file named: + prelinked_{kext_name}.bin --kext_prelinkinfo [kext_name] - Print _Prelink properties from PRELINK_INFO,__info for a give {kext_name} + Print _Prelink properties from PRELINK_INFO,__info for + a give {kext_name} --kmod_info kext_name - Parse kmod_info structure for the given {kext_name} from Kernel Cache + Parse kmod_info structure for the given {kext_name} + from Kernel Cache --kext_entry kext_name - Calculate the virtual memory address of the __start (entrypoint) for the given {kext_name} - Kernel Extension + Calculate the virtual memory address of the __start + (entrypoint) for the given {kext_name} Kernel + Extension --kext_exit kext_name - Calculate the virtual memory address of the __stop (exitpoint) for the given {kext_name} - Kernel Extension + Calculate the virtual memory address of the __stop + (exitpoint) for the given {kext_name} Kernel Extension --mig Search for MIG subsystem and prints message handlers --has_suid Check if the file has SetUID bit set --has_sgid Check if the file has SetGID bit set --has_sticky Check if the file has sticky bit set - --injectable_dyld Check if the binary is injectable using DYLD_INSERT_LIBRARIES - --test_insert_dylib Check if it is possible to inject dylib using DYLD_INSERT_LIBRARIES (INVASIVE - the binary - is executed) - --test_prune_dyld Check if Dyld Environment Variables are cleared (using DYLD_PRINT_INITIALIZERS=1) - (INVASIVE - the binary is executed) - --test_dyld_print_to_file - Check if DYLD_PRINT_TO_FILE Dyld Environment Variables works (INVASIVE - the binary is + --injectable_dyld Check if the binary is injectable using + DYLD_INSERT_LIBRARIES + --test_insert_dylib Check if it is possible to inject dylib using + DYLD_INSERT_LIBRARIES (INVASIVE - the binary is + executed) + --test_prune_dyld Check if Dyld Environment Variables are cleared (using + DYLD_PRINT_INITIALIZERS=1) (INVASIVE - the binary is + executed) + --test_dyld_print_to_file + Check if DYLD_PRINT_TO_FILE Dyld Environment Variables + works (INVASIVE - the binary is executed) + --test_dyld_SLC Check if DYLD_SHARED_REGION=private Dyld Environment + Variables works and code can be injected using + DYLD_SHARED_CACHE_DIR (INVASIVE - the binary is executed) - --test_dyld_SLC Check if DYLD_SHARED_REGION=private Dyld Environment Variables works and code can be - injected using DYLD_SHARED_CACHE_DIR (INVASIVE - the binary is executed) ANTIVIRUS ARGS: --xattr Print all extended attributes names @@ -272,35 +350,67 @@ ANTIVIRUS ARGS: Print single extended attribute value --xattr_all Print all extended attributes names and their values --has_quarantine Check if the file has quarantine extended attribute - --remove_quarantine Remove com.apple.quarantine extended attribute from the file - --add_quarantine Add com.apple.quarantine extended attribute to the file + --remove_quarantine Remove com.apple.quarantine extended attribute from + the file + --add_quarantine Add com.apple.quarantine extended attribute to the + file SANDBOX ARGS: --sandbox_container_path Print the sandbox container path --sandbox_container_metadata - Print the .com.apple.containermanagerd.metadata.plist contents for the given bundlein XML - format + Print the .com.apple.containermanagerd.metadata.plist + contents for the given bundlein XML format --sandbox_redirectable_paths - Print the redirectable paths from the sandbox container metadata as list - --sandbox_parameters Print the parameters from the sandbox container metadata as key-value pairs + Print the redirectable paths from the sandbox + container metadata as list + --sandbox_parameters Print the parameters from the sandbox container + metadata as key-value pairs --sandbox_entitlements - Print the entitlements from the sandbox container metadata in JSON format - --sandbox_build_uuid Print the sandbox build UUID from the sandbox container metadata + Print the entitlements from the sandbox container + metadata in JSON format + --sandbox_build_uuid Print the sandbox build UUID from the sandbox + container metadata --sandbox_redirected_paths - Print the redirected paths from the sandbox container metadata as list + Print the redirected paths from the sandbox container + metadata as list --sandbox_system_images - Print the system images from the sandbox container metadata as key-value pairs + Print the system images from the sandbox container + metadata as key-value pairs --sandbox_system_profiles - Print the system profile from the sandbox container metadata in JSON format + Print the system profile from the sandbox container + metadata in JSON format --sandbox_content_protection - Print the content protection from the sandbox container metadata + Print the content protection from the sandbox + container metadata --sandbox_profile_data - Print raw bytes ofthe sandbox profile data from the sandbox container metadata + Print raw bytes ofthe sandbox profile data from the + sandbox container metadata --dump_kext kext_name - Dump the kernel extension binary from the kernelcache.decompressed file + Dump the kernel extension binary from the + kernelcache.decompressed file --extract_sandbox_operations Extract sandbox operations from the Sandbox.kext file + +TCC ARGS: + --tcc Print TCC permissions of the binary + --tcc_fda Check Full Disk Access (FDA) TCC permission for the + binary + --tcc_automation Check Automation TCC permission for the binary + --tcc_sysadmin Check System Policy SysAdmin Files TCC permission for + the binary + --tcc_desktop Check Desktop Folder TCC permission for the binary + --tcc_documents Check Documents Folder TCC permission for the binary + --tcc_downloads Check Downloads Folder TCC permission for the binary + --tcc_photos Check Photos Library TCC permission for the binary + --tcc_contacts Check Contacts TCC permission for the binary + --tcc_calendar Check Calendar TCC permission for the binary + --tcc_camera Check Camera TCC permission for the binary + --tcc_microphone Check Microphone TCC permission for the binary + --tcc_location Check Location Services TCC permission for the binary + --tcc_recording Check Screen Recording TCC permission for the binary + --tcc_accessibility Check Accessibility TCC permission for the binary + --tcc_icloud Check iCloud (Ubiquity) TCC permission for the binary ``` * Example: ```bash @@ -586,6 +696,45 @@ Notes: - When using --list, each path should be on a new line in the list file - The tool automatically converts relative paths to absolute paths ``` +### [TCCParser](IX.%20TCC/python/TCCParser.py) +A tool for querying macOS TCC (Transparency, Consent, and Control) databases. +It was introduced in the article [](todo) +```bash +usage: TCCParser [-h] [-p PATH] [-t] [-a] [-l] + +Parse TCC Database for Permissions Information + +options: + -h, --help Show this help message and exit + -p PATH, --path PATH Path to TCC.db file to analyze + -t, --table Output results in table format + -a, --all Automatically query all available TCC databases on the system + -l, --list_db List all available TCC databases on the system + +Examples: +--------- + +1. List all available TCC databases on the system: + --list_db + -l + +2. Query a specific TCC database: + --path /path/to/TCC.db + -p /path/to/TCC.db + +3. Display the query results in a formatted table: + --path /path/to/TCC.db --table + -p /path/to/TCC.db -t + +4. Automatically query all known TCC databases: + --all + -a + +Notes: +------ +- The tool retrieves details such as client, service, and authorization status for each entry in the TCC database. +- The `--list_db` option helps users locate all known TCC databases on the system, sourced from `REG.db`. +``` ## INSTALL ```