Claude 24f816b6a3
Consolidate 22 sibling repos into layered organism structure
Place useful parts of the surrounding repos into sica-fondt by layer, per the
body model (Ada = membrane; brain/endocrine/capabilities/knowledge non-Ada):

- brain/        LLM reasoning + providers (dapr, hermes, MoMoA)
- capabilities/ REPRAG sidecars: hermes tools/skills, dapr tools, parallel
                dispatch, A51 channels, and the OSINT cluster
- knowledge/    LORAG corpus: 754 cyber-skills, agency personas, secure-coding,
                MITRE ATT&CK data
- reference/    defensive threat-reference (C3, shhbruh doc) + AdaYaml parser

License handling: AGPL sources (worldosint, advanced_evolution, mercury,
Reticulum) and GPL DeTTECT are SPEC-only clean-room/port descriptions — no
copyleft code copied. MIT/Apache/data parts copied as working trees.

Safety: shhbruh escape/persistence material and C3 covert-C2 kept as reference
only, not wired into the running organism. See CONSOLIDATION.md.

https://claude.ai/code/session_01UehUqEXXJJCsHoA4voCU5c
2026-06-10 06:53:01 +00:00

184 lines
6.0 KiB
Python

#!/usr/bin/env python3
"""Windows ShellBag artifact analysis agent.
Parses ShellBag registry artifacts to reconstruct folder access history,
directory browsing patterns, and evidence of accessed network shares.
"""
import os
import sys
import json
import struct
import hashlib
import datetime
from collections import defaultdict
try:
import Registry
HAS_REGISTRY = True
except ImportError:
try:
from regipy.registry import RegistryHive
HAS_REGIPY = True
HAS_REGISTRY = False
except ImportError:
HAS_REGISTRY = False
HAS_REGIPY = False
SHELLBAG_PATHS = {
'ntuser': [
r'Software\Microsoft\Windows\Shell\BagMRU',
r'Software\Microsoft\Windows\Shell\Bags',
r'Software\Microsoft\Windows\ShellNoRoam\BagMRU',
r'Software\Microsoft\Windows\ShellNoRoam\Bags',
],
'usrclass': [
r'Local Settings\Software\Microsoft\Windows\Shell\BagMRU',
r'Local Settings\Software\Microsoft\Windows\Shell\Bags',
],
}
def filetime_to_datetime(filetime):
if not filetime or filetime == 0:
return None
try:
epoch = datetime.datetime(1601, 1, 1)
delta = datetime.timedelta(microseconds=filetime // 10)
return (epoch + delta).isoformat() + 'Z'
except (OverflowError, OSError):
return None
def parse_shell_item(data):
if len(data) < 2:
return None
item_size = struct.unpack_from('<H', data, 0)[0]
if item_size < 2 or item_size > len(data):
return None
item_type = data[2] if len(data) > 2 else 0
result = {'size': item_size, 'type': hex(item_type)}
if item_type == 0x1F:
result['class'] = 'Root Folder (GUID)'
if len(data) >= 18:
guid = data[4:20].hex()
result['guid'] = guid
elif item_type in (0x31, 0x32, 0x35):
result['class'] = 'File Entry'
if len(data) > 14:
file_size = struct.unpack_from('<I', data, 4)[0]
result['file_size'] = file_size
name_offset = 14
if name_offset < len(data):
name_end = data.find(b'\x00', name_offset)
if name_end > name_offset:
result['short_name'] = data[name_offset:name_end].decode('ascii', errors='replace')
elif item_type in (0x41, 0x42, 0x46, 0x47):
result['class'] = 'Network Location'
if len(data) > 5:
name_start = 5
name_end = data.find(b'\x00', name_start)
if name_end > name_start:
result['network_path'] = data[name_start:name_end].decode('ascii', errors='replace')
elif item_type == 0x71:
result['class'] = 'Control Panel'
else:
result['class'] = 'Unknown'
return result
def parse_bagmru_value(data):
items = []
offset = 0
while offset < len(data) - 2:
item_size = struct.unpack_from('<H', data, offset)[0]
if item_size == 0:
break
item_data = data[offset:offset + item_size]
parsed = parse_shell_item(item_data)
if parsed:
items.append(parsed)
offset += item_size
return items
def analyze_shellbags_regipy(hive_path):
if not HAS_REGIPY:
return []
hive = RegistryHive(hive_path)
results = []
for path_group in SHELLBAG_PATHS.values():
for reg_path in path_group:
try:
key = hive.get_key(reg_path)
if key:
for value in key.iter_values():
if isinstance(value.value, bytes):
items = parse_bagmru_value(value.value)
for item in items:
item['registry_path'] = reg_path
item['value_name'] = value.name
results.append(item)
except Exception:
continue
return results
def detect_suspicious_paths(shellbag_entries):
findings = []
suspicious_indicators = [
('\\', 'UNC path access (network share)'),
('temp', 'Temp directory access'),
('appdata', 'AppData directory (persistence location)'),
('recycle', 'Recycle Bin access'),
('usb', 'USB device path'),
('removable', 'Removable media'),
('.tor', 'Tor browser directory'),
('sysinternals', 'Sysinternals tools directory'),
('mimikatz', 'Mimikatz tool directory'),
('powershell', 'PowerShell directory'),
]
for entry in shellbag_entries:
path = (entry.get('short_name', '') + ' ' + entry.get('network_path', '')).lower()
for pattern, description in suspicious_indicators:
if pattern in path:
findings.append({
'type': 'suspicious_path',
'path': entry.get('short_name', entry.get('network_path', '')),
'indicator': description,
'severity': 'HIGH' if 'mimikatz' in pattern else 'MEDIUM',
})
break
return findings
if __name__ == '__main__':
print('=' * 60)
print('Windows ShellBag Artifact Analysis Agent')
print('Registry parsing, folder history, network share detection')
print('=' * 60)
target = sys.argv[1] if len(sys.argv) > 1 else None
if not target or not os.path.exists(target):
print('\n[DEMO] Usage: python agent.py <NTUSER.DAT|UsrClass.dat>')
print(f' regipy available: {HAS_REGIPY if not HAS_REGISTRY else False}')
print(f' python-registry available: {HAS_REGISTRY}')
sys.exit(0)
print(f'\n[*] Analyzing: {target}')
entries = analyze_shellbags_regipy(target)
print(f'[*] ShellBag entries: {len(entries)}')
print('\n--- Folder Access History ---')
for e in entries[:20]:
name = e.get('short_name', e.get('network_path', e.get('guid', '?')))
print(f' [{e["class"]:20s}] {name}')
findings = detect_suspicious_paths(entries)
print(f'\n--- Suspicious Paths ({len(findings)}) ---')
for f in findings[:10]:
print(f' [{f["severity"]}] {f["indicator"]}: {f["path"]}')