mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/macos-hardening/macos-security-and-privilege-escalation
This commit is contained in:
parent
3f63131350
commit
dcbbf10ce0
@ -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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [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)
|
- [PNG tricks](generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/png-tricks.md)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Trucos específicos de software/tipo de archivo
|
# Trucos específicos de software/tipos de archivo
|
||||||
|
|
||||||
{{#include ../../../banners/hacktricks-training.md}}
|
{{#include ../../../banners/hacktricks-training.md}}
|
||||||
|
|
||||||
@ -54,4 +54,9 @@ video-and-audio-file-analysis.md
|
|||||||
zips-tricks.md
|
zips-tricks.md
|
||||||
{{#endref}}
|
{{#endref}}
|
||||||
|
|
||||||
|
|
||||||
|
{{#ref}}
|
||||||
|
mach-o-entitlements-and-ipsw-indexing.md
|
||||||
|
{{#endref}}
|
||||||
|
|
||||||
{{#include ../../../banners/hacktricks-training.md}}
|
{{#include ../../../banners/hacktricks-training.md}}
|
||||||
|
@ -0,0 +1,213 @@
|
|||||||
|
# Extracción de Entitlements de Mach-O e Indexado de IPSW
|
||||||
|
|
||||||
|
{{#include ../../../banners/hacktricks-training.md}}
|
||||||
|
|
||||||
|
## Visión general
|
||||||
|
|
||||||
|
Esta página explica cómo extraer entitlements de binarios Mach-O de forma programática recorriendo LC_CODE_SIGNATURE y analizando el SuperBlob de la firma de código, y cómo escalar esto a través de firmwares IPSW de Apple montando e indexando su contenido para búsquedas/diffs forenses.
|
||||||
|
|
||||||
|
Si necesitas un repaso sobre el formato Mach-O y code signing, consulta también: macOS code signing and SuperBlob internals.
|
||||||
|
- Consulta 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)
|
||||||
|
- Consulta 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 en Mach-O: dónde residen
|
||||||
|
|
||||||
|
Los entitlements se almacenan dentro de los datos de la firma de código referenciados por el load command LC_CODE_SIGNATURE y ubicados en el segmento __LINKEDIT. La firma es un CS_SuperBlob que contiene múltiples blobs (code directory, requirements, entitlements, CMS, etc.). El blob de entitlements es un CS_GenericBlob cuyo contenido es un Apple Binary Property List (bplist00) que mapea claves de entitlements a valores.
|
||||||
|
|
||||||
|
Estructuras clave (de 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("<I", macho_bytes, 0)
|
||||||
|
is64 = magic in (0xfeedfacf,)
|
||||||
|
if is64:
|
||||||
|
ncmds = struct.unpack_from("<I", macho_bytes, 0x10)[0]
|
||||||
|
sizeofcmds = struct.unpack_from("<I", macho_bytes, 0x14)[0]
|
||||||
|
off = 0x20
|
||||||
|
else:
|
||||||
|
# 32-bit not shown
|
||||||
|
return None
|
||||||
|
|
||||||
|
code_sig_off = code_sig_size = None
|
||||||
|
for _ in range(ncmds):
|
||||||
|
cmd, cmdsize = struct.unpack_from("<II", macho_bytes, off)
|
||||||
|
if cmd == LC_CODE_SIGNATURE:
|
||||||
|
# struct linkedit_data_command is little-endian in file
|
||||||
|
_, _, dataoff, datasize = struct.unpack_from("<IIII", macho_bytes, off)
|
||||||
|
code_sig_off, code_sig_size = dataoff, datasize
|
||||||
|
off += cmdsize
|
||||||
|
|
||||||
|
if code_sig_off is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
blob = macho_bytes[code_sig_off: code_sig_off + code_sig_size]
|
||||||
|
if be32(blob, 0x0) != CSMAGIC_EMBEDDED_SIGNATURE:
|
||||||
|
return None
|
||||||
|
|
||||||
|
count = be32(blob, 0x8)
|
||||||
|
# iterate BlobIndex entries (8 bytes each after 12-byte header)
|
||||||
|
for i in range(count):
|
||||||
|
idx_off = 12 + i*8
|
||||||
|
btype = be32(blob, idx_off)
|
||||||
|
boff = be32(blob, idx_off+4)
|
||||||
|
if btype == CSMAGIC_EMBEDDED_ENTITLEMENTS:
|
||||||
|
# GenericBlob is big-endian header followed by bplist
|
||||||
|
glen = be32(blob, boff+4)
|
||||||
|
data = blob[boff+8: boff+glen]
|
||||||
|
return plistlib.loads(data)
|
||||||
|
return None
|
||||||
|
```
|
||||||
|
Usage tips:
|
||||||
|
- Para tratar binarios fat, primero lee struct fat_header/fat_arch, elige la slice de arquitectura deseada, luego pasa el subrango a parse_entitlements.
|
||||||
|
- En macOS puedes validar los resultados con: codesign -d --entitlements :- /path/to/binary
|
||||||
|
|
||||||
|
|
||||||
|
## Ejemplos de hallazgos
|
||||||
|
|
||||||
|
Los binarios de plataforma privilegiada suelen solicitar entitlements sensibles como:
|
||||||
|
- com.apple.security.network.server = true
|
||||||
|
- com.apple.rootless.storage.early_boot_mount = true
|
||||||
|
- com.apple.private.kernel.system-override = true
|
||||||
|
- com.apple.private.pmap.load-trust-cache = ["cryptex1.boot.os", "cryptex1.boot.app", "cryptex1.safari-downlevel"]
|
||||||
|
|
||||||
|
Buscar estos a escala a través de imágenes de firmware es extremadamente valioso para mapear la superficie de ataque y comparar diferencias entre lanzamientos/dispositivos.
|
||||||
|
|
||||||
|
|
||||||
|
## Escalado a través de IPSWs (montaje e indexación)
|
||||||
|
|
||||||
|
Para enumerar ejecutables y extraer entitlements a escala sin almacenar imágenes completas:
|
||||||
|
|
||||||
|
- Usa la herramienta ipsw de @blacktop para descargar y montar los sistemas de archivos de firmware. El montaje aprovecha apfs-fuse, por lo que puedes recorrer volúmenes APFS sin extracción completa.
|
||||||
|
```bash
|
||||||
|
# Download latest IPSW for iPhone11,2 (iPhone XS)
|
||||||
|
ipsw download ipsw -y --device iPhone11,2 --latest
|
||||||
|
|
||||||
|
# Mount IPSW filesystem (uses underlying apfs-fuse)
|
||||||
|
ipsw mount fs <IPSW_FILE>
|
||||||
|
```
|
||||||
|
- Recorrer volúmenes montados para localizar archivos Mach-O (comprobar magic y/o usar file/otool), luego analizar entitlements y frameworks importados.
|
||||||
|
- Persistir una vista normalizada en una base de datos relacional para evitar crecimiento lineal a través de miles de IPSWs:
|
||||||
|
- executables, operating_system_versions, entitlements, frameworks
|
||||||
|
- many-to-many: executable↔OS version, executable↔entitlement, executable↔framework
|
||||||
|
|
||||||
|
Ejemplo de consulta para listar todas las versiones del sistema operativo que contienen un nombre de ejecutable dado:
|
||||||
|
```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";
|
||||||
|
```
|
||||||
|
Notas sobre la portabilidad de la DB (si implementas tu propio indexador):
|
||||||
|
- Usa una abstracción/ORM (por ejemplo, SeaORM) para mantener el código agnóstico a la DB (SQLite/PostgreSQL).
|
||||||
|
- SQLite requiere AUTOINCREMENT solo en un INTEGER PRIMARY KEY; si quieres PKs i64 en Rust, genera entidades como i32 y convierte los tipos, SQLite almacena INTEGER internamente como entero con signo de 8 bytes.
|
||||||
|
|
||||||
|
|
||||||
|
## Herramientas de código abierto y referencias para 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)
|
||||||
|
|
||||||
|
Para más información sobre los detalles internos de code signing (Code Directory, special slots, DER entitlements), consulta: [macOS Code Signing](../../../macos-hardening/macos-security-and-privilege-escalation/macos-security-protections/macos-code-signing.md)
|
||||||
|
|
||||||
|
|
||||||
|
## Referencias
|
||||||
|
|
||||||
|
- [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}}
|
@ -1,15 +1,15 @@
|
|||||||
# macOS Universal binaries & Mach-O Format
|
# macOS Binarios universales & Formato Mach-O
|
||||||
|
|
||||||
{{#include ../../../banners/hacktricks-training.md}}
|
{{#include ../../../banners/hacktricks-training.md}}
|
||||||
|
|
||||||
## Información Básica
|
## Información básica
|
||||||
|
|
||||||
Los binarios de Mac OS generalmente se compilan como **universal binaries**. Un **universal binary** puede **soportar múltiples arquitecturas en el mismo archivo**.
|
Los binarios de macOS normalmente se compilan como **binarios universales**. Un **binario universal** puede **soportar múltiples arquitecturas en el mismo archivo**.
|
||||||
|
|
||||||
Estos binarios siguen la **estructura Mach-O** que está compuesta básicamente de:
|
Estos binarios siguen la **estructura Mach-O**, que básicamente se compone de:
|
||||||
|
|
||||||
- Encabezado
|
- Encabezado
|
||||||
- Comandos de Carga
|
- Comandos de carga
|
||||||
- Datos
|
- Datos
|
||||||
|
|
||||||
.png>)
|
.png>)
|
||||||
@ -22,40 +22,40 @@ Busca el archivo con: `mdfind fat.h | grep -i mach-o | grep -E "fat.h$"`
|
|||||||
</strong><strong>#define FAT_CIGAM 0xbebafeca /* NXSwapLong(FAT_MAGIC) */
|
</strong><strong>#define FAT_CIGAM 0xbebafeca /* NXSwapLong(FAT_MAGIC) */
|
||||||
</strong>
|
</strong>
|
||||||
struct fat_header {
|
struct fat_header {
|
||||||
<strong> uint32_t magic; /* FAT_MAGIC o FAT_MAGIC_64 */
|
<strong> uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */
|
||||||
</strong><strong> uint32_t nfat_arch; /* número de estructuras que siguen */
|
</strong><strong> uint32_t nfat_arch; /* number of structs that follow */
|
||||||
</strong>};
|
</strong>};
|
||||||
|
|
||||||
struct fat_arch {
|
struct fat_arch {
|
||||||
cpu_type_t cputype; /* especificador de cpu (int) */
|
cpu_type_t cputype; /* cpu specifier (int) */
|
||||||
cpu_subtype_t cpusubtype; /* especificador de máquina (int) */
|
cpu_subtype_t cpusubtype; /* machine specifier (int) */
|
||||||
uint32_t offset; /* desplazamiento del archivo a este archivo objeto */
|
uint32_t offset; /* file offset to this object file */
|
||||||
uint32_t size; /* tamaño de este archivo objeto */
|
uint32_t size; /* size of this object file */
|
||||||
uint32_t align; /* alineación como una potencia de 2 */
|
uint32_t align; /* alignment as a power of 2 */
|
||||||
};
|
};
|
||||||
</code></pre>
|
</code></pre>
|
||||||
|
|
||||||
El encabezado tiene los bytes **mágicos** seguidos por el **número** de **archs** que el archivo **contiene** (`nfat_arch`) y cada arch tendrá una estructura `fat_arch`.
|
La cabecera tiene los bytes **magic** seguidos por el **número** de **arquitecturas** que el archivo **contiene** (`nfat_arch`) y cada arquitectura tendrá una estructura `fat_arch`.
|
||||||
|
|
||||||
Verifícalo con:
|
Compruébalo con:
|
||||||
|
|
||||||
<pre class="language-shell-session"><code class="lang-shell-session">% file /bin/ls
|
<pre class="language-shell-session"><code class="lang-shell-session">% file /bin/ls
|
||||||
/bin/ls: Mach-O universal binary con 2 arquitecturas: [x86_64:Mach-O 64-bit executable x86_64] [arm64e:Mach-O 64-bit executable arm64e]
|
/bin/ls: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64e:Mach-O 64-bit executable arm64e]
|
||||||
/bin/ls (para arquitectura x86_64): Mach-O 64-bit executable x86_64
|
/bin/ls (for architecture x86_64): Mach-O 64-bit executable x86_64
|
||||||
/bin/ls (para arquitectura arm64e): Mach-O 64-bit executable arm64e
|
/bin/ls (for architecture arm64e): Mach-O 64-bit executable arm64e
|
||||||
|
|
||||||
% otool -f -v /bin/ls
|
% otool -f -v /bin/ls
|
||||||
Fat headers
|
Fat headers
|
||||||
fat_magic FAT_MAGIC
|
fat_magic FAT_MAGIC
|
||||||
<strong>nfat_arch 2
|
<strong>nfat_arch 2
|
||||||
</strong><strong>arquitectura x86_64
|
</strong><strong>architecture x86_64
|
||||||
</strong> cputype CPU_TYPE_X86_64
|
</strong> cputype CPU_TYPE_X86_64
|
||||||
cpusubtype CPU_SUBTYPE_X86_64_ALL
|
cpusubtype CPU_SUBTYPE_X86_64_ALL
|
||||||
capabilities 0x0
|
capabilities 0x0
|
||||||
<strong> offset 16384
|
<strong> offset 16384
|
||||||
</strong><strong> size 72896
|
</strong><strong> size 72896
|
||||||
</strong> align 2^14 (16384)
|
</strong> align 2^14 (16384)
|
||||||
<strong>arquitectura arm64e
|
<strong>architecture arm64e
|
||||||
</strong> cputype CPU_TYPE_ARM64
|
</strong> cputype CPU_TYPE_ARM64
|
||||||
cpusubtype CPU_SUBTYPE_ARM64E
|
cpusubtype CPU_SUBTYPE_ARM64E
|
||||||
capabilities PTR_AUTH_VERSION USERSPACE 0
|
capabilities PTR_AUTH_VERSION USERSPACE 0
|
||||||
@ -68,11 +68,11 @@ o usando la herramienta [Mach-O View](https://sourceforge.net/projects/machoview
|
|||||||
|
|
||||||
<figure><img src="../../../images/image (1094).png" alt=""><figcaption></figcaption></figure>
|
<figure><img src="../../../images/image (1094).png" alt=""><figcaption></figcaption></figure>
|
||||||
|
|
||||||
Como puedes estar pensando, generalmente un universal binary compilado para 2 arquitecturas **duplica el tamaño** de uno compilado para solo 1 arch.
|
Como puedes imaginar, normalmente un binario universal compilado para 2 arquitecturas **duplica el tamaño** de uno compilado sólo para 1 arquitectura.
|
||||||
|
|
||||||
## **Encabezado Mach-O**
|
## **Cabecera Mach-O**
|
||||||
|
|
||||||
El encabezado contiene información básica sobre el archivo, como bytes mágicos para identificarlo como un archivo Mach-O e información sobre la arquitectura objetivo. Puedes encontrarlo en: `mdfind loader.h | grep -i mach-o | grep -E "loader.h$"`
|
La cabecera contiene información básica sobre el archivo, como los bytes magic para identificarlo como un archivo Mach-O y la información sobre la arquitectura objetivo. Puedes encontrarla en: `mdfind loader.h | grep -i mach-o | grep -E "loader.h$"`
|
||||||
```c
|
```c
|
||||||
#define MH_MAGIC 0xfeedface /* the mach magic number */
|
#define MH_MAGIC 0xfeedface /* the mach magic number */
|
||||||
#define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */
|
#define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */
|
||||||
@ -99,20 +99,20 @@ uint32_t flags; /* flags */
|
|||||||
uint32_t reserved; /* reserved */
|
uint32_t reserved; /* reserved */
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
### Tipos de Archivos Mach-O
|
### Tipos de archivo Mach-O
|
||||||
|
|
||||||
Hay diferentes tipos de archivos, puedes encontrarlos definidos en el [**código fuente, por ejemplo aquí**](https://opensource.apple.com/source/xnu/xnu-2050.18.24/EXTERNAL_HEADERS/mach-o/loader.h). Los más importantes son:
|
Hay diferentes tipos de archivo, puedes encontrarlos definidos en el [**source code for example here**](https://opensource.apple.com/source/xnu/xnu-2050.18.24/EXTERNAL_HEADERS/mach-o/loader.h). Los más importantes son:
|
||||||
|
|
||||||
- `MH_OBJECT`: Archivo objeto relocatable (productos intermedios de la compilación, aún no ejecutables).
|
- `MH_OBJECT`: Archivo objeto reubicable (productos intermedios de la compilación, aún no ejecutables).
|
||||||
- `MH_EXECUTE`: Archivos ejecutables.
|
- `MH_EXECUTE`: Archivos ejecutables.
|
||||||
- `MH_FVMLIB`: Archivo de biblioteca VM fija.
|
- `MH_FVMLIB`: Archivo de biblioteca de VM fija.
|
||||||
- `MH_CORE`: Volcados de código.
|
- `MH_CORE`: Volcados de código
|
||||||
- `MH_PRELOAD`: Archivo ejecutable pre-cargado (ya no soportado en XNU).
|
- `MH_PRELOAD`: Archivo ejecutable precargado (ya no es compatible en XNU)
|
||||||
- `MH_DYLIB`: Bibliotecas dinámicas.
|
- `MH_DYLIB`: Bibliotecas dinámicas
|
||||||
- `MH_DYLINKER`: Enlazador dinámico.
|
- `MH_DYLINKER`: Enlazador dinámico
|
||||||
- `MH_BUNDLE`: "Archivos de plugin". Generados usando -bundle en gcc y cargados explícitamente por `NSBundle` o `dlopen`.
|
- `MH_BUNDLE`: "Plugin files". Generados usando -bundle en gcc y cargados explícitamente por `NSBundle` o `dlopen`.
|
||||||
- `MH_DYSM`: Archivo compañero `.dSym` (archivo con símbolos para depuración).
|
- `MH_DYSM`: Archivo complementario `.dSym` (archivo con símbolos para depuración).
|
||||||
- `MH_KEXT_BUNDLE`: Extensiones del núcleo.
|
- `MH_KEXT_BUNDLE`: Extensiones del kernel.
|
||||||
```bash
|
```bash
|
||||||
# Checking the mac header of a binary
|
# Checking the mac header of a binary
|
||||||
otool -arch arm64e -hv /bin/ls
|
otool -arch arm64e -hv /bin/ls
|
||||||
@ -120,75 +120,75 @@ Mach header
|
|||||||
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
|
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
|
||||||
MH_MAGIC_64 ARM64 E USR00 EXECUTE 19 1728 NOUNDEFS DYLDLINK TWOLEVEL PIE
|
MH_MAGIC_64 ARM64 E USR00 EXECUTE 19 1728 NOUNDEFS DYLDLINK TWOLEVEL PIE
|
||||||
```
|
```
|
||||||
O usando [Mach-O View](https://sourceforge.net/projects/machoview/):
|
Or using [Mach-O View](https://sourceforge.net/projects/machoview/):
|
||||||
|
|
||||||
<figure><img src="../../../images/image (1133).png" alt=""><figcaption></figcaption></figure>
|
<figure><img src="../../../images/image (1133).png" alt=""><figcaption></figcaption></figure>
|
||||||
|
|
||||||
## **Flags de Mach-O**
|
## **Mach-O Flags**
|
||||||
|
|
||||||
El código fuente también define varios flags útiles para cargar bibliotecas:
|
El código fuente también define varias flags útiles para cargar librerías:
|
||||||
|
|
||||||
- `MH_NOUNDEFS`: Sin referencias indefinidas (totalmente enlazado)
|
- `MH_NOUNDEFS`: Sin referencias indefinidas (completamente enlazado)
|
||||||
- `MH_DYLDLINK`: Enlace Dyld
|
- `MH_DYLDLINK`: Enlazado por dyld
|
||||||
- `MH_PREBOUND`: Referencias dinámicas preenlazadas.
|
- `MH_PREBOUND`: Referencias dinámicas preenlazadas.
|
||||||
- `MH_SPLIT_SEGS`: El archivo divide segmentos r/o y r/w.
|
- `MH_SPLIT_SEGS`: El archivo divide segmentos r/o y r/w.
|
||||||
- `MH_WEAK_DEFINES`: El binario tiene símbolos definidos débiles
|
- `MH_WEAK_DEFINES`: El binario tiene símbolos definidos como débiles
|
||||||
- `MH_BINDS_TO_WEAK`: El binario usa símbolos débiles
|
- `MH_BINDS_TO_WEAK`: El binario utiliza símbolos débiles
|
||||||
- `MH_ALLOW_STACK_EXECUTION`: Hacer que la pila sea ejecutable
|
- `MH_ALLOW_STACK_EXECUTION`: Hacer la pila ejecutable
|
||||||
- `MH_NO_REEXPORTED_DYLIBS`: Biblioteca no tiene comandos LC_REEXPORT
|
- `MH_NO_REEXPORTED_DYLIBS`: La librería no tiene comandos LC_REEXPORT
|
||||||
- `MH_PIE`: Ejecutable Independiente de Posición
|
- `MH_PIE`: Ejecutable independiente de posición
|
||||||
- `MH_HAS_TLV_DESCRIPTORS`: Hay una sección con variables locales de hilo
|
- `MH_HAS_TLV_DESCRIPTORS`: Hay una sección con variables locales por hilo
|
||||||
- `MH_NO_HEAP_EXECUTION`: Sin ejecución para páginas de heap/datos
|
- `MH_NO_HEAP_EXECUTION`: No ejecución en páginas de heap/datos
|
||||||
- `MH_HAS_OBJC`: El binario tiene secciones de oBject-C
|
- `MH_HAS_OBJC`: El binario tiene secciones Objective-C
|
||||||
- `MH_SIM_SUPPORT`: Soporte para simuladores
|
- `MH_SIM_SUPPORT`: Soporte para simulador
|
||||||
- `MH_DYLIB_IN_CACHE`: Usado en dylibs/frameworks en la caché de bibliotecas compartidas.
|
- `MH_DYLIB_IN_CACHE`: Usado en dylibs/frameworks en la caché de librerías compartidas.
|
||||||
|
|
||||||
## **Comandos de carga de Mach-O**
|
## **Mach-O Load commands**
|
||||||
|
|
||||||
El **diseño del archivo en memoria** se especifica aquí, detallando la **ubicación de la tabla de símbolos**, el contexto del hilo principal al inicio de la ejecución y las **bibliotecas compartidas** requeridas. Se proporcionan instrucciones al cargador dinámico **(dyld)** sobre el proceso de carga del binario en memoria.
|
El diseño del archivo en memoria se especifica aquí, detallando la ubicación de la tabla de símbolos, el contexto del hilo principal al iniciar la ejecución y las librerías compartidas requeridas. Se proporcionan instrucciones al cargador dinámico (dyld) sobre el proceso de carga del binario en memoria.
|
||||||
|
|
||||||
Utiliza la estructura **load_command**, definida en el mencionado **`loader.h`**:
|
Esto usa la estructura `load_command`, definida en el mencionado `loader.h`:
|
||||||
```objectivec
|
```objectivec
|
||||||
struct load_command {
|
struct load_command {
|
||||||
uint32_t cmd; /* type of load command */
|
uint32_t cmd; /* type of load command */
|
||||||
uint32_t cmdsize; /* total size of command in bytes */
|
uint32_t cmdsize; /* total size of command in bytes */
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
Hay alrededor de **50 tipos diferentes de comandos de carga** que el sistema maneja de manera diferente. Los más comunes son: `LC_SEGMENT_64`, `LC_LOAD_DYLINKER`, `LC_MAIN`, `LC_LOAD_DYLIB` y `LC_CODE_SIGNATURE`.
|
Hay alrededor de **50 diferentes tipos de load commands** que el sistema maneja de forma distinta. Los más comunes son: `LC_SEGMENT_64`, `LC_LOAD_DYLINKER`, `LC_MAIN`, `LC_LOAD_DYLIB`, y `LC_CODE_SIGNATURE`.
|
||||||
|
|
||||||
### **LC_SEGMENT/LC_SEGMENT_64**
|
### **LC_SEGMENT/LC_SEGMENT_64**
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> Básicamente, este tipo de comando de carga define **cómo cargar el \_\_TEXT** (código ejecutable) **y \_\_DATA** (datos para el proceso) **segmentos** de acuerdo con los **desplazamientos indicados en la sección de datos** cuando se ejecuta el binario.
|
> Básicamente, este tipo de Load Command define **cómo cargar los \_\_TEXT** (código ejecutable) **y \_\_DATA** (datos para el proceso) **segments** de acuerdo con los **offsets indicados en la sección de datos** cuando el binario se ejecuta.
|
||||||
|
|
||||||
Estos comandos **definen segmentos** que son **mapeados** en el **espacio de memoria virtual** de un proceso cuando se ejecuta.
|
Estos comandos **definen segmentos** que se **mapean** en el **espacio de memoria virtual** de un proceso cuando se ejecuta.
|
||||||
|
|
||||||
Hay **diferentes tipos** de segmentos, como el **\_\_TEXT** segmento, que contiene el código ejecutable de un programa, y el **\_\_DATA** segmento, que contiene datos utilizados por el proceso. Estos **segmentos se encuentran en la sección de datos** del archivo Mach-O.
|
Hay **diferentes tipos** de segmentos, como el segmento **\_\_TEXT**, que contiene el código ejecutable de un programa, y el segmento **\_\_DATA**, que contiene los datos usados por el proceso. Estos **segmentos están ubicados en la sección de datos** del archivo Mach-O.
|
||||||
|
|
||||||
**Cada segmento** puede ser **dividido** en múltiples **secciones**. La **estructura del comando de carga** contiene **información** sobre **estas secciones** dentro del segmento respectivo.
|
**Cada segmento** puede ser a su vez **dividido** en múltiples **secciones**. La **estructura del load command** contiene **información** sobre **estas secciones** dentro del segmento correspondiente.
|
||||||
|
|
||||||
En el encabezado primero encuentras el **encabezado del segmento**:
|
En el encabezado primero encuentras la **cabecera del segmento**:
|
||||||
|
|
||||||
<pre class="language-c"><code class="lang-c">struct segment_command_64 { /* for 64-bit architectures */
|
<pre class="language-c"><code class="lang-c">struct segment_command_64 { /* for 64-bit architectures */
|
||||||
uint32_t cmd; /* LC_SEGMENT_64 */
|
uint32_t cmd; /* LC_SEGMENT_64 */
|
||||||
uint32_t cmdsize; /* incluye sizeof section_64 structs */
|
uint32_t cmdsize; /* includes sizeof section_64 structs */
|
||||||
char segname[16]; /* nombre del segmento */
|
char segname[16]; /* segment name */
|
||||||
uint64_t vmaddr; /* dirección de memoria de este segmento */
|
uint64_t vmaddr; /* memory address of this segment */
|
||||||
uint64_t vmsize; /* tamaño de memoria de este segmento */
|
uint64_t vmsize; /* memory size of this segment */
|
||||||
uint64_t fileoff; /* desplazamiento de archivo de este segmento */
|
uint64_t fileoff; /* file offset of this segment */
|
||||||
uint64_t filesize; /* cantidad a mapear desde el archivo */
|
uint64_t filesize; /* amount to map from the file */
|
||||||
int32_t maxprot; /* protección máxima de VM */
|
int32_t maxprot; /* maximum VM protection */
|
||||||
int32_t initprot; /* protección inicial de VM */
|
int32_t initprot; /* initial VM protection */
|
||||||
<strong> uint32_t nsects; /* número de secciones en el segmento */
|
<strong> uint32_t nsects; /* number of sections in segment */
|
||||||
</strong> uint32_t flags; /* banderas */
|
</strong> uint32_t flags; /* flags */
|
||||||
};
|
};
|
||||||
</code></pre>
|
</code></pre>
|
||||||
|
|
||||||
Ejemplo de encabezado de segmento:
|
Ejemplo de cabecera de segmento:
|
||||||
|
|
||||||
<figure><img src="../../../images/image (1126).png" alt=""><figcaption></figcaption></figure>
|
<figure><img src="../../../images/image (1126).png" alt=""><figcaption></figcaption></figure>
|
||||||
|
|
||||||
Este encabezado define el **número de secciones cuyos encabezados aparecen después** de él:
|
Esta cabecera define el **número de secciones cuyos encabezados aparecen después** de ella:
|
||||||
```c
|
```c
|
||||||
struct section_64 { /* for 64-bit architectures */
|
struct section_64 { /* for 64-bit architectures */
|
||||||
char sectname[16]; /* name of this section */
|
char sectname[16]; /* name of this section */
|
||||||
@ -209,58 +209,58 @@ Ejemplo de **encabezado de sección**:
|
|||||||
|
|
||||||
<figure><img src="../../../images/image (1108).png" alt=""><figcaption></figcaption></figure>
|
<figure><img src="../../../images/image (1108).png" alt=""><figcaption></figcaption></figure>
|
||||||
|
|
||||||
Si **agregas** el **desplazamiento de sección** (0x37DC) + el **desplazamiento** donde **comienza la arquitectura**, en este caso `0x18000` --> `0x37DC + 0x18000 = 0x1B7DC`
|
Si **sumas** el **offset de sección** (0x37DC) + el **offset** donde **empieza la arch**, en este caso `0x18000` --> `0x37DC + 0x18000 = 0x1B7DC`
|
||||||
|
|
||||||
<figure><img src="../../../images/image (701).png" alt=""><figcaption></figcaption></figure>
|
<figure><img src="../../../images/image (701).png" alt=""><figcaption></figcaption></figure>
|
||||||
|
|
||||||
También es posible obtener **información de encabezados** desde la **línea de comandos** con:
|
También es posible obtener la **información de encabezados** desde la **línea de comandos** con:
|
||||||
```bash
|
```bash
|
||||||
otool -lv /bin/ls
|
otool -lv /bin/ls
|
||||||
```
|
```
|
||||||
Segmentos comunes cargados por este cmd:
|
Common segments loaded by this cmd:
|
||||||
|
|
||||||
- **`__PAGEZERO`:** Instruye al kernel a **mapear** la **dirección cero** para que **no pueda ser leída, escrita o ejecutada**. Las variables maxprot y minprot en la estructura se establecen en cero para indicar que **no hay derechos de lectura-escritura-ejecución en esta página**.
|
- **`__PAGEZERO`:** Indica al kernel que **mapee** la **dirección cero** para que **no pueda ser leída, escrita ni ejecutada**. Las variables maxprot y minprot en la estructura se establecen a cero para indicar que **no hay permisos de lectura-escritura-ejecución en esta página**.
|
||||||
- Esta asignación es importante para **mitigar vulnerabilidades de desreferencia de punteros NULL**. Esto se debe a que XNU impone una página cero dura que asegura que la primera página (solo la primera) de la memoria sea inaccesible (excepto en i386). Un binario podría cumplir con estos requisitos creando un pequeño \_\_PAGEZERO (usando `-pagezero_size`) para cubrir los primeros 4k y teniendo el resto de la memoria de 32 bits accesible tanto en modo usuario como en modo kernel.
|
- Esta asignación es importante para **mitigar vulnerabilidades por desreferencia de puntero NULL**. Esto es porque XNU aplica una página cero estricta que asegura que la primera página (solo la primera) de la memoria sea inaccesible (excepto en i386). Un binario podría cumplir este requisito creando un pequeño \_\_PAGEZERO (usando `-pagezero_size`) para cubrir los primeros 4k y haciendo que el resto de la memoria de 32 bits sea accesible tanto en modo usuario como en modo kernel.
|
||||||
- **`__TEXT`**: Contiene **código** **ejecutable** con permisos de **lectura** y **ejecución** (no escribible)**.** Secciones comunes de este segmento:
|
- **`__TEXT`**: Contiene **código** **ejecutable** con permisos de **lectura** y **ejecución** (no escribible)**.** Secciones comunes de este segmento:
|
||||||
- `__text`: Código binario compilado
|
- `__text`: Código binario compilado
|
||||||
- `__const`: Datos constantes (solo lectura)
|
- `__const`: Datos constantes (solo lectura)
|
||||||
- `__[c/u/os_log]string`: Constantes de cadenas C, Unicode o os logs
|
- `__[c/u/os_log]string`: Constantes de cadenas C, Unicode u os_log
|
||||||
- `__stubs` y `__stubs_helper`: Involucrados durante el proceso de carga de la biblioteca dinámica
|
- `__stubs` and `__stubs_helper`: Involucradas durante el proceso de carga de librerías dinámicas
|
||||||
- `__unwind_info`: Datos de deshacer la pila.
|
- `__unwind_info`: Datos para unwind del stack.
|
||||||
- Tenga en cuenta que todo este contenido está firmado pero también marcado como ejecutable (creando más opciones para la explotación de secciones que no necesariamente necesitan este privilegio, como secciones dedicadas a cadenas).
|
- Ten en cuenta que todo este contenido está firmado pero además marcado como ejecutable (creando más opciones para la explotación de secciones que no necesitan necesariamente este privilegio, como secciones dedicadas a cadenas).
|
||||||
- **`__DATA`**: Contiene datos que son **legibles** y **escribibles** (no ejecutables)**.**
|
- **`__DATA`**: Contiene datos que son **legibles** y **escribibles** (no ejecutables)**.**
|
||||||
- `__got:` Tabla de Desplazamiento Global
|
- `__got:` Global Offset Table
|
||||||
- `__nl_symbol_ptr`: Puntero de símbolo no perezoso (vinculación al cargar)
|
- `__nl_symbol_ptr`: Puntero a símbolo non-lazy (bind al cargar)
|
||||||
- `__la_symbol_ptr`: Puntero de símbolo perezoso (vinculación al usar)
|
- `__la_symbol_ptr`: Puntero a símbolo lazy (bind al usar)
|
||||||
- `__const`: Debería ser datos de solo lectura (no realmente)
|
- `__const`: Debería ser datos de solo lectura (no siempre lo es)
|
||||||
- `__cfstring`: Cadenas de CoreFoundation
|
- `__cfstring`: Cadenas de CoreFoundation
|
||||||
- `__data`: Variables globales (que han sido inicializadas)
|
- `__data`: Variables globales (que han sido inicializadas)
|
||||||
- `__bss`: Variables estáticas (que no han sido inicializadas)
|
- `__bss`: Variables estáticas (que no han sido inicializadas)
|
||||||
- `__objc_*` (\_\_objc_classlist, \_\_objc_protolist, etc): Información utilizada por el tiempo de ejecución de Objective-C
|
- `__objc_*` (\_\_objc_classlist, \_\_objc_protolist, etc): Información usada por el runtime de Objective-C
|
||||||
- **`__DATA_CONST`**: \_\_DATA.\_\_const no está garantizado que sea constante (permisos de escritura), ni lo están otros punteros y la GOT. Esta sección hace que `__const`, algunos inicializadores y la tabla GOT (una vez resuelta) sean **solo lectura** usando `mprotect`.
|
- **`__DATA_CONST`**: \_\_DATA.\_\_const no está garantizado como constante (tiene permisos de escritura), ni lo están otros punteros y la GOT. Esta sección hace que `__const`, algunos inicializadores y la tabla GOT (una vez resuelta) sean **solo lectura** usando `mprotect`.
|
||||||
- **`__LINKEDIT`**: Contiene información para el enlazador (dyld) como, símbolos, cadenas y entradas de tabla de reubicación. Es un contenedor genérico para contenidos que no están en `__TEXT` o `__DATA` y su contenido se describe en otros comandos de carga.
|
- **`__LINKEDIT`**: Contiene información para el linker (dyld) como tablas de símbolos, cadenas y entradas de relocación. Es un contenedor genérico para contenidos que no están en `__TEXT` ni en `__DATA` y su contenido se describe en otros load commands.
|
||||||
- Información de dyld: Rebase, opcodes de vinculación no perezosa/perezosa/débil e información de exportación
|
- Información de dyld: Rebase, opcodes de enlace Non-lazy/lazy/weak e información de exportación
|
||||||
- Comienzos de funciones: Tabla de direcciones de inicio de funciones
|
- Functions starts: Tabla de direcciones de inicio de funciones
|
||||||
- Datos en Código: Islas de datos en \_\_text
|
- Data In Code: Islas de datos en \_\_text
|
||||||
- Tabla de Símbolos: Símbolos en binario
|
- SYmbol Table: Símbolos en el binario
|
||||||
- Tabla de Símbolos Indirectos: Punteros/símbolos de stub
|
- Indirect Symbol Table: Símbolos puntero/stub
|
||||||
- Tabla de Cadenas
|
- String Table
|
||||||
- Firma de Código
|
- Code Signature
|
||||||
- **`__OBJC`**: Contiene información utilizada por el tiempo de ejecución de Objective-C. Aunque esta información también podría encontrarse en el segmento \_\_DATA, dentro de varias secciones en \_\_objc\_\*.
|
- **`__OBJC`**: Contiene información usada por el runtime de Objective-C. Aunque esta información también puede encontrarse en el segmento \_\_DATA, dentro de varias secciones \_\_objc\_\*.
|
||||||
- **`__RESTRICT`**: Un segmento sin contenido con una sola sección llamada **`__restrict`** (también vacía) que asegura que al ejecutar el binario, ignorará las variables de entorno de DYLD.
|
- **`__RESTRICT`**: Un segmento sin contenido con una sola sección llamada **`__restrict`** (también vacía) que asegura que al ejecutar el binario, se ignorarán las variables de entorno de DYLD.
|
||||||
|
|
||||||
Como se pudo ver en el código, **los segmentos también admiten flags** (aunque no se utilizan mucho):
|
As it was possible to see in the code, **segments also support flags** (although they aren't used very much):
|
||||||
|
|
||||||
- `SG_HIGHVM`: Solo núcleo (no utilizado)
|
- `SG_HIGHVM`: Core only (not used)
|
||||||
- `SG_FVMLIB`: No utilizado
|
- `SG_FVMLIB`: Not used
|
||||||
- `SG_NORELOC`: El segmento no tiene reubicación
|
- `SG_NORELOC`: Segment has no relocation
|
||||||
- `SG_PROTECTED_VERSION_1`: Cifrado. Usado, por ejemplo, por Finder para cifrar el segmento de texto `__TEXT`.
|
- `SG_PROTECTED_VERSION_1`: Encryption. Used for example by Finder to encrypt text `__TEXT` segment.
|
||||||
|
|
||||||
### **`LC_UNIXTHREAD/LC_MAIN`**
|
### **`LC_UNIXTHREAD/LC_MAIN`**
|
||||||
|
|
||||||
**`LC_MAIN`** contiene el punto de entrada en el **atributo entryoff.** En el momento de la carga, **dyld** simplemente **agrega** este valor a la **base del binario** (en memoria), luego **salta** a esta instrucción para comenzar la ejecución del código del binario.
|
**`LC_MAIN`** contains the entrypoint in the **entryoff attribute.** At load time, **dyld** simply **adds** this value to the (in-memory) **base of the binary**, then **jumps** to this instruction to start execution of the binary’s code.
|
||||||
|
|
||||||
**`LC_UNIXTHREAD`** contiene los valores que el registro debe tener al iniciar el hilo principal. Esto ya fue desaprobado, pero **`dyld`** aún lo utiliza. Es posible ver los valores de los registros establecidos por esto con:
|
**`LC_UNIXTHREAD`** contains the values the register must have when starting the main thread. This was already deprecated but **`dyld`** still uses it. It's possible to see the vlaues of the registers set by this with:
|
||||||
```bash
|
```bash
|
||||||
otool -l /usr/lib/dyld
|
otool -l /usr/lib/dyld
|
||||||
[...]
|
[...]
|
||||||
@ -286,34 +286,39 @@ cpsr 0x00000000
|
|||||||
```
|
```
|
||||||
### **`LC_CODE_SIGNATURE`**
|
### **`LC_CODE_SIGNATURE`**
|
||||||
|
|
||||||
Contiene información sobre la **firma de código del archivo Macho-O**. Solo contiene un **desplazamiento** que **apunta** al **blob de firma**. Esto suele estar al final del archivo.\
|
{{#ref}}
|
||||||
Sin embargo, puedes encontrar algo de información sobre esta sección en [**esta publicación de blog**](https://davedelong.com/blog/2018/01/10/reading-your-own-entitlements/) y en este [**gist**](https://gist.github.com/carlospolop/ef26f8eb9fafd4bc22e69e1a32b81da4).
|
../../../generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md
|
||||||
|
{{#endref}}
|
||||||
|
|
||||||
|
|
||||||
|
Contiene información sobre la **code signature del archivo Mach-O**. Solo contiene un **offset** que **apunta** al **signature blob**. Esto típicamente está al final del archivo.\
|
||||||
|
Sin embargo, puedes encontrar algo de información sobre esta sección en [**this blog post**](https://davedelong.com/blog/2018/01/10/reading-your-own-entitlements/) y en este [**gists**](https://gist.github.com/carlospolop/ef26f8eb9fafd4bc22e69e1a32b81da4).
|
||||||
|
|
||||||
### **`LC_ENCRYPTION_INFO[_64]`**
|
### **`LC_ENCRYPTION_INFO[_64]`**
|
||||||
|
|
||||||
Soporte para la encriptación de binarios. Sin embargo, por supuesto, si un atacante logra comprometer el proceso, podrá volcar la memoria sin encriptar.
|
Soporte para binary encryption. Sin embargo, claro, si un atacante logra comprometer el proceso, podrá dump the memory sin cifrar.
|
||||||
|
|
||||||
### **`LC_LOAD_DYLINKER`**
|
### **`LC_LOAD_DYLINKER`**
|
||||||
|
|
||||||
Contiene la **ruta al ejecutable del enlazador dinámico** que mapea bibliotecas compartidas en el espacio de direcciones del proceso. El **valor siempre se establece en `/usr/lib/dyld`**. Es importante notar que en macOS, el mapeo de dylib ocurre en **modo de usuario**, no en modo kernel.
|
Contiene el **path to the dynamic linker executable** que mapea shared libraries en el espacio de direcciones del proceso. El **valor siempre está establecido en `/usr/lib/dyld`**. Es importante notar que en macOS, el dylib mapping ocurre en **user mode**, no en kernel mode.
|
||||||
|
|
||||||
### **`LC_IDENT`**
|
### **`LC_IDENT`**
|
||||||
|
|
||||||
Obsoleto, pero cuando se configura para generar volcado en caso de pánico, se crea un volcado de núcleo Mach-O y la versión del kernel se establece en el comando `LC_IDENT`.
|
Obsoleto, pero cuando está configurado para generar dumps on panic, se crea un Mach-O core dump y la versión del kernel se establece en el comando `LC_IDENT`.
|
||||||
|
|
||||||
### **`LC_UUID`**
|
### **`LC_UUID`**
|
||||||
|
|
||||||
UUID aleatorio. Es útil para cualquier cosa directamente, pero XNU lo almacena en caché con el resto de la información del proceso. Puede ser utilizado en informes de fallos.
|
UUID aleatorio. No es particularmente útil por sí solo, pero XNU lo cachea con el resto de la información del proceso. Puede usarse en crash reports.
|
||||||
|
|
||||||
### **`LC_DYLD_ENVIRONMENT`**
|
### **`LC_DYLD_ENVIRONMENT`**
|
||||||
|
|
||||||
Permite indicar variables de entorno al dyld antes de que se ejecute el proceso. Esto puede ser muy peligroso, ya que puede permitir ejecutar código arbitrario dentro del proceso, por lo que este comando de carga solo se utiliza en dyld construido con `#define SUPPORT_LC_DYLD_ENVIRONMENT` y restringe aún más el procesamiento solo a variables de la forma `DYLD_..._PATH` especificando rutas de carga.
|
Permite indicar environment variables to the dyld antes de que el proceso sea ejecutado. Esto puede ser muy peligroso, ya que puede permitir la ejecución de código arbitrario dentro del proceso, por lo que este load command solo se usa en builds de dyld con `#define SUPPORT_LC_DYLD_ENVIRONMENT` y además restringe el procesamiento solo a variables de la forma `DYLD_..._PATH` que especifican load paths.
|
||||||
|
|
||||||
### **`LC_LOAD_DYLIB`**
|
### **`LC_LOAD_DYLIB`**
|
||||||
|
|
||||||
Este comando de carga describe una dependencia de **biblioteca** **dinámica** que **instruye** al **cargador** (dyld) a **cargar y vincular dicha biblioteca**. Hay un comando de carga `LC_LOAD_DYLIB` **para cada biblioteca** que el binario Mach-O requiere.
|
Este load command describe una dependencia de **dynamic library** que **instruciona** al **loader** (dyld) para **load and link dicha librería**. Existe un `LC_LOAD_DYLIB` load command **por cada librería** que el binary Mach-O requiere.
|
||||||
|
|
||||||
- Este comando de carga es una estructura de tipo **`dylib_command`** (que contiene una estructura dylib, describiendo la biblioteca dinámica dependiente real):
|
- Este load command es una estructura del tipo **`dylib_command`** (que contiene un struct dylib, describiendo la actual dynamic library dependiente):
|
||||||
```objectivec
|
```objectivec
|
||||||
struct dylib_command {
|
struct dylib_command {
|
||||||
uint32_t cmd; /* LC_LOAD_{,WEAK_}DYLIB */
|
uint32_t cmd; /* LC_LOAD_{,WEAK_}DYLIB */
|
||||||
@ -330,7 +335,7 @@ uint32_t compatibility_version; /* library's compatibility vers number*/
|
|||||||
```
|
```
|
||||||
.png>)
|
.png>)
|
||||||
|
|
||||||
También podrías obtener esta información desde la línea de comandos con:
|
También puedes obtener esta información desde la CLI con:
|
||||||
```bash
|
```bash
|
||||||
otool -L /bin/ls
|
otool -L /bin/ls
|
||||||
/bin/ls:
|
/bin/ls:
|
||||||
@ -338,32 +343,32 @@ otool -L /bin/ls
|
|||||||
/usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0)
|
/usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0)
|
||||||
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.0.0)
|
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.0.0)
|
||||||
```
|
```
|
||||||
Algunas bibliotecas potencialmente relacionadas con malware son:
|
Algunas librerías relacionadas con malware potencial son:
|
||||||
|
|
||||||
- **DiskArbitration**: Monitoreo de unidades USB
|
- **DiskArbitration**: Monitoreo de unidades USB
|
||||||
- **AVFoundation:** Captura de audio y video
|
- **AVFoundation:** Capturar audio y vídeo
|
||||||
- **CoreWLAN**: Escaneos de Wifi.
|
- **CoreWLAN**: Escaneos de Wi‑Fi.
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> Un binario Mach-O puede contener uno o **más** **constructores**, que serán **ejecutados** **antes** de la dirección especificada en **LC_MAIN**.\
|
|
||||||
> Los desplazamientos de cualquier constructor se mantienen en la sección **\_\_mod_init_func** del segmento **\_\_DATA_CONST**.
|
|
||||||
|
|
||||||
## **Datos de Mach-O**
|
|
||||||
|
|
||||||
En el núcleo del archivo se encuentra la región de datos, que está compuesta por varios segmentos como se define en la región de comandos de carga. **Una variedad de secciones de datos puede estar contenida dentro de cada segmento**, con cada sección **conteniendo código o datos** específicos de un tipo.
|
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> Los datos son básicamente la parte que contiene toda la **información** que es cargada por los comandos de carga **LC_SEGMENTS_64**
|
> Un binario Mach-O puede contener uno o **más** **constructores**, que serán **ejecutados** **antes** de la dirección especificada en **LC_MAIN**.\
|
||||||
|
> Los offsets de cualquier constructor se almacenan en la sección **\_\_mod_init_func** del segmento **\_\_DATA_CONST**.
|
||||||
|
|
||||||
|
## **Datos Mach-O**
|
||||||
|
|
||||||
|
En el núcleo del archivo se encuentra la región de datos, que está compuesta por varios segmentos según se definen en la región de load-commands. **Una variedad de secciones de datos puede alojarse dentro de cada segmento**, con cada sección **conteniendo código o datos** específicos de un tipo.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> Los datos son básicamente la parte que contiene toda la **información** que es cargada por los load commands **LC_SEGMENTS_64**
|
||||||
|
|
||||||
 (3).png>)
|
 (3).png>)
|
||||||
|
|
||||||
Esto incluye:
|
Esto incluye:
|
||||||
|
|
||||||
- **Tabla de funciones:** Que contiene información sobre las funciones del programa.
|
- **Function table:** Que contiene información sobre las funciones del programa.
|
||||||
- **Tabla de símbolos**: Que contiene información sobre la función externa utilizada por el binario
|
- **Symbol table**: Que contiene información sobre las funciones externas usadas por el binario
|
||||||
- También podría contener funciones internas, nombres de variables y más.
|
- También podría contener funciones internas, nombres de variables y más.
|
||||||
|
|
||||||
Para verificarlo, podrías usar la herramienta [**Mach-O View**](https://sourceforge.net/projects/machoview/):
|
Para comprobarlo puedes usar la herramienta [**Mach-O View**](https://sourceforge.net/projects/machoview/):
|
||||||
|
|
||||||
<figure><img src="../../../images/image (1120).png" alt=""><figcaption></figcaption></figure>
|
<figure><img src="../../../images/image (1120).png" alt=""><figcaption></figcaption></figure>
|
||||||
|
|
||||||
@ -371,20 +376,20 @@ O desde la cli:
|
|||||||
```bash
|
```bash
|
||||||
size -m /bin/ls
|
size -m /bin/ls
|
||||||
```
|
```
|
||||||
## Secciones Comunes de Objetive-C
|
## Secciones comunes de Objective-C
|
||||||
|
|
||||||
En el segmento `__TEXT` (r-x):
|
En el segmento `__TEXT` (r-x):
|
||||||
|
|
||||||
- `__objc_classname`: Nombres de clases (cadenas)
|
- `__objc_classname`: Nombres de clase (cadenas)
|
||||||
- `__objc_methname`: Nombres de métodos (cadenas)
|
- `__objc_methname`: Nombres de método (cadenas)
|
||||||
- `__objc_methtype`: Tipos de métodos (cadenas)
|
- `__objc_methtype`: Tipos de método (cadenas)
|
||||||
|
|
||||||
En el segmento `__DATA` (rw-):
|
En el segmento `__DATA` (rw-):
|
||||||
|
|
||||||
- `__objc_classlist`: Punteros a todas las clases de Objetive-C
|
- `__objc_classlist`: Punteros a todas las clases de Objective-C
|
||||||
- `__objc_nlclslist`: Punteros a clases de Objetive-C No Perezosas
|
- `__objc_nlclslist`: Punteros a Non-Lazy Objective-C classes
|
||||||
- `__objc_catlist`: Puntero a Categorías
|
- `__objc_catlist`: Puntero a Categories
|
||||||
- `__objc_nlcatlist`: Puntero a Categorías No Perezosas
|
- `__objc_nlcatlist`: Puntero a Non-Lazy Categories
|
||||||
- `__objc_protolist`: Lista de protocolos
|
- `__objc_protolist`: Lista de protocolos
|
||||||
- `__objc_const`: Datos constantes
|
- `__objc_const`: Datos constantes
|
||||||
- `__objc_imageinfo`, `__objc_selrefs`, `objc__protorefs`...
|
- `__objc_imageinfo`, `__objc_selrefs`, `objc__protorefs`...
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
# macOS Code Signing
|
# Firma de código en macOS
|
||||||
|
|
||||||
{{#include ../../../banners/hacktricks-training.md}}
|
{{#include ../../../banners/hacktricks-training.md}}
|
||||||
|
|
||||||
## Información Básica
|
## Información básica
|
||||||
|
|
||||||
Los binarios Mach-o contienen un comando de carga llamado **`LC_CODE_SIGNATURE`** que indica el **offset** y **size** de las firmas dentro del binario. De hecho, utilizando la herramienta GUI MachOView, es posible encontrar al final del binario una sección llamada **Code Signature** con esta información:
|
{{#ref}}
|
||||||
|
../../../generic-methodologies-and-resources/basic-forensic-methodology/specific-software-file-type-tricks/mach-o-entitlements-and-ipsw-indexing.md
|
||||||
|
{{#endref}}
|
||||||
|
|
||||||
|
|
||||||
|
Los binarios Mach-o contienen un comando de carga llamado **`LC_CODE_SIGNATURE`** que indica el **offset** y el **size** de las firmas dentro del binario. De hecho, usando la herramienta GUI MachOView, es posible encontrar al final del binario una sección llamada **Code Signature** con esta información:
|
||||||
|
|
||||||
<figure><img src="../../../images/image (1) (1) (1) (1).png" alt="" width="431"><figcaption></figcaption></figure>
|
<figure><img src="../../../images/image (1) (1) (1) (1).png" alt="" width="431"><figcaption></figcaption></figure>
|
||||||
|
|
||||||
El encabezado mágico de la Code Signature es **`0xFADE0CC0`**. Luego tienes información como la longitud y el número de blobs del superBlob que los contiene.\
|
El header mágico de la Code Signature es **`0xFADE0CC0`**. Después tienes información como la longitud y el número de blobs del superBlob que las contiene.\
|
||||||
Es posible encontrar esta información en el [código fuente aquí](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L276):
|
It's possible to find this information in the [source code here](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L276):
|
||||||
```c
|
```c
|
||||||
/*
|
/*
|
||||||
* Structure of an embedded-signature SuperBlob
|
* Structure of an embedded-signature SuperBlob
|
||||||
@ -38,14 +43,14 @@ char data[];
|
|||||||
} CS_GenericBlob
|
} CS_GenericBlob
|
||||||
__attribute__ ((aligned(1)));
|
__attribute__ ((aligned(1)));
|
||||||
```
|
```
|
||||||
Los blobs comunes que se contienen son el Directorio de Código, Requisitos y Derechos, y un Sintaxis de Mensaje Criptográfico (CMS).\
|
Los blobs comunes incluyen Code Directory, Requirements y Entitlements, y un Cryptographic Message Syntax (CMS).
|
||||||
Además, note cómo los datos codificados en los blobs están codificados en **Big Endian.**
|
Además, ten en cuenta cómo los datos codificados en los blobs están en **Big Endian.**
|
||||||
|
|
||||||
Además, las firmas pueden ser separadas de los binarios y almacenadas en `/var/db/DetachedSignatures` (utilizado por iOS).
|
Además, las firmas pueden estar separadas de los binarios y almacenadas en `/var/db/DetachedSignatures` (usado por iOS).
|
||||||
|
|
||||||
## Blob del Directorio de Código
|
## Code Directory Blob
|
||||||
|
|
||||||
Es posible encontrar la declaración del [Blob del Directorio de Código en el código](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L104):
|
Es posible encontrar la declaración de la [Code Directory Blob in the code](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L104):
|
||||||
```c
|
```c
|
||||||
typedef struct __CodeDirectory {
|
typedef struct __CodeDirectory {
|
||||||
uint32_t magic; /* magic number (CSMAGIC_CODEDIRECTORY) */
|
uint32_t magic; /* magic number (CSMAGIC_CODEDIRECTORY) */
|
||||||
@ -101,12 +106,12 @@ char end_withLinkage[0];
|
|||||||
} CS_CodeDirectory
|
} CS_CodeDirectory
|
||||||
__attribute__ ((aligned(1)));
|
__attribute__ ((aligned(1)));
|
||||||
```
|
```
|
||||||
Nota que hay diferentes versiones de esta estructura donde las antiguas pueden contener menos información.
|
Ten en cuenta que existen diferentes versiones de esta struct donde las antiguas podrían contener menos información.
|
||||||
|
|
||||||
## Páginas de Firma de Código
|
## Signing Code Pages
|
||||||
|
|
||||||
Hacer un hash del binario completo sería ineficiente e incluso inútil si solo se carga en memoria parcialmente. Por lo tanto, la firma del código es en realidad un hash de hashes donde cada página binaria se hash individualmente.\
|
Calcular el hash del binary completo sería ineficiente e incluso inútil si este solo se carga parcialmente en memory. Por lo tanto, la code signature es en realidad un hash of hashes donde cada binary page se hashea individualmente.\
|
||||||
De hecho, en el código del **Directorio de Código** anterior puedes ver que **el tamaño de la página está especificado** en uno de sus campos. Además, si el tamaño del binario no es un múltiplo del tamaño de una página, el campo **CodeLimit** especifica dónde está el final de la firma.
|
En la sección anterior de **Code Directory** puedes ver que el **page size is specified** en uno de sus campos. Además, si el tamaño del binary no es múltiplo del tamaño de una page, el campo **CodeLimit** especifica dónde está el final de la signature.
|
||||||
```bash
|
```bash
|
||||||
# Get all hashes of /bin/ps
|
# Get all hashes of /bin/ps
|
||||||
codesign -d -vvvvvv /bin/ps
|
codesign -d -vvvvvv /bin/ps
|
||||||
@ -142,27 +147,27 @@ dd if=$BINARY of=/tmp/`basename $BINARY`.page.$i bs=$PAGESIZE skip=$i count=1
|
|||||||
done
|
done
|
||||||
openssl sha256 /tmp/*.page.*
|
openssl sha256 /tmp/*.page.*
|
||||||
```
|
```
|
||||||
## Entitlements Blob
|
## Blob de entitlements
|
||||||
|
|
||||||
Tenga en cuenta que las aplicaciones también pueden contener un **entitlement blob** donde se definen todos los derechos. Además, algunos binarios de iOS pueden tener sus derechos específicos en el slot especial -7 (en lugar de en el slot especial de derechos -5).
|
Ten en cuenta que las aplicaciones también pueden contener un **entitlement blob** donde se definen todos los **entitlements**. Además, algunos binarios de iOS pueden tener sus entitlements específicos en el special slot -7 (en lugar de en el special slot -5 de entitlements).
|
||||||
|
|
||||||
## Special Slots
|
## Ranuras especiales
|
||||||
|
|
||||||
Las aplicaciones de MacOS no tienen todo lo que necesitan para ejecutarse dentro del binario, sino que también utilizan **recursos externos** (generalmente dentro del **bundle** de las aplicaciones). Por lo tanto, hay algunos slots dentro del binario que contendrán los hashes de algunos recursos externos interesantes para verificar que no han sido modificados.
|
Las aplicaciones de macOS no tienen todo lo necesario para ejecutarse dentro del binario, sino que también usan **external resources** (normalmente dentro del **bundle** de la aplicación). Por ello, hay algunas ranuras dentro del binario que contendrán los hashes de ciertos recursos externos interesantes para comprobar que no han sido modificados.
|
||||||
|
|
||||||
De hecho, es posible ver en las estructuras del Directorio de Código un parámetro llamado **`nSpecialSlots`** que indica el número de los slots especiales. No hay un slot especial 0 y los más comunes (del -1 al -6) son:
|
En realidad, es posible ver en las estructuras Code Directory un parámetro llamado **`nSpecialSlots`** que indica el número de special slots. No existe un special slot 0 y los más comunes (de -1 a -6) son:
|
||||||
|
|
||||||
- Hash de `info.plist` (o el que está dentro de `__TEXT.__info__plist`).
|
- Hash de `info.plist` (o el que está dentro de `__TEXT.__info__plist`).
|
||||||
- Hash de los Requisitos
|
- Hash de los Requirements
|
||||||
- Hash del Directorio de Recursos (hash del archivo `_CodeSignature/CodeResources` dentro del bundle).
|
- Hash del Resource Directory (hash del archivo `_CodeSignature/CodeResources` dentro del bundle).
|
||||||
- Específico de la aplicación (no utilizado)
|
- Específico de la aplicación (no usado)
|
||||||
- Hash de los derechos
|
- Hash de los entitlements
|
||||||
- Firmas de código DMG solamente
|
- Solo firmas de código DMG
|
||||||
- Derechos DER
|
- DER Entitlements
|
||||||
|
|
||||||
## Code Signing Flags
|
## Code Signing Flags
|
||||||
|
|
||||||
Cada proceso tiene asociado un bitmask conocido como `status` que es iniciado por el kernel y algunos de ellos pueden ser anulados por la **firma de código**. Estas banderas que pueden incluirse en la firma de código están [definidas en el código](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L36):
|
Cada proceso tiene relacionada una máscara de bits conocida como `status` que es inicializada por el kernel y algunas de esas flags pueden ser anuladas por la **code signature**. Estas flags que pueden incluirse en el code signing están [definidas en el código](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/osfmk/kern/cs_blobs.h#L36):
|
||||||
```c
|
```c
|
||||||
/* code signing attributes of a process */
|
/* code signing attributes of a process */
|
||||||
#define CS_VALID 0x00000001 /* dynamically valid */
|
#define CS_VALID 0x00000001 /* dynamically valid */
|
||||||
@ -207,15 +212,15 @@ CS_RESTRICT | CS_ENFORCEMENT | CS_REQUIRE_LV | CS_RUNTIME | CS_LINKER_SIGNED)
|
|||||||
|
|
||||||
#define CS_ENTITLEMENT_FLAGS (CS_GET_TASK_ALLOW | CS_INSTALLER | CS_DATAVAULT_CONTROLLER | CS_NVRAM_UNRESTRICTED)
|
#define CS_ENTITLEMENT_FLAGS (CS_GET_TASK_ALLOW | CS_INSTALLER | CS_DATAVAULT_CONTROLLER | CS_NVRAM_UNRESTRICTED)
|
||||||
```
|
```
|
||||||
Note que la función [**exec_mach_imgact**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/kern/kern_exec.c#L1420) también puede agregar dinámicamente las banderas `CS_EXEC_*` al iniciar la ejecución.
|
Ten en cuenta que la función [**exec_mach_imgact**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/kern/kern_exec.c#L1420) también puede añadir las banderas `CS_EXEC_*` dinámicamente al iniciar la ejecución.
|
||||||
|
|
||||||
## Requisitos de Firma de Código
|
## Requisitos de la firma de código
|
||||||
|
|
||||||
Cada aplicación almacena algunos **requisitos** que debe **satisfacer** para poder ser ejecutada. Si los **requisitos de la aplicación no son satisfechos por la aplicación**, no se ejecutará (ya que probablemente ha sido alterada).
|
Cada aplicación almacena algunos **requisitos** que debe **satisfacer** para poder ejecutarse. Si los **requisitos contenidos en la aplicación** no son satisfechos por la aplicación, no se ejecutará (ya que probablemente ha sido alterada).
|
||||||
|
|
||||||
Los requisitos de un binario utilizan una **gramática especial** que es un flujo de **expresiones** y están codificados como blobs usando `0xfade0c00` como el mágico cuyo **hash se almacena en un slot de código especial**.
|
Los requisitos de un binario usan una **gramática especial** que es un flujo de **expresiones** y se codifican como blobs usando `0xfade0c00` como valor mágico cuyo **hash** se almacena en un slot de código especial.
|
||||||
|
|
||||||
Los requisitos de un binario se pueden ver ejecutando:
|
Los requisitos de un binario pueden verse ejecutando:
|
||||||
```bash
|
```bash
|
||||||
codesign -d -r- /bin/ls
|
codesign -d -r- /bin/ls
|
||||||
Executable=/bin/ls
|
Executable=/bin/ls
|
||||||
@ -225,10 +230,10 @@ codesign -d -r- /Applications/Signal.app/
|
|||||||
Executable=/Applications/Signal.app/Contents/MacOS/Signal
|
Executable=/Applications/Signal.app/Contents/MacOS/Signal
|
||||||
designated => identifier "org.whispersystems.signal-desktop" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = U68MSDN6DR
|
designated => identifier "org.whispersystems.signal-desktop" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = U68MSDN6DR
|
||||||
```
|
```
|
||||||
> [!NOTE]
|
> [!TIP]
|
||||||
> Nota cómo estas firmas pueden verificar cosas como información de certificación, TeamID, IDs, derechos y muchos otros datos.
|
> Observa cómo estas firmas pueden verificar cosas como información del certificado, TeamID, IDs, entitlements y muchos otros datos.
|
||||||
|
|
||||||
Además, es posible generar algunos requisitos compilados utilizando la herramienta `csreq`:
|
Además, es posible generar algunos requisitos compilados usando la herramienta `csreq`:
|
||||||
```bash
|
```bash
|
||||||
# Generate compiled requirements
|
# Generate compiled requirements
|
||||||
csreq -b /tmp/output.csreq -r='identifier "org.whispersystems.signal-desktop" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = U68MSDN6DR'
|
csreq -b /tmp/output.csreq -r='identifier "org.whispersystems.signal-desktop" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = U68MSDN6DR'
|
||||||
@ -240,57 +245,57 @@ od -A x -t x1 /tmp/output.csreq
|
|||||||
0000020 00 00 00 21 6f 72 67 2e 77 68 69 73 70 65 72 73
|
0000020 00 00 00 21 6f 72 67 2e 77 68 69 73 70 65 72 73
|
||||||
[...]
|
[...]
|
||||||
```
|
```
|
||||||
Es posible acceder a esta información y crear o modificar requisitos con algunas APIs del `Security.framework` como:
|
Es posible acceder a esta información y crear o modificar requisitos con algunas APIs de `Security.framework` como:
|
||||||
|
|
||||||
#### **Verificación de Validez**
|
#### **Comprobación de validez**
|
||||||
|
|
||||||
- **`Sec[Static]CodeCheckValidity`**: Verifica la validez de SecCodeRef por Requisito.
|
- **`Sec[Static]CodeCheckValidity`**: Verifica la validez de un SecCodeRef según el requisito.
|
||||||
- **`SecRequirementEvaluate`**: Valida el requisito en el contexto del certificado.
|
- **`SecRequirementEvaluate`**: Valida un requisito en el contexto de certificados.
|
||||||
- **`SecTaskValidateForRequirement`**: Valida un SecTask en ejecución contra el requisito `CFString`.
|
- **`SecTaskValidateForRequirement`**: Valida un SecTask en ejecución frente al requisito `CFString`.
|
||||||
|
|
||||||
#### **Creación y Gestión de Requisitos de Código**
|
#### **Creación y gestión de requisitos de código**
|
||||||
|
|
||||||
- **`SecRequirementCreateWithData`:** Crea un `SecRequirementRef` a partir de datos binarios que representan el requisito.
|
- **`SecRequirementCreateWithData`:** Crea un `SecRequirementRef` a partir de datos binarios que representan el requisito.
|
||||||
- **`SecRequirementCreateWithString`:** Crea un `SecRequirementRef` a partir de una expresión de cadena del requisito.
|
- **`SecRequirementCreateWithString`:** Crea un `SecRequirementRef` a partir de una expresión en cadena del requisito.
|
||||||
- **`SecRequirementCopy[Data/String]`**: Recupera la representación de datos binarios de un `SecRequirementRef`.
|
- **`SecRequirementCopy[Data/String]`**: Recupera la representación en datos binarios de un `SecRequirementRef`.
|
||||||
- **`SecRequirementCreateGroup`**: Crea un requisito para la membresía de grupo de aplicaciones.
|
- **`SecRequirementCreateGroup`**: Crea un requisito para la pertenencia a app-group.
|
||||||
|
|
||||||
#### **Acceso a Información de Firma de Código**
|
#### **Acceso a la información de firma de código**
|
||||||
|
|
||||||
- **`SecStaticCodeCreateWithPath`**: Inicializa un objeto `SecStaticCodeRef` a partir de una ruta del sistema de archivos para inspeccionar firmas de código.
|
- **`SecStaticCodeCreateWithPath`**: Inicializa un objeto `SecStaticCodeRef` desde una ruta del sistema de ficheros para inspeccionar firmas de código.
|
||||||
- **`SecCodeCopySigningInformation`**: Obtiene información de firma de un `SecCodeRef` o `SecStaticCodeRef`.
|
- **`SecCodeCopySigningInformation`**: Obtiene información de firma desde un `SecCodeRef` o `SecStaticCodeRef`.
|
||||||
|
|
||||||
#### **Modificación de Requisitos de Código**
|
#### **Modificación de requisitos de código**
|
||||||
|
|
||||||
- **`SecCodeSignerCreate`**: Crea un objeto `SecCodeSignerRef` para realizar operaciones de firma de código.
|
- **`SecCodeSignerCreate`**: Crea un objeto `SecCodeSignerRef` para realizar operaciones de firma de código.
|
||||||
- **`SecCodeSignerSetRequirement`**: Establece un nuevo requisito para que el firmante de código lo aplique durante la firma.
|
- **`SecCodeSignerSetRequirement`**: Establece un nuevo requisito que el code signer aplicará durante la firma.
|
||||||
- **`SecCodeSignerAddSignature`**: Agrega una firma al código que se está firmando con el firmante especificado.
|
- **`SecCodeSignerAddSignature`**: Añade una firma al código que se está firmando con el signer especificado.
|
||||||
|
|
||||||
#### **Validación de Código con Requisitos**
|
#### **Validación de código con requisitos**
|
||||||
|
|
||||||
- **`SecStaticCodeCheckValidity`**: Valida un objeto de código estático contra requisitos especificados.
|
- **`SecStaticCodeCheckValidity`**: Valida un objeto de código estático contra los requisitos especificados.
|
||||||
|
|
||||||
#### **APIs Útiles Adicionales**
|
#### **APIs adicionales útiles**
|
||||||
|
|
||||||
- **`SecCodeCopy[Internal/Designated]Requirement`: Obtener SecRequirementRef de SecCodeRef**
|
- **`SecCodeCopy[Internal/Designated]Requirement`: Get SecRequirementRef from SecCodeRef**
|
||||||
- **`SecCodeCopyGuestWithAttributes`**: Crea un `SecCodeRef` que representa un objeto de código basado en atributos específicos, útil para el sandboxing.
|
- **`SecCodeCopyGuestWithAttributes`**: Crea un `SecCodeRef` que representa un objeto de código basado en atributos específicos, útil para sandboxing.
|
||||||
- **`SecCodeCopyPath`**: Recupera la ruta del sistema de archivos asociada con un `SecCodeRef`.
|
- **`SecCodeCopyPath`**: Recupera la ruta del sistema de ficheros asociada a un `SecCodeRef`.
|
||||||
- **`SecCodeCopySigningIdentifier`**: Obtiene el identificador de firma (por ejemplo, Team ID) de un `SecCodeRef`.
|
- **`SecCodeCopySigningIdentifier`**: Obtiene el signing identifier (por ejemplo, Team ID) desde un `SecCodeRef`.
|
||||||
- **`SecCodeGetTypeID`**: Devuelve el identificador de tipo para objetos `SecCodeRef`.
|
- **`SecCodeGetTypeID`**: Devuelve el identificador de tipo para objetos `SecCodeRef`.
|
||||||
- **`SecRequirementGetTypeID`**: Obtiene un CFTypeID de un `SecRequirementRef`.
|
- **`SecRequirementGetTypeID`**: Obtiene un CFTypeID de un `SecRequirementRef`.
|
||||||
|
|
||||||
#### **Banderas y Constantes de Firma de Código**
|
#### **Flags y constantes de Code Signing**
|
||||||
|
|
||||||
- **`kSecCSDefaultFlags`**: Banderas predeterminadas utilizadas en muchas funciones de Security.framework para operaciones de firma de código.
|
- **`kSecCSDefaultFlags`**: Flags por defecto usados en muchas funciones de Security.framework para operaciones de firma de código.
|
||||||
- **`kSecCSSigningInformation`**: Bandera utilizada para especificar que se debe recuperar información de firma.
|
- **`kSecCSSigningInformation`**: Flag usado para especificar que se debe recuperar la información de firma.
|
||||||
|
|
||||||
## Aplicación de la Firma de Código
|
## Code Signature Enforcement
|
||||||
|
|
||||||
El **kernel** es el que **verifica la firma de código** antes de permitir que el código de la aplicación se ejecute. Además, una forma de poder escribir y ejecutar nuevo código en memoria es abusar de JIT si `mprotect` se llama con la bandera `MAP_JIT`. Tenga en cuenta que la aplicación necesita un derecho especial para poder hacer esto.
|
El **kernel** es quien **verifica la firma del código** antes de permitir la ejecución del código de la aplicación. Además, una forma de poder escribir y ejecutar en memoria código nuevo es abusando del JIT si `mprotect` se llama con la bandera `MAP_JIT`. Ten en cuenta que la aplicación necesita un entitlement especial para poder hacer esto.
|
||||||
|
|
||||||
## `cs_blobs` & `cs_blob`
|
## `cs_blobs` & `cs_blob`
|
||||||
|
|
||||||
[**cs_blob**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/sys/ubc_internal.h#L106) la estructura contiene la información sobre el derecho de la proceso en ejecución sobre él. `csb_platform_binary` también informa si la aplicación es un binario de plataforma (que es verificado en diferentes momentos por el OS para aplicar mecanismos de seguridad como proteger los derechos de SEND a los puertos de tarea de estos procesos).
|
[**cs_blob**](https://github.com/apple-oss-distributions/xnu/blob/94d3b452840153a99b38a3a9659680b2a006908e/bsd/sys/ubc_internal.h#L106) struct contiene la información sobre el entitlement del proceso en ejecución en él. `csb_platform_binary` también indica si la aplicación es un platform binary (lo cual se comprueba en distintos momentos por el OS para aplicar mecanismos de seguridad, por ejemplo para proteger los SEND rights hacia los task ports de estos procesos).
|
||||||
```c
|
```c
|
||||||
struct cs_blob {
|
struct cs_blob {
|
||||||
struct cs_blob *csb_next;
|
struct cs_blob *csb_next;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user