Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 12 additions & 15 deletions scripts/artifacts/callHistoryTransactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"name": "Call History Transactions",
"description": "Parses transaction.log file in Call History Transactions",
"author": "@JohnHyla",
"version": "0.0.1",
"date": "2024-12-11",
"creation_date": "2024-12-11",
"last_update_date": "2025-11-12",
"requirements": "none",
"category": "Call History",
"notes": "",
Expand All @@ -13,20 +13,17 @@
}
}

import os
import blackboxprotobuf
from datetime import *
import struct
import nska_deserialize as nd
from scripts.ilapfuncs import artifact_processor, webkit_timestampsconv, convert_ts_human_to_timezone_offset, \
convert_plist_date_to_timezone_offset
from scripts.ilapfuncs import artifact_processor, \
convert_plist_date_to_utc


@artifact_processor
def callHistoryTransactions(files_found, report_folder, seeker, wrap_text, timezone_offset):
def callHistoryTransactions(context):
data_list = []

for file_found in files_found:
for file_found in context.get_files_found():
file_found = str(file_found)
with open(file_found, 'rb') as file:
file.seek(0, 2)
Expand All @@ -38,15 +35,15 @@ def callHistoryTransactions(files_found, report_folder, seeker, wrap_text, timez
plist_data = file.read(length)
ds_plist = nd.deserialize_plist_from_string(plist_data)
inner_record = nd.deserialize_plist_from_string(ds_plist['record'])
date = convert_plist_date_to_timezone_offset(inner_record.get('date', ''), timezone_offset)
data_list.append([date, inner_record['handleType'], inner_record['callStatus'],
date = convert_plist_date_to_utc(inner_record.get('date', ''))
data_list.append((date, inner_record['handleType'], inner_record['callStatus'],
inner_record['duration'], inner_record['remoteParticipantHandles'][0]['value'],
inner_record['callerId'], inner_record['timeToEstablish'],
inner_record['disconnectedCause'], inner_record['uniqueId']])
inner_record['disconnectedCause'], inner_record['uniqueId'], file_found))

data_headers = [('Date', 'datetime'), 'handleType', 'callStatus', 'duration', 'remoteParticipantHandle', 'callerId',
'timeToEstablish', 'disconnectedCause', 'uniqueId']
data_headers = (('Date', 'datetime'), 'handleType', 'callStatus', 'duration', 'remoteParticipantHandle', 'callerId',
'timeToEstablish', 'disconnectedCause', 'uniqueId', 'Source File')

return data_headers, data_list, file_found
return data_headers, data_list, 'see Source File for more info'


58 changes: 28 additions & 30 deletions scripts/artifacts/carCD.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"name": "Last Car Connection and UDID",
"description": "",
"author": "@AlexisBrignoni",
"version": "0.0.2",
"date": "2023-09-30",
"creation_date": "2023-09-30",
"last_update_date": "2025-11-12",
"requirements": "none",
"category": "Identifiers",
"notes": "",
Expand All @@ -13,38 +13,36 @@
}
}


import plistlib
from scripts.ilapfuncs import artifact_processor, webkit_timestampsconv, device_info
from scripts.ilapfuncs import artifact_processor, webkit_timestampsconv, device_info, get_plist_file_content

@artifact_processor
def carCD(files_found, report_folder, seeker, wrap_text, timezone_offset):
def carCD(context):
files_found = context.get_files_found()
source_path = str(files_found[0])

