diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 27f33cff3..2062b6f9d 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -61,6 +61,7 @@ - [Deofuscation vbs (cscript.exe)](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/desofuscation-vbs-cscript.exe.md) - [Discord Cache Forensics](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/discord-cache-forensics.md) - [Local Cloud Storage](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/local-cloud-storage.md) + - [Mach O Entitlements And Ipsw Indexing](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md) - [Office file analysis](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/office-file-analysis.md) - [PDF File analysis](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/pdf-file-analysis.md) - [PNG tricks](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/png-tricks.md) diff --git a/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/README.md b/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/README.md index cb10a2e91..72690f3a0 100644 --- a/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/README.md +++ b/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/README.md @@ -54,4 +54,9 @@ video-and-audio-file-analysis.md zips-tricks.md {{#endref}} -{{#include ../../../banners/hacktricks-training.md}} + +{{#ref}} +mach-o-entitlements-and-ipsw-indexing.md +{{#endref}} + +{{#include ../../../banners/hacktricks-training.md}} \ No newline at end of file diff --git a/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md b/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md new file mode 100644 index 000000000..5ee572ae9 --- /dev/null +++ b/src/generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md @@ -0,0 +1,221 @@ +# Mach-O Entitlements Extraction & IPSW Indexing + +{{#include ../../../banners/hacktricks-training.md}} + +## Overview + +This page covers how to extract entitlements from Mach-O binaries programmatically by walking LC_CODE_SIGNATURE and parsing the code signing SuperBlob, and how to scale this across Apple IPSW firmwares by mounting and indexing their contents for forensic search/diff. + +If you need a refresher on Mach-O format and code signing, see also: macOS code signing and SuperBlob internals. +- Check macOS code signing details (SuperBlob, Code Directory, special slots): [macOS Code Signing](../../../macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-code-signing.md) +- Check general Mach-O structures/load commands: [Universal binaries & Mach-O Format](../../../macos-hardening/macos-security-and-privilege-escalation/macos-files-folders-and-binaries/universal-binaries-and-mach-o-format.md) + + +## Entitlements in Mach-O: where they live + +Entitlements are stored inside the code signature data referenced by the LC_CODE_SIGNATURE load command and placed in the __LINKEDIT segment. The signature is a CS_SuperBlob containing multiple blobs (code directory, requirements, entitlements, CMS, etc.). The entitlements blob is a CS_GenericBlob whose data is an Apple Binary Property List (bplist00) mapping entitlement keys to values. + +Key structures (from xnu): + +```c +/* mach-o/loader.h */ +struct mach_header_64 { + uint32_t magic; + cpu_type_t cputype; + cpu_subtype_t cpusubtype; + uint32_t filetype; + uint32_t ncmds; + uint32_t sizeofcmds; + uint32_t flags; + uint32_t reserved; +}; + +struct load_command { + uint32_t cmd; + uint32_t cmdsize; +}; + +/* Entitlements live behind LC_CODE_SIGNATURE (cmd=0x1d) */ +struct linkedit_data_command { + uint32_t cmd; /* LC_CODE_SIGNATURE */ + uint32_t cmdsize; /* sizeof(struct linkedit_data_command) */ + uint32_t dataoff; /* file offset of data in __LINKEDIT */ + uint32_t datasize; /* file size of data in __LINKEDIT */ +}; + +/* osfmk/kern/cs_blobs.h */ +typedef struct __SC_SuperBlob { + uint32_t magic; /* CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0 */ + uint32_t length; + uint32_t count; + CS_BlobIndex index[]; +} CS_SuperBlob; + +typedef struct __BlobIndex { + uint32_t type; /* e.g., CSMAGIC_EMBEDDED_ENTITLEMENTS = 0xfade7171 */ + uint32_t offset; /* offset of entry */ +} CS_BlobIndex; + +typedef struct __SC_GenericBlob { + uint32_t magic; /* same as type when standalone */ + uint32_t length; + char data[]; /* Apple Binary Plist containing entitlements */ +} CS_GenericBlob; +``` + +Important constants: +- LC_CODE_SIGNATURE cmd = 0x1d +- CS SuperBlob magic = 0xfade0cc0 +- Entitlements blob type (CSMAGIC_EMBEDDED_ENTITLEMENTS) = 0xfade7171 +- DER entitlements may be present via special slot (e.g., -7), see the macOS Code Signing page for special slots and DER entitlements notes + +Note: Multi-arch (fat) binaries contain multiple Mach-O slices. You must pick the slice for the architecture you want to inspect and then walk its load commands. + + +## Extraction steps (generic, lossless-enough) + +1) Parse Mach-O header; iterate ncmds worth of load_command records. +2) Locate LC_CODE_SIGNATURE; read linkedit_data_command.dataoff/datasize to map the Code Signing SuperBlob placed in __LINKEDIT. +3) Validate CS_SuperBlob.magic == 0xfade0cc0; iterate count entries of CS_BlobIndex. +4) Locate index.type == 0xfade7171 (embedded entitlements). Read the pointed CS_GenericBlob and parse its data as an Apple binary plist (bplist00) to key/value entitlements. + +Implementation notes: +- Code signature structures use big-endian fields; swap byte order when parsing on little-endian hosts. +- The entitlements GenericBlob data itself is a binary plist (handled by standard plist libraries). +- Some iOS binaries may carry DER entitlements; also some stores/slots differ across platforms/versions. Cross-check both standard and DER entitlements as needed. +- For fat binaries, use the fat headers (FAT_MAGIC/FAT_MAGIC_64) to locate the correct slice and offset before walking Mach-O load commands. + + +## Minimal parsing outline (Python) + +The following is a compact outline showing the control flow to find and decode entitlements. It intentionally omits robust bounds checks and full fat binary support for brevity. + +```python +import plistlib, struct + +LC_CODE_SIGNATURE = 0x1d +CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0 +CSMAGIC_EMBEDDED_ENTITLEMENTS = 0xfade7171 + +# all code-signing integers are big-endian per cs_blobs.h +be32 = lambda b, off: struct.unpack_from(">I", b, off)[0] + +def parse_entitlements(macho_bytes): + # assume already positioned at a single-arch Mach-O slice + magic, = struct.unpack_from(" +``` + +- Walk mounted volumes to locate Mach-O files (check magic and/or use file/otool), then parse entitlements and imported frameworks. +- Persist a normalized view into a relational database to avoid linear growth across thousands of IPSWs: + - executables, operating_system_versions, entitlements, frameworks + - many-to-many: executable↔OS version, executable↔entitlement, executable↔framework + +Example query to list all OS versions containing a given executable name: + +```sql +SELECT osv.version AS "Versions" +FROM device d +LEFT JOIN operating_system_version osv ON osv.device_id = d.id +LEFT JOIN executable_operating_system_version eosv ON eosv.operating_system_version_id = osv.id +LEFT JOIN executable e ON e.id = eosv.executable_id +WHERE e.name = "launchd"; +``` + +Notes on DB portability (if you implement your own indexer): +- Use an ORM/abstraction (e.g., SeaORM) to keep code DB-agnostic (SQLite/PostgreSQL). +- SQLite requires AUTOINCREMENT only on an INTEGER PRIMARY KEY; if you want i64 PKs in Rust, generate entities as i32 and convert types, SQLite stores INTEGER as 8-byte signed internally. + + +## Open-source tooling and references for entitlement hunting + +- Firmware mount/download: https://github.com/blacktop/ipsw +- Entitlement databases and references: + - Jonathan Levin’s entitlement DB: https://newosxbook.com/ent.php + - entdb: https://github.com/ChiChou/entdb +- Large-scale indexer (Rust, self-hosted Web UI + OpenAPI): https://github.com/synacktiv/appledb_rs +- Apple headers for structures and constants: + - loader.h (Mach-O headers, load commands) + - cs_blobs.h (SuperBlob, GenericBlob, CodeDirectory) + +For more on code signing internals (Code Directory, special slots, DER entitlements), see: [macOS Code Signing](../../../macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-code-signing.md) + + +## References + +- [appledb_rs: a research support tool for Apple platforms](https://www.synacktiv.com/publications/appledbrs-un-outil-daide-a-la-recherche-sur-plateformes-apple.html) +- [synacktiv/appledb_rs](https://github.com/synacktiv/appledb_rs) +- [blacktop/ipsw](https://github.com/blacktop/ipsw) +- [Jonathan Levin’s entitlement DB](https://newosxbook.com/ent.php) +- [ChiChou/entdb](https://github.com/ChiChou/entdb) +- [XNU cs_blobs.h](https://github.com/apple-oss-distributions/xnu/blob/main/osfmk/kern/cs_blobs.h) +- [XNU mach-o/loader.h](https://github.com/apple-oss-distributions/xnu/blob/main/EXTERNAL_HEADERS/mach-o/loader.h) +- [SQLite Datatypes](https://sqlite.org/datatype3.html) + +{{#include ../../../banners/hacktricks-training.md}} diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-files-folders-and-binaries/universal-binaries-and-mach-o-format.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-files-folders-and-binaries/universal-binaries-and-mach-o-format.md index f53e59565..41d29629a 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-files-folders-and-binaries/universal-binaries-and-mach-o-format.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-files-folders-and-binaries/universal-binaries-and-mach-o-format.md @@ -298,6 +298,11 @@ Load command 13 ### **`LC_CODE_SIGNATURE`** +{{#ref}} +../../../generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md +{{#endref}} + + Contains information about the **code signature of the Macho-O file**. It only contains an **offset** that **points** to the **signature blob**. This is typically at the very end of the file.\ However, you can find some information about this section in [**this blog post**](https://davedelong.com/blog/2018/01/10/reading-your-own-entitlements/) and this [**gists**](https://gist.github.com/carlospolop/ef26f8eb9fafd4bc22e69e1a32b81da4). diff --git a/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-code-signing.md b/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-code-signing.md index 47a1f4851..315fdc545 100644 --- a/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-code-signing.md +++ b/src/macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-code-signing.md @@ -4,6 +4,11 @@ ## Basic Information +{{#ref}} +../../../generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md +{{#endref}} + + Mach-o binaries contains a load command called **`LC_CODE_SIGNATURE`** that indicates the **offset** and **size** of the signatures inside the binary. Actually, using the GUI tool MachOView, it's possible to find at the end of the binary a section called **Code Signature** with this information: