martedì 5 marzo 2024

Published marzo 05, 2024 by Django Faiola with 0 comment

iOS Burner

Introduzione

Buner è un’applicazione mobile per iOS e Android sviluppata da Ad Hoc Labs, Inc. che consente agli utenti di mantenere privato il proprio numero (SIM) di telefono acquistando numeri di telefono usa e getta virtuali per scopi come annunci online, gioco d’azzardo, chat di incontri, privacy e altro.

Basta fornire il numero burner e per esempio una chiamata in arrivo su questo numero viene reindirizzata in modo trasparente al numero personale (SIM) a meno che non si decida di bloccare il contatto. Per maggiori dettagli sulle funzionalità dell'app consulta https://www.burnerapp.com.

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 DigitalCorporaLa versione di Burner è 5.3.8.

Phoenix.sqlite è il database principale che contiene le tabelle degli account, contatti, numeri burner, messaggi e chiamate, etc. La tabella "ZBURNER" per esempio contiene solo i numeri burner attivi; infatti quando l’abbonamento scade il numero viene "bruciato" e rimosso da questa tabella. Tutti i valori data/ora (timestamp) sono riferiti al tempo UTC e nel formato Mac absolute time che conta il numero di secondi dal 1 gennaio del 2001.

Di seguito un dettaglio non esaustivo delle tabelle di interesse:

ZBURNER (numeri burner)

  • Z_PK: chiave primaria;
  • ZDATECREATED: data e ora di creazione del numero;
  • ZEXPIRATIONDATE: data e ora di scadenza dell’abbonamento;
  • ZNAME: nome visualizzato;
  • ZPHONENUMBER: numero burner;
  • ZBURNERID: identificatore del burner;
  • ZREMAININGMINUTES: minuti di conversazione vocale residui;
  • ZTOTALMINUTES: minuti di conversazione totali (abbonamento);
  • ZREMAININGTEXTS: numero di messaggi di testo residui;
  • ZTOTALTEXTS: numero di messaggi di testo totali (abbonamento);
  • ZAUTOREPLYACTIVE: abilita/disabilita il messaggio di testo di risposta automatica (0=Off);
  • ZAUTOREPLYTEXT: messaggio di testo della risposta automatica;
  • ZUSER: chiave esterna dell’account associato al numero (Z_PK della tabella ZUSER);
  • ZCALLERIDENABLED: mostra le chiamate in entrata come numero  burner (0=Burner Number) o come numero di telefono del chiamante (1=Caller Number);
  • ZNOTIFICATIONS: abilita/disabilita le notifiche (1=On);
  • ZRINGER: abilita/disabilita la suoneria (1=On);
  • ZUSESIP: In-App Calling (VoIP); 0=usa il numero burner per effettuare o ricevere chiamate "VoIP" o 1=chiamate telefoniche "Voice";
  • ZVOICEMAILURL: URL del messaggio vocale di benvenuto “richiesta di lasciare un messaggio vocale” personalizzato;
  • ZIMAGE: contiene l’immagine del profilo (offset: 0x02).
SELECT
  B.Z_PK AS "B_PK",
  U.Z_PK AS "U_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",
  U.ZPHONENUMBER AS "mobilePhone",
  U.ZUSERID AS "userId",
  B.ZBURNERID AS "burnerId"
FROM ZBURNER AS "B"
LEFT JOIN ZUSER AS "U" ON (B.ZUSER = U.Z_PK)

ZUSER (account)

  • Z_PK: chiave primaria;
  • ZDNDENABLED: abilita/disabilita "Non disturbare" (1=On);
  • ZTOTALNUMBERBURNERS: numero totale di burner creati;
  • ZDATECREATED: data e ora di creazione dell’account;
  • ZCOUNTRYCODE: codice paese;
  • ZNAME: nome visualizzato;
  • ZPHONENUMBER: numero di telefono;
  • ZUSERID: identificatore utente.
