mirror of
https://github.com/Karmaz95/Snake_Apple.git
synced 2026-06-08 18:03:53 +02:00
VIII. SANDBOX patch
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,158 @@
|
||||
_hook_iokit_check_get_property
|
||||
_hook_iokit_check_filter_properties
|
||||
_hook_vnode_notify_link
|
||||
_hook_kext_check_unload
|
||||
_hook_kext_check_load
|
||||
_hook_pty_notify_close
|
||||
_hook_pty_notify_grant
|
||||
_hook_system_check_info
|
||||
_hook_vnode_check_lookup_preflight
|
||||
_hook_system_check_kas_info
|
||||
_hook_vnode_notify_deleteextattr
|
||||
_hook_vnode_check_setacl
|
||||
_hook_vnode_notify_rename
|
||||
_hook_vnode_notify_create
|
||||
_hook_proc_check_ledger
|
||||
_hook_iokit_check_open
|
||||
_hook_vnode_check_fsgetpath
|
||||
_hook_proc_check_map_anon
|
||||
_hook_priv_grant
|
||||
_hook_priv_check
|
||||
_hook_vnode_check_searchfs
|
||||
_hook_iokit_check_set_properties
|
||||
___hook_iokit_check_set_properties_block_invoke
|
||||
___hook_iokit_check_set_properties_block_invoke_2
|
||||
_hook_thread_userret
|
||||
_hook_proc_check_suspend_resume
|
||||
_hook_vnode_check_uipc_connect
|
||||
_hook_vnode_check_uipc_bind
|
||||
_hook_vnode_label_recycle
|
||||
_hook_vnode_label_destroy
|
||||
_hook_vnode_label_copy
|
||||
_hook_vnode_check_unlink
|
||||
_hook_vnode_check_truncate
|
||||
_hook_vnode_check_stat
|
||||
_hook_vnode_check_setutimes
|
||||
_hook_vnode_check_setowner
|
||||
_hook_vnode_check_setmode
|
||||
_hook_vnode_check_setflags
|
||||
_hook_vnode_check_setextattr
|
||||
_hook_vnode_check_setattrlist
|
||||
_hook_vnode_check_revoke
|
||||
_hook_vnode_check_readlink
|
||||
_hook_vnode_check_open
|
||||
_hook_vnode_check_listextattr
|
||||
_hook_vnode_check_link
|
||||
_hook_vnode_check_ioctl
|
||||
_hook_vnode_check_getextattr
|
||||
_hook_vnode_check_getattrlist
|
||||
_hook_vnode_check_exchangedata
|
||||
_hook_vnode_check_deleteextattr
|
||||
_hook_vnode_check_create
|
||||
_hook_vnode_check_chroot
|
||||
_hook_vnode_check_access
|
||||
_hook_iokit_check_hid_control
|
||||
_hook_proc_check_set_cs_info
|
||||
_hook_proc_check_get_cs_info
|
||||
_hook_vnode_check_clone
|
||||
_hook_mount_check_snapshot_delete
|
||||
_hook_mount_check_snapshot_create
|
||||
_hook_mount_check_snapshot_revert
|
||||
_hook_proc_notify_exit
|
||||
_hook_sysvshm_check_shmget
|
||||
_hook_sysvshm_check_shmdt
|
||||
_hook_sysvshm_check_shmctl
|
||||
_hook_sysvshm_check_shmat
|
||||
_hook_sysvsem_check_semop
|
||||
_hook_sysvsem_check_semget
|
||||
_hook_sysvsem_check_semctl
|
||||
_hook_sysvmsq_check_msqsnd
|
||||
_hook_sysvmsq_check_msqrcv
|
||||
_hook_sysvmsq_check_msqget
|
||||
_hook_sysvmsq_check_msqctl
|
||||
_hook_sysvmsq_check_msgrmid
|
||||
_hook_sysvmsq_check_msgrcv
|
||||
_hook_sysvmsq_check_enqueue
|
||||
_hook_socket_check_ioctl
|
||||
_hook_system_check_swapon
|
||||
_hook_system_check_swapoff
|
||||
_hook_system_check_settime
|
||||
_hook_system_check_reboot
|
||||
_hook_system_check_nfsd
|
||||
_hook_system_check_host_priv
|
||||
_hook_system_check_auditon
|
||||
_hook_system_check_auditctl
|
||||
_hook_system_check_audit
|
||||
_hook_system_check_acct
|
||||
_hook_iokit_check_open_service
|
||||
_hook_thread_microstackshot
|
||||
_hook_proc_check_memorystatus_control
|
||||
_hook_socket_check_getsockopt
|
||||
_hook_socket_check_setsockopt
|
||||
_hook_socket_check_send
|
||||
_hook_socket_check_receive
|
||||
_hook_socket_check_listen
|
||||
_hook_socket_check_create
|
||||
_hook_socket_check_connect
|
||||
_hook_socket_check_bind
|
||||
_hook_proc_check_signal
|
||||
_hook_proc_check_setauid
|
||||
_hook_proc_check_setaudit
|
||||
_hook_proc_check_sched
|
||||
_hook_proc_check_fork
|
||||
_hook_proc_check_debug
|
||||
_hook_posixshm_check_unlink
|
||||
_hook_posixshm_check_open
|
||||
_hook_posixshm_check_create
|
||||
_hook_posixsem_check_wait
|
||||
_hook_posixsem_check_unlink
|
||||
_hook_posixsem_check_post
|
||||
_hook_posixsem_check_open
|
||||
_hook_posixsem_check_create
|
||||
_hook_skywalk_flow_check_listen
|
||||
_hook_skywalk_flow_check_connect
|
||||
_hook_mount_check_snapshot_mount
|
||||
_hook_mount_check_mount_late
|
||||
_hook_vnode_check_trigger_resolve
|
||||
_hook_proc_check_set_host_exception_port
|
||||
_hook_proc_check_set_host_special_port
|
||||
_hook_proc_check_syscall_unix
|
||||
_hook_proc_notify_exec_complete
|
||||
_hook_kext_check_query
|
||||
_hook_vnode_check_rename
|
||||
_hook_system_check_sysctlbyname
|
||||
_hook_policy_syscall
|
||||
_hook_policy_initbsd
|
||||
_hook_policy_init
|
||||
_hook_proc_check_migroutine_invoke
|
||||
_hook_proc_check_syscall_mach
|
||||
_hook_proc_check_syscall_mac
|
||||
_hook_proc_check_get_task_with_flavor
|
||||
_hook_proc_check_expose_task_with_flavor
|
||||
_hook_mount_label_init
|
||||
_hook_mount_label_destroy
|
||||
_hook_mount_label_associate
|
||||
_hook_mount_check_umount
|
||||
_hook_mount_check_remount
|
||||
_hook_mount_check_mount
|
||||
_hook_mount_check_fsctl
|
||||
_hook_mount_check_quotactl
|
||||
_hook_vnode_check_copyfile
|
||||
_hook_vnode_notify_unlink
|
||||
_hook_proc_check_set_task_special_port
|
||||
_hook_proc_check_get_task_special_port
|
||||
_hook_vnode_notify_setflags
|
||||
_hook_vnode_notify_setextattr
|
||||
_hook_necp_check_client_action
|
||||
_hook_necp_check_open
|
||||
_hook_file_check_set
|
||||
_hook_file_check_mmap
|
||||
_hook_file_check_lock
|
||||
_hook_file_check_fcntl
|
||||
_hook_cred_label_update
|
||||
_hook_cred_label_destroy
|
||||
_hook_cred_label_associate
|
||||
_hook_cred_check_label_update
|
||||
_hook_vnode_check_exec
|
||||
_hook_cred_check_label_update_execve
|
||||
_hook_cred_label_update_execve
|
||||
@@ -97,7 +97,7 @@ class SnakeHatchery:
|
||||
''' Initialize the binary object in global scope.'''
|
||||
global binaries # It must be global, becuase after this object is destructed, the snake_instance would point to invalid memory ("binary" is dependant on "binaries").
|
||||
|
||||
if self.file_path_exists:
|
||||
if self.file_path: # We cannot use here self.file_path_exists because at this point the file_path cpuld be set fron None to a valid path by filePathInit() method (when only -b specified)
|
||||
adhoc_macho_processor = MachOProcessor() # Just for this limited scope
|
||||
|
||||
if adhoc_macho_processor.isFileMachO(self.file_path):
|
||||
@@ -208,6 +208,14 @@ class BundleProcessor:
|
||||
else:
|
||||
return None
|
||||
|
||||
def getBundleId(self):
|
||||
''' Return CFBundleIdentifier from Info.plist of the App Bundle. '''
|
||||
if self.info_plist_exists:
|
||||
with open(self.info_plist_path, 'rb') as f:
|
||||
plist = plistlib.load(f)
|
||||
return plist.get('CFBundleIdentifier')
|
||||
return None
|
||||
|
||||
class SnakeAppBundleExtension:
|
||||
def __init__(self, binaries, file_path):
|
||||
''' It stores only logic for CrimsonUroboros flags. Most of the code related to parsing and extracting data from App Bundle is in BundleProcessor class.
|
||||
@@ -248,6 +256,14 @@ class SnakeAppBundleExtension:
|
||||
else:
|
||||
print("No plugins found.")
|
||||
|
||||
def printBundleId(self):
|
||||
''' Print the CFBundleIdentifier from Info.plist of the App Bundle. '''
|
||||
bundle_id = bundle_processor.getBundleId()
|
||||
if bundle_id:
|
||||
print(bundle_id)
|
||||
else:
|
||||
print("No bundle id found.")
|
||||
|
||||
### --- I. MACH-O --- ###
|
||||
class MachOProcessor:
|
||||
def __init__(self):
|
||||
@@ -384,6 +400,9 @@ class MachOProcessor:
|
||||
if args.dump_section: # Dump section to a stdout
|
||||
snake_instance.dumpSectionToStdout(args.dump_section)
|
||||
|
||||
if args.dump_binary: # Dump binary to a given file
|
||||
snake_instance.dumpBinaryToFile(args.dump_binary)
|
||||
|
||||
def isFileMachO(self, file_path):
|
||||
'''Check if file is Mach-O. '''
|
||||
try:
|
||||
@@ -695,12 +714,12 @@ class SnakeI(SnakeAppBundleExtension):
|
||||
|
||||
def getStringSection(self):
|
||||
'''Return strings from the __cstring (string table).'''
|
||||
extracted_strings = set()
|
||||
extracted_strings = []
|
||||
for section in self.binary.sections:
|
||||
if section.type == lief.MachO.SECTION_TYPES.CSTRING_LITERALS:
|
||||
strings_bytes = section.content.tobytes()
|
||||
strings = strings_bytes.decode('utf-8', errors='ignore') # Adjust the encoding as per your requirements
|
||||
extracted_strings.update(strings.split('\x00'))
|
||||
strings = strings_bytes.decode('utf-8', errors='ignore')
|
||||
extracted_strings.extend(strings.split('\x00'))
|
||||
return extracted_strings
|
||||
|
||||
def findAllStringsInBinary(self):
|
||||
@@ -914,7 +933,15 @@ class SnakeI(SnakeAppBundleExtension):
|
||||
segment_name = segment_section[0]
|
||||
section_name = segment_section[1]
|
||||
extracted_bytes = self.extractSection(segment_name, section_name)
|
||||
print(extracted_bytes)
|
||||
sys.stdout.buffer.write(extracted_bytes)
|
||||
|
||||
def dumpBinaryToFile(self, output_path):
|
||||
''' Dump ARM64 binary from FAT binary and save to a given file. '''
|
||||
if binaries is not None:
|
||||
if self.binary is not None:
|
||||
if not output_path.startswith('/'):
|
||||
output_path = os.path.join(os.getcwd(), output_path)
|
||||
self.binary.write(output_path)
|
||||
|
||||
### --- II. CODE SIGNING --- ###
|
||||
class CodeSigningProcessor:
|
||||
@@ -2809,6 +2836,281 @@ class SnakeVII(SnakeVI):
|
||||
value_as_bytes = value.encode()
|
||||
xattr.setxattr(self.file_path, 'com.apple.quarantine', value_as_bytes)
|
||||
|
||||
### ---- VIII. SANDBOX --- ###
|
||||
class SandboxProcessor:
|
||||
def __init__(self):
|
||||
'''This class contains part of the code from the main() for the SnakeVIII: Sandbox.'''
|
||||
pass
|
||||
|
||||
def process(self, args):
|
||||
if args.sandbox_container_path: # Print the sandbox container path
|
||||
snake_instance.printSandboxContainerPath()
|
||||
|
||||
if args.sandbox_container_metadata: # Print the sandbox container metadata
|
||||
snake_instance.printSandboxContainerMetadata()
|
||||
|
||||
if args.sandbox_redirectable_paths: # Print the sandbox redirectable paths
|
||||
snake_instance.printSandboxRedirectablePaths()
|
||||
|
||||
if args.sandbox_parameters: # Print the sandbox parameters
|
||||
snake_instance.printSandboxParameters()
|
||||
|
||||
if args.sandbox_entitlements: # Print the sandbox entitlements
|
||||
snake_instance.printSandboxEntitlements()
|
||||
|
||||
if args.sandbox_build_uuid: # Print the sandbox build UUID
|
||||
snake_instance.printSandboxBuildUUID()
|
||||
|
||||
if args.sandbox_redirected_paths: # Print the sandbox redirected paths
|
||||
snake_instance.printSandboxRedirectedPaths()
|
||||
|
||||
if args.sandbox_system_images: # Print the sandbox system images
|
||||
snake_instance.printSandboxSystemImages()
|
||||
|
||||
if args.sandbox_system_profiles: # Print the sandbox system profiles
|
||||
snake_instance.printSandboxSystemProfiles()
|
||||
|
||||
if args.sandbox_content_protection: # Print the sandbox com.apple.MobileInstallation.ContentProtectionClass value
|
||||
snake_instance.printContentProtectionClass()
|
||||
|
||||
if args.sandbox_profile_data: # Print the sandbox profile data
|
||||
snake_instance.printSandboxProfileData()
|
||||
|
||||
if args.dump_kext: # Dump the kernel extension binary from the kernelcache.decompressed file
|
||||
snake_instance.dumpKernelExtensionBinary(args.dump_kext)
|
||||
|
||||
if args.extract_sandbox_operations: # Extract sandbox operations from the kernelcache.decompressed file
|
||||
snake_instance.printSandboxOperations()
|
||||
|
||||
|
||||
class SnakeVIII(SnakeVII):
|
||||
def __init__(self, binaries, file_path):
|
||||
super().__init__(binaries, file_path)
|
||||
self.kext_map.update({
|
||||
'com.apple.security.sandbox' : 'sandbox',
|
||||
'sandbox.kext' : 'sandbox',
|
||||
})
|
||||
self.container_metadata_file = ".com.apple.containermanagerd.metadata.plist"
|
||||
|
||||
def getSandboxContainerPath(self):
|
||||
''' Check if sandbox container exists for the given App Bundle and if it exists, return the path to the container. '''
|
||||
bundle_id = bundle_processor.getBundleId()
|
||||
if bundle_id:
|
||||
container_path = os.path.join(os.path.expanduser('~'), 'Library', 'Containers', bundle_id)
|
||||
if os.path.exists(container_path):
|
||||
return container_path
|
||||
else:
|
||||
print("Bundle id is not set in Info.plist for the given App Bundle.")
|
||||
return None
|
||||
|
||||
def printSandboxContainerPath(self):
|
||||
''' Print the sandbox container path. '''
|
||||
container_path = self.getSandboxContainerPath()
|
||||
if container_path:
|
||||
print(f'APP BUNDLE SANDBOX CONTAINER: {container_path}')
|
||||
else:
|
||||
print("No sandbox container found for the given App Bundle.")
|
||||
|
||||
def getSandboxContainerMetadata(self):
|
||||
''' Return the sandbox container metadata in XML format. '''
|
||||
container_path = self.getSandboxContainerPath()
|
||||
if container_path:
|
||||
container_metadata_path = os.path.join(container_path, self.container_metadata_file)
|
||||
if os.path.exists(container_metadata_path):
|
||||
with open(container_metadata_path, 'rb') as f:
|
||||
container_metadata = plistlib.load(f)
|
||||
return container_metadata
|
||||
return None
|
||||
|
||||
def printSandboxContainerMetadata(self):
|
||||
''' Print the sandbox container metadata in XML format. '''
|
||||
container_metadata = self.getSandboxContainerMetadata()
|
||||
if container_metadata is None:
|
||||
print("No sandbox container found for the given App Bundle.")
|
||||
else:
|
||||
container_metadata_xml = (plistlib.dumps(container_metadata, fmt=plistlib.FMT_XML).decode('utf-8'))
|
||||
print(container_metadata_xml)
|
||||
|
||||
def getSandboxRedirectablePaths(self):
|
||||
''' Return the redirectable paths as array. '''
|
||||
container_metadata = self.getSandboxContainerMetadata()
|
||||
if container_metadata:
|
||||
redirectable_paths = container_metadata.get('MCMMetadataInfo', {}).get('SandboxProfileDataValidationInfo', {}).get('RedirectablePaths', [])
|
||||
return redirectable_paths
|
||||
return None
|
||||
|
||||
def printSandboxRedirectablePaths(self):
|
||||
''' Print the redirectable paths. '''
|
||||
redirectable_paths = self.getSandboxRedirectablePaths()
|
||||
if redirectable_paths:
|
||||
for path in redirectable_paths:
|
||||
print(path)
|
||||
else:
|
||||
print("No redirectable paths found for the given App Bundle.")
|
||||
|
||||
def getSandboxParameters(self):
|
||||
''' Return the sandbox parameters as dictionary. '''
|
||||
container_metadata = self.getSandboxContainerMetadata()
|
||||
if container_metadata:
|
||||
parameters = container_metadata.get('MCMMetadataInfo', {}).get('SandboxProfileDataValidationInfo', {}).get('Parameters', {})
|
||||
return parameters
|
||||
return None
|
||||
|
||||
def printSandboxParameters(self):
|
||||
''' Print the sandbox parameters as key-value pairs. '''
|
||||
parameters = self.getSandboxParameters()
|
||||
if parameters:
|
||||
for parameter_key, parameter_value in parameters.items():
|
||||
print(f"{parameter_key}: {parameter_value}")
|
||||
else:
|
||||
print("No sandbox parameters found for the given App Bundle.")
|
||||
|
||||
def getSandboxEntitlements(self):
|
||||
''' Return the sandbox entitlements as dictionary. '''
|
||||
container_metadata = self.getSandboxContainerMetadata()
|
||||
if container_metadata:
|
||||
entitlements = container_metadata.get('MCMMetadataInfo', {}).get('SandboxProfileDataValidationInfo', {}).get('Entitlements', {})
|
||||
return entitlements
|
||||
return None
|
||||
|
||||
def printSandboxEntitlements(self):
|
||||
''' Print the sandbox entitlements as JSON. '''
|
||||
entitlements = self.getSandboxEntitlements()
|
||||
if entitlements:
|
||||
print(json.dumps(entitlements, indent=4))
|
||||
else:
|
||||
print("No sandbox entitlements found for the given App Bundle.")
|
||||
|
||||
def getSandboxBuildUUID(self):
|
||||
''' Return the sandbox build UUID as string. '''
|
||||
container_metadata = self.getSandboxContainerMetadata()
|
||||
if container_metadata:
|
||||
build_uuid = container_metadata.get('MCMMetadataInfo', {}).get('SandboxProfileDataValidationInfo', {}).get('Sandbox_Build_UUID', '')
|
||||
return build_uuid
|
||||
return None
|
||||
|
||||
def printSandboxBuildUUID(self):
|
||||
''' Print the sandbox build UUID as string. '''
|
||||
build_uuid = self.getSandboxBuildUUID()
|
||||
if build_uuid:
|
||||
print(f"Build UUID: {build_uuid}")
|
||||
else:
|
||||
print("No sandbox build UUID found for the given App Bundle.")
|
||||
|
||||
def getSandboxRedirectedPaths(self):
|
||||
''' Return the redirected paths as list. '''
|
||||
container_metadata = self.getSandboxContainerMetadata()
|
||||
if container_metadata:
|
||||
redirected_paths = container_metadata.get('MCMMetadataInfo', {}).get('SandboxProfileDataValidationInfo', {}).get('RedirectedPaths', [])
|
||||
return redirected_paths
|
||||
return None
|
||||
|
||||
def printSandboxRedirectedPaths(self):
|
||||
''' Print the redirected paths as dictionary. '''
|
||||
redirected_paths = self.getRedirectedPaths()
|
||||
if redirected_paths:
|
||||
for path in redirected_paths:
|
||||
print(path)
|
||||
else:
|
||||
print("No redirected paths found for the given App Bundle.")
|
||||
|
||||
def getSandboxSystemImages(self):
|
||||
''' Return the system images as list. '''
|
||||
container_metadata = self.getSandboxContainerMetadata()
|
||||
if container_metadata:
|
||||
system_images = container_metadata.get('MCMMetadataInfo', {}).get('SandboxProfileDataValidationInfo', {}).get('SystemImages', [])
|
||||
return system_images
|
||||
return None
|
||||
|
||||
def printSandboxSystemImages(self):
|
||||
''' Print the system images as dictionary. '''
|
||||
system_images = self.getSandboxSystemImages()
|
||||
if system_images:
|
||||
for path in system_images:
|
||||
print(path)
|
||||
else:
|
||||
print("No system images found for the given App Bundle.")
|
||||
|
||||
def getSandboxSystemProfiles(self):
|
||||
''' Return the system profiles as dict. '''
|
||||
container_metadata = self.getSandboxContainerMetadata()
|
||||
if container_metadata:
|
||||
system_profiles = container_metadata.get('MCMMetadataInfo', {}).get('SandboxProfileDataValidationInfo', {}).get('SystemProfiles', {})
|
||||
return system_profiles
|
||||
return None
|
||||
|
||||
def printSandboxSystemProfiles(self):
|
||||
''' Print the system profiles as JSON. '''
|
||||
system_profiles = self.getSandboxSystemProfiles()
|
||||
if system_profiles:
|
||||
# Convert datetime to string for all profiles
|
||||
for profile in system_profiles:
|
||||
if 'AppSandboxProfileSnippetModificationDateKey' in profile:
|
||||
profile['AppSandboxProfileSnippetModificationDateKey'] = profile['AppSandboxProfileSnippetModificationDateKey'].isoformat()
|
||||
|
||||
# Print all profiles as a single JSON object
|
||||
print(json.dumps(system_profiles, indent=4))
|
||||
else:
|
||||
print("No system profiles found for the given App Bundle.")
|
||||
|
||||
def getContentProtectionClass(self):
|
||||
'''Return the com.apple.MobileInstallation.ContentProtectionClass value'''
|
||||
container_metadata = self.getSandboxContainerMetadata()
|
||||
if container_metadata:
|
||||
content_protection = container_metadata.get('MCMMetadataInfo', {}).get('com.apple.MobileInstallation.ContentProtectionClass')
|
||||
return content_protection
|
||||
return None
|
||||
|
||||
def printContentProtectionClass(self):
|
||||
'''Print the com.apple.MobileInstallation.ContentProtectionClass value'''
|
||||
content_protection = self.getContentProtectionClass()
|
||||
if content_protection is not None:
|
||||
print(f"com.apple.MobileInstallation.ContentProtectionClass: {content_protection}")
|
||||
else:
|
||||
print("No com.apple.MobileInstallation.ContentProtectionClass found for the given App Bundle.")
|
||||
|
||||
def getSandboxProfileData(self):
|
||||
''' Return the sandbox profile data as bytes. '''
|
||||
container_metadata = self.getSandboxContainerMetadata()
|
||||
if container_metadata:
|
||||
sandbox_profile_data = container_metadata.get('MCMMetadataInfo', {}).get('SandboxProfileData', None)
|
||||
return sandbox_profile_data
|
||||
return None
|
||||
|
||||
def printSandboxProfileData(self):
|
||||
''' Print the sandbox profile data as bytes. '''
|
||||
sandbox_profile_data = self.getSandboxProfileData()
|
||||
if sandbox_profile_data:
|
||||
sys.stdout.buffer.write(sandbox_profile_data)
|
||||
else:
|
||||
print("No SandboxProfileData found for the given App Bundle.")
|
||||
|
||||
def dumpKernelExtensionBinary(self, kext_name):
|
||||
''' Dump the kernel extension binary from the kernelcache.decompressed file.
|
||||
For now it is only wrapper arround ipsw'''
|
||||
os.system(f"ipsw kernel extract {self.file_path} {kext_name}")
|
||||
|
||||
def extractSandboxOperations(self):
|
||||
''' Extract sandbox operations from the Sandbox.kext file. '''
|
||||
all_strings = self.getStringSection()
|
||||
operations = []
|
||||
capture = False
|
||||
|
||||
for string in all_strings:
|
||||
if string == 'default':
|
||||
capture = True
|
||||
if capture:
|
||||
operations.append(string)
|
||||
if string == 'xpc-message-send':
|
||||
capture = False
|
||||
|
||||
return operations
|
||||
|
||||
def printSandboxOperations(self):
|
||||
'''Print the sandbox operations.'''
|
||||
operations = self.extractSandboxOperations()
|
||||
for operation in operations:
|
||||
print(operation)
|
||||
|
||||
### --- ARGUMENT PARSER --- ###
|
||||
class ArgumentParser:
|
||||
@@ -2824,6 +3126,7 @@ class ArgumentParser:
|
||||
self.addDyldArgs()
|
||||
self.addAMFIArgs()
|
||||
self.addAntivirusArgs()
|
||||
self.addSandboxArgs()
|
||||
|
||||
def addGeneralArgs(self):
|
||||
general_group = self.parser.add_argument_group('GENERAL ARGS')
|
||||
@@ -2837,6 +3140,7 @@ class ArgumentParser:
|
||||
bundle_group.add_argument('--bundle_info_syntax_check', action='store_true', help="Check if bundle info syntax is valid")
|
||||
bundle_group.add_argument('--bundle_frameworks', action='store_true', help="Print the list of frameworks in the bundle")
|
||||
bundle_group.add_argument('--bundle_plugins', action='store_true', help="Print the list of plugins in the bundle")
|
||||
bundle_group.add_argument('--bundle_id', action='store_true', help="Print the CFBundleIdentifier value from the Info.plist file if it exists")
|
||||
|
||||
def addMachOArgs(self):
|
||||
macho_group = self.parser.add_argument_group('MACH-O ARGS')
|
||||
@@ -2867,6 +3171,7 @@ class ArgumentParser:
|
||||
macho_group.add_argument('--calc_offset', help="Calculate the real address (file on disk) of the given Virtual Memory {vm_offset} (e.g. 0xfffffe000748f580)", metavar='vm_offset')
|
||||
macho_group.add_argument('--constructors', action='store_true', help="Print binary constructors")
|
||||
macho_group.add_argument('--dump_section', help="Dump '__SEGMENT,__section' to standard output as a raw bytes", metavar='__SEGMENT,__section')
|
||||
macho_group.add_argument('--dump_binary', help="Dump arm64 binary to a given file", metavar='output_path')
|
||||
|
||||
def addCodeSignArgs(self):
|
||||
codesign_group = self.parser.add_argument_group('CODE SIGNING ARGS')
|
||||
@@ -2954,6 +3259,24 @@ class ArgumentParser:
|
||||
antivirus_group.add_argument('--remove_quarantine', action='store_true', help="Remove com.apple.quarantine extended attribute from the file")
|
||||
antivirus_group.add_argument('--add_quarantine', action='store_true', help="Add com.apple.quarantine extended attribute to the file")
|
||||
|
||||
def addSandboxArgs(self):
|
||||
sandbox_group = self.parser.add_argument_group('SANDBOX ARGS')
|
||||
sandbox_group.add_argument('--sandbox_container_path', action='store_true', help="todo")
|
||||
sandbox_group.add_argument('--sandbox_container_metadata', action='store_true', help="Print the .com.apple.containermanagerd.metadata.plist contents for the given bundlein XML format")
|
||||
sandbox_group.add_argument('--sandbox_redirectable_paths', action='store_true', help="Print the redirectable paths from the sandbox container metadata as list")
|
||||
sandbox_group.add_argument('--sandbox_parameters', action='store_true', help="Print the parameters from the sandbox container metadata as key-value pairs")
|
||||
sandbox_group.add_argument('--sandbox_entitlements', action='store_true', help="Print the entitlements from the sandbox container metadata in JSON format")
|
||||
sandbox_group.add_argument('--sandbox_build_uuid', action='store_true', help="Print the sandbox build UUID from the sandbox container metadata")
|
||||
sandbox_group.add_argument('--sandbox_redirected_paths', action='store_true', help="Print the redirected paths from the sandbox container metadata as list")
|
||||
sandbox_group.add_argument('--sandbox_system_images', action='store_true', help="Print the system images from the sandbox container metadata as key-value pairs")
|
||||
sandbox_group.add_argument('--sandbox_system_profiles', action='store_true', help="Print the system profile from the sandbox container metadata in JSON format")
|
||||
sandbox_group.add_argument('--sandbox_content_protection', action='store_true', help="Print the content protection from the sandbox container metadata")
|
||||
sandbox_group.add_argument('--sandbox_profile_data', action='store_true', help="Print raw bytes ofthe sandbox profile data from the sandbox container metadata")
|
||||
sandbox_group.add_argument('--dump_kext', help="Dump the kernel extension binary from the kernelcache.decompressed file", metavar='kext_name')
|
||||
sandbox_group.add_argument('--extract_sandbox_operations', action='store_true', help="Extract sandbox operations from the kernelcache.decompressed file")
|
||||
|
||||
|
||||
|
||||
def parseArgs(self):
|
||||
args = self.parser.parse_args()
|
||||
|
||||
@@ -3324,7 +3647,7 @@ if __name__ == "__main__":
|
||||
args = arg_parser.parseArgs()
|
||||
|
||||
### --- APP BUNDLE EXTENSION --- ###
|
||||
snake_hatchery = SnakeHatchery(args, SnakeVII)
|
||||
snake_hatchery = SnakeHatchery(args, SnakeVIII)
|
||||
snake_hatchery.hatch()
|
||||
|
||||
### --- I. MACH-O --- ###
|
||||
@@ -3354,3 +3677,7 @@ if __name__ == "__main__":
|
||||
### --- VII. ANTIVIRUS --- ###
|
||||
antivirus_processor = AntivirusProcessor()
|
||||
antivirus_processor.process(args)
|
||||
|
||||
### --- VIII. SANDBOX --- ###
|
||||
sandbox_processor = SandboxProcessor()
|
||||
sandbox_processor.process(args)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import os
|
||||
import plistlib
|
||||
import argparse
|
||||
import base64
|
||||
|
||||
class SandboxInspector:
|
||||
def __init__(self, home_dir):
|
||||
@@ -71,7 +72,7 @@ def main():
|
||||
parser.add_argument('-p', '--path', type=str, required=True, help="Path to the application (e.g., /Applications/Notes.app)")
|
||||
parser.add_argument('-m', '--metadata', action='store_true', help="Print the .com.apple.containermanagerd.metadata.plist contents")
|
||||
parser.add_argument('-r', '--redirectable', action='store_true', help="Print the redirectable paths")
|
||||
parser.add_argument('-s', '--sandbox_profile_data', action='store_true', help="Print the SandboxProfileData bytes")
|
||||
parser.add_argument('-s', '--sandbox_profile_data', action='store_true', help="Print the SandboxProfileData as base64-encoded bytes")
|
||||
args = parser.parse_args()
|
||||
|
||||
app_path = args.path
|
||||
@@ -103,7 +104,8 @@ def main():
|
||||
sandbox_profile_data = inspector.get_sandbox_profile_data(bundle_id)
|
||||
if sandbox_profile_data:
|
||||
parsed_data = inspector.parse_sandbox_profile_data(sandbox_profile_data)
|
||||
print(f"SandboxProfileData for {bundle_id}:\n{parsed_data}")
|
||||
encoded_data = base64.b64encode(parsed_data).decode('utf-8')
|
||||
print(f"SandboxProfileData for {bundle_id} (base64-encoded):\n{encoded_data}")
|
||||
else:
|
||||
print(f"No SandboxProfileData found for {bundle_id}.")
|
||||
else:
|
||||
|
||||
@@ -1 +1 @@
|
||||
../App Bundle Extension/python/CrimsonUroboros.py
|
||||
../VIII. Sandbox/python/CrimsonUroboros.py
|
||||
@@ -306,6 +306,9 @@ class TestSnakeI():
|
||||
# Purge the compiled files
|
||||
cls.compiler.purgeCompiledFiles()
|
||||
assert not os.path.exists("hello_1") # Check if the file is removed after purging
|
||||
|
||||
os.remove("test_bin")
|
||||
assert not os.path.exists("test_bin") # Check if the file is removed after purging
|
||||
|
||||
def test_MachOProcessor(self):
|
||||
'''Test the initialization of MachOProcessor.
|
||||
@@ -769,7 +772,15 @@ class TestSnakeI():
|
||||
|
||||
def test_dump_section(self):
|
||||
'''Test the --dump_section flag of SnakeI.'''
|
||||
args_list = ['-p', 'hello_1', '--dump_section', '__TEXT,__cstring']
|
||||
uroboros_output = run_and_get_stdout('python3 CrimsonUroboros.py -p hello_1 --dump_section "__TEXT,__cstring"')
|
||||
print(uroboros_output)
|
||||
expected_output = 'Hello, World!'
|
||||
|
||||
assert expected_output in uroboros_output
|
||||
|
||||
def test_dump_binary(self):
|
||||
'''Test the --dump_binary flag of SnakeI.'''
|
||||
args_list = ['-p', 'hello_1', '--dump_binary', 'test_bin']
|
||||
args = argumentWrapper(args_list)
|
||||
snake_hatchery = SnakeHatchery(args, snake_class)
|
||||
snake_hatchery.hatch()
|
||||
@@ -779,9 +790,11 @@ class TestSnakeI():
|
||||
macho_processor.process(args)
|
||||
|
||||
uroboros_output = executeCodeBlock(code_block)
|
||||
expected_output = 'Hello, World!'
|
||||
expected_output = ''
|
||||
|
||||
assert expected_output in uroboros_output
|
||||
assert os.path.exists('test_bin')
|
||||
assert run_and_get_stdout('file test_bin') == 'test_bin: Mach-O 64-bit executable arm64'
|
||||
|
||||
class TestSnakeII():
|
||||
'''Testing II. CODE SIGNING'''
|
||||
|
||||
Reference in New Issue
Block a user