
마이크로아키텍처 채널은 현대 사이버보안의 필수적이지만 자주 오해되는 측면입니다. 네트워킹의 전통적인 측면 채널과 달리, 마이크로아키텍처 채널은 현대 CPU의 저수준 하드웨어 동작을 악용하여 민감한 정보를 유출합니다. 이 블로그 게시물은 이러한 채널이 무엇인지, 어떻게 작동하는지, 왜 위험한지, 그리고 이를 탐지하고 예방하기 위해 취할 수 있는 실질적인 조치를 심도 있게 파헤칩니다. 실제 예제와 코드 샘플도 함께 제공됩니다.
목차
현대의 CPU는 속도, 효율성 및 병렬 처리를 최적화한 공학의 경이로움입니다. 그러나 소프트웨어의 추상화 아래에는 캐시, 메모리 컨트롤러 및 실행 유닛과 같은 물리적 자원을 프로세스가 공유하는 복잡한 시스템이 있습니다. 마이크로아키텍처 채널은 이러한 공유 리소스를 악용하는 통신 경로로, 완화되지 않으면 프로세스 경계를 넘어 비밀을 유출하여 기본 보안 가정을 위반할 수 있습니다.
측면 채널은 소프트웨어 취약점을 직접적으로 이용하지 않고, 대신 시스템 동작의 차이(예: 전력 사용, 타이밍, 캐시 히트/미스)를 관찰하여 비밀을 추론하는 정보 유출 경로입니다. 예를 들어, 공격자는 특정 작업에 소요된 시간을 관찰함으로써 암호화 키를 추론할 수 있습니다.
은닉 채널은 시스템의 보안 정책을 위반하는 방식으로 정보를 전송하는 의사소통 경로입니다. 측면 채널과 달리, 은닉 채널은 일반적으로 정보 교환을 수수께끼처럼 수행하는 두 협력자 간에 의도적으로 사용됩니다.
주요 차이점:
마이크로아키텍처 채널은 프로세스 간 리소스가 공유되는 방식을 악용하여 하드웨어 깊숙이에서 기능하며, 네트워킹 채널은 데이터 전송 매체를 사용합니다.
공유 CPU 리소스를 사용하여 어떻게 공격자가 마이크로아키텍처 은닉(및 측면) 채널을 구축하는지 살펴보겠습니다.
// Prime+Probe의 간소화된 단계
1. 프라임: 특정 캐시 세트를 채우기 위해 캐시 라인에 액세스함
2. 피해자가 실행되도록 둠
3. 프로브: 동일한 캐시 라인에 액세스하고 액세스 시간을 측정함
4. 캐시 미스는 피해자의 액세스로 인한 제거를 의미함
이들은 CPU가 성능을 위해 미래 지시어를 예측할 때 발생하는 추측 실행을 악용합니다. 잘못된 예측은 롤백되지만, 마이크로아키텍처의 부작용(예: 캐시 상태)은 남아, 비밀을 유출합니다.
분기 예측 테이블의 이력을 사용하여, 공격자는 피해자 코드의 흐름을 추론할 수 있습니다.
두 프로세스가 물리적 실행 유닛을 공유하면 경합이 측정 가능한 타이밍 변화를 유발합니다.
프로세스 A(공격자)와 프로세스 B(피해자)가 동일한 기계에서 실행되며 캐시 리소스를 공유한다고 가정해 보겠습니다.
마이크로아키텍처 은닉 채널은 이론적인 것에 그치지 않으며, 현대 컴퓨팅 인프라에 대한 가장 의미 있는 실제 공격을 가능하게 만들었습니다.
클라우드 환경에서 타겟과 동일한 하드웨어에 함께 있는 공격자는 캐시 공격을 사용하여 이웃 VM의 정보를 유출할 수 있습니다.
JavaScript 코드는 시간 간격을 측정하고 공유 캐시 상태를 사용하여 사용자의 브라우저 컨텍스트에서 민감한 데이터를 부분적으로 유출할 수 있습니다.
이 채널을 탐지하는 것은 어렵지만, 몇 가지 실용적인 접근 방식이 존재합니다.
현대 CPU는 캐시 미스, 분기 예측 실패, 실행 지연과 같은 이벤트에 대한 카운터를 제공합니다. 스파이크 또는 비정상적인 패턴은 공격을 시사할 수 있습니다.
관련 이벤트의 예:
cache-referencescache-missesbranch-instructionsbranch-misses고급 운영 체제(및 하이퍼바이저)는 프로세스 타이밍 이상을 모니터링하고 로그 추가하고 분석하여 의심스러운 행동을 식별할 수 있습니다.
최근 연구는 정상 패턴을 모델링하고 이상치를 플래그하여 하드웨어 리소스의 정상 및 악의적인 사용을 구별하기 위해 머신러닝을 활용합니다.
마이크로아키텍처 은닉 채널을 방지하기 위해 종종 하드웨어 및 소프트웨어 접근 방식 모두가 필요합니다.
가능한 타이머의 정밀도를 낮추거나 지터/노이즈를 추가하여 특히 JavaScript 기반 공격의 효과를 줄입니다.
비밀 데이터에 따라 실행 시간이 달라지지 않는 코드를 작성하여 많은 타이밍 채널을 막습니다.
일부 CPU는 이제 파티셔닝 캐시 또는 추측 실행 완화를 통해 "측면 채널 저항" 설계를 포함합니다.
실무자가 오픈소스 도구와 코드를 사용하여 마이크로아키텍처 이상을 스캔하는 방법을 알아보겠습니다.
perf 유틸리티를 사용하여 성능 데이터 수집perf list | grep cache
<pid> 변경)sudo perf stat -e cache-references,cache-misses -p <pid>
104,212 cache-references
12,342 cache-misses
sudo perf record -e cache-misses -p <pid> -- sleep 10
sudo perf report
sudo perf stat -a --per-socket -e cache-misses sleep 5 | grep "cache-misses"
또는 프로세스별:
ps -eo pid,comm | while read pid comm; do
sudo perf stat -p $pid -e cache-misses -I 1000 -- sleep 1 2>&1 | grep cache-misses
done
여러 프로세스를 자동으로 스캔하거나 perf 결과를 파싱하여 이상 탐지를 수행하고 싶다고 가정해 봅시다.
perf stat 출력 파싱하여 의심스러운 캐시 미스 탐지import subprocess
import re
def get_cache_misses(pid):
cmd = ["perf", "stat", "-p", str(pid), "-e", "cache-misses", "--", "sleep", "2"]
result = subprocess.run(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
match = re.search(r"([\d,]+)\s+cache-misses", result.stderr)
if match:
count = int(match.group(1).replace(",", ""))
return count
else:
return None
# 모든 프로세스 스캔
import psutil
for proc in psutil.process_iter(attrs=['pid', 'name']):
pid = proc.info['pid']
name = proc.info['name']
try:
misses = get_cache_misses(pid)
if misses and misses > 100000:
print(f"의심스러움: PID {pid} ({name})가 {misses} 캐시 미스를 기록함")
except Exception:
continue
#!/bin/bash
THRESHOLD=100000
for pid in $(ps -e -o pid=); do
MISS=$(sudo perf stat -p $pid -e cache-misses -- sleep 1 2>&1 | grep cache-misses | awk '{print $1}' | tr -d ',')
if [ ! -z "$MISS" ] && [ "$MISS" -gt "$THRESHOLD" ]; then
echo "경고: PID $pid 높은 캐시 미스 ($MISS)"
fi
done
윤리적이고 법적 이유로, 안전하고 격리된 허가된 테스트 환경에서만 실험하세요.
// 경고: 데모용으로만 사용하세요. 프로덕션 시스템에서 사용하지 마세요.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <x86intrin.h>
#include <unistd.h>
#define CACHE_LINE_SIZE 64
#define PROBE_COUNT 100000
volatile char *array;
void prime_cache() {
for (int i = 0; i < 4096; i += CACHE_LINE_SIZE)
_mm_clflush(&array[i]);
}
int probe_cache() {
int sum = 0;
uint64_t start, end;
for (int i = 0; i < 4096; i += CACHE_LINE_SIZE) {
start = __rdtscp(&i);
volatile char x = array[i];
end = __rdtscp(&i);
sum += (end - start);
}
return sum;
}
int main() {
array = malloc(4096);
for (int i = 0; i < PROBE_COUNT; i++) {
prime_cache();
usleep(1); // "피해자" 실행
int timing = probe_cache();
printf("%d\n", timing);
}
free((void *)array);
return 0;
}
설명:
이 코드는 "피해자"가 실행되기 전후에 캐시 액세스 시간을 측정하여, 캐시가 다른 프로세스에 의해 사용되었는지를 추론합니다 — 많은 마이크로아키텍처 공격의 기본 아이디어입니다.
마이크로아키텍처 채널은 멀티코어 및 클라우드 컴퓨팅 시대에 정보 보안에 대한 독특하고 점점 더 중요한 위협을 나타냅니다. 전통적인 네트워크 기반 측면 채널과 달리, 이러한 공격은 물리적 하드웨어 리소스의 복잡한 공유를 악용합니다. 이 분야는 빠르게 진화하고 있으며, 모든 실무자는 기본 및 고급 의미를 이해해야 합니다.
중요 사항:
perf), OS 강화 및 코딩 관행을 사용하여 탐지하고 방어하세요.보안이 중요한 환경 — 클라우드, 브라우저, 암호화 앱 — 에서는 마이크로아키텍처 보안에 주의를 기울이는 것이 선택 사항이 아닙니다.
이 글은 교육 목적으로 작성되었습니다. 보안 연구를 수행할 때 항상 윤리적 지침과 현지 규정을 준수하세요.
이 콘텐츠가 유용하다고 생각하셨다면, 저희의 포괄적인 47주 엘리트 교육 프로그램으로 무엇을 달성할 수 있을지 상상해 보세요. Unit 8200 기술로 경력을 변화시킨 1,200명 이상의 학생들과 함께하세요.