📚 Bagian 3 dari Seri Riset Digital Forensik Memori Pascasarjana (S-2)
Notebook ini merupakan kelanjutan hands-on dari kajian di Part 1: Bedah Kritis volGPT dan Part 2: Arsitektur On-Premise Threat Graph.
AUTOMATED IN-MEMORY THREAT CORRELATION PIPELINE & INTERACTIVE THREAT GRAPH
Framework Forensik Memori Volatile Terotomasi dengan Korelasi Lintas-Artifak dan Pemetaan Taksonomi MITRE ATT&CK
- Program Studi: Magister Teknik Informatika (S-2) - Universitas Pamulang
- Mata Kuliah: Sistem Komputer dan Jaringan / Digital Forensik
- Dosen Pengampu: Dr. Arya Adhyaksa Waskita, S.Si., M.Si.
- Penyusun: Raihanudin Rafif
- Rujukan Akademis Utama: Oh et al. (2024), "volGPT: Evaluation on triaging ransomware process in memory forensics with Large Language Model", Elsevier - Forensic Science International: Digital Investigation (Scopus Q1).
Alur Pipeline Forensik Hulu ke Hilir (End-to-End): #
- Tahap 1: Akuisisi & Ekstraksi Artefak Memori Kernel Windows (Volatility 3 CLI:
pslist,malfind,netscan,handles,cmdline). - Tahap 2: Konstruksi Heterogeneous In-Memory Threat Graph menggunakan pustaka NetworkX ().
- Tahap 3: Mesin Inferensi Deterministik Pemetaan Taksonomi MITRE ATT&CK Enterprise (T1055, T1036, T1071, T1486, T1490).
- Tahap 4: Formulasi Kuantitatif Composite Threat Score Terbobot ().
- Tahap 5: Visualisasi Interaktif Laporan Triase Langsung di Google Colab (Vis.js Network Engine).
1. Pemasangan Pustaka Dependensi #
Seluruh pustaka pendukung diinstal langsung ke dalam lingkungan komputasi Google Colab, meliputi Volatility 3, NetworkX, dan modul visualisasi.
# Pemasangan dependensi utama di Google Colab
!pip install -q volatility3 networkx jinja2 pandas
import sys
import os
import json
import re
import networkx as nx
from IPython.display import display, HTML
print("[INFO] Pustaka berhasil dipasang:")
print(f" - Python Version : {sys.version.split()[0]}")
print(f" - NetworkX : {nx.__version__}")
print("[OK] Lingkungan komputasi Google Colab siap digunakan.")
[2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m1.4/1.4 MB[0m [31m16.1 MB/s[0m eta [36m0:00:00[0m [2K [90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━[0m [32m74.8/74.8 kB[0m [31m2.7 MB/s[0m eta [36m0:00:00[0m [?25h[INFO] Pustaka berhasil dipasang: - Python Version : 3.13.16 - NetworkX : 3.7 [OK] Lingkungan komputasi Google Colab siap digunakan.
2. Pemilihan Sumber Data Citra Memori (Rujukan Paper & Live Dump)
Notebook ini menyediakan 4 opsi pengujian:
- Opsi 1 (
CONTI_RANSOMWARE): Skenario serangan Conti Ransomware (Penyamaran svchost.exe PID 4812, C2 IP 185.220.101.45, dan VSS deletion). - Opsi 2 (
LOCKBIT_RANSOMWARE): Skenario serangan LockBit 3.0 Ransomware (Process Hollowing pada spoolsv.exe PID 1824, lockbit.exe PID 3320, C2 IP 194.26.29.112, dan ekstensi .lockbit). - Opsi 3 (
SAMSCLASS_MEMDUMP): Eksperimen live Volatility 3 mengunduh citra RAM fisik nyata Samsclass (memdump.memukuran ~17 MB terkompresi). - Opsi 4 (
CUSTOM_FILE): Membaca berkas dump RAM Anda sendiri (.raw / .vmem / .dmp) jika tersedia.
# Konfigurasi Pemilihan Sumber Data
# Pilihan: 'CONTI_RANSOMWARE', 'LOCKBIT_RANSOMWARE', 'SAMSCLASS_MEMDUMP', atau 'CUSTOM_FILE'
SUMBER_DATA = 'CONTI_RANSOMWARE'
# Path jika memilih CUSTOM_FILE (misal diletakkan di Google Drive: '/content/drive/MyDrive/evidence.raw')
CUSTOM_IMAGE_PATH = '/content/evidence.raw'
print(f"[INFO] Mode Sumber Data Terpilih: {SUMBER_DATA}")
[INFO] Mode Sumber Data Terpilih: CONTI_RANSOMWARE
# Pembuatan Folder Kerja dan Penyiapan Data
WORKSPACE_DIR = "/content/dfir_workspace"
os.makedirs(WORKSPACE_DIR, exist_ok=True)
os.makedirs(os.path.join(WORKSPACE_DIR, "output"), exist_ok=True)
artifacts_data = {
"pslist": [],
"malfind": [],
"netscan": [],
"handles": [],
"cmdline": []
}
if SUMBER_DATA == 'CONTI_RANSOMWARE':
print("[INFO] Mengompilasi artefak benchmark Conti Ransomware Incident...")
# 1. pslist
artifacts_data["pslist"] = [
{"PID": 4, "PPID": 0, "ImageFileName": "System", "Offset": "0xfa8001c9b040", "Threads": 142, "Handles": 0, "CreateTime": "2026-10-07 08:00:01"},
{"PID": 368, "PPID": 4, "ImageFileName": "smss.exe", "Offset": "0xfa8002a11040", "Threads": 2, "Handles": 28, "CreateTime": "2026-10-07 08:00:03"},
{"PID": 492, "PPID": 368, "ImageFileName": "csrss.exe", "Offset": "0xfa8002a83040", "Threads": 11, "Handles": 450, "CreateTime": "2026-10-07 08:00:05"},
{"PID": 568, "PPID": 368, "ImageFileName": "wininit.exe", "Offset": "0xfa8002b11040", "Threads": 3, "Handles": 115, "CreateTime": "2026-10-07 08:00:06"},
{"PID": 672, "PPID": 568, "ImageFileName": "services.exe", "Offset": "0xfa8002ba5040", "Threads": 18, "Handles": 490, "CreateTime": "2026-10-07 08:00:07"},
{"PID": 688, "PPID": 568, "ImageFileName": "lsass.exe", "Offset": "0xfa8002be9040", "Threads": 8, "Handles": 850, "CreateTime": "2026-10-07 08:00:07"},
{"PID": 840, "PPID": 672, "ImageFileName": "svchost.exe", "Offset": "0xfa8002c91040", "Threads": 24, "Handles": 380, "CreateTime": "2026-10-07 08:00:10"},
{"PID": 928, "PPID": 672, "ImageFileName": "svchost.exe", "Offset": "0xfa8002d12040", "Threads": 14, "Handles": 210, "CreateTime": "2026-10-07 08:00:12"},
{"PID": 2412, "PPID": 568, "ImageFileName": "explorer.exe", "Offset": "0xfa8003110040", "Threads": 45, "Handles": 1420, "CreateTime": "2026-10-07 08:05:22"},
# PROSES INFILTRASI ANOMALI
{"PID": 4812, "PPID": 2412, "ImageFileName": "svchost.exe", "Offset": "0xfa8003b55040", "Threads": 6, "Handles": 125, "CreateTime": "2026-10-07 09:14:30"},
{"PID": 5924, "PPID": 4812, "ImageFileName": "conti_locker.exe", "Offset": "0xfa8003f19040", "Threads": 32, "Handles": 980, "CreateTime": "2026-10-07 09:18:15"},
{"PID": 6108, "PPID": 5924, "ImageFileName": "powershell.exe", "Offset": "0xfa8004101040", "Threads": 4, "Handles": 82, "CreateTime": "2026-10-07 09:18:40"}
]
# 2. malfind (Injeksi VAD)
artifacts_data["malfind"] = [
{
"PID": 4812,
"Process": "svchost.exe",
"Start_VPN": "0x7fff20000000",
"Protection": "PAGE_EXECUTE_READWRITE",
"CommitCharge": 4,
"HexDump": "4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00 MZ..............\ne8 00 00 00 00 5d 83 ed 0d 89 ea 52 68 00 00 00 .....].....Rh..."
},
{
"PID": 5924,
"Process": "conti_locker.exe",
"Start_VPN": "0x000002050000",
"Protection": "PAGE_EXECUTE_READWRITE",
"CommitCharge": 16,
"HexDump": "55 8b ec 83 ec 14 53 56 57 8b 7d 08 8b 75 0c 8b U.....SVW.}..u..\n45 10 33 c9 85 f6 74 1a 8a 14 0e 88 14 07 41 3b E.3...t.......A;"
}
]
# 3. netscan (Soket C2)
artifacts_data["netscan"] = [
{"Proto": "TCP", "LocalAddr": "192.168.1.105", "LocalPort": 49152, "ForeignAddr": "185.220.101.45", "ForeignPort": 4444, "State": "ESTABLISHED", "PID": 4812, "Owner": "svchost.exe"},
{"Proto": "TCP", "LocalAddr": "192.168.1.105", "LocalPort": 135, "ForeignAddr": "0.0.0.0", "ForeignPort": 0, "State": "LISTENING", "PID": 840, "Owner": "svchost.exe"},
{"Proto": "TCP", "LocalAddr": "192.168.1.105", "LocalPort": 445, "ForeignAddr": "0.0.0.0", "ForeignPort": 0, "State": "LISTENING", "PID": 4, "Owner": "System"},
{"Proto": "TCP", "LocalAddr": "192.168.1.105", "LocalPort": 49210, "ForeignAddr": "91.240.118.172", "ForeignPort": 8080, "State": "SYN_SENT", "PID": 5924, "Owner": "conti_locker.exe"}
]
# 4. handles (File, Mutex)
artifacts_data["handles"] = [
{"PID": 4812, "Type": "Mutant", "Name": "\\BaseNamedObjects\\msagent_beacon_mutex"},
{"PID": 5924, "Type": "Mutant", "Name": "\\BaseNamedObjects\\CONTI_RANSOMWARE_MUTEX_0x44"},
{"PID": 5924, "Type": "File", "Name": "C:\\Users\\Admin\\Documents\\skripsi_final_magister.docx.conti"},
{"PID": 5924, "Type": "File", "Name": "C:\\Users\\Admin\\Documents\\data_keuangan_kampus.xlsx.conti"},
{"PID": 5924, "Type": "File", "Name": "C:\\Users\\Admin\\Desktop\\readme.txt"},
{"PID": 2412, "Type": "File", "Name": "C:\\Windows\\explorer.exe"},
{"PID": 688, "Type": "Key", "Name": "\\REGISTRY\\MACHINE\\SAM\\SAM"}
]
# 5. cmdline
artifacts_data["cmdline"] = [
{"PID": 4812, "Process": "svchost.exe", "Args": "C:\\Windows\\System32\\svchost.exe -k netsvcs -p -s BITS"},
{"PID": 5924, "Process": "conti_locker.exe", "Args": "C:\\Users\\Admin\\AppData\\Local\\Temp\\conti_locker.exe -m net -size 10 -nomutex"},
{"PID": 6108, "Process": "powershell.exe", "Args": "powershell.exe -w hidden -enc dmFkbWluIGRlbGV0ZSBzaGFkb3dzIC9hbGwgL3F1aWV0"}
]
print(f"[OK] Artefak benchmark berhasil dimuat: {len(artifacts_data['pslist'])} proses.")
elif SUMBER_DATA in ['LOCKBIT_RANSOMWARE', 'BENCHMARK_LOCKBIT']:
print("[INFO] Mengompilasi artefak benchmark LockBit 3.0 Ransomware (Keluarga 2 dari Paper volGPT - Elsevier 2024)...")
# 1. pslist (12 proses: spoolsv.exe korban hollowing, powershell dropper, lockbit.exe, cmd.exe)
artifacts_data["pslist"] = [
{"PID": 4, "PPID": 0, "ImageFileName": "System", "Offset": "0xfa8001c9b040", "Threads": 138, "Handles": 0, "CreateTime": "2026-10-08 10:00:01"},
{"PID": 368, "PPID": 4, "ImageFileName": "smss.exe", "Offset": "0xfa8002a11040", "Threads": 2, "Handles": 30, "CreateTime": "2026-10-08 10:00:02"},
{"PID": 492, "PPID": 368, "ImageFileName": "csrss.exe", "Offset": "0xfa8002a83040", "Threads": 10, "Handles": 420, "CreateTime": "2026-10-08 10:00:03"},
{"PID": 568, "PPID": 368, "ImageFileName": "wininit.exe", "Offset": "0xfa8002b11040", "Threads": 3, "Handles": 110, "CreateTime": "2026-10-08 10:00:04"},
{"PID": 672, "PPID": 568, "ImageFileName": "services.exe", "Offset": "0xfa8002ba5040", "Threads": 16, "Handles": 480, "CreateTime": "2026-10-08 10:00:05"},
{"PID": 688, "PPID": 568, "ImageFileName": "lsass.exe", "Offset": "0xfa8002be9040", "Threads": 7, "Handles": 810, "CreateTime": "2026-10-08 10:00:05"},
{"PID": 840, "PPID": 672, "ImageFileName": "svchost.exe", "Offset": "0xfa8002c91040", "Threads": 20, "Handles": 350, "CreateTime": "2026-10-08 10:00:07"},
{"PID": 2110, "PPID": 568, "ImageFileName": "explorer.exe", "Offset": "0xfa8003110040", "Threads": 42, "Handles": 1390, "CreateTime": "2026-10-08 10:05:00"},
# PROSES INFILTRASI LOCKBIT 3.0
{"PID": 1824, "PPID": 672, "ImageFileName": "spoolsv.exe", "Offset": "0xfa8003310040", "Threads": 12, "Handles": 290, "CreateTime": "2026-10-08 10:00:15"},
{"PID": 2840, "PPID": 2110, "ImageFileName": "powershell.exe", "Offset": "0xfa8003710040", "Threads": 5, "Handles": 95, "CreateTime": "2026-10-08 10:12:10"},
{"PID": 3320, "PPID": 2840, "ImageFileName": "lockbit.exe", "Offset": "0xfa8003990040", "Threads": 28, "Handles": 890, "CreateTime": "2026-10-08 10:13:00"},
{"PID": 4012, "PPID": 3320, "ImageFileName": "cmd.exe", "Offset": "0xfa8003bb0040", "Threads": 2, "Handles": 45, "CreateTime": "2026-10-08 10:13:20"}
]
# 2. malfind (Injeksi Process Hollowing pada spoolsv.exe dan biner lockbit.exe)
artifacts_data["malfind"] = [
{
"PID": 1824,
"Process": "spoolsv.exe",
"Start_VPN": "0x000001800000",
"Protection": "PAGE_EXECUTE_READWRITE",
"CommitCharge": 8,
"HexDump": "4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00 MZ.............."
},
{
"PID": 3320,
"Process": "lockbit.exe",
"Start_VPN": "0x000002100000",
"Protection": "PAGE_EXECUTE_READWRITE",
"CommitCharge": 16,
"HexDump": "55 8b ec 83 ec 14 53 56 57 8b 7d 08 8b 75 0c 8b U.....SVW.}..u.."
}
]
# 3. netscan (Koneksi C2 LockBit 3.0)
artifacts_data["netscan"] = [
{"Proto": "TCP", "LocalAddr": "192.168.1.110", "LocalPort": 49188, "ForeignAddr": "194.26.29.112", "ForeignPort": 8443, "State": "ESTABLISHED", "PID": 3320, "Owner": "lockbit.exe"},
{"Proto": "TCP", "LocalAddr": "192.168.1.110", "LocalPort": 135, "ForeignAddr": "0.0.0.0", "ForeignPort": 0, "State": "LISTENING", "PID": 840, "Owner": "svchost.exe"}
]
# 4. handles (File .lockbit, Mutex LockBit, dan Catatan Tebusan)
artifacts_data["handles"] = [
{"PID": 3320, "Type": "Mutant", "Name": "\\BaseNamedObjects\\Global\\{LOCKBIT_3_MUTEX_0x99}"},
{"PID": 3320, "Type": "File", "Name": "C:\\Users\\Admin\\Documents\\laporan_keuangan_q3.xlsx.lockbit"},
{"PID": 3320, "Type": "File", "Name": "C:\\Users\\Admin\\Desktop\\Restore-My-Files.txt"},
{"PID": 2110, "Type": "File", "Name": "C:\\Windows\\explorer.exe"}
]
# 5. cmdline
artifacts_data["cmdline"] = [
{"PID": 2840, "Process": "powershell.exe", "Args": "powershell.exe -ExecutionPolicy Bypass -w hidden -enc JABzACAAPQAgAE4AZQB3AC0ATwBiAGoAZQBjAHQA"},
{"PID": 3320, "Process": "lockbit.exe", "Args": "C:\\Temp\\lockbit.exe -k -pass lockbit3_master_key"},
{"PID": 4012, "Process": "cmd.exe", "Args": "cmd.exe /c vssadmin delete shadows /all /quiet"}
]
print(f"[OK] Artefak LockBit 3.0 berhasil dimuat: {len(artifacts_data['pslist'])} proses.")
elif SUMBER_DATA in ['SAMSCLASS_MEMDUMP', 'DOWNLOAD_PUBLIC_SAMPLE']:
print("[INFO] Mengunduh citra memori publik Samsclass Live RAM Dump (memdump.7z)...")
sample_url = "https://samsclass.info/121/proj/memdump.7z"
os.system("apt-get install -y -q p7zip-full > /dev/null 2>&1")
os.system(f"wget -q -O /content/memdump.7z {sample_url}")
os.system("7z x /content/memdump.7z -o/content/ -y > /dev/null 2>&1")
target_mem = "/content/memdump.mem"
def parse_vol3_output(raw_str):
try:
data = json.loads(raw_str)
if isinstance(data, list) and len(data) > 0 and isinstance(data[0], dict):
first = data[0]
cols_key = "Columns" if "Columns" in first else ("columns" if "columns" in first else None)
rows_key = "Rows" if "Rows" in first else ("rows" if "rows" in first else None)
if cols_key and rows_key:
cols = [c.replace(" ", "_") for c in first[cols_key]]
res = []
for item in data:
for r in item.get(rows_key, []):
res.append(dict(zip(cols, r)))
return res
return data
elif isinstance(data, dict):
cols_key = "Columns" if "Columns" in data else ("columns" if "columns" in data else None)
rows_key = "Rows" if "Rows" in data else ("rows" if "rows" in data else None)
if cols_key and rows_key:
cols = [c.replace(" ", "_") for c in data[cols_key]]
return [dict(zip(cols, r)) for r in data[rows_key]]
except Exception:
pass
return []
if os.path.exists(target_mem):
mem_size_mb = os.path.getsize(target_mem) / (1024 * 1024)
print(f"[OK] Citra memori publik berhasil diekstrak: {target_mem} ({mem_size_mb:.2f} MB)")
print("[INFO] Menjalankan Volatility 3 live (dengan argumen '-r json' yang benar)...")
import subprocess
for plugin in ["pslist", "malfind", "netscan", "cmdline"]:
print(f" -> Mengekstrak windows.{plugin}...")
try:
# Argumen -r json WAJIB diletakkan SEBELUM nama plugin!
res = subprocess.run(["vol", "-f", target_mem, "-r", "json", f"windows.{plugin}"],
capture_output=True, text=True, timeout=180)
parsed = parse_vol3_output(res.stdout) if res.stdout else []
if parsed:
artifacts_data[plugin] = parsed
print(f" [OK] windows.{plugin}: {len(parsed)} baris data dimuat.")
else:
err_msg = res.stderr.strip().splitlines()[-1] if res.stderr.strip() else "Tidak ada data baris"
print(f" [INFO] windows.{plugin}: {err_msg}")
except Exception as e:
print(f" [WARN] Gagal mengekstrak windows.{plugin}: {e}")
else:
print("[ERROR] Berkas /content/memdump.mem tidak ditemukan.")
elif SUMBER_DATA == 'CUSTOM_FILE':
print(f"[INFO] Memeriksa keberadaan berkas citra memori: {CUSTOM_IMAGE_PATH}")
if os.path.exists(CUSTOM_IMAGE_PATH):
print(f"[OK] Berkas ditemukan: {os.path.getsize(CUSTOM_IMAGE_PATH) / (1024*1024):.2f} MB")
print(f"[INFO] Menjalankan Volatility 3 terhadap: {CUSTOM_IMAGE_PATH}...")
import subprocess
for plugin in ["pslist", "malfind", "netscan", "cmdline"]:
try:
res = subprocess.run(["vol", "-f", CUSTOM_IMAGE_PATH, "-r", "json", f"windows.{plugin}"],
capture_output=True, text=True, timeout=180)
parsed = parse_vol3_output(res.stdout) if res.stdout else []
if parsed:
artifacts_data[plugin] = parsed
except Exception as e:
print(f"[WARN] Ekstraksi windows.{plugin} gagal: {e}")
else:
print(f"[WARN] Berkas {CUSTOM_IMAGE_PATH} tidak ditemukan. Silakan unggah terlebih dahulu.")
[INFO] Mengompilasi artefak benchmark Conti Ransomware Incident... [OK] Artefak benchmark berhasil dimuat: 12 proses.
3. Tahap 2: Konstruksi Heterogeneous In-Memory Threat Graph (NetworkX) #
Memodelkan entitas memori RAM sebagai graf terarah :
- Simpul (): Entitas heterogen meliputi Proses (
PROCESS), Ruang Memori Virtual (MEMORY_VAD), Koneksi Soket Jaringan (SOCKET), dan Objek Sistem (HANDLE). - Sisi (): Relasi operasional meliputi hierarki proses (
PARENT_OF), injeksi kode (HAS_INJECTION), koneksi keluar (OPENS_SOCKET), dan pembukaan objek sistem (HOLDS_HANDLE).
# Modul Correlator: Membangun Struktur Graf Ancaman Heterogen
class MemoryThreatGraph:
def __init__(self):
self.graph = nx.DiGraph()
self.process_map = {}
def build_graph(self, artifacts):
self.graph.clear()
self.process_map.clear()
# 1. Tambahkan node PROCESS
for proc in artifacts.get("pslist", []):
pid = int(proc.get("PID", 0))
ppid = int(proc.get("PPID", 0))
name = proc.get("ImageFileName", proc.get("Process", "unknown.exe"))
create_time = str(proc.get("CreateTime", ""))
proc_data = {
"id": f"PROC_{pid}",
"type": "PROCESS",
"pid": pid,
"ppid": ppid,
"name": name,
"create_time": create_time,
"cmdline": "",
"injections": [],
"sockets": [],
"handles": [],
"threat_score": 0,
"mitre_techniques": []
}
self.process_map[pid] = proc_data
self.graph.add_node(
f"PROC_{pid}",
node_type="PROCESS",
label=f"{name} ({pid})",
pid=pid,
ppid=ppid,
name=name
)
# 2. Hubungkan relasi hierarki (PARENT_OF)
for pid, proc in self.process_map.items():
ppid = proc["ppid"]
if ppid in self.process_map:
self.graph.add_edge(f"PROC_{ppid}", f"PROC_{pid}", relation="PARENT_OF", label="spawns")
# 3. Integrasikan CMDLINE
for cmd in artifacts.get("cmdline", []):
pid = int(cmd.get("PID", 0))
args = str(cmd.get("Args") or cmd.get("CommandLine") or "")
if pid in self.process_map:
self.process_map[pid]["cmdline"] = args
self.graph.nodes[f"PROC_{pid}"]["cmdline"] = args
# 4. Integrasikan INJEKSI MEMORI (malfind)
for idx, mal in enumerate(artifacts.get("malfind", [])):
pid = int(mal.get("PID", 0))
start_vpn = str(mal.get("Start_VPN") or mal.get("StartVPN") or "0x0")
prot = str(mal.get("Protection") or "UNKNOWN")
vad_id = f"VAD_{pid}_{idx}"
vad_data = {"id": vad_id, "start_vpn": start_vpn, "protection": prot}
self.graph.add_node(vad_id, node_type="MEMORY_VAD", label=f"VAD [{prot}]", protection=prot)
if pid in self.process_map:
self.process_map[pid]["injections"].append(vad_data)
self.graph.add_edge(f"PROC_{pid}", vad_id, relation="HAS_INJECTION", label="injected")
# 5. Integrasikan SOKET JARINGAN (netscan)
for idx, net in enumerate(artifacts.get("netscan", [])):
pid = int(net.get("PID", 0))
for_ip = str(net.get("ForeignAddr") or net.get("ForeignIP") or "0.0.0.0")
for_port = str(net.get("ForeignPort") or "0")
sock_id = f"SOCK_{pid}_{idx}"
sock_data = {"id": sock_id, "foreign_ip": for_ip, "foreign_port": for_port, "proto": net.get("Proto", "TCP")}
self.graph.add_node(sock_id, node_type="SOCKET", label=f"Socket -> {for_ip}:{for_port}", foreign_ip=for_ip, foreign_port=for_port)
if pid in self.process_map:
self.process_map[pid]["sockets"].append(sock_data)
self.graph.add_edge(f"PROC_{pid}", sock_id, relation="OPENS_SOCKET", label="connects")
# 6. Integrasikan HANDLES
for idx, hdl in enumerate(artifacts.get("handles", [])):
pid = int(hdl.get("PID", 0))
h_type = str(hdl.get("Type") or "")
name = str(hdl.get("Name") or "")
if not name or any(skip in name.lower() for skip in ["\\knowndlls\\", "\\device\\ksecdd"]):
continue
hdl_id = f"HDL_{pid}_{idx}"
hdl_data = {"id": hdl_id, "type": h_type, "name": name}
self.graph.add_node(hdl_id, node_type="HANDLE", label=f"{h_type}: {name[:25]}", name=name)
if pid in self.process_map:
self.process_map[pid]["handles"].append(hdl_data)
self.graph.add_edge(f"PROC_{pid}", hdl_id, relation="HOLDS_HANDLE", label="holds")
return self.graph
threat_graph = MemoryThreatGraph()
nx_g = threat_graph.build_graph(artifacts_data)
print(f"[OK] Heterogeneous Threat Graph terbangun: {nx_g.number_of_nodes()} Nodes, {nx_g.number_of_edges()} Edges.")
[OK] Heterogeneous Threat Graph terbangun: 25 Nodes, 24 Edges.
4. Tahap 3: Mesin Inferensi Deterministik MITRE ATT&CK
Mengevaluasi simpul proses dan relasinya terhadap taksonomi formal MITRE ATT&CK Enterprise Matrix v14:
- T1055.001: Process Injection (DLL Injection) melalui proteksi VAD
PAGE_EXECUTE_READWRITE. - T1036: Masquerading (Abnormal Parent-Child Hierarchy) melalui pelanggaran silsilah kernel Windows.
- T1071.001: Application Layer Protocol (Command and Control) melalui koneksi keluar ke IP publik asing.
- T1486: Data Encrypted for Impact melalui deteksi mutex unik atau ekstensi ransomware.
- T1490: Inhibit System Recovery melalui deteksi eksekusi
vssadmin delete shadows.
# Modul MITRE ATT&CK Mapper (Sistem Pakar Deterministik)
class MitreAttackMapper:
STANDARD_SYSTEM_PARENTS = {
"smss.exe": ["System"],
"csrss.exe": ["smss.exe"],
"wininit.exe": ["smss.exe"],
"services.exe": ["wininit.exe"],
"lsass.exe": ["wininit.exe"],
"svchost.exe": ["services.exe"],
"explorer.exe": ["userinit.exe", "winlogon.exe"]
}
RANSOMWARE_EXTS = [".conti", ".lockbit", ".wnry", ".crypted", ".locked"]
RANSOM_NOTES = ["readme.txt", "how_to_decrypt", "restore_files"]
def evaluate_process(self, proc_data, process_map):
techs = []
name = str(proc_data.get("name") or "").lower()
cmdline = str(proc_data.get("cmdline") or "").lower()
injections = proc_data.get("injections", [])
sockets = proc_data.get("sockets", [])
handles = proc_data.get("handles", [])
ppid = proc_data.get("ppid", 0)
# 1. T1055.001: Process Injection (RWX)
for vad in injections:
prot = str(vad.get("protection") or "").upper()
if "EXECUTE_READWRITE" in prot or "EXECUTE_WRITECOPY" in prot:
techs.append({
"id": "T1055.001",
"tactic": "Defense Evasion, Privilege Escalation",
"name": "Dynamic-link Library Injection",
"evidence": f"Alokasi memori VAD {vad.get('start_vpn')} memiliki hak akses berbahaya: {prot}."
})
break
# 2. T1036: Masquerading (Parent Anomaly)
parent_proc = process_map.get(ppid, {})
parent_name = str(parent_proc.get("name") or "").lower()
if name in self.STANDARD_SYSTEM_PARENTS:
expected = [p.lower() for p in self.STANDARD_SYSTEM_PARENTS[name]]
if parent_name and parent_name not in expected:
techs.append({
"id": "T1036",
"tactic": "Defense Evasion",
"name": "Masquerading (Abnormal Parent Hierarchy)",
"evidence": f"Proses '{name}' dilahirkan oleh {parent_name} (PID {ppid}), seharusnya oleh {expected}."
})
# 3. T1071.001: C2 Communication
for sock in sockets:
for_ip = str(sock.get("foreign_ip") or "")
for_port = str(sock.get("foreign_port") or "0")
if for_ip and not for_ip.startswith("127.") and not for_ip.startswith("0.0.0.0"):
if for_port in ["4444", "8080", "8443", "1337", "9001", "80", "443"]:
techs.append({
"id": "T1071.001",
"tactic": "Command and Control",
"name": "Web Protocols: Command & Control",
"evidence": f"Koneksi aktif ke IP C2 luar: {for_ip}:{for_port}."
})
break
# 4. T1486: Ransomware Handles
for hdl in handles:
h_name = str(hdl.get("name") or "").lower()
if any(ext in h_name for ext in self.RANSOMWARE_EXTS) or any(note in h_name for note in self.RANSOM_NOTES):
techs.append({
"id": "T1486",
"tactic": "Impact",
"name": "Data Encrypted for Impact (Ransomware)",
"evidence": f"Proses memegang file handle ransomware: '{hdl.get('name')}'."
})
break
# 5. T1490: Inhibit System Recovery
if "vssadmin" in cmdline and "delete" in cmdline and "shadows" in cmdline:
techs.append({
"id": "T1490",
"tactic": "Impact",
"name": "Inhibit System Recovery",
"evidence": f"Perintah pemusnahan Shadow Copies Windows: '{cmdline}'."
})
# 6. T1059.001: Encoded Scripting
if "powershell" in name or "powershell" in cmdline:
if any(flg in cmdline for flg in ["-enc", "-w hidden", "-nop"]):
techs.append({
"id": "T1059.001",
"tactic": "Execution",
"name": "Command and Scripting: PowerShell",
"evidence": f"Eksekusi PowerShell terselubung: '{cmdline}'."
})
# Deduplikasi
unique_t = []
seen = set()
for t in techs:
if t["id"] not in seen:
seen.add(t["id"])
unique_t.append(t)
return unique_t
mitre_mapper = MitreAttackMapper()
print("[OK] Mesin Inferensi Deterministik MITRE ATT&CK siap.")
[OK] Mesin Inferensi Deterministik MITRE ATT&CK siap.
5. Tahap 4: Formulasi Kuantitatif Composite Threat Score #
Skor ancaman komposit untuk setiap proses dirumuskan sebagai:
Dengan bobot indikator empiris:
- : Injeksi Memori VAD dengan proteksi
PAGE_EXECUTE_READWRITE(RWX). - : Koneksi soket aktif ke alamat IP C2 eksternal.
- : Penyamaran hierarki proses / PPID anomali (Masquerading).
- : Handle berkas ekstensi ransomware / ransom note.
- : Perintah penghapusan salinan bayangan (vssadmin delete shadows).
- : Eksekusi skrip terselubung / Base64 Encoded PowerShell.
# Modul Threat Scorer: Kalkulator Skor Risiko Komposit
class ThreatScorer:
WEIGHTS = {
"rwx_injection": 35,
"c2_socket": 25,
"masquerading": 20,
"ransom_handles": 20,
"inhibit_recovery": 20,
"suspicious_script": 15
}
def calculate_score(self, proc_data, mitre_techniques):
score = 0
indicators = []
t_ids = [t["id"] for t in mitre_techniques]
if "T1055.001" in t_ids:
score += self.WEIGHTS["rwx_injection"]
indicators.append("Injeksi VAD RWX (+35)")
if "T1071.001" in t_ids:
score += self.WEIGHTS["c2_socket"]
indicators.append("Koneksi C2 Aktif (+25)")
if "T1036" in t_ids:
score += self.WEIGHTS["masquerading"]
indicators.append("Masquerading / Anomali PPID (+20)")
if "T1486" in t_ids:
score += self.WEIGHTS["ransom_handles"]
indicators.append("Handle File/Mutex Ransomware (+20)")
if "T1490" in t_ids:
score += self.WEIGHTS["inhibit_recovery"]
indicators.append("Pemusnahan Backup Windows (+20)")
if "T1059.001" in t_ids:
score += self.WEIGHTS["suspicious_script"]
indicators.append("Skrip PowerShell Terselubung (+15)")
final_score = min(100, score)
if final_score >= 75:
severity = "CRITICAL"
badge_color = "#DC2626"
elif final_score >= 50:
severity = "HIGH"
badge_color = "#EA580C"
elif final_score >= 25:
severity = "MEDIUM"
badge_color = "#EAB308"
else:
severity = "LOW"
badge_color = "#10B981"
return {"score": final_score, "severity": severity, "badge_color": badge_color, "indicators": indicators}
def score_all(self, process_map, mapper):
compromised = []
stats = {"total": len(process_map), "critical": 0, "high": 0, "medium": 0, "low": 0}
for pid, proc in process_map.items():
techs = mapper.evaluate_process(proc, process_map)
proc["mitre_techniques"] = techs
res = self.calculate_score(proc, techs)
proc["threat_score"] = res["score"]
proc["severity"] = res["severity"]
proc["badge_color"] = res["badge_color"]
proc["indicators"] = res["indicators"]
if res["severity"] == "CRITICAL":
stats["critical"] += 1
compromised.append(proc)
elif res["severity"] == "HIGH":
stats["high"] += 1
compromised.append(proc)
elif res["severity"] == "MEDIUM":
stats["medium"] += 1
else:
stats["low"] += 1
compromised.sort(key=lambda x: x["threat_score"], reverse=True)
stats["compromised"] = len(compromised)
stats["top_compromised"] = compromised
return stats
scorer = ThreatScorer()
process_map = threat_graph.process_map
eval_results = scorer.score_all(process_map, mitre_mapper)
print("================ HASIL EVALUASI TRIASE FORENSIK ================")
print(f" Total Proses Diinspeksi : {eval_results['total']}")
print(f" Proses Terinfeksi/Kritis: {eval_results['compromised']}")
print(f" Rincian Tingkat Risiko : {eval_results['critical']} CRITICAL | {eval_results['high']} HIGH | {eval_results['medium']} MEDIUM | {eval_results['low']} LOW")
print("----------------------------------------------------------------")
for p in eval_results["top_compromised"]:
print(f"[ALERT] PID {p['pid']} - {p['name']} [SKOR: {p['threat_score']}/100 - {p['severity']}]")
print(f" Induk (PPID): {p['ppid']} | Waktu Buat: {p['create_time']}")
for t in p["mitre_techniques"]:
print(f" -> [{t['id']}] {t['name']}: {t['evidence']}")
if p.get("cmdline"):
print(f" -> CMDLINE: {p['cmdline']}")
================ HASIL EVALUASI TRIASE FORENSIK ================
Total Proses Diinspeksi : 12
Proses Terinfeksi/Kritis: 2
Rincian Tingkat Risiko : 2 CRITICAL | 0 HIGH | 0 MEDIUM | 10 LOW
----------------------------------------------------------------
[ALERT] PID 4812 - svchost.exe [SKOR: 80/100 - CRITICAL]
Induk (PPID): 2412 | Waktu Buat: 2026-10-07 09:14:30
-> [T1055.001] Dynamic-link Library Injection: Alokasi memori VAD 0x7fff20000000 memiliki hak akses berbahaya: PAGE_EXECUTE_READWRITE.
-> [T1036] Masquerading (Abnormal Parent Hierarchy): Proses 'svchost.exe' dilahirkan oleh explorer.exe (PID 2412), seharusnya oleh ['services.exe'].
-> [T1071.001] Web Protocols: Command & Control: Koneksi aktif ke IP C2 luar: 185.220.101.45:4444.
-> CMDLINE: C:\Windows\System32\svchost.exe -k netsvcs -p -s BITS
[ALERT] PID 5924 - conti_locker.exe [SKOR: 80/100 - CRITICAL]
Induk (PPID): 4812 | Waktu Buat: 2026-10-07 09:18:15
-> [T1055.001] Dynamic-link Library Injection: Alokasi memori VAD 0x000002050000 memiliki hak akses berbahaya: PAGE_EXECUTE_READWRITE.
-> [T1071.001] Web Protocols: Command & Control: Koneksi aktif ke IP C2 luar: 91.240.118.172:8080.
-> [T1486] Data Encrypted for Impact (Ransomware): Proses memegang file handle ransomware: 'C:\Users\Admin\Documents\skripsi_final_magister.docx.conti'.
-> CMDLINE: C:\Users\Admin\AppData\Local\Temp\conti_locker.exe -m net -size 10 -nomutex
6. Tahap 5: Visualisasi Graf Rantai Serangan Interaktif (Vis.js Network) #
Graf di bawah ini dirender secara interaktif langsung di dalam Google Colab.
- Simpul Merah: Proses Kritis Terkompromi.
- Simpul Merah Muda: Wilayah Injeksi Memori VAD RWX.
- Simpul Oranye: Koneksi Soket C2 Aktif.
- Simpul Hijau: Berkas Ransomware / Mutex yang Terkunci.
- Anda dapat melakukan Zoom in/out, Menggeser (Drag), dan Mengklik Simpul untuk inspeksi bukti mendalam.
# Modul Visualisasi Graf Interaktif Vis.js di Colab
def render_colab_dashboard(nx_graph, process_map, eval_results):
nodes_data = []
edges_data = []
for n, data in nx_graph.nodes(data=True):
n_type = data.get("node_type", "UNKNOWN")
threat_score = 0
if n_type == "PROCESS":
pid = data.get("pid", 0)
threat_score = process_map.get(pid, {}).get("threat_score", 0)
# Penentuan visual node
if n_type == "PROCESS":
color = "#DC2626" if threat_score >= 75 else ("#EA580C" if threat_score >= 50 else "#3B82F6")
shape = "box"
size = 28 if threat_score >= 75 else 20
elif n_type == "MEMORY_VAD":
color = "#F43F5E"
shape = "dot"
size = 18
elif n_type == "SOCKET":
color = "#F59E0B"
shape = "diamond"
size = 18
elif n_type == "HANDLE":
color = "#10B981"
shape = "triangle"
size = 16
else:
color = "#64748B"
shape = "ellipse"
size = 14
nodes_data.append({
"id": n,
"label": data.get("label", n),
"group": n_type,
"shape": shape,
"size": size,
"color": {"background": color, "border": "#FFFFFF", "highlight": {"background": "#FBBF24", "border": "#FFFFFF"}},
"font": {"color": "#FFFFFF", "size": 12, "face": "monospace"}
})
for u, v, data in nx_graph.edges(data=True):
rel = data.get("relation", "")
edges_data.append({
"from": u,
"to": v,
"label": data.get("label", ""),
"arrows": "to",
"color": {"color": "#EF4444" if "INJECTION" in rel or "SOCKET" in rel else "#64748B", "highlight": "#FBBF24"},
"font": {"color": "#94A3B8", "size": 10, "align": "middle"},
"smooth": {"type": "curvedCW", "roundness": 0.2}
})
nodes_json = json.dumps(nodes_data)
edges_json = json.dumps(edges_data)
html_content = f'''
<div style="background-color: #0B0F19; color: #F8FAFC; padding: 20px; border-radius: 12px; font-family: sans-serif;">
<div style="display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #334155; padding-bottom: 12px; margin-bottom: 16px;">
<div>
<h2 style="margin: 0; color: #FFFFFF;">Interactive In-Memory Threat Graph (Colab View)</h2>
<p style="margin: 4px 0 0 0; color: #94A3B8; font-size: 13px;">Visualisasi Korelasi Relasi Proses, VAD RWX, Soket C2, dan File Mutex</p>
</div>
<div style="display: flex; gap: 12px;">
<span style="background: #DC2626; padding: 6px 12px; border-radius: 6px; font-weight: bold; font-size: 12px;">CRITICAL: {eval_results['critical']}</span>
<span style="background: #EA580C; padding: 6px 12px; border-radius: 6px; font-weight: bold; font-size: 12px;">HIGH: {eval_results['high']}</span>
<span style="background: #3B82F6; padding: 6px 12px; border-radius: 6px; font-weight: bold; font-size: 12px;">TOTAL PROSES: {eval_results['total']}</span>
</div>
</div>
<div id="vis_network" style="width: 100%; height: 500px; background-color: #151D2F; border: 1px solid #334155; border-radius: 8px;"></div>
<div style="margin-top: 16px; font-size: 12px; color: #94A3B8; display: flex; gap: 20px;">
<div><span style="display:inline-block; width:12px; height:12px; background:#DC2626; margin-right:6px;"></span>Kotak Merah: Proses Kritis</div>
<div><span style="display:inline-block; width:12px; height:12px; background:#F43F5E; border-radius:50%; margin-right:6px;"></span>Lingkaran Pink: Injeksi VAD RWX</div>
<div><span style="display:inline-block; width:12px; height:12px; background:#F59E0B; transform:rotate(45deg); margin-right:6px;"></span>Diamond Oranye: Soket C2</div>
<div><span style="display:inline-block; width:12px; height:12px; background:#10B981; margin-right:6px;"></span>Segitiga Hijau: File/Mutex</div>
</div>
</div>
<script type="text/javascript" src="https://unpkg.com/vis-network/standalone/umd/vis-network.min.js"></script>
<script type="text/javascript">
var container = document.getElementById('vis_network');
var data = {{
nodes: new vis.DataSet({nodes_json}),
edges: new vis.DataSet({edges_json})
}};
var options = {{
physics: {{
stabilization: true,
barnesHut: {{
gravitationalConstant: -3500,
springLength: 90,
springConstant: 0.04
}}
}},
interaction: {{
hover: true,
navigationButtons: true,
keyboard: true
}}
}};
var network = new vis.Network(container, data, options);
</script>
'''
return HTML(html_content)
# Render Visual Graf Langsung di Sel Google Colab
render_colab_dashboard(nx_g, process_map, eval_results)
7. Rekomendasi Tindakan Tanggap Insiden (DFIR Action Checklist) #
Berdasarkan hasil pemetaan MITRE ATT&CK dan nilai Composite Threat Score, tindakan terarah (Containment & Eradication) dapat segera diambil:
- Isolasi Jaringan Segera: Putus antarmuka jaringan host untuk memutus sesi aktif C2 ke IP
185.220.101.45. - Terminasi Pohon Proses Malicious: Matikan secara paksa (kill process tree)
svchost.exe(PID 4812) beserta seluruh anak prosesnya (conti_locker.exePID 5924 danpowershell.exePID 6108). - Pencabutan Kunci Enkripsi di Memori: Periksa dump memori VAD
0x000002050000untuk mengekstrak artefak kunci enkripsi simetris sebelum sistem di-reboot. - Indikator Kompromi (IoC): Daftarkan IP C2 dan hash injeksi ke dalam firewall dan SIEM internal instansi.