with open(source_path, "rb") as fp:
pl = plistlib.load(fp)
for key, value in pl.items():
if key == 'LastVehicleConnection':
lastconn = value
contype = lastconn[2]
device_info("Vehicle", "Type", contype, source_path)
connected = webkit_timestampsconv(lastconn[0])
device_info("Vehicle", "Last Connected", connected, source_path)
disconnected = webkit_timestampsconv(lastconn[1])
device_info("Vehicle", "Last Disconnected", disconnected, source_path)
elif key == 'LastVehicleConnectionV2':
lastconnv2 = value
contype = lastconnv2[2]
device_info("Vehicle", "Type", contype, source_path)
connected = webkit_timestampsconv(lastconnv2[0])
device_info("Vehicle", "Last Connected", connected, source_path)
disconnected = webkit_timestampsconv(lastconnv2[1])
device_info("Vehicle", "Last Disconnected", disconnected, source_path)
elif key == 'CalibrationUDID':
uid = value
device_info("Vehicle", "CalibrationUDID", uid, source_path)
else:
pass
pl = get_plist_file_content(source_path)
for key, value in pl.items():
if key == 'LastVehicleConnection':
lastconn = value
contype = lastconn[2]
device_info("Vehicle", "Type", contype, source_path)
connected = webkit_timestampsconv(lastconn[0])
device_info("Vehicle", "Last Connected", connected, source_path)
disconnected = webkit_timestampsconv(lastconn[1])
device_info("Vehicle", "Last Disconnected", disconnected, source_path)
elif key == 'LastVehicleConnectionV2':
lastconnv2 = value
contype = lastconnv2[2]
device_info("Vehicle", "Type", contype, source_path)
connected = webkit_timestampsconv(lastconnv2[0])
device_info("Vehicle", "Last Connected", connected, source_path)
disconnected = webkit_timestampsconv(lastconnv2[1])
device_info("Vehicle", "Last Disconnected", disconnected, source_path)
elif key == 'CalibrationUDID':
uid = value
device_info("Vehicle", "CalibrationUDID", uid, source_path)
else:
pass

# Return empty data since this artifact only collects device info
return (), [], source_path
70 changes: 31 additions & 39 deletions scripts/artifacts/cashApp.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
import re

from scripts.artifact_report import ArtifactHtmlReport
from scripts.ilapfuncs import logfunc, tsv, timeline, open_sqlite_db_readonly


def get_cashApp(files_found, report_folder, seeker, wrap_text, timezone_offset):
for file_found in files_found:
__artifacts_v2__ = {
"get_cashApp": {
"name": "Cash App",
"description": "",
"author": "@gforce4n6",
"creation_date": "2021-10-06",
"last_update_date": "2025-11-12",
"requirements": "none",
"category": "Cash App",
"notes": "",
"paths": ('*/mobile/Containers/Shared/AppGroup/*/CCEntitySync-api.squareup.com.sqlite*',
'*/mobile/Containers/Shared/AppGroup/*/CCEntitySync-internal.cashappapi.com.sqlite*'),
"output_types": "standard",
}
}

from scripts.ilapfuncs import open_sqlite_db_readonly, artifact_processor, convert_unix_ts_to_utc

@artifact_processor
def get_cashApp(context):
data_list = []
for file_found in context.get_files_found():
file_found = str(file_found)

if file_found.endswith('.sqlite'):
db = open_sqlite_db_readonly(file_found)
db.text_factory = lambda b: b.decode(errors = 'ignore')
Expand Down Expand Up @@ -42,43 +55,22 @@ def get_cashApp(files_found, report_folder, seeker, wrap_text, timezone_offset):
CASE WHEN ZPAYMENT.ZSYNCPAYMENT LIKE '%"COMPLETED"%' THEN 'COMPLETED' WHEN ZPAYMENT.ZSYNCPAYMENT LIKE '%"CANCELED"%' THEN 'CANCELED' ELSE 'WAITING ON RECIPIENT' END AS 'Transaction State',

--Unix Epoch timestamp for the transaction display time.
datetime(ZPAYMENT.ZDISPLAYDATE/1000.0,'unixepoch') as "TRANSACTION DISPLAY DATE"
ZPAYMENT.ZDISPLAYDATE as "TRANSACTION DISPLAY DATE"

