
Tabla de Contenidos
Los sistemas de computación modernos a menudo cuentan con CPU y GPU fuertemente integrados, con memoria y recursos microarquitectónicos compartidos. Aunque esta integración ofrece inmensos beneficios de rendimiento, también conlleva riesgos significativos en forma de canales laterales y canales encubiertos. Estos permiten a los atacantes exfiltrar información entre componentes, eludiendo el aislamiento tradicional de procesos.
Este artículo ofrece una revisión técnica detallada de los canales encubiertos entre componentes en CPUs integradas, centrándose especialmente en aquellos que explotan componentes microarquitectónicos compartidos—cachés, predictores de bifurcación y otros. Exploraremos fundamentos teóricos, factibilidad del mundo real, demostraciones de código y estrategias de mitigación actuales. Ya sea que seas un principiante en seguridad o un investigador avanzado, esta guía cubrirá modelos de amenaza, PoC prácticos y las mejores prácticas de defensa.
Un canal encubierto es una vía de comunicación que no fue diseñada para la transferencia de información. En computación, el término a menudo se refiere a situaciones donde un proceso (el emisor, o proceso "alto") transmite deliberadamente información a otro proceso (el receptor, o proceso "bajo") de una manera que está prohibida por la política de seguridad.
Los canales encubiertos no se limitan al tráfico de red. Muchos existen en capas de sistema más bajas, incluyendo canales de almacenamiento (usando archivos, temporización de memoria, etc.) y canales de temporización (diferencias en la disponibilidad de recursos).
Las CPUs y GPUs modernas utilizan recursos compartidos para la rapidez:
Cuando dos procesos comparten estos recursos, pueden señalizar información usando cambios en el estado o temporización del hardware compartido, incluso cuando no se permite comunicación directa.
Los canales encubiertos más notorios son los basados en caché:
Ambos ataques explotan la naturaleza compartida de las cachés multinivel de la CPU, especialmente la última caché de nivel (LLC).
Las CPUs modernas usan predictores de bifurcación para acelerar la ejecución. Estos predictores son compartidos entre procesos y, a veces, entre núcleos. Si un emisor entrena el predictor, el receptor puede probar y observar cambios en la predicción, permitiendo la transmisión de datos.
Ver: "Covert channels through branch predictors: a feasibility study"
Los sistemas integrados de CPU-GPU comparten DRAM y, a veces, incluso componentes más granulados (e.g., LLC, buses del sistema). Esta compartición de recursos entre componentes abre nuevas y en gran medida inexploradas superficies de ataque:
La investigación académica examina ataques donde la CPU y la GPU, o diferentes procesos ejecutándose en cualquiera de ellos, forman un canal encubierto a través de líneas de caché o ancho de banda de memoria compartidos (Leaky Buddies).
clflush).Punto Clave: Las diferencias de tiempo revelan las acciones del emisor.
Usado principalmente en entornos de nube, donde la memoria compartida puede no existir.
Ver "Covert channels through branch predictors: a feasibility study" para la demostración del ataque.
Comienza reuniendo información sobre caché de CPU y predictores de bifurcación.
# Lista detalles de caché de CPU
lscpu | grep -i cache
# Avanzado: analiza tamaños de caché de CPU directamente
cat /proc/cpuinfo | grep -E 'cache size|model name'
# Lista bibliotecas compartidas mapeadas por un proceso
pidof firefox # Por ejemplo
cat /proc/<pid>/maps | grep r-xp | grep 'lib'
# Python: Analiza para buscar regiones de objeto compartido
import os
pid = <your_pid>
with open(f"/proc/{pid}/maps") as f:
for line in f:
if 'lib' in line and 'r-xp' in line:
print(line.strip())
// gcc -O2 -o flush_reload flush_reload.c
#include <stdio.h>
#include <stdint.h>
#include <x86intrin.h>
uint64_t measure_access_time(volatile char *addr) {
uint64_t start = __rdtscp(&start);
*(volatile char *)addr;
uint64_t end = __rdtscp(&end);
return end - start;
}
int main() {
char *ptr = ...; // map to shared object
while (1) {
_mm_clflush(ptr); // Emisor: o omitir para Receptor
uint64_t t = measure_access_time(ptr);
printf("Access time: %lu\n", t);
}
}
import ctypes
import time
# Mapea una biblioteca/archivo compartido, p.ej., vía mmap
libc = ctypes.CDLL("libc.so.6")
address = ctypes.c_void_p(...)
def measure_access_time(addr):
t1 = time.perf_counter_ns()
dummy = ctypes.c_char.from_address(addr.value)
val = dummy.value
t2 = time.perf_counter_ns()
return t2 - t1
while True:
t = measure_access_time(address)
print(f"Access time: {t}ns")
// Pseudocódigo para emisor y receptor en ataque del predictor de bifurcación
// Bit de datos para comunicar: 0 o 1
// Emisor: "entrena" el predictor de bifurcación
if (bit_to_send == 1) {
for (int i = 0; i < 1000; i++) { if (cond) foo(); }
} else {
for (int i = 0; i < 1000; i++) { if (!cond) foo(); }
}
// Receptor: mide tiempo de error de predicción de bifurcación
uint64_t t1 = rdtscp();
if (cond) foo();
uint64_t t2 = rdtscp();
uint64_t elapsed = t2 - t1;
if (elapsed > THRESHOLD) decode as bit 1 else 0;
Nota: Ninguna mitigación es perfecta—los compromisos involucran rendimiento/seguridad.
Estos representan un superconjunto de canales laterales/encubiertos, explotando ejecución especulativa (Spectre, Meltdown) y otras instrucciones ejecutadas transitoriamente para filtrar estado a través de canales microarquitectónicos:
Ver la serie de conferencias "Side Channels and Transient Execution" para desgloses visuales/temporales.
perf stat ...)# Monitorea fallos de caché y errores de predicción de bifurcación
sudo perf stat -e cache-misses,branch-misses ./your_app
import psutil
# Monitorea el uso de caché y CPU de cada proceso con el tiempo
for proc in psutil.process_iter(['pid', 'name', 'cpu_percent']):
print(proc.info)
Los canales encubiertos entre componentes subrayan un riesgo crítico y persistente en la seguridad microarquitectónica. A medida que las CPUs y GPUs se vuelven más integradas, la frontera en la que los datos secretos pueden filtrarse se amplía, desde cachés compartidas de CPU hasta predictores de bifurcación sofisticados y hacia recursos compartidos entre CPU-GPU.
Las defensas requieren esfuerzos coordinados de hardware, SO y software—y siempre vienen con costos de rendimiento. Cuanto más profundo el ataque, más difícil la elección.
Para los investigadores, continuar enumerando, modelando y mitigando nuevas técnicas de canales encubiertos entre componentes es un proceso continuo. Para las organizaciones, el modelado de amenazas y la conciencia situacional son vitales.
Para las últimas investigaciones y divulgación de vulnerabilidades, monitorea frecuentemente sitios académicos/conferencias de confianza y asesorías CVE.
Si encontraste este contenido valioso, imagina lo que podrías lograr con nuestro programa de capacitación élite integral de 47 semanas. Únete a más de 1.200 estudiantes que han transformado sus carreras con las técnicas de la Unidad 8200.