SELECT
  U.Z_PK AS "U_PK",
  B.B_PK,
  datetime(U.ZDATECREATED + 978307200, 'unixepoch') AS "dateCreated",
  U.ZPHONENUMBER AS "mobilePhone",
  U.ZCOUNTRYCODE AS "countryCode",
  (coalesce(B.nBurners, "0") || "/" || U.ZTOTALNUMBERBURNERS) AS "nBurners",
  B.burnerNames,
  B.burnerIds,
  CASE U.ZDNDENABLED
    WHEN 1 THEN "On"
    ELSE "Off"
  END AS "dndEnabled",
  U.ZVOICEMAILURL AS "voicemailUrl",
  U.ZUSERID AS "userId"
FROM ZUSER AS "U"
LEFT JOIN (
  SELECT 
    BU.ZUSER,
group_concat(BU.Z_PK, char(29)) AS "B_PK",
count(BU.ZUSER) AS "nBurners",
group_concat(IIF(BU.ZNAME NOT NULL, BU.ZPHONENUMBER || " (" || BU.ZNAME || ")", BU.ZPHONENUMBER), char(29)) AS "burnerNames",
group_concat(BU.ZBURNERID, char(29)) AS "burnerIds"
  FROM ZBURNER AS "BU" 
  GROUP BY BU.ZUSER  
) AS "B" ON (U.Z_PK = B.ZUSER)

ZCONTACT (contatti)

  • Z_PK: chiave primaria;
  • ZBLOCKED: 1=contatto bloccato;
  • ZMUTED: 1=modalità silenziosa;
  • ZVERIFIED: 1=contatto verificato;
  • ZCONTACTID: identificatore del contatto;
  • ZFRIENDLYPHONENUMBER: numero di telefono nel formato “numero telefonico”;
  • ZIMAGEURL: URL dell’immagine del contatto;
  • ZNAME: nome visualizzato;
  • ZNOTE: chiave esterna delle note (Z_PK della tabella ZCONTACTNOTE);
  • ZPHONENUMBER: numero di telefono;
  • ZTHUMBNAILURL: URL della miniatura dell’immagine del contatto;
  • ZIMAGE: contiene l’immagine del contatto (offset: 0x02);
  • ZTHUMBNAIL: contiene la miniatura dell’immagine del contatto (offset: 0x02).

ZCONTACTPHONENUMBER (altri numeri di telefono)

  • Z_PK: chiave primaria;
  • ZCONTACT: chiave esterna del contatto associato al numero di telefono (Z_PK della tabella ZCONTACT);
  • ZPHONENUMBER: numero di telefono;
  • ZPHONENUMBERLABEL: etichetta, esempio nome dell’app associata al numero "TextNow".

ZCONTACTNOTE (note)

  • Z_PK: chiave primaria;
  • ZCONTACT: chiave esterna del contatto associato alla nota (Z_PK della tabella ZCONTACT);
  • ZNOTEVALUE: la nota.
SELECT
  C.Z_PK AS "C_PK",
  CPN.CPN_PK,
  CN.CN_PK,
  C.ZPHONENUMBER AS "phoneNumber",
  C.ZNAME AS "name",
  CPN.otherPhones,
  CN.notes,
  substr(C.ZIMAGE, 2, length(C.ZIMAGE) - 2) AS "image",
  substr(C.ZTHUMBNAIL, 2, length(C.ZTHUMBNAIL) - 2) AS "thumbnail",
  C.ZIMAGEURL AS "imageUrl",
  C.ZTHUMBNAILURL AS "thumbnailUrl",
  C.ZVERIFIED AS "verified",
  C.ZBLOCKED AS "blocked",
  C.ZMUTED AS "muted",
  C.ZCONTACTID AS "contactId"
