Forensik Perangkat Seluler Digital Python

Bab ini akan menjelaskan forensik digital Python pada perangkat seluler dan konsep yang terlibat.

pengantar

Forensik perangkat seluler adalah cabang forensik digital yang berhubungan dengan akuisisi dan analisis perangkat seluler untuk memulihkan bukti digital dari minat investigasi. Cabang ini berbeda dengan forensik komputer karena perangkat seluler memiliki sistem komunikasi bawaan yang berguna untuk memberikan informasi berguna terkait lokasi.

Meskipun penggunaan smartphone meningkat dalam forensik digital dari hari ke hari, tetap saja itu dianggap tidak standar karena heterogenitasnya. Di sisi lain, perangkat keras komputer, seperti hard disk, dianggap standar dan juga dikembangkan sebagai disiplin yang stabil. Dalam industri forensik digital, banyak perdebatan tentang teknik yang digunakan untuk perangkat non-standar, yang memiliki bukti sementara, seperti smartphone.

Artefak Diekstraksi dari Perangkat Seluler

Perangkat seluler modern memiliki banyak informasi digital dibandingkan dengan ponsel lama yang hanya memiliki log panggilan atau pesan SMS. Dengan demikian, perangkat seluler dapat memberikan banyak wawasan kepada penyelidik tentang penggunanya. Beberapa artefak yang dapat diekstraksi dari perangkat seluler adalah seperti yang disebutkan di bawah ini -

  • Messages - Ini adalah artefak berguna yang dapat mengungkapkan keadaan pikiran pemiliknya dan bahkan dapat memberikan beberapa informasi yang tidak diketahui sebelumnya kepada penyelidik.

  • Location History- Data riwayat lokasi adalah artefak berguna yang dapat digunakan oleh penyelidik untuk memvalidasi tentang lokasi tertentu seseorang.

  • Applications Installed - Dengan mengakses jenis aplikasi yang diinstal, penyelidik mendapatkan beberapa wawasan tentang kebiasaan dan pemikiran pengguna ponsel.

Sumber Bukti dan Pemrosesan dengan Python

Ponsel cerdas memiliki basis data SQLite dan file PLIST sebagai sumber utama bukti. Pada bagian ini kita akan memproses sumber-sumber bukti dengan menggunakan python.

Menganalisis file PLIST

A PLIST (Daftar Properti) adalah format yang fleksibel dan nyaman untuk menyimpan data aplikasi terutama pada perangkat iPhone. Ini menggunakan ekstensi.plist. Jenis file yang digunakan untuk menyimpan informasi tentang bundel dan aplikasi. Ini bisa dalam dua format:XML dan binary. Kode Python berikut akan membuka dan membaca file PLIST. Perhatikan bahwa sebelum melanjutkan ke ini, kita harus membuatnya sendiriInfo.plist mengajukan.

Pertama, instal pustaka pihak ketiga bernama biplist dengan perintah berikut -

Pip install biplist

Sekarang, impor beberapa pustaka yang berguna untuk memproses file plist -

import biplist
import os
import sys

Sekarang, gunakan perintah berikut di bawah metode utama dapat digunakan untuk membaca file plist menjadi variabel -

def main(plist):
   try:
      data = biplist.readPlist(plist)
   except (biplist.InvalidPlistException,biplist.NotBinaryPlistException) as e:
print("[-] Invalid PLIST file - unable to be opened by biplist")
sys.exit(1)

Sekarang, kita bisa membaca data di konsol atau langsung mencetaknya, dari variabel ini.

Database SQLite

SQLite berfungsi sebagai tempat penyimpanan data utama di perangkat seluler. SQLite pustaka dalam proses yang mengimplementasikan mesin database SQL transaksional, tanpa server, tanpa konfigurasi, dan mandiri. Ini adalah database, yang tidak terkonfigurasi, Anda tidak perlu mengkonfigurasinya di sistem Anda, tidak seperti database lain.

Jika Anda seorang pemula atau tidak terbiasa dengan database SQLite, Anda dapat mengikuti tautan www.tutorialspoint.com/sqlite/index.htm Selain itu, Anda dapat mengikuti tautan www.tutorialspoint.com/sqlite/sqlite_python.htm jika Anda ingin membahas detail SQLite dengan Python.

Selama forensik seluler, kita dapat berinteraksi dengan sms.db file dari perangkat seluler dan dapat mengekstrak informasi berharga dari messagemeja. Python memiliki pustaka bawaan bernamasqlite3untuk menghubungkan dengan database SQLite. Anda dapat mengimpor yang sama dengan perintah berikut -

