sabato 26 ottobre 2024

Published ottobre 26, 2024 by Django Faiola with 1 comment

Happy 3rd Birthday to dfAPKdngrader

Il 27 ottobre 2021 ho iniziato il progetto di dfAPKdngrader con lo scopo di fornire alla comunità forense uno strumento di semplice utilizzo e robusto allo stesso tempo, in grado di eseguire il metodo del downgrade delle app su dispositivi Android.

E' la prima volta che lo senti nominare? Leggi il post di riferimento del programma dfAPKdngrader (Forensic extraction tool for Android Backup APK Downgrade method).

Da allora sono trascorsi 3 anni e ad oggi posso dire che il progetto ha riscosso un discreto successo sia in Italia che all'estero.

Per festeggiare questo anniversario ho deciso di rilasciare la versione v0.4.0:

  • Added: Riconoscimento automatico della lingua locale e caricamento del file .po/.mo con la lingua associata se esiste.
  • Added: Forzatura della lingua passando il parametro --lang <code> all'avvio del programma; <code>=es per caricare il file con la lingua spagnola o <code>=de per quella tedesca etc. se presenti.
  • Added: Schermata di riepilogo dei pacchetti sincronizzati online: nuovi, cambiati ed eliminati.
  • Added: Schermata dispositivo: il messaggio di attenzione "Abilita resta attivo", se cliccato, svolge in automatico l'operazione.
  • Changed: La struttura del file APKs.ini per il supporto della schermata di riepilogo (trasparente all'utente); "isCustom": true è obsoleto, sostituito con "state": "custom".
  • Added: Migliorata l'interfaccia grafica per l'elenco dei pacchetti disponibili: aggiunto menu contestuale.
  • Added: Opzione "Forza il caricamento di tutte le app (fallite o eseguite con successo" per il metodo di RIPRISTINO.
  • Fixed: bug minori.

Oltre 400 sono ora le app disponibili per il downgrade, quasi 100 in più della precedente lista. Un pacchetto enorme e comunque piccolo se si considerano le app localizzate più popolari dei vari paesi.

Ribadisco, l'APK downgrade non è un metodo sostitutivo per l'estrazione dei dati ma un'alternativa, come dire di "ultima spiaggia", quando tutti gli altri non sono praticabili.

Schermata di riepilogo:

Riepilogo del package (doppio click) sulla riga:

Inoltre è possibile aprire il browser alla pagina dell'app all'interno del Play Store  (link WhatsApp Messenger nel caso in figura).

Colgo l'occasione per sottolineare che ho fornito con l'eseguibile anche i file PO (Portable Object) per chi fosse interessato a dare il suo contributo per il supporto multilingua. Inoltre se avete package personalizzati non inclusi nella mia lista, sentitevi liberi di condividerli 😂 .

👏 Grazie a tutti per aver apprezzato il mio lavoro. Un ringraziamento speciale va fatto a Andrea Lazzarotto per avermi spinto a creare questo blog e per aver contribuito con i suoi preziosi suggerimenti a migliorare il prodotto. 

Ultima versione

Windows | Linux

Il software è proprietario (Freeware - closed source) e per l'uso commerciale considera una piccola donazione valida come autorizzazione implicita al suo utilizzo.

 

Elenco delle nuove app supportate

  1. Airalo
  2. AlfredCamera
  3. Allegro
  4. AM - Ashley Madison
  5. Auto.ru
  6. Bonjour RATP (RATP)
  7. CallApp (CallApp Contacts)
  8. Cartão Continente
  9. Cashify
  10. com.l
  11. DAILYHOTEL (데일리호텔)
  12. Daraz
  13. Disco
  14. Dolap
  15. DoorDash
  16. droom
  17. EatSure (Faasos)
  18. eHarmony
  19. Eyecon
  20. Familo (Familonet)
  21. Favor
  22. Feeld
  23. Finally
  24. Fiverr
  25. foodora (OnlinePizza)
  26. Foody
  27. FREENOW for drivers (mytaxi)
  28. GMX Mail (Mail)
  29. Grab Driver
  30. GrubHub
  31. Hacoo (Hacoo SaraMart, Doop, SaraMart)
  32. Hungama
  33. iFood comida e mercado em casa
  34. immowelt
  35. ixigo
  36. Jaumo
  37. JD Sports
  38. Justdial
  39. Kaufland
  40. Klook
  41. Lalamove
  42. Lazada
  43. Lovely
  44. Mail.ru
  45. Match (match.com)
  46. Mercado Libre
  47. Mingle2
  48. Myntra
  49. Neenbo
  50. Nextcloud
  51. noon
  52. OpenSooq (السوق المفتوح)
  53. Ourtime Date, Meet 50+ Singles
  54. ownCloud
  55. OZON (OZON.ru)
  56. pCloud
  57. PedidosYa
  58. Pegasus
  59. PlantNet Plant Identification (Pl@ntNet)
  60. Polarsteps
  61. priceline
  62. PURE
  63. Ruhavik
  64. Save Location GPS
  65. Shop Samsung
  66. Snapdeal
  67. Spicy
  68. Star Taxi
  69. talabat
  70. Tappsi Easy (Tappsi)
  71. TAXI 18300
  72. TAXI Deutschland
  73. taxi.eu
  74. TaxiMe Driver
  75. Tchibo
  76. Tellonym
  77. TicketSwap
  78. Tokopedia
  79. Traveloka
  80. Trendyol
  81. TripCase
  82. Turo
  83. Vivino
  84. Waiter
  85. Wapa
  86. Weather Underground
  87. WEB.DE Mail (Mail)
  88. Whoosh
  89. Wikiloc
  90. wine-searcher
  91. Xe (Currency)
  92. Yandex Disk
  93. Yandex Weather
  94. Yanolja (야놀자)
  95. Yassir
  96. Zipcar
Read More

giovedì 26 settembre 2024

Published settembre 26, 2024 by Django Faiola with 0 comment

iOS Burner - Update

Introduzione

Lo scopo di questo post è quello di mettere in risalto le differenze tra le vecchie versioni e le attuali, nonché aggiornare le query precedenti. Diversi passaggi sono dati per scontato, quindi prima di iniziare la lettura di questo approfondimento, consiglio di dare un'occhiata se non l'hai già fatto ai precedenti articoli: iOS BurneriOS Burner - Cache.db.

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 ForensicsReference Guide Poster” con le informazioni più rilevanti per l’analisi dell’app.

Analisi degli artefatti

Per lo studio di questa app ho utilizzato tutte le immagini pubbliche di Josh Hickman disponibili su DigitalCorpora: la versione iOS 13.3.1, 13.4.1, 14.3, 15.3.1, 16.1.2 e 17.3 con le relative versioni di Burner 4.0.18, 4.0.18, 4.3.3, 5.3.8, 5.4.11 e 5.4.11.

Purtroppo alla data odierna l'ultima versione di Burner è la 5.13.1 dell'11 settembre 2024 mentre la 5.4.11 è del 9 gennaio 2024; oltre una quindicina di versioni sono state rilasciate per risolvere bug e per migliorare le prestazioni, ma alcune hanno introdotto anche delle novità come la possibilità di condividere video ad alta qualità. Quindi non ho modo di verificare la correttezza del procedimento di analisi di seguito esposto per queste versioni e/o vedere cosa è cambiato. 

Phoenix.sqlite

Per quanto riguarda l'analisi del database SQLite le vecchie query diciamo che hanno qualche problema. Infatti dalle prime versioni in esame fino alla recente 5.4.11 le tabelle hanno subito una ristrutturazione durante questa evoluzione e non solo: sono rimasti campi inutilizzati (vuoti), successivamente rimossi, inseriti nuovi identificatori e per completare l'opera alcune relazioni tra le tabelle sono cambiate.

Accounts

Fino alla versione di Burner 4.3.3 inclusa, la tabella ZBURNER è in relazione con la tabella ZUSER (account) per mezzo della chiave esterna ZBURNER.ZUSER-> ZUSER.Z_PK. Nella versione 5.3.8 il campo ZBURNER.ZUSER è vuoto e nella 5.4.11 è stato rimosso. In iLEAPP la query è dinamica ed è basata sulla presenza o meno del campo ZUSER.

La versione aggiornata "diciamo adattata":

SELECT
    U.Z_PK AS "U_PK",
    datetime(U.ZDATECREATED + 978307200, 'unixepoch') AS "dateCreated",
    U.ZPHONENUMBER AS "mobilePhone",
    U.ZCOUNTRYCODE AS "countryCode",
    ("0" || "/" || U.ZTOTALNUMBERBURNERS) AS "nBurners",
    CASE U.ZDNDENABLED WHEN 1 THEN "On" ELSE "Off" END AS "dndEnabled",
    U.ZVOICEMAILURL AS "voicemailUrl",
    U.ZUSERID AS "userId"
FROM ZUSER AS "U"

Contatti

Non ci sono modifiche, la query è la stessa.

Numeri Burner

Stesso discorso dell'Account, non avendo più il riferimento tra le tabelle ZBURNER e ZUSER la query è adattata sempre sulla base della presenza del campo ZBURNER.ZUSER.

La versione aggiornata:

SELECT
    B.Z_PK AS "B_PK",
    substr(B.ZIMAGE, 2, length(B.ZIMAGE) - 2) AS "image",
    B.ZPHONENUMBER AS "burnerNumber",
    B.ZNAME AS "displayName",
    datetime(B.ZDATECREATED + 978307200, 'unixepoch') AS "dateCreated",
    datetime(B.ZEXPIRATIONDATE + 978307200, 'unixepoch') AS "expirationDate",
    CASE B.ZNOTIFICATIONS WHEN 1 THEN "On" ELSE "Off" END AS "notifications",
    CASE B.ZCALLERIDENABLED WHEN 0 THEN "Burner Number" ELSE "Caller Number" END AS "inboundCallerId",
    CASE B.ZUSESIP WHEN 0 THEN "Standard Voice" ELSE "VoIP" END AS "VoIPinAppCalling",
    CASE B.ZAUTOREPLYACTIVE WHEN 0 THEN "No" ELSE "Yes" END AS "autoReplyActive",
    B.ZAUTOREPLYTEXT AS "autoReplyText",
    coalesce(B.ZREMAININGMINUTES, "0") || "/" || coalesce(B.ZTOTALMINUTES, "0") AS "minutes",
    coalesce(B.ZREMAININGTEXTS, "0") || "/" || coalesce(B.ZTOTALTEXTS, "0") AS "texts",
  B.ZBURNERID AS "burnerId"
FROM ZBURNER AS "B"

Messaggi

Per i messaggi la questione si fa un po' più spinosa: diverse sono le colonne (campi) che entrano in gioco. Le relazioni principali sono sempre la ZMESSAGE.ZMESSAGETHREAD->ZMESSAGETHREAD.Z_PK e la ZMESSAGETHREAD.ZCONTACT->ZCONTACT.Z_PK.

Il problema sorge quando i valori ZMESSAGE.ZMESSAGETHREAD e/o ZMESSAGETHREAD.ZCONTACT sono nulli: viene a mancare il collegamento tra il messaggio e il thread e di conseguenza quello tra il thread e il contatto. Come risultato si ha solo il numero di telefono del contatto e non il nome completo.

Come mettere di nuovo in relazione queste tabelle per ottenere i nomi dei contatti?

Nella versione 5.4.11 è presente un nuovo campo sia in ZMESSAGETHREAD.ZCONVERSATIONID che in ZMESSAGE.ZCONVERSATIONID, l'identificatore della conversazione (in pratica il numero di telefono con il prefisso internazionale), utile per creare il nuovo legame. Ma il numero di telefono del contatto, ovvero il contatto, può essere associato a diversi burner quindi bisogna impostare un'ulteriore restrizione su questo nuovo legame tenendo conto dell'identificatore del burner.

Con l'aggiunta della seguente espressione è possibile ristabilire il legame tra il thread e il messaggio.

 OR (M.ZMESSAGETHREAD IS NULL AND M.ZBURNERID = MT.ZBURNERID AND M.ZCONVERSATIONID = MT.ZCONVERSATIONID)

Nella versione 5.3.8, ZCONVERSATIONID non esiste, quindi il legame si ottiene con ZCONTACTID o ZCONTACTPHONENUMBER.

 OR (M.ZMESSAGETHREAD IS NULL AND M.ZBURNERID = MT.ZBURNERID AND coalesce(M.ZCONTACTID, M.ZCONTACTPHONENUMBER) = MT.ZCONTACTPHONENUMBER)

Per le versioni precedenti alla 4.3.3 inclusa i campi non sono nulli quindi non viene aggiunta nessuna espressione.

Ora bisogna ripristinare il legame dei contatti tra le tabelle ZMESSAGETHREAD e ZCONTACT. Se è presente il campo ZMESSAGE->ZCONTACTID (per la versioni 5.3.8 e 5.4.11) e tenuto conto che nella versione 5.3.8 i valori di ZCONTACTID sono nulli mentre nella 5.4.11 invece sono i valori di ZCONTACTPHONENUMBER ad essere nulli, allora l'espressione finale è:

 OR (MT.ZCONTACT IS NULL AND coalesce(M.ZCONTACTID, M.ZCONTACTPHONENUMBER) = C.ZPHONENUMBER)

altrimenti non si aggiunge nulla.

La versione aggiornata:

SELECT
    MT.Z_PK AS "MT_PK",
    C.Z_PK AS "C_PK",
    M.Z_PK AS "M_PK",
    B.Z_PK AS "B_PK",
    IIF(C.ZNAME IS NOT NULL, C.ZPHONENUMBER || " (" || C.ZNAME || ")", C.ZPHONENUMBER) AS "thread",
    datetime(M.ZDATECREATED + 978307200, 'unixepoch') AS "dateCreated",
    IIF(M.ZDIRECTION = 1, "Incoming", "Outgoing") AS "direction",
    IIF(M.ZREAD = 1, "Read", "Not read") AS "read",
    IIF (M.ZDIRECTION = 1, 
    IIF(C.ZNAME IS NOT NULL, C.ZPHONENUMBER || " (" || C.ZNAME || ")", C.ZPHONENUMBER),
IIF(B.ZNAME IS NOT NULL, B.ZPHONENUMBER || " (" || B.ZNAME || ")", B.ZPHONENUMBER)
  ) AS "sender",
  IIF (M.ZDIRECTION = 2, 
IIF(C.ZNAME IS NOT NULL, C.ZPHONENUMBER || " (" || C.ZNAME || ")", C.ZPHONENUMBER),
    IIF(B.ZNAME IS NOT NULL, B.ZPHONENUMBER || " (" || B.ZNAME || ")", B.ZPHONENUMBER) 
  ) AS "recipient",
    CASE 
        WHEN (M.ZDIRECTION = 1) AND (M.ZSTATE = 3) THEN "Completed incoming call"
        WHEN (M.ZDIRECTION = 2) AND (M.ZSTATE = 3) THEN "Completed outgoing call"
        WHEN (M.ZDIRECTION = 1) AND (M.ZSTATE = 4) THEN "Missed incoming call"
        WHEN (M.ZDIRECTION = 2) AND (M.ZSTATE = 4) THEN "Missed outgoing call"
        WHEN (M.ZDIRECTION = 1) AND (M.ZSTATE = 5) THEN "Missed incoming call with voicemail"
        WHEN (M.ZDIRECTION = 2) AND (M.ZSTATE = 5) THEN "Missed outgoing call with voicemail"
        ELSE M.ZBODY
    END AS "message",
    CASE 
        WHEN (M.ZTYPE = 1) AND (M.ZSTATE in (3, 4)) THEN "Call"
        WHEN (M.ZTYPE = 1) AND (M.ZSTATE = 5) THEN "Voicemail"
        WHEN (M.ZTYPE = 2) AND (M.ZASSETURL IS NULL) THEN "Text"
        WHEN (M.ZTYPE = 2) THEN "Picture"
        ELSE M.ZTYPE
    END AS "mType",
    M.ZLOCALASSETURL AS "localAsset",
    M.ZLOCALTHUMBNAILURL AS "localThumbnail",
    M.ZASSETURL AS "mediaUrl",
    M.ZVOICEMAILURL AS "voiceUrl",
    M.ZMESSAGEID AS "messageId",
    M.ZBURNERID AS "burnerId",
    MT.ZMESSAGETHREADID AS "threadId"
FROM ZMESSAGE AS "M"
LEFT JOIN ZBURNER AS "B" ON (M.ZBURNERID = B.ZBURNERID)
LEFT JOIN ZMESSAGETHREAD AS "MT" ON (M.ZMESSAGETHREAD = MT.Z_PK)  OR (M.ZMESSAGETHREAD IS NULL AND M.ZBURNERID = MT.ZBURNERID AND coalesce(M.ZCONTACTID, M.ZCONTACTPHONENUMBER) = MT.ZCONTACTPHONENUMBER)
LEFT JOIN ZCONTACT AS "C" ON (MT.ZCONTACT = C.Z_PK) OR (MT.ZCONTACT IS NULL AND coalesce(M.ZCONTACTID, M.ZCONTACTPHONENUMBER) = C.ZPHONENUMBER)

Cache.db

Con il rilascio delle nuove immagini per iOS 16 e 17 da parte di Josh Hickman ho eseguito iLEAPP per verificare se i miei plugin svolgono il loro compito. Purtroppo non è stato così. La vecchia query basata solo sulle interrogazioni relative ai messaggi non produce alcun risultato significativo, quindi ho deciso di affrontare la questione.

Le analisi che seguono fanno riferimento all'iOS 17.3 e versione di Burner 5.4.11. Ispezionando la cache ho visto che sono presenti diversi file JSON, qualche immagine e anche la voicemail; quindi ho analizzato i singoli JSON e ho trovato particolarmente interessante alcuni file relativi alle conversazioni e non ai singoli messaggi. Ripercorrendo il percorso all'indietro sono risalito nel database a due tipi di richiesta:

https://phoenix.burnerapp.com/v2/user/<user_id>/burners/<burner_id>/conversations/<phone_number>/messages?pageSize=50&page=1 

https://phoenix.burnerapp.com/v2/user/<user_id>/burners/<burner_id>/conversations/<phone_number>/messages/conversations/<phone_number>/messages

La nuova query: 

SELECT
    cr.request_key AS "URL",
    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 REGEXP "https:\/\/phoenix\.burnerapp\.com(\/v\d)?\/user\/[a-fA-F\d-]{36}(\/messages($|\?.*contactPhoneNumber=.+)|(\/burners\/[a-fA-F\d-]{36}\/conversations\/.+\/messages($|\?.*pageSize=.+)))"

Il file JSON (isDataOnFS=121B2F296-61C6-48FB-AA53-55D632FE4757 nell'Internal App Path "/Library/Caches/com.adhoclabs.burner/fsCachedData/" per esempio contiene le conversazioni.

Per la visualizzazione ho usato dfDataViewer, il mio visualizzatore di (B)Plist, JSON(B), (B)XML, ASN.1, Protobuf, LevelDB, etc. ancora in fase di sviluppo e non pubblico.

21B2F296-61C6-48FB-AA53-55D632FE4757

La struttura tipica di una chiamata vocale: (per esempio l'oggetto [1])

  • [1].dateCreated1720381116752 (data di creazione nel formato Unix Epoch in millisecondi, 07 luglio 2024 19:38:36);
  • [1].directionOutbound (direzione della conversazione, Outbound=uscita o Inbound=entrata);
  • [1].readtrue (flag che indica se il messaggio è stato letto, true=letto, false=non letto);
  • [1].conversation
    • conversationId+19192059xxx (numero di telefono della conversazione);
  • [1].textnull (testo del messaggio);
  • [1].messageTypeVoice (tipo di messaggio, Text=testo/immagine o Voice=chiamata/voicemail);
  • [1].stateCallCompleted (stato della conversazione, CallCompleted=fine chiamata, Voicemail=segreteria telefonica, Delivered=consegnato, CallMissed=chiamata persa);
  • [1].callDetails
    • durationMinutes: 3 (durata della chiamata in minuti);
  • [1].burnerId4f6141ae-48dc-408a-8c95-18f830aaaxxx (identificatore del burner);
  • [1].userId21d2ca9c-aba1-4ada-b7f5-23b0d97acxxx (identificatore univoco dell'utente);
  • [1].id: 32361dba-1733-4606-8df3-c8b4289a2xxx (identificatore univoco della conversazione).

La struttura tipica di un messaggio vocale: (per esempio l'oggetto [4])

    • [4]. ...
    • [4].messageTypeVoice (chiamata vocale);
    • [4].stateVoicemail (segreteria telefonica);
    • [4].voicemail
      • audioUrl: https://s3.amazonaws.com/burner-voicemail/prod/b245df6b-a316-417f-9ad8-64bf5c7fbdcd.wav (URL della registrazione audio);
      • durationSeconds: 3 (durata dell'audio in secondi).
    La struttura tipica di una immagine: (per esempio l'oggetto [7])
    • [7]. ...
    • [7].messageTypeText (testo o immagine con testo);
    • [7].stateDelivered (consegnato);
    • [7].mediaUrl: https://s3.amazonaws.com/burner-mms/prod/5196a5b3-f089-49c9-a25d-5e654d43583d.jpg (URL dell'immagine).

    Ho rimesso insieme tutti questi "pezzi" e il risultato è "stupendo", da zero a 34 messaggi.

    iLEAPP 💖

    Come di consueto, a supporto del progetto iLEAPP (iOS Logs, Events, And Plists Parser) di Alexis Brignoni ho aggiornato i plugin burner.py e burnerCache.py che alla data odierna sono in “pull request” e comunque disponibili sul mio GitHub.

    Di seguito due "screenshot" del report di Burner Cache Messages: iOS 15.3.1 e iOS 17.3

    Read More

    giovedì 8 agosto 2024

    Published agosto 08, 2024 by Django Faiola with 0 comment

    Identity Lookup Service

    Indice dei contenuti

    Introduzione

    Nel 2019 la Cellebrite pubblica l'articolo How iOS Properties Files Can Confirm a Suspect’s Contacts Even If Deleted dove in sintesi spiega l'importanza di trovare un archivio affidabile delle comunicazioni tra le parti che sia permanente e legittimo da consultare durante le indagini e in tribunale.

    L'identificazione dell'elenco dei contatti sul telefono cellulare di un sospettato è sempre stata una sfida, poiché la deliberata cancellazione delle informazioni da parte del sospetto porta alla necessità di trovare un modo corretto dal punto di vista forense per recuperale. 

    La ricercatrice della Cellebrite Izhar Carmel ha scoperto che il file com.apple.identityservices.idstatuscache.plist presente nel percorso "/private/var/mobile/Library/Preferences/" è la cache che contiene i record delle autenticazioni degli ID Apple.

    Un utente Apple che utilizza iMessage o FaceTime, quando tenta di contattare un destinatario, viene interrogato l'Enterprise Shared Services, il server delle autenticazioni di Apple per la verifica dell'identità. A fine convalida, se è la prima volta che si cerca il destinatario, viene creato un nuovo record (dizionario) con l'ID del primo tentativo di contatto come numero di telefono (es. tel:+14693560xxx) o come indirizzo email (es. mailto:joshuahickmanxxx@gmail.com) e la data dell'evento stesso nel dizionario associato al servizio utilizzato (es. com.apple.madrid).

    Non è necessario che l'operazione per esempio dell'invio del messaggio venga portata a termine; il nuovo record viene comunque registrato nella cache. Questi record non vengono sovrascritti dalle successive ricerche o selezione dello stesso destinatario e per la stessa applicazione.  

    Successivamente nel 2020 pubblica How to Use the Identity Lookup Service in Cellebrite Physical Analyzeruna demo video con l'analisi dell'artefatto. 

    Identity Lookup Service (Servizio di Ricerca dell'Identità) è il servizio di Apple che gestisce l'autenticazione dei processi. Questi dati confermano solo che è avvenuta l'autenticazione del destinatario e non danno nessuna informazione utile per quanto riguarda l'avvenuto invio di un messaggio o l'avvio di una conversazione. E' solo un indizio che indica che qualcosa è successo, ma per dimostrare che qualcosa è realmente avvenuto, bisogna tracciarlo altrove.

    Per lo studio di questo artefatto è stata utilizzata una delle immagini pubbliche di iOS note nel settore e in particolare quella di Josh Hickman iOS 14.3 disponibile su MediaFire e i dati estratti dal mio iPhone 8 con iOS 16.7.8.

    La struttura del record di autenticazione

    Per la visualizzazione ho usato dfDataViewer, il mio visualizzatore di (B)Plist, JSON(B), (B)XML, ASN.1, Protobuf, LevelDB, etc. ancora in fase di sviluppo e non pubblico.

    com.apple.identityservices.idstatuscache.plist

    Il servizio com.apple.ess: (FaceTime)

    • tel:+19192895xxx: (numero di telefono)
      • IDStatus2 (1=iDevice, 2=Not iDevice);
      • LookupDate635363625.519218 (timestamp della verifica dell'identità come real nel formato MAC Absolute Time 18 febbraio 2021 17:53:45);
    • ...

    Il servizio com.apple.madrid: (iMessage)

    • tel:+14693560xxx: (numero di telefono)
      • IDStatus: 2 (Not iDevice);
      • LookupDate: 635433067.361745 (19 febbraio 2021 13:11:07);
    • ...

    com.apple.ess e com.apple.madrid sono gli identificatori dei servizi. E' noto a tutti che com.apple.madrid è l'identificatore del servizio iMessage e che com.apple.private.alloy.facetime.video è quello di FaceTime Video; ma come è possibile associare questi servizi a un nome da visualizzare? La risposta è nella directory "/System/Library/IdentityServices/ServiceDefinitions/" che contiene un serie di file Plist con le definizioni dei servizi.

    com.apple.iMessage.plist

    Queste sono le chiavi rappresentative per una corretta mappatura degli identificatori (Identifier e LegacyIdentifier) con il nome da visualizzare (DisplayName) oppure con il nome del servizio (ServiceName):

    • DisplayNameiMessage (nome visualizzato "applicazione");
    • Identifiercom.apple.madrid (identificatore univoco);
    • LegacyIdentifiercom.apple.iMessage (identificatore univoco nelle vecchie versioni);
    • ServiceNameMessenger (nome del servizio).
    Quindi da questo file si ottengono due associazioni (id = valore):
    1. com.apple.madrid = iMessage
    2. com.apple.iMessage = iMessage
    Altri esempi di associazioni:
    • com.apple.private.ac = Calling
    • com.apple.ess = FaceTime
    • com.apple.private.alloy.sms = SMSRelay
    • com.apple.private.alloy.maps = Maps
    • com.apple.private.alloy.nearbyNearby

    idstatuscache.plist

    A partire dalla versione iOS 14.7.0 il file com.apple.identityservices.idstatuscache.plist è vuoto o assente. La mia attenzione è stata catturata durante l'utilizzo di FaceTime, quando digitando per la prima volta i destinatari, sono stati autenticati in Blu per i dispositivi Apple e in Verde per gli altri, con un tempo superiore rispetto alla successiva ricerca degli stessi. L'effetto è visibile quando per esempio si digita un solo carattere comune a tanti contatti es. "a" e i colori cambiano di pari passo con il processo di autenticazione. Quindi mi son detto: dov'è questa cache con i record delle autenticazioni?

    Rimboccandomi le maniche ed eseguendo qualche ricerca sul contenuto dei file è saltato fuori un file dal nome interessante idstatuscache.plist nel percorso  "/private/var/mobile/Library/IdentityServices/". Una verifica del Plist ha confermato che ha la stessa struttura del file com.apple.identityservices.idstatuscache.plist ed è presente solo nelle nuove versioni iOS. Bene! sembra di essere tornati alla vecchia situazione, ma è realmente così?

    Per rispondere a questa domanda ho eseguito un po' di test su FaceTime e al fine di discriminare gli eventi in modo grossolano, ogni test è stato svolto a step di 1 minuto di distanza con riferimento all'ora sullo schermo del dispositivo.

    Tutti i test consistono nella ricerca del destinatario, nella selezione/conferma un minuto dopo ed eventualmente un altro minuto nell'avvio della videochiamata.

    Per facilitare l'estrazione e una prima analisi del file Plist ho utilizzato ArtEx di Ian Whiffin in modalità Live Connection: l'analisi finale con dfDataViewer.

    Premessa: l'archivio iniziale idstatuscache.plist è allo stato di fabbrica e la ricerca di un destinatario per la prima volta nei test è proprio il primo tentativo di contatto.

    Test 1

    Questa prima sequenza di test è composta solo da "ricerca e selezione" del contatto iPhone (+393485495xxx): due volte al giorno e per due giorni consecutivi.

    La prima richiesta di autenticazione del giorno viene registrata normalmente e la successiva nello stesso giorno non modifica il record. Nel secondo giorno viene aggiornato il record come prima autenticazione giornaliera e lo stato del record non viene modificato per la successiva nella stessa giornata.

    Test 2

    Il secondo test è molto simile al primo: solo un tentativo al giorno con il contatto iPhone (+393396472xxx).

    Il secondo giorno aggiorna i timestamp come nel caso precedente.

    Test 3

    Il primo test è una videochiamata "senza risposta" con l'altro mio iPhone SE 2020 (django.faiola@xxx.com); il secondo test è una videochiamata "con risposta". Nel secondo giorno, il terzo test, di nuovo una videochiamata "senza risposta".

    Anche in questo caso i timestamp sono aggiornati a quelli della prima autenticazione del secondo giorno.

    Test 4

    Questo è sempre un test di "ricerca e selezione" del contatto Android (+393381956xxx).

    A differenza del Test 1 per il contatto iPhone, nel caso di Android viene aggiornato solo il timestamp dell'identificatore com.apple.private.alloy.facetime.multi, il servizio per la gestione delle chiamate in multiutente di FaceTime.

    Test 5

    Questo test è il più importante: dimostra la persistenza del record nella cache del contatto (+393489209xxx) dopo averlo eliminato dalla rubrica.

    Attenzione! se il contatto viene di nuovo inserito in rubrica e poi autenticato in data successiva al 30 luglio 2024, il timestamp viene aggiornato come nei casi precedenti.

    Ulteriore conferma della persistenza del record dopo qualche giorno dall'eliminazione del contatto.

    Il record resiste alla eliminazione del contatto.

    Test vari

    Altri test non esaustivi sono stati svolti e non riportati sopra ma confermano quanto già esposto. Dalla rubrica per esempio, solita procedura test di ricerca e selezione di un contatto iDevice ho riscontrato in corrispondenza della selezione (visualizzazione della scheda) un aggiornamento del timestamp di FaceTime (com.apple.ess).

    La verifica dell'identità non si limita solo a iMessage o FaceTime, ma viene eseguita anche per gli altri servizi, per es. FindMyFriend.

    Ulteriori test possono mettere in luce situazioni particolari ma la sostanza è che i timestamp non rappresentano più il primo contatto come nel caso di com.apple.identityservices.idstatuscache.plist.

    Percorsi

    • /System/Library/IdentityServices/ServiceDefinitions/*.plist:  definizioni dei servizi;
    • /private/var/mobile/Library/Preferences/com.apple.identityservices.idstatuscache.plist: cache dei record delle autenticazioni fino alla versione iOS 14.6.0 (incluso anche nel Backup);
    • /private/var/mobile/Library/IdentityServices/idstatuscache.plist: cache dei record delle autenticazioni a partire dalla versione iOS 14.7.0 (non incluso nel Backup).

    Il dubbio "Cellebrite"

    Onestamente mi è sorto un dubbio: come mai questo comportamento così diverso se tutto sembra essere uguale? Inoltre i timestamp ottenuti dalla vecchia versione della cache non sembrano essere i più datati, da primo contatto, oserei quasi dire da ricerca recente. 

    Non ho modo di fare qualche test con la vecchia cache quella precedente alla versione iOS 14.7.0, quindi ho pensato di dare giusto un'occhiata veloce ai dati estratti con iLEAPP dall'immagine di Josh Hickman iOS 14.3.

    Per esempio il contatto (919) 888-7xxx This Is DFIR Two (quello con più messaggi scambiati in iMessage) ha da Identity Lookup Service il timestamp 2021-02-19 19:16:47.

    iMessage

    • 2021-02-15 18:14:29 primo messaggio in uscita "I have now switched to iPhone.";
    • altri messaggi;
    • 2021-02-15 18:33:17 ultimo messaggio in uscita "IMG_0018.JPG";
    • 2021-02-15 18:34:53 ultimo messaggio (letto) in entrata "Very nice, and very true.";
    • 2021-02-19 19:16:46 primo e ultimo messaggio (letto) in entrata "Memes 3.zip";
    • 2021-02-19 19:49:34 primo e ultimo messaggio in uscita "iOS_Bug_Reporting_for_Forensic_Purposes_1.2.pdf".

    InteractionC:

    • 2021-02-15 18:04:46 prima interazione in uscita;
    • altre interazioni;
    • 2021-02-19 19:16:46 ultima interazione in entrata.

    Ovvio che questo è come dire un controllo "superficiale", ma la domanda è: possibile che in tutte queste interazioni con il contatto quella riportata da ILS è temporalmente compatibile con l'ultima (la prima del giorno 19)?

      Conclusioni

      Quello che si può affermare è:

      1. Eliminando il contatto dalla rubrica il record nella cache persiste;
      2. I timestamp non sono quelli del primo contatto (caso limite), ma quelli del primo contatto del giorno dell'ultima richiesta di verifica dell'autenticazione;
      3. Il contatto alla data/ora di ricerca di sicuro è presente nel dispositivo.

      In conclusione, nella vecchia cache lo scopo dell'analisi era quello di avere un indizio di un potenziale contatto: bene, anche in questo caso la situazione è la stessa.

      iLEAPP 💖

      Come di consueto, a supporto del progetto iLEAPP (iOS Logs, Events, And Plists Parser) di Alexis Brignoni ho sviluppato il plugin idstatuscache.py che alla data odierna è in “pull request” e comunque disponibile sul mio GitHub.

      Di seguito alcuni screenshot del report di Identity Lookup Service:


      Read More