FROM ZCONTACT AS "C"
LEFT JOIN (
  SELECT 
PN.ZCONTACT,
    group_concat(coalesce(PN.Z_PK, ""), char(29)) AS "CPN_PK",
group_concat(IIF(PN.ZPHONENUMBERLABEL IS NOT NULL, "(" || PN.ZPHONENUMBERLABEL || ") " || PN.ZPHONENUMBER, PN.ZPHONENUMBER), char(29)) AS "otherPhones"
  FROM ZCONTACTPHONENUMBER AS "PN"
  GROUP BY PN.ZCONTACT
) AS "CPN" ON (C.Z_PK = CPN.ZCONTACT)
LEFT JOIN (
  SELECT
    N.ZCONTACT,
    group_concat(coalesce(N.Z_PK, ""), char(29)) AS "CN_PK",
group_concat(coalesce(N.ZNOTEVALUE, ""), char(29)) AS "notes"
  FROM ZCONTACTNOTE AS "N"
  GROUP BY N.ZCONTACT
) AS "CN" ON (C.Z_PK = CN.ZCONTACT)

ZMESSAGE (messaggi/chiamate)

  • Z_PK: chiave primaria;
  • ZDIRECTION: direzione del messaggio/chiamata 1=entrata, 2=uscita;
  • ZREAD: 1=letto;
  • ZSTATE: 3=completo, 4=chiamata persa, 5=chiamata persa con messaggio vocale;
  • ZTYPE: tipo di messaggio 1=chiamata o messaggio vocale, 2=testo o immagine;
  • ZMESSAGETHREAD: chiave esterna della conversazione associata al messaggio (Z_PK della tabella ZMESSAGETHREAD);
  • ZDATECREATED: data e ora di creazione del messaggio;
  • ZLASTUPDATED: data e ora dell’ultimo aggiornamento;
  • ZASSETURL: URL della risorsa (es: immagine);
  • ZBODY: testo del messaggio;
  • ZBURNERID: identificatore del burner;
  • ZCONTACTPHONENUMBER: numero di telefono dell'interlocutore;
  • ZLOCALASSETURL: percorso locale (dispositivo) dell’immagine;
  • ZLOCALTHUMBNAILURL: percorso locale (dispositivo) della miniatura dell’immagine;
  • ZMESSAGEID: identificatore del messaggio;
  • ZVOICEMAILURL: URL del messaggio vocale.

ZMESSAGETHREAD (conversazioni)

  • Z_PK: chiave primaria;
  • ZDIRECTION: direzione del messaggio/chiamata 1=entrata, 2=uscita;
  • ZREAD: 1=letto;
  • ZSTATE: 3=completo, 4=chiamata persa, 5=chiamata persa con messaggio vocale;
  • ZTYPE: tipo di messaggio 1=chiamata o messaggio vocale, 2=testo o immagine;
  • ZBURNER: chiave esterna del burner associato alla conversazione (Z_PK della tabella ZBURNER);
  • ZCONTACT: chiave esterna del contatto associato al numero di telefono (Z_PK della tabella ZCONTACT);
  • ZDATECREATED: data e ora di creazione della conversazione;
  • ZLASTUPDATEDDATE: data e ora dell'ultimo aggiornamento;
  • ZASSETURL: URL della risorsa (es: immagine);
  • ZBODY: testo dell'ultimo messaggio;
  • ZCONTACTPHONENUMBER: numero di telefono dell'interlocutore;
  • ZMESSAGETHREADID: identificativo della conversazione.
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 (coalesce(M.ZLOCALASSETURL, M.ZLOCALTHUMBNAILURL) 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 M.ZCONTACTPHONENUMBER = MT.ZCONTACTPHONENUMBER)
LEFT JOIN ZCONTACT AS "C" ON (MT.ZCONTACT = C.Z_PK) OR (MT.ZCONTACT IS NULL AND M.ZCONTACTPHONENUMBER = C.ZPHONENUMBER)

iLEAPP

Al fine di facilitare l'analisi di Burner per iOS ho sviluppato un plugin per iLEAPP (iOS Logs, Events, And Plists Parser) di Alexis Brignoni. Alla data di pubblicazione il plugin è in “pull request” e comunque disponibile sul mio GitHub.

Di seguito alcuni screenshot del report di Burner:


0 comments:

Posta un commento