Introduzione
Questa seconda parte è un approfondimento dell'analisi di Burner, la cache. Se non l'hai ancora fatto ti consiglio di leggere la prima parte iOS Burner sull'analisi del database "Phoenix.sqlite".
App Store: https://apps.apple.com/us/app/burner-private-phone-line/id505800761
Percorsi
Di seguito lo stralcio di Burner del poster della SANS “iOS Third-Party Apps Forensics Reference Guide Poster” con le informazioni più rilevanti per l’analisi dell’app.
Analisi degli artefatti
Per lo studio di questa app ho utilizzato una delle immagini pubbliche di iOS note nel settore e in particolare quella di Josh Hickman iOS 15.3.1 disponibile su DigitalCorpora. La versione di Burner è 5.3.8.
Questo database SQLite tiene traccia dei dati che l'app ha ricevuto da fonti esterne come un server o internet, una cache per velocizzare il caricamento se necessario. Tre sono le tabelle principali di interesse:
- cfurl_cache_response: contiene i dati e l'ora della richiesta;
- cfurl_cache_blob_data: contiene i dati BLOB (Binary Large Object) con la risposta del server;
- cfurl_cache_receiver_data: contiene i dati ricevuti dal server in risposta alla richiesta al server tramite la tabella cfurl_cache_response.
Mettere in relazione queste tabelle è importante in quanto può fornire informazioni che non sono memorizzate altrove; ad esempio i messaggi vocali riprodotti. Se la dimensione dei dati è di 4096 byte o superiore verranno memorizzati su file (cfurl_cache_response.isDataOnFs=1) con il nome dell'UUID assegnato al campo cfurl_cache_receiver_data.receiver_data, altrimenti verranno memorizzati nel database (cfurl_cache_response.isDataOnFs=0) come BLOB.
Per prima cosa bisogna ricostruire le relazioni delle tabelle di questo database SQLite.
SELECTcr.request_key AS "URL",datetime(strftime("%s", cr.time_stamp), 'unixepoch') AS "timestamp",crd.isDataOnFS,crd.receiver_data AS "data"FROM cfurl_cache_response AS "cr"LEFT JOIN cfurl_cache_receiver_data AS "crd" ON (cr.entry_ID = crd.entry_ID)
Non entro nel dettaglio delle tabelle, quello che maggiormente interessa sono i campi:
- cfurl_cache_response.request_key (URL): è la stringa di richiesta al server;
- cfurl_cache_receiver_data.isDataOnFS (isDataOnFS): indica che i dati sono 1=esterni su file, 0=incorporati nel campo data;
- cfurl_cache_receiver_data.receiver_data (data): contiene i dati ricevuti o il nome del file presente nella sottocartella "fsCachedData".
Allegati
Da un'ispezione visiva degli URL è possibile identificare due domini di interesse; quello per l'archiviazione delle risorse esterne "s3.amazonaws.com" (Amazon S3) e l'altro per l'interazione dell'app con il server "phoenix.burnerapp.com" (Burner).
Per quanto riguarda Amazon S3, il primo tratto del percorso dell'URL identifica il tipo di risorsa; /burner-mms/ per le immagini e /burner-voicemail/ per i messaggi vocali.
SELECTcr.request_key AS "URL",datetime(strftime("%s", cr.time_stamp), 'unixepoch') AS "timestamp",crd.isDataOnFS,crd.receiver_data AS "data"FROM cfurl_cache_response AS "cr"LEFT JOIN cfurl_cache_receiver_data AS "crd" ON (cr.entry_ID = crd.entry_ID)WHERE cr.request_key like "https://s3.amazonaws.com/burner-%"
Questa query permette di creare una mappatura tra il campo receiver_data (nome del file presente nella sottocartella "fsCachedData" o BLOB) e l'URL della risorsa che servirà in seguito per associare l'allegato al messaggio ad esempio.
Messaggi
Questo è il contenuto del file "fsCachedData/34A0C948-4FFD-4FA3-B5DC-5DB8ADBD8B0D" in dfDataViewer (il mio visualizzatore di (B)Plist, JSON, (B)XML, ASN.1, etc. ancora in fase di sviluppo):
Identificare gli allegati presenti nel JSON è semplice: nell'object 6 (messaggio), con l' assetUrl="https://s3.amazonaws.com/burner-mms/prod/9ebdd109-01bf-46b9-af6a-b59f671b8c85.jpg" si cerca la corrispondenza dell'URL nella query dei media sopra. A questo URL corrisponde il file (isDataOnFS=1) "54F501A4-8AB8-4BCE-8681-163E7559ADA5".
Ora bisogna analizzare la struttura del JSON dei messaggi. In genere come ho detto sopra i messaggi sono presenti o in file esterni o come dati incorporati nel campo receiver_data. In entrambi i casi la root del JSON può essere o un array (1 o più messaggi) o un object (1 messaggio).
L'immagine della struttura del JSON sopra riportata è riferita al file "fsCachedData/34A0C948-4FFD-4FA3-B5DC-5DB8ADBD8B0D" e come si può osservare per l'object 6 le proprietà/valori di interesse per la ricostruzione del messaggio sono più o meno le stesse di quelle del database "Phoenix.sqlite" salvo qualche eccezione; per esempio i timestamp sono nel formato Unix Epoch (millisecondi).
Prima di procedere alla ricostruzione del messaggio è necessario identificare in "Cache.db" quali sono i record che contengono i messaggi. Da una ispezione visiva dei valori in data e dall'analisi di tutti i file esterni, il tutto riconduce agli URL con percorso iniziale "https://phoenix.burnerapp.com" e che contengono "/user/<USER UUID>/messages" (POST) o "/user/<USER UUID>/messages?" (GET).
SELECT
crd.isDataOnFS AS "isDataOnFS",
crd.receiver_data
FROM cfurl_cache_response AS "cr"
LEFT JOIN cfurl_cache_receiver_data AS "crd" ON (cr.entry_ID = crd.entry_ID)
WHERE cr.request_key REGEXP "https:\/\/phoenix\.burnerapp\.com(\/v\d)?\/user\/[a-fA-F\d-]{36}\/messages($|\?.*contactPhoneNumber=.+)"
E' arrivato il momento di ricostruire il messaggio 6:
- dateCreated: 1683568403040 (08 maggio 2023 17:53:23+00:00);
- direction: 2 (uscita);
- read: true (letto);
- contactPhoneNumber: +19198887xxx (destinatario);
- message: ;
- messageType: 2 (Testo/Immagine);
- assetUrl: https://s3.amazonaws.com/burner-mms/prod/9ebdd109-01bf-46b9-af6a-b59f671b8c85.jpg;
- voiceUrl: null;
- burnerId: 3419959a-a3aa-4cd0-b5e1-eed24fa52xxx;
- id: a0732e75-a4de-45b9-a320-b18af9002xxx.
Numeri Burner
SELECT
crd.isDataOnFS AS "isDataOnFS",
crd.receiver_data
FROM cfurl_cache_response AS "cr"
LEFT JOIN cfurl_cache_receiver_data AS "crd" ON (cr.entry_ID = crd.entry_ID)
WHERE cr.request_key REGEXP "https:\/\/phoenix\.burnerapp\.com(\/v\d)?\/user\/[a-fA-F\d-]{36}\/burners(\/[a-fA-F\d-]{36})?$"
Un solo numero burner:
- settings.name: My New Burner;
- phoneNumber: +18285205xxx;
- dateCreated: 1683566577088 (08 maggio 2023 17:22:57+00:00);
- expirationDate: 1686158577088 (07 giugno 2023 17:22:57+00:00);
- settings.notificationsEnabled: true (On);
- settings.voipEnabled: false (Standard Voice);
- settings.autoReplyMessage.active: false (Off);
- settings.autoReplyMessage.text: I'm away from my phone. I'll get back to you ASAP.;
- entitlements.remainingMinutes: 48;
- entitlements.totalMinutes: 50;
- entitlements.remainingTexts : 87;
- entitlements.totalTexts : 100;
- id: 3419959a-a3aa-4cd0-b5e1-eed24fa52xxx;
Contatti
SELECTcrd.isDataOnFS AS "isDataOnFS",crd.receiver_dataFROM cfurl_cache_response AS "cr"LEFT JOIN cfurl_cache_receiver_data AS "crd" ON (cr.entry_ID = crd.entry_ID)WHERE cr.request_key REGEXP "https:\/\/phoenix\.burnerapp\.com(\/v\d)?\/user\/[a-fA-F\d-]{36}\/contacts\?.+"
Due contatti. Object 0 (primo contatto):
- dateCreated: 1613670031089 (18 febbraio 2021 17:40:31+00:00);
- name: This Is DFIR Two;
- phoneNumber: +19198887xxx;
- notes: (0 items);
- verified: false (No);
- blocked: false (No);
- muted: false (No);
- images: (0 items)
- id: 1955458a-57c4-4b4e-9105-205f58f9fxxx.
Account
SELECT
crd.isDataOnFS AS "isDataOnFS",
crd.receiver_data
FROM cfurl_cache_response AS "cr"
LEFT JOIN cfurl_cache_receiver_data AS "crd" ON (cr.entry_ID = crd.entry_ID)
WHERE cr.request_key REGEXP "https:\/\/phoenix\.burnerapp\.com(\/v\d)?(\/register(\/phone)?$|\/user\/[a-fA-F\d-]{36}\/token)"
- dateCreated: 1586047847213 (05 aprile 2020 00:50:47+00:00);
- phoneNumber: +19195794xxx;
- carrierName: T-Mobile USA, Inc.;
- countryCode: US;
- appVersion: 5.3.8;
- token: eyJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJodHRwczovL2lkZW50a...
- id: 21d2ca9c-aba1-4ada-b7f5-23b0d97acxxx.
0 comments:
Posta un commento