FROM ZPAYMENT
INNER JOIN ZCUSTOMER ON ZCUSTOMER.ZCUSTOMERTOKEN = ZPAYMENT.ZREMOTECUSTOMERID
ORDER BY ZPAYMENT.ZDISPLAYDATE ASC
''')

all_rows = cursor.fetchall()
db_file = file_found

for row in all_rows:
date = convert_unix_ts_to_utc(row[6])
data_list.append((date, row[1], row[2], row[0], row[3], row[5], row[4], file_found))

if len(all_rows) > 0:

data_list = []
for row in all_rows:
data_list.append((row[6], row[1], row[2], row[0], row[3], row[5], row[4]))

report = ArtifactHtmlReport('Transactions')
report.start_artifact_report(report_folder, 'Transactions')
report.add_script()
data_headers = ('Transaction Date', 'Display Name', 'Cashtag', 'Account Owner Role', 'Currency Amount', 'Transaction State', 'Transaction State')
report.write_artifact_data_table(data_headers, data_list, db_file)
report.end_artifact_report()

tsvname = 'Cash App Transactions'
tsv(report_folder, data_headers, data_list, tsvname)

tlactivity = 'Cash App Transactions'
timeline(report_folder, tlactivity, data_list, data_headers)
else:
logfunc('No Cash App Transactions available')
data_headers = (('Transaction Date', 'datetime'), 'Display Name', 'Cashtag', 'Account Owner Role',
'Currency Amount', 'Transaction State', 'Transaction State', 'Source File')

db.close()
return

__artifacts__ = {
"cashapp": (
"Cash App",
('*/mobile/Containers/Shared/AppGroup/*/CCEntitySync-api.squareup.com.sqlite*', '*/mobile/Containers/Shared/AppGroup/*/CCEntitySync-internal.cashappapi.com.sqlite*'),
get_cashApp)
}

return data_headers, data_list, 'see Source File for more info'
75 changes: 50 additions & 25 deletions scripts/artifacts/cashAppB.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,28 @@
"name": "Cash App",
"description": "",
"author": "Alexis Brignoni",
"version": "0.0.1",
"date": "2025-08-24",
"creation_date": "2025-08-24",
"last_update_date": "2025-11-12",
"requirements": "none",
"category": "Banking",
"notes": "",
"paths": ('*/Environments/Production/Accounts/*/*-internal.cashappapi.com.sqlite*'),
"output_types": "none",
"function": "get_cashAppB",
"output_types": "all",
"artifact_icon": "dollar-sign",
}
}

import blackboxprotobuf
import sqlite3
import json
from datetime import datetime, timezone
from scripts.ilapfuncs import artifact_processor, get_file_path, get_sqlite_db_records
from scripts.ilapfuncs import artifact_processor, get_sqlite_db_records, convert_unix_ts_to_utc

@artifact_processor
def get_cashAppB(files_found, report_folder, seeker, wrap_text, timezone_offset):
def get_cashAppB(context):
data_list = []
for file_found in files_found:
for file_found in context.get_files_found():
file_found = str(file_found)

if file_found.endswith('.sqlite'):
source = file_found

if file_found.endswith('.sqlite'):
query = """
SELECT
ZDISPLAYDATE,
Expand All @@ -44,11 +38,34 @@ def get_cashAppB(files_found, report_folder, seeker, wrap_text, timezone_offset)
results = get_sqlite_db_records(file_found, query)

for row in results:
timestamp = datetime.fromtimestamp(row[0]/1000, tz=timezone.utc)
timestamp = convert_unix_ts_to_utc(row[0])
customertoken = row[1]
protocustomer, types = blackboxprotobuf.decode_message(row[2])
protopayment, types = blackboxprotobuf.decode_message(row[3])
protocustomer, _ = blackboxprotobuf.decode_message(row[2])
protopayment, _ = blackboxprotobuf.decode_message(row[3])

# initialize optional fields to avoid NameError if keys are missing
role = None
howmuch = None
currency = None
note = None
cardbrand = None
suffix = None
displayname = None
displayinstrument = None
instrumenttype = None
transactionid = None
state = None
createdat = None
capturedat = None
reachedcustomerat = None
paidoutat = None
depositedat = None
displaydate = None
identificator = None
fullname = None
region = None
dunits = None

payment = (protopayment['1'].get('16'))
if payment is not None:
payment = payment.decode()
Expand All @@ -72,27 +89,27 @@ def get_cashAppB(files_found, report_folder, seeker, wrap_text, timezone_offset)

createdat = (payment.get('created_at'))
if createdat is not None:
createdat = datetime.fromtimestamp(createdat/1000, tz=timezone.utc)
createdat = convert_unix_ts_to_utc(createdat)

capturedat = (payment.get('captured_at'))
if capturedat is not None:
capturedat = datetime.fromtimestamp(capturedat/1000, tz=timezone.utc)
capturedat = convert_unix_ts_to_utc(capturedat)

reachedcustomerat = (payment.get('reached_customer_at'))
if reachedcustomerat is not None:
reachedcustomerat = datetime.fromtimestamp(reachedcustomerat/1000, tz=timezone.utc)
reachedcustomerat = convert_unix_ts_to_utc(reachedcustomerat)

paidoutat = (payment.get('paid_out_at'))
if paidoutat is not None:
paidoutat = datetime.fromtimestamp(paidoutat/1000, tz=timezone.utc)
paidoutat = convert_unix_ts_to_utc(paidoutat)

depositedat = (payment.get('deposited_at'))
if depositedat is not None:
depositedat = datetime.fromtimestamp(depositedat/1000, tz=timezone.utc)
depositedat = convert_unix_ts_to_utc(depositedat)

displaydate = (payment.get('display_date'))
if displaydate is not None:
displaydate = datetime.fromtimestamp(displaydate/1000, tz=timezone.utc)
displaydate = convert_unix_ts_to_utc(displaydate)

url = protocustomer['1'].get('5')
if url is not None:
Expand All @@ -111,14 +128,22 @@ def get_cashAppB(files_found, report_folder, seeker, wrap_text, timezone_offset)
extrainfo = extrainfo.decode()
extrainfo = json.loads(extrainfo)

id = (extrainfo['id'])
identificator = (extrainfo['id'])
fullname = (extrainfo['full_name'])
region = (extrainfo.get('region'))
dunits = (extrainfo.get('display_units'))

data_list.append((timestamp,customertoken,name,username,id,fullname,role,howmuch,currency,note,region,dunits,url,cardbrand,suffix,displayname,displayinstrument,instrumenttype,transactionid,state,createdat,capturedat,reachedcustomerat,paidoutat,depositedat,displaydate))
data_list.append((timestamp, customertoken, name, username, identificator, fullname,
role, howmuch, currency, note, region, dunits, url, cardbrand,
suffix, displayname, displayinstrument, instrumenttype, transactionid,
state, createdat, capturedat, reachedcustomerat,
paidoutat, depositedat, displaydate, file_found))

data_headers = (('Timestamp', 'datetime'),'Customer Token','Name','Username','ID','Full Name','Role','Amount','Currency','Note','Region','Units','URL','Card Brand','Suffix','Display Name','Display Instrument','Instrument Type','Transaction ID','State',('Created At', 'datetime'),('Captured At', 'datetime'),('Reached Customer At', 'datetime'),('Paid Out At', 'datetime'),('Deposited At', 'datetime'),('Display Date', 'datetime'))
return data_headers,data_list,source
data_headers = (('Timestamp', 'datetime'), 'Customer Token', 'Name', 'Username', 'ID', 'Full Name',
'Role', 'Amount', 'Currency', 'Note', 'Region', 'Units', 'URL', 'Card Brand',
'Suffix', 'Display Name', 'Display Instrument', 'Instrument Type', 'Transaction ID',
'State', ('Created At', 'datetime'), ('Captured At', 'datetime'), ('Reached Customer At', 'datetime'),
('Paid Out At', 'datetime'), ('Deposited At', 'datetime'), ('Display Date', 'datetime'), 'Source File')
return data_headers, data_list, 'see source File for more info'


Loading