import sqlite3

Sekarang, dengan bantuan perintah berikut, kita dapat terhubung dengan database, misalnya sms.db dalam kasus perangkat seluler -

Conn = sqlite3.connect(‘sms.db’)
C = conn.cursor()

Di sini, C adalah objek kursor dengan bantuan yang bisa kita gunakan untuk berinteraksi dengan database.

Sekarang, misalkan jika kita ingin menjalankan perintah tertentu, katakanlah untuk mendapatkan detail dari abc table, itu dapat dilakukan dengan bantuan perintah berikut -

c.execute(“Select * from abc”)
c.close()

Hasil dari perintah di atas akan disimpan di file cursorobyek. Demikian pula yang bisa kita gunakanfetchall() metode untuk membuang hasil ke dalam variabel yang dapat kita manipulasi.

Kita dapat menggunakan perintah berikut untuk mendapatkan data nama kolom dari tabel pesan sms.db -

c.execute(“pragma table_info(message)”)
table_data = c.fetchall()
columns = [x[1] for x in table_data

Perhatikan bahwa di sini kita menggunakan perintah SQLite PRAGMA yang merupakan perintah khusus yang akan digunakan untuk mengontrol berbagai variabel lingkungan dan bendera negara dalam lingkungan SQLite. Pada perintah di atas, filefetchall()metode mengembalikan tupel hasil. Setiap nama kolom disimpan di indeks pertama setiap tupel.

Sekarang, dengan bantuan perintah berikut kita dapat membuat kueri tabel untuk semua datanya dan menyimpannya dalam variabel bernama data_msg -

c.execute(“Select * from message”)
data_msg = c.fetchall()

Perintah di atas akan menyimpan data dalam variabel dan selanjutnya kita juga dapat menulis data di atas dalam file CSV dengan menggunakan csv.writer() metode.

Cadangan iTunes

Forensik seluler iPhone dapat dilakukan pada cadangan yang dibuat oleh iTunes. Pemeriksa forensik mengandalkan analisis backup logis iPhone yang diperoleh melalui iTunes. Protokol AFC (koneksi file Apple) digunakan oleh iTunes untuk mengambil cadangan. Selain itu, proses pencadangan tidak mengubah apa pun di iPhone kecuali catatan kunci escrow.

Sekarang, muncul pertanyaan mengapa penting bagi ahli forensik digital untuk memahami teknik backup iTunes? Hal ini penting jika kita mendapatkan akses ke komputer tersangka daripada iPhone secara langsung karena ketika komputer digunakan untuk melakukan sinkronisasi dengan iPhone, maka sebagian besar informasi di iPhone kemungkinan besar akan dicadangkan di komputer.

Proses Pencadangan dan Lokasinya

Setiap kali produk Apple dicadangkan ke komputer, itu selaras dengan iTunes dan akan ada folder tertentu dengan ID unik perangkat. Dalam format cadangan terbaru, file disimpan dalam subfolder yang berisi dua karakter heksadesimal pertama dari nama file. Dari file cadangan tersebut, terdapat beberapa file seperti info.plist yang berguna bersama dengan database bernama Manifest.db. Tabel berikut menunjukkan lokasi cadangan, yang bervariasi dengan sistem operasi cadangan iTunes -

OS Lokasi Cadangan
Win7 C: \ Users \ [nama pengguna] \ AppData \ Roaming \ AppleComputer \ MobileSync \ Backup \
MAC OS X ~ / Library / Application Suport / MobileSync / Backup /

Untuk memproses cadangan iTunes dengan Python, pertama-tama kita perlu mengidentifikasi semua cadangan di lokasi cadangan sesuai sistem operasi kita. Kemudian kita akan melakukan iterasi melalui setiap backup dan membaca database Manifest.db.

Sekarang, dengan bantuan kode Python berikut kita dapat melakukan hal yang sama -

Pertama, impor pustaka yang diperlukan sebagai berikut -

from __future__ import print_function
import argparse
import logging
import os

from shutil import copyfile
import sqlite3
import sys
logger = logging.getLogger(__name__)

Sekarang, berikan dua argumen posisi yaitu INPUT_DIR dan OUTPUT_DIR yang mewakili cadangan iTunes dan folder keluaran yang diinginkan -

if __name__ == "__main__":
   parser.add_argument("INPUT_DIR",help = "Location of folder containing iOS backups, ""e.g. ~\Library\Application Support\MobileSync\Backup folder")
   parser.add_argument("OUTPUT_DIR", help = "Output Directory")
   parser.add_argument("-l", help = "Log file path",default = __file__[:-2] + "log")
   parser.add_argument("-v", help = "Increase verbosity",action = "store_true") args = parser.parse_args()

Sekarang, atur log sebagai berikut -

if args.v:
   logger.setLevel(logging.DEBUG)
else:
   logger.setLevel(logging.INFO)

Sekarang, atur format pesan untuk log ini sebagai berikut -

msg_fmt = logging.Formatter("%(asctime)-15s %(funcName)-13s""%(levelname)-8s %(message)s")
strhndl = logging.StreamHandler(sys.stderr)
strhndl.setFormatter(fmt = msg_fmt)

fhndl = logging.FileHandler(args.l, mode = 'a')
fhndl.setFormatter(fmt = msg_fmt)

logger.addHandler(strhndl)
logger.addHandler(fhndl)
logger.info("Starting iBackup Visualizer")
logger.debug("Supplied arguments: {}".format(" ".join(sys.argv[1:])))
logger.debug("System: " + sys.platform)
logger.debug("Python Version: " + sys.version)

Baris kode berikut akan membuat folder yang diperlukan untuk direktori keluaran yang diinginkan dengan menggunakan os.makedirs() fungsi -

if not os.path.exists(args.OUTPUT_DIR):
   os.makedirs(args.OUTPUT_DIR)

Sekarang, teruskan direktori input dan output yang disediakan ke fungsi main () sebagai berikut -

if os.path.exists(args.INPUT_DIR) and os.path.isdir(args.INPUT_DIR):
   main(args.INPUT_DIR, args.OUTPUT_DIR)
else:
   logger.error("Supplied input directory does not exist or is not ""a directory")
   sys.exit(1)

Sekarang Tulis main() fungsi yang selanjutnya akan dipanggil backup_summary() berfungsi untuk mengidentifikasi semua cadangan yang ada di folder input -

def main(in_dir, out_dir):
   backups = backup_summary(in_dir)
def backup_summary(in_dir):
   logger.info("Identifying all iOS backups in {}".format(in_dir))
   root = os.listdir(in_dir)
   backups = {}
   
   for x in root:
      temp_dir = os.path.join(in_dir, x)
      if os.path.isdir(temp_dir) and len(x) == 40:
         num_files = 0
         size = 0
         
         for root, subdir, files in os.walk(temp_dir):
            num_files += len(files)
            size += sum(os.path.getsize(os.path.join(root, name))
               for name in files)
         backups[x] = [temp_dir, num_files, size]
   return backups

Sekarang, cetak ringkasan setiap cadangan ke konsol sebagai berikut -

print("Backup Summary")
print("=" * 20)

if len(backups) > 0:
   for i, b in enumerate(backups):
      print("Backup No.: {} \n""Backup Dev. Name: {} \n""# Files: {} \n""Backup Size (Bytes): {}\n".format(i, b, backups[b][1], backups[b][2]))

Sekarang, buang konten file Manifest.db ke variabel bernama db_items.

try:
   db_items = process_manifest(backups[b][0])
   except IOError:
      logger.warn("Non-iOS 10 backup encountered or " "invalid backup. Continuing to next backup.")
continue

Sekarang, mari kita tentukan fungsi yang akan mengambil jalur direktori cadangan -

def process_manifest(backup):
   manifest = os.path.join(backup, "Manifest.db")
   
   if not os.path.exists(manifest):
      logger.error("Manifest DB not found in {}".format(manifest))
      raise IOError

Sekarang, menggunakan SQLite3 kita akan terhubung ke database dengan kursor bernama c -

c = conn.cursor()
items = {}

for row in c.execute("SELECT * from Files;"):
   items[row[0]] = [row[2], row[1], row[3]]
return items

create_files(in_dir, out_dir, b, db_items)
   print("=" * 20)
else:
   logger.warning("No valid backups found. The input directory should be
      " "the parent-directory immediately above the SHA-1 hash " "iOS device backups")
      sys.exit(2)

Sekarang, tentukan create_files() metode sebagai berikut -

def create_files(in_dir, out_dir, b, db_items):
   msg = "Copying Files for backup {} to {}".format(b, os.path.join(out_dir, b))
   logger.info(msg)

Sekarang, lakukan iterasi melalui setiap kunci di file db_items kamus -

for x, key in enumerate(db_items):
   if db_items[key][0] is None or db_items[key][0] == "":
      continue
   else:
      dirpath = os.path.join(out_dir, b,
os.path.dirname(db_items[key][0]))
   filepath = os.path.join(out_dir, b, db_items[key][0])
   
   if not os.path.exists(dirpath):
      os.makedirs(dirpath)
      original_dir = b + "/" + key[0:2] + "/" + key
   path = os.path.join(in_dir, original_dir)
   
   if os.path.exists(filepath):
      filepath = filepath + "_{}".format(x)

Sekarang, gunakan shutil.copyfile() metode untuk menyalin file cadangan sebagai berikut -

try:
   copyfile(path, filepath)
   except IOError:
      logger.debug("File not found in backup: {}".format(path))
         files_not_found += 1
   if files_not_found > 0:
      logger.warning("{} files listed in the Manifest.db not" "found in
backup".format(files_not_found))
   copyfile(os.path.join(in_dir, b, "Info.plist"), os.path.join(out_dir, b,
"Info.plist"))
   copyfile(os.path.join(in_dir, b, "Manifest.db"), os.path.join(out_dir, b,
"Manifest.db"))
   copyfile(os.path.join(in_dir, b, "Manifest.plist"), os.path.join(out_dir, b,
"Manifest.plist"))
   copyfile(os.path.join(in_dir, b, "Status.plist"),os.path.join(out_dir, b,
"Status.plist"))

Dengan skrip Python di atas, kita bisa mendapatkan struktur file cadangan yang diperbarui di folder output kita. Kita bisa gunakanpycrypto pustaka python untuk mendekripsi cadangan.

Wifi

Perangkat seluler dapat digunakan untuk terhubung ke dunia luar dengan menghubungkan melalui jaringan Wi-Fi yang tersedia di mana-mana. Terkadang perangkat terhubung ke jaringan terbuka ini secara otomatis.

Dalam kasus iPhone, daftar koneksi Wi-Fi terbuka yang terhubung dengan perangkat disimpan dalam file PLIST bernama com.apple.wifi.plist. File ini akan berisi Wi-Fi SSID, BSSID dan waktu koneksi.

Kita perlu mengekstrak detail Wi-Fi dari laporan XML Cellebrite standar menggunakan Python. Untuk ini, kita perlu menggunakan API dari Wireless Geographic Logging Engine (WIGLE), platform populer yang dapat digunakan untuk menemukan lokasi perangkat menggunakan nama jaringan Wi-Fi.

Kita bisa menggunakan pustaka Python bernama requestsuntuk mengakses API dari WIGLE. Itu dapat diinstal sebagai berikut -

pip install requests

API dari WIGLE

Kami perlu mendaftar di situs WIGLE https://wigle.net/accountuntuk mendapatkan API gratis dari WIGLE. Skrip Python untuk mendapatkan informasi tentang perangkat pengguna dan koneksinya melalui API WIGEL dibahas di bawah ini -

Pertama, impor pustaka berikut untuk menangani berbagai hal -

from __future__ import print_function

import argparse
import csv
import os
import sys
import xml.etree.ElementTree as ET
import requests

Sekarang, berikan dua argumen posisi yaitu INPUT_FILE dan OUTPUT_CSV yang akan mewakili file input dengan alamat MAC Wi-Fi dan file CSV output yang diinginkan masing-masing -

if __name__ == "__main__":
   parser.add_argument("INPUT_FILE", help = "INPUT FILE with MAC Addresses")
   parser.add_argument("OUTPUT_CSV", help = "Output CSV File")
   parser.add_argument("-t", help = "Input type: Cellebrite XML report or TXT
file",choices = ('xml', 'txt'), default = "xml")
   parser.add_argument('--api', help = "Path to API key
   file",default = os.path.expanduser("~/.wigle_api"),
   type = argparse.FileType('r'))
   args = parser.parse_args()

Sekarang baris kode berikut akan memeriksa apakah file input ada dan merupakan file. Jika tidak, itu keluar dari skrip -

if not os.path.exists(args.INPUT_FILE) or \ not os.path.isfile(args.INPUT_FILE):
   print("[-] {} does not exist or is not a
file".format(args.INPUT_FILE))
   sys.exit(1)
directory = os.path.dirname(args.OUTPUT_CSV)
if directory != '' and not os.path.exists(directory):
   os.makedirs(directory)
api_key = args.api.readline().strip().split(":")

Sekarang, berikan argumen ke main sebagai berikut -

main(args.INPUT_FILE, args.OUTPUT_CSV, args.t, api_key)
def main(in_file, out_csv, type, api_key):
   if type == 'xml':
      wifi = parse_xml(in_file)
   else:
      wifi = parse_txt(in_file)
query_wigle(wifi, out_csv, api_key)

Sekarang, kita akan mengurai file XML sebagai berikut -

def parse_xml(xml_file):
   wifi = {}
   xmlns = "{http://pa.cellebrite.com/report/2.0}"
   print("[+] Opening {} report".format(xml_file))
   
   xml_tree = ET.parse(xml_file)
   print("[+] Parsing report for all connected WiFi addresses")
   
   root = xml_tree.getroot()

Sekarang, lakukan iterasi melalui elemen turunan dari root sebagai berikut -

for child in root.iter():
   if child.tag == xmlns + "model":
      if child.get("type") == "Location":
         for field in child.findall(xmlns + "field"):
            if field.get("name") == "TimeStamp":
               ts_value = field.find(xmlns + "value")
               try:
               ts = ts_value.text
               except AttributeError:
continue

Sekarang, kita akan memeriksa apakah string 'ssid' ada di teks nilai atau tidak -

if "SSID" in value.text:
   bssid, ssid = value.text.split("\t")
   bssid = bssid[7:]
   ssid = ssid[6:]

Sekarang, kita perlu menambahkan BSSID, SSID, dan timestamp ke kamus wifi sebagai berikut -

if bssid in wifi.keys():

wifi[bssid]["Timestamps"].append(ts)
   wifi[bssid]["SSID"].append(ssid)
else:
   wifi[bssid] = {"Timestamps": [ts], "SSID":
[ssid],"Wigle": {}}
return wifi

Pengurai teks yang jauh lebih sederhana daripada pengurai XML ditunjukkan di bawah ini -

def parse_txt(txt_file):
   wifi = {}
   print("[+] Extracting MAC addresses from {}".format(txt_file))
   
   with open(txt_file) as mac_file:
      for line in mac_file:
         wifi[line.strip()] = {"Timestamps": ["N/A"], "SSID":
["N/A"],"Wigle": {}}
return wifi

Sekarang, mari kita gunakan modul permintaan untuk membuat WIGLE APIpanggilan telepon dan perlu beralih ke query_wigle() metode -

def query_wigle(wifi_dictionary, out_csv, api_key):
   print("[+] Querying Wigle.net through Python API for {} "
"APs".format(len(wifi_dictionary)))
   for mac in wifi_dictionary:

   wigle_results = query_mac_addr(mac, api_key)
def query_mac_addr(mac_addr, api_key):

   query_url = "https://api.wigle.net/api/v2/network/search?" \
"onlymine = false&freenet = false&paynet = false" \ "&netid = {}".format(mac_addr)
   req = requests.get(query_url, auth = (api_key[0], api_key[1]))
   return req.json()

Sebenarnya ada batasan per hari untuk panggilan WIGLE API, jika batas itu melebihi maka pasti akan muncul error sebagai berikut -

try:
   if wigle_results["resultCount"] == 0:
      wifi_dictionary[mac]["Wigle"]["results"] = []
         continue
   else:
      wifi_dictionary[mac]["Wigle"] = wigle_results
except KeyError:
   if wigle_results["error"] == "too many queries today":
      print("[-] Wigle daily query limit exceeded")
      wifi_dictionary[mac]["Wigle"]["results"] = []
      continue
   else:
      print("[-] Other error encountered for " "address {}: {}".format(mac,
wigle_results['error']))
   wifi_dictionary[mac]["Wigle"]["results"] = []
   continue
prep_output(out_csv, wifi_dictionary)

Sekarang, kami akan menggunakan prep_output() metode untuk meratakan kamus menjadi bagian yang mudah ditulis -

def prep_output(output, data):
   csv_data = {}
   google_map = https://www.google.com/maps/search/

Sekarang, akses semua data yang telah kami kumpulkan sejauh berikut -

for x, mac in enumerate(data):
   for y, ts in enumerate(data[mac]["Timestamps"]):
      for z, result in enumerate(data[mac]["Wigle"]["results"]):
         shortres = data[mac]["Wigle"]["results"][z]
         g_map_url = "{}{},{}".format(google_map, shortres["trilat"],shortres["trilong"])

Sekarang, kita dapat menulis output dalam file CSV seperti yang telah kita lakukan di skrip sebelumnya di bab ini dengan menggunakan write_csv() fungsi.