USB 디바이스 연결 기록 분석은(는) 무엇을 하나요?
사용 시기
- 이동식 저장 장치를 통한 잠재적 데이터 유출을 조사할 때
- 내부자 위협 조사 중 USB 디바이스 사용을 추적할 때
- 규정 준수 감사에서 이동식 미디어 정책 시행을 확인할 때
- USB 연결과 파일 접근·복사 이벤트를 상관 분석할 때
- 사고 대응 중 디바이스 연결 타임라인을 구축할 때
전제 조건
- 포렌식 이미지 또는 추출된 레지스트리 하이브 및 이벤트 로그
- SYSTEM, SOFTWARE, NTUSER.DAT 레지스트리 하이브에 접근 가능
- SetupAPI 로그 (setupapi.dev.log)
- Windows 이벤트 로그 (시스템, 보안, DriverFrameworks-UserMode)
- USBDeview, USB Forensic Tracker 또는 RegRipper
- USB 디바이스 식별(VID, PID, 일련번호)에 대한 이해
워크플로우
1단계: USB 관련 아티팩트 추출
# 포렌식 이미지를 마운트하고 관련 아티팩트 복사
mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/evidence.dd /mnt/evidence
mkdir -p /cases/case-2024-001/usb/
# 레지스트리 하이브
cp /mnt/evidence/Windows/System32/config/SYSTEM /cases/case-2024-001/usb/
cp /mnt/evidence/Windows/System32/config/SOFTWARE /cases/case-2024-001/usb/
cp /mnt/evidence/Users/*/NTUSER.DAT /cases/case-2024-001/usb/
# SetupAPI 로그 (최초 연결 타임스탬프)
cp /mnt/evidence/Windows/INF/setupapi.dev.log /cases/case-2024-001/usb/
# 이벤트 로그
cp /mnt/evidence/Windows/System32/winevt/Logs/System.evtx /cases/case-2024-001/usb/
cp "/mnt/evidence/Windows/System32/winevt/Logs/Microsoft-Windows-DriverFrameworks-UserMode%4Operational.evtx" \
/cases/case-2024-001/usb/ 2>/dev/null
cp "/mnt/evidence/Windows/System32/winevt/Logs/Microsoft-Windows-Partition%4Diagnostic.evtx" \
/cases/case-2024-001/usb/ 2>/dev/null
2단계: USBSTOR 레지스트리 키 파싱
# SYSTEM 하이브에서 USBSTOR 항목 추출
python3 << 'PYEOF'
from Registry import Registry
import json
reg = Registry.Registry("/cases/case-2024-001/usb/SYSTEM")
# 현재 ControlSet 찾기
select = reg.open("Select")
current = select.value("Current").value()
controlset = f"ControlSet{current:03d}"
# USBSTOR 파싱
usbstor_path = f"{controlset}\\Enum\\USBSTOR"
usbstor = reg.open(usbstor_path)
devices = []
print("=== USBSTOR 장치 ===\n")
for device_class in usbstor.subkeys():
# 형식: Disk&Ven_VENDOR&Prod_PRODUCT&Rev_REVISION
class_name = device_class.name()
parts = class_name.split('&')
vendor = parts[1].replace('Ven_', '') if len(parts) > 1 else '알 수 없음'
product = parts[2].replace('Prod_', '') if len(parts) > 2 else '알 수 없음'
revision = parts[3].replace('Rev_', '') if len(parts) > 3 else '알 수 없음'
for instance in device_class.subkeys():
serial = instance.name()
last_write = instance.timestamp()
device_info = {
'vendor': vendor,
'product': product,
'revision': revision,
'serial': serial,
'last_connected': str(last_write),
}
# 친숙한 이름이 있으면 가져오기
try:
friendly = instance.value("FriendlyName").value()
device_info['friendly_name'] = friendly
except:
pass
# 장치 파라미터 가져오기
try:
params = instance.subkey("Device Parameters")
try:
device_info['class_guid'] = params.value("ClassGUID").value()
except:
pass
except:
pass
devices.append(device_info)
print(f"장치: {vendor} {product}")
print(f" 일련번호: {serial}")
print(f" 마지막 연결: {last_write}")
print(f" 친숙한 이름: {device_info.get('friendly_name', 'N/A')}")
print()
# 결과 저장
with open('/cases/case-2024-001/analysis/usb_devices.json', 'w') as f:
json.dump(devices, f, indent=2)
print(f"\n총 USB 저장 장치 발견: {len(devices)}")
PYEOF
3단계: 드라이브 문자 할당 및 사용자 연결 확인
# SYSTEM 하이브에서 MountedDevices 파싱
python3 << 'PYEOF'
from Registry import Registry
import struct
reg = Registry.Registry("/cases/case-2024-001/usb/SYSTEM")
mounted = reg.open("MountedDevices")
print("=== 마운트된 장치 (드라이브 문자 할당) ===\n")
for value in mounted.values():
name = value.name()
data = value.value()
if name.startswith("\\DosDevices\\"):
drive_letter = name.replace("\\DosDevices\\", "")
if len(data) > 24:
# USB 장치 - 장치 경로 문자열 포함
try:
device_path = data.decode('utf-16-le').strip('\x00')
if 'USBSTOR' in device_path or 'USB#' in device_path:
print(f" {drive_letter} -> {device_path}")
except:
pass
else:
# 고정 디스크 - 디스크 서명 + 오프셋 포함
disk_sig = struct.unpack('<I', data[0:4])[0]
offset = struct.unpack('<Q', data[4:12])[0]
print(f" {drive_letter} -> 디스크 서명: 0x{disk_sig:08X}, 오프셋: {offset}")
PYEOF
# 사용자 MountPoints2 파싱 (어느 사용자가 어떤 장치에 접근했는지)
python3 << 'PYEOF'
from Registry import Registry
import os, glob
print("\n=== 사용자 마운트 포인트 (MountPoints2) ===\n")
for ntuser in glob.glob("/cases/case-2024-001/usb/NTUSER*.DAT"):
try:
reg = Registry.Registry(ntuser)
mp2 = reg.open("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MountPoints2")
print(f"사용자 하이브: {os.path.basename(ntuser)}")
for key in mp2.subkeys():
guid = key.name()
last_write = key.timestamp()
if '{' in guid:
print(f" 볼륨: {guid} | 마지막 접근: {last_write}")
print()
except Exception as e:
print(f" {ntuser} 파싱 오류: {e}")
PYEOF
4단계: SetupAPI에서 최초 연결 타임스탬프 추출
# USB 장치 최초 설치 타임스탬프를 위해 setupapi.dev.log 파싱
python3 << 'PYEOF'
import re
print("=== SETUPAPI USB 장치 설치 기록 ===\n")
with open('/cases/case-2024-001/usb/setupapi.dev.log', 'r', errors='ignore') as f:
content = f.read()
# USB 장치 설치 섹션 찾기
pattern = r'>>>\s+\[Device Install.*?\n.*?Section start (\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}).*?\n(.*?)<<<'
matches = re.findall(pattern, content, re.DOTALL)
usb_installs = []
for timestamp, section in matches:
if 'USBSTOR' in section or 'USB\\VID' in section:
# 장치 ID 추출
dev_match = re.search(r'(USBSTOR\\[^\s]+|USB\\VID_\w+&PID_\w+[^\s]*)', section)
if dev_match:
device_id = dev_match.group(1)
usb_installs.append({
'first_install': timestamp,
'device_id': device_id
})
print(f" {timestamp} | {device_id}")
print(f"\n총 USB 설치 항목: {len(usb_installs)}")
PYEOF
# USB 이벤트를 위해 Windows 이벤트 로그 파싱
# 이벤트 ID: 2003, 2010, 2100, 2102 (DriverFrameworks-UserMode)
# 이벤트 ID: 6416 (보안 - 새 외부 장치 인식)
python3 << 'PYEOF'
import json
from evtx import PyEvtxParser
try:
parser = PyEvtxParser("/cases/case-2024-001/usb/System.evtx")
print("\n=== 시스템 이벤트 로그 USB 이벤트 ===\n")
for record in parser.records_json():
data = json.loads(record['data'])
event_id = str(data['Event']['System']['EventID'])
# USB 장치 연결 이벤트
if event_id in ('20001', '20003', '10000', '10100'):
timestamp = data['Event']['System']['TimeCreated']['#attributes']['SystemTime']
event_data = data['Event'].get('UserData', data['Event'].get('EventData', {}))
print(f" [{timestamp}] 이벤트ID {event_id}: {json.dumps(event_data, default=str)[:200]}")
except Exception as e:
print(f"오류: {e}")
PYEOF
5단계: USB 활동 타임라인 및 보고서 작성
# 모든 USB 증거를 통합 타임라인으로 편집
python3 << 'PYEOF'
import json, csv
timeline = []
# USBSTOR 데이터 로드
with open('/cases/case-2024-001/analysis/usb_devices.json') as f:
devices = json.load(f)
for device in devices:
timeline.append({
'timestamp': device['last_connected'],
'source': 'USBSTOR 레지스트리',
'device': f"{device['vendor']} {device['product']}",
'serial': device['serial'],
'event': '마지막 연결',
'detail': device.get('friendly_name', '')
})
# 시간순 정렬
timeline.sort(key=lambda x: x['timestamp'])
# 타임라인 CSV 작성
with open('/cases/case-2024-001/analysis/usb_timeline.csv', 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=['timestamp', 'source', 'device', 'serial', 'event', 'detail'])
writer.writeheader()
writer.writerows(timeline)
print(f"USB 타임라인: {len(timeline)}개 이벤트가 usb_timeline.csv에 기록됨")
# 요약 출력
print("\n=== USB 장치 요약 ===")
for entry in timeline:
print(f" {entry['timestamp']} | {entry['device']} | {entry['serial'][:20]} | {entry['event']}")
PYEOF
주요 개념
| 개념 | 설명 |
|---|---|
| USBSTOR | USB 대용량 저장 장치 식별 및 연결 데이터를 저장하는 레지스트리 키 |
| VID/PID | USB 장치 제조사와 모델을 고유하게 식별하는 공급업체 ID 및 제품 ID |
| 장치 일련번호 | 개별 USB 장치의 고유 식별자 (일부 장치는 일련번호를 공유함) |
| MountedDevices | 볼륨 GUID와 드라이브 문자를 물리적 장치에 매핑하는 레지스트리 키 |
| MountPoints2 | 사용자가 접근한 볼륨을 보여주는 사용자별 레지스트리 키 |
| SetupAPI 로그 | 최초 장치 연결을 기록하는 Windows 드라이버 설치 로그 |
| DeviceContainers | SOFTWARE 하이브 내 장치 메타데이터와 타임스탬프가 있는 레지스트리 키 |
| EMDMgmt | 일련번호와 타임스탬프가 있는 ReadyBoost 호환 장치를 추적하는 레지스트리 키 |
도구 및 시스템
| 도구 | 목적 |
|---|---|
| USB Forensic Tracker | USB 장치 기록 추출 전용 도구 |
| USBDeview | 시스템에 연결된 모든 USB 장치를 나열하는 NirSoft 도구 |
| RegRipper (usbstor 플러그인) | 레지스트리 하이브에서 USB 아티팩트 자동 추출 |
| Registry Explorer | USB 관련 키에 대한 대화형 레지스트리 분석 |
| KAPE | USB 관련 아티팩트 자동 수집 |
| Plaso/log2timeline | USB 연결 이벤트를 포함한 타임라인 생성 |
| FTK Imager | 이동식 미디어를 포함한 포렌식 이미징 |
| Velociraptor | USB 장치 기록 헌팅 아티팩트를 갖춘 엔드포인트 에이전트 |
일반적인 시나리오
시나리오 1: 퇴사 직원에 의한 데이터 유출 USBSTOR 항목을 추출하여 연결된 모든 USB 장치를 식별하고, 장치 일련번호를 MountPoints2와 상관 분석하여 사용자 접근을 확인하며, 타임스탬프를 파일 접근 로그 및 점프 목록 최근 파일과 교차 참조하고, USN 저널에서 대용량 파일 복사 패턴을 확인합니다.
시나리오 2: 보안 시스템 내 무단 장치 모든 USBSTOR 항목을 승인된 장치 목록과 대조 감사하고, 회사 승인 하드웨어와 일치하지 않는 VID/PID로 무단 장치를 식별하며, 무단 장치가 처음 및 마지막으로 연결된 시점을 확인하고, 데이터가 전송되었는지 확인합니다.
시나리오 3: USB를 통한 악성코드 전달 악성코드 실행 직전(프리페치 타임스탬프)에 연결된 USB 장치를 식별하고, 장치 일련번호와 공급업체 정보를 추출하며, 해당 장치에 대해 자동 실행이 활성화되었는지 확인하고, 프리페치 및 ShimCache에서 이동식 드라이브 문자에서의 실행 파일 실행을 찾습니다.
시나리오 4: 여러 시스템에서 특정 USB 드라이브 추적 모든 포렌식 이미지에서 동일한 장치 일련번호를 USBSTOR에서 검색하고, 드라이브가 연결된 시스템과 시점에 대한 지도를 구축하며, 조직 내 장치의 시간순 경로를 식별하고, 네트워크 공유 접근 로그와 상관 분석합니다.
출력 형식
USB 장치 기록 분석:
시스템: DESKTOP-ABC123 (Windows 10 Pro)
총 USB 저장 장치: 12
분석 출처: USBSTOR, MountedDevices, MountPoints2, SetupAPI, 이벤트 로그
장치 목록:
1. Kingston DataTraveler 3.0 (일련번호: 0019E06B4521A2B0)
최초 연결: 2024-01-10 09:15:32 (SetupAPI)
마지막 연결: 2024-01-18 14:30:00 (USBSTOR)
드라이브 문자: E:
사용자 접근: suspect_user (MountPoints2)
2. WD My Passport (일련번호: 575834314131363035)
최초 연결: 2024-01-15 20:00:00
마지막 연결: 2024-01-15 23:45:00
드라이브 문자: F:
사용자 접근: suspect_user
의심되는 발견:
- Kingston 드라이브가 조사 기간 중 15회 연결됨
- WD Passport가 단 한 번만 연결, 늦은 저녁 (비정상 시간)
- 알 수 없는 장치 (VID_1234&PID_5678)가 2024-01-17에 연결됨, 승인된 장치와 일치하지 않음
타임라인: /cases/case-2024-001/analysis/usb_timeline.csv