1 puntos por GN⁺ 2024-02-24 | 1 comentarios | Compartir por WhatsApp
  • Al activar el controlador xDCI oculto de una ThinkPad X1 Carbon 6th Gen, la propia laptop pudo emular dispositivos USB arbitrarios, como un teclado o una unidad de almacenamiento
  • La pista fue /sys/class/usb_role/intel_xhci_usb_sw-role-switch, pero cambiar solo el rol de xHCI no alcanzaba: también tenía que exponerse como dispositivo PCIe un UDC xDCI basado en DWC3 independiente
  • En la imagen del BIOS había una opción xDCI Support, pero estaba oculta en la interfaz de configuración predeterminada; tras activarla, aparecieron en lspci el xDCI 8086:9d30 y el driver dwc3-pci
  • El método que funcionó fue desbloquear la página Advanced del BIOS y parchar la NVRAM; reconfigurar los registros del PCH solo logró algunos cambios en el PMC y falló por el bloqueo del PSF
  • Después de activar xDCI, g_mass_storage, Raw Gadget, reproductores de syzkaller y un backend de Facedancer funcionaron sin hardware externo, aunque hacen falta un cable USB con VBUS desconectado y cambiar el rol a device

La pista del modo de dispositivo USB encontrada en una ThinkPad

  • Raw Gadget es un módulo del kernel que ofrece una API de espacio de usuario para el subsistema USB Gadget del kernel Linux, y puede usarse para fuzzing y exploits contra hosts USB al proporcionar descriptores USB malformados
  • Las PC comunes normalmente no tienen USB Device Controller, es decir, UDC, que suele venir integrado sobre todo en computadoras de placa única como la Raspberry Pi
    • En trabajos anteriores hacía falta hardware externo, como una Raspberry Pi o una EC3380-AB basada en USB 3380
  • En una ThinkPad X1 Carbon 6th Gen se encontró intel_xhci_usb_sw-role-switch bajo /sys/class/usb_role
    • /sys/class/usb_role es una interfaz para cambiar componentes USB de hardware entre modo host y modo device
    • Al principio, aunque se escribiera device en el archivo role, no aparecían mensajes en dmesg ni entradas en /sys/class/udc/
  • xHCI es el HCD que permite que un sistema x86 funcione como host USB, y xDCI es el nombre que usa Intel para la interfaz del lado de dispositivo USB

Estructura confirmada con el código del kernel y las listas de correo

  • En el kernel Linux, intel_xhci_usb_sw aparece en dos ubicaciones
    • drivers/usb/roles/intel-xhci-usb-role-switch.c implementa el driver USB Role Switch que manipula registros xHCI cuando se escribe device o host
    • drivers/usb/host/xhci-ext-caps.c crea el dispositivo de plataforma virtual intel_xhci_usb_sw si el driver xHCI configuró el quirk XHCI_INTEL_USB_ROLE_SW
  • El device ID PCIe del xHCI de la ThinkPad era 0x9d2f, coincidente con PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI del kernel
  • En discusiones de la lista de correo del kernel Linux se confirmó que xHCI y el UDC DWC3 son dispositivos separados, y que hay un mux entre ambos
    • El role switch se encarga de cambiar ese mux
    • Si el propio UDC DWC3 no aparece como dispositivo PCI, no hay ningún UDC disponible para usar en modo device
  • DWC3 es la IP DesignWare Core SuperSpeed USB 3.0 Controller de Synopsys, usada en sistemas de varios proveedores, incluido Intel
  • Al revisar lspci en la ThinkPad, al principio solo se veía el xHCI 8086:9d2f, y no aparecía 0x9d30, el device ID de xDCI en Sunrise Point-LP según dwc3-pci.c

Rastros de xDCI que quedaban en ACPI y en el BIOS

  • En el DSDT de ACPI existían Device (XDCI) y el método _STA
    • /sys/bus/acpi/devices/device:33/path era \_SB_.PCI0.XDCI
    • /sys/bus/acpi/devices/device:33/status era 15, lo que significa que el dispositivo estaba en estado enabled and functioning
    • Pero como xDCI no aparecía en lspci, solo parecía estar correcto desde el punto de vista de ACPI
  • En la pantalla predeterminada de configuración del BIOS no se veía ninguna opción relacionada con xDCI u OTG
  • Se descargó la imagen de actualización Lenovo BIOS Bootable CD, se extrajo el binario del BIOS /mnt/bios/FLASH/N23ET86W/$0AN2300.FL1 y se inspeccionó con UEFITool
  • Al buscar cadenas en el PE32 image section del módulo Setup, aparecieron estos elementos
    • xDCI Support
    • Enable/Disable xDCI (USB OTG Device).
  • Dentro del BIOS existe una opción xDCI Support, pero está oculta en la UI predeterminada

Activar xDCI desde la página Advanced del BIOS

  • Siguiendo la documentación del proyecto x1c6-hackintosh, se probó un método para abrir la página Advanced del BIOS oculta
  • Este método requería volver a flashear el chip SPI donde está almacenado el BIOS
    • En vez de usar un clip SPI, se reemplazó el chip SPI por un zócalo para poder retirar e insertar varias veces el chip durante las pruebas
    • Se usaron un FTDI FT2232H Mini Module y flashrom para volcar y reescribir el contenido del chip SPI
  • El parche del BIOS consta de dos pasos
    • Con UEFIPatch, se cambia la referencia GUID de la página Date/Time del BIOS hacia la página Advanced
    • Con un parche de bytes adicional, se fuerza el TPM a MFG Mode para evitar que Boot Guard detecte la modificación del BIOS
  • En BIOS 1.37, aplicar solo el primer parche hacía que la laptop emitiera pitidos y no arrancara; después de aplicar también el segundo parche, apareció la página Advanced
  • Al cambiar xDCI Support a Enabled en Intel Advanced MenuPCI-IO ConfigurationUSB Configuration, xDCI quedó expuesto tras el arranque
    • En lspci apareció 00:14.1 USB controller [8086:9d30]
    • El kernel cargó automáticamente el driver dwc3-pci
    • En /sys/class/udc/ apareció dwc3.1.auto

Puerto xDCI y condiciones del cable

  • Para encontrar el puerto USB externo conectado a xDCI, se dejó el rol en device y se conectó una unidad flash USB en cada puerto
    • En un puerto específico, el SO no detectaba la unidad flash; al volver el rol a host, funcionaba de nuevo
    • Ese puerto fue identificado como el puerto conectado a xDCI
  • Como el puerto xDCI de la ThinkPad era USB Type-A, para conectarla a una computadora host hacía falta un cable Type-A a Type-A macho-macho
  • Como el role switching no apagaba la alimentación VBUS del puerto, se usó un cable con VBUS desconectado para evitar que el VBUS de ambos dispositivos quedara conectado directamente
    • Al principio se fabricó manualmente un cable macho-macho cortando dos cables USB 2.0 y desconectando VBUS
    • Más tarde se usaron un PortaPow USB Power Blocker y un cable USB 2.0 macho-macho
  • Al cargar el gadget driver g_zero, el dispositivo USB de prueba se emuló correctamente en otra laptop
  • Según una actualización del 11 de junio de 2024, el DataPro USB 3.0 Super-Speed A/A Debugging Cable también tiene desconectados D- y D+ de USB 2.0, por lo que falla la conexión High-Speed necesaria para establecer una conexión SuperSpeed
    • Un cable LogiLink CU0038 con VBUS desconectado manualmente funciona para emular dispositivos SuperSpeed

Intento de activación por software con registros del PCH

  • Para entender cómo el BIOS activa xDCI, se revisó Pch/Library/Private/PeiPchInitLib/PchXdci.c del código fuente de BIOS para Kaby Lake
  • La ruta de desactivación de xDCI en el BIOS lo deshabilitaba desde PMC y PSF
  • Cambios en PMC

    • Se consideró que borrar el bit #24 XDCI Function Disable del registro NST_PG_FDIS_1 del PMC, offset 0x628, podría quitar el corte de energía de xDCI
    • Se escribió un módulo del kernel que reutilizaba el mapeo de pmc_core_device y pmc->regbase del kernel Linux
    • Justo después del arranque, el bit #31 ST_FDIS_LK de ST_PG_FDIS1 estaba configurado, por lo que no era posible cambiar el valor de NST_PG_FDIS_1
    • Después de suspender y reactivar la laptop, el bit de bloqueo no estaba configurado, y se logró borrar el bit XDCI Function Disable
  • Cambios en PSF

    • El BIOS deshabilita xDCI configurando el bit USB Dual Role (OTG) Function Disable en el PCR PSF2 del Port ID 0xBB de PID_PSF2
    • La dirección PCR se calcula combinando PCH_PCR_BASE_ADDRESS 0xFD000000, el Port ID y el offset
    • En el módulo del kernel, se mapeó el PCR PSF2 con ioremap, pero el valor leído fue 0xffffffff y no cambió
    • Aunque se hiciera unhide de P2SB, el resultado era el mismo
    • RemoveSidebandAccess del BIOS separa PID_PSF2 de IOSF-SB usando EPMASK5 y lo bloquea con MASKLOCK, por lo que el SO no puede volver a configurar PSF
    • El acceso al PCH logró modificar algunos ajustes del PMC, pero como falló la reconfiguración del PSF, no sirvió como método para activar xDCI

Activación con parche de NVRAM sin evadir Boot Guard

  • Como los valores de configuración del BIOS se almacenan en el área NVRAM del chip SPI, se probó cambiar solo el valor de xDCI Support sin abrir la página Advanced oculta
  • Se extrajo la información UEFI IFR del módulo Setup con IFRExtractor-RS
  • La opción xDCI Support estaba almacenada dentro de la variable UEFI PchSetup
    • VarStore GUID: 4570B7F1-ADE8-4943-8DC3-406472842384
    • VarStoreId: 0x5
    • VarOffset: 0x40
    • Rango de valores: 0x0 o 0x1
  • En efivarfs de Linux se revisó /sys/firmware/efi/efivars/PchSetup-4570b7f1-ade8-4943-8dc3-406472842384
    • Como los primeros 4 bytes de un archivo efivarfs son el encabezado, el valor real de xDCI Support está en el offset 0x44 del archivo
    • Con xDCI desactivado, el valor era 00; después de activarlo desde la página Advanced del BIOS, cambiaba a 01
  • Al intentar escribir directamente esa variable desde espacio de usuario o desde EFI Shell, se produjo un error EFI_WRITE_PROTECTED
    • Aunque se eliminara el atributo immutable de efivarfs, aparecía el error Read-only file system
    • Al cambiarlo desde EFI Shell con chipsec, se producía el mismo error
  • En la imagen original del BIOS leída con un programador SPI, se buscó la secuencia de bytes alrededor de PchSetup, se parchó solo el bit xDCI Support a 01 y se volvió a flashear; con eso xDCI quedó activado
  • Este método todavía requiere reflashear el chip SPI, pero no necesita el parche de la página Advanced ni evadir Boot Guard, y tampoco rompe el TPM
  • Tras parchar la NVRAM en BIOS 1.37 y actualizar a 1.61, el valor de configuración del BIOS se mantuvo, por lo que no hizo falta volver a aplicar el parche

Emular dispositivos USB con xDCI

  • Todos los ejemplos asumen que xDCI está activado en el BIOS, que intel_xhci_usb_sw-role-switch fue cambiado a device, y que el puerto xDCI está conectado al USB host con un cable que tiene VBUS desconectado
  • Legacy gadget drivers

    • Los legacy gadget drivers del subsistema Linux USB Gadget emulan un dispositivo de una clase USB específica al cargar el módulo
    • g_mass_storage expone una imagen de sistema de archivos como dispositivo USB mass storage
    • Después de crear la imagen FAT disk.img y poner Hi from xDCI en file.txt, se carga con sudo modprobe g_mass_storage file=./disk.img stall=0
    • En el USB host, la unidad se monta automáticamente y se verifica el contenido del archivo
  • Raw Gadget

    • Se ejecutó Raw Gadget con xDCI para probar un ejemplo de teclado USB
    • Al principio se quedaba detenido durante el manejo de SET_CONFIGURATION
    • La causa era que dwc3 y algunos drivers UDC asumían que podían hacer acknowledge de inmediato a un control request de 0 bytes sin consultar al gadget driver
    • Tras aplicar a Raw Gadget el parche workaround y también corregir GadgetFS, la emulación de teclado funcionó correctamente
    • El comportamiento relacionado se documentó en este commit

Uso con syzkaller y Facedancer

  • syzkaller puede usar Raw Gadget para hacer fuzzing externo del stack USB del kernel Linux
  • El fuzzing USB predeterminado de syzkaller usa Dummy HCD/UDC, que conecta internamente en el kernel un dispositivo USB virtual y un controlador host
  • Para usar xDCI, se cambió el código de syzkaller que especifica el UDC de dummy_udc a dwc3-gadget, dwc3.1.auto
  • Se ejecutó con syz-execprog -enable=usb el reproducer del bug WARNING in smsusb_start_streaming/usb_submit_urb encontrado por syzkaller
    • En una laptop con el kernel Ubuntu 5.15.0-91-generic como host, se reprodujo la advertencia en usb_submit_urb
    • Ese bug era un WARNING causado porque el driver smsusb omitía validar el tipo de endpoint USB, y no era un comportamiento dañino
  • Facedancer es un framework de emulación de dispositivos USB basado en Python
    • El backend de Facedancer basado en Raw Gadget todavía es un prototipo y depende de parches de Raw Gadget out-of-tree
    • Al configurar BACKEND=rawgadget, RG_UDC_DRIVER=dwc3-gadget, RG_UDC_DEVICE=dwc3.1.auto y ejecutar el ejemplo rubber-ducky.py, funcionó correctamente
  • El USB Proxy basado en Raw Gadget también se ejecutó con xDCI, y usar xDCI permite usar la laptop como sniffer USB o herramienta de USB Man-in-the-Middle

Posibilidades en otros equipos y por software

  • Puede ser posible activar xDCI también en otras PC además de la ThinkPad X1 Carbon 6th Gen
    • En el caso más simple, podría funcionar con solo activar xDCI en la configuración del BIOS
    • Debe haber soporte de ACPI y role switching, y el puerto xDCI tiene que estar cableado a un puerto externo
  • Es posible que otras ThinkPad también tengan la opción xDCI del BIOS oculta y protegida, por lo que podría hacer falta reflashear el chip SPI
    • El método por NVRAM puede aplicarse sin evadir Boot Guard
    • En algunos sistemas más nuevos, el reflashing del chip SPI puede estar protegido con RPMC, y estos chips pueden incluir una R en el nombre, como W25R128FW
  • Según una actualización, Shiny Quagsire ya había activado xDCI en una XPS 13 y una Surface Go 1 modificando la variable PchSetup con grub-mod-setup_var
    • En esos dispositivos, la variable PchSetup no estaba protegida, por lo que era posible un método puramente por software
  • Otro enfoque por software podría ser usar una vulnerabilidad del BIOS para cambiar las variables NVRAM relacionadas con xDCI, o atacar el BIOS durante el arranque mediante DMA para ejecutar código arbitrario
  • La palabra “secret” del título se refiere más a una función no documentada que a un ocultamiento intencional

1 comentarios

 
GN⁺ 2024-02-24
Comentarios de Hacker News
  • Siempre me he preguntado por qué no es más común usar una laptop como teclado y monitor genéricos para otra computadora
    Tener que comprar un teclado y un monitor nuevos para dar mantenimiento a una máquina headless se siente raro, porque una laptop ya podría cumplir ese papel

    • La GPD Pocket 3 tiene un módulo KVM que hace exactamente esto: recibe entrada por HDMI y USB-C, y actúa como la pantalla, el teclado y el mouse de la máquina conectada: https://gpd.hk/gpdpocket3
      La próxima tablet Minisforum V3 también tendrá entrada de video, así que podrá usarse como monitor externo, aunque no parece que vaya a compartir también el teclado y el mouse
      Ojalá este tipo de función se vuelva más común
    • Sí. Un amigo construyó un cyberdeck solo para eso
      Puede redirigir el mouse y el teclado a puertos externos para conectarlos por cable a otra máquina, y en un costado tiene dos puertos HDMI, uno de salida y otro de entrada
      Con un switch interno puede elegir si el monitor usa como fuente la propia máquina del deck o una entrada externa
    • Como alguien que trabaja seguido con máquinas headless, la mejor solución que encontré para usar la laptop como monitor fue este producto: https://www.amazon.com/dp/B0BJ2YDV7Q
      Básicamente es un chip que captura la señal HDMI de la máquina headless y la expone a la laptop por USB como si fuera una webcam emulada, y es lo bastante pequeño como para que los componentes electrónicos quepan dentro del cable
      Para el teclado, fuera de usar un teclado inalámbrico estándar y comprar uno con trackpad integrado para cuando rara vez hace falta mouse, no he encontrado una buena solución
    • Siempre me ha molestado que no puedas simplemente conectar una computadora a otra
      Según entiendo, USB 4 tiene un modo que permite algo así
    • Con hidclient, una laptop puede hacerse pasar por teclado y mouse Bluetooth
      https://web.archive.org/web/20180610141436/http://anselm.hoffmeister.be/computer/hidclient/index.html.en
      https://github.com/benizi/hidclient
  • Esto me recordó algo que hizo Travis Goodspeed hace algunos años
    Una smart TV aceptaba actualizaciones de firmware desde archivos en una memoria USB común, y la TV leía el archivo completo una vez para verificar la firma digital y luego lo volvía a leer para hacer la actualización
    Un dispositivo que fingiera ser almacenamiento USB podría entregar el firmware del fabricante en la primera lectura y firmware no oficial en la segunda

  • Muy interesante. He estado investigando opciones parecidas que podrían hacerse realidad
    Tengo un servidor NAS potente para el que sigo buscando una excusa de uso, y además tengo conexiones de 40G y 10G por toda la casa
    La PS5 y la XBox usan discos duros USB como almacenamiento adicional
    Revisando si era posible exponer almacenamiento del NAS a la PS5 y a la XBox, vi que sí. Basta con montar el recurso compartido del NAS por iSCSI o NFS y luego usar el módulo g_mass_storage para emular un dispositivo de almacenamiento USB y exponer ese almacenamiento al host USB
    El principal obstáculo actual, además del tiempo y el costo, es el ancho de banda que ofrecería un sistema así. La mejora no sería tan grande
    La Raspberry Pi es conocida por soportar USB-OTG, pero se queda en velocidades de USB 2.0, y la mayoría de las otras SBC de la misma clase que revisé también. La excepción fue la RockPi4, y la RockPi tiene un puerto Ethernet gigabit, así que si saturas Ethernet podría dar velocidades estables de HDD tanto a la PS5 como a la Xbox
    Si existiera una solución con una tarjeta de red PCIe personalizada o una express card que permitiera superar 1GbE, sería bastante interesante, porque sí podría saturar de verdad una interfaz USB 3.0

    • Tengo un homelab parecido y estoy probando USB sobre IP con https://www.virtualhere.com
      Sí hace falta un cliente que se comunique con el servidor, pero parece funcionar bastante bien
      Estoy pensando en poner un “cliente USB delgado” sobre el escritorio, conectar ahí los dispositivos USB y luego adjuntarlos o cambiarlos al host físico o al host de VM que quiera dentro del laboratorio
    • Me da curiosidad cómo conectarías físicamente la PS5 y el NAS
      Supongo que sería NAS → SBC → PS5, pero ¿o estarías conectando el NAS directamente a la PS5 con un cable USB?
      También me pregunto cómo funcionaría la reproducción de contenido en la PS5. Según entiendo, el NVMe interno tiene que cumplir cierta velocidad; ¿eso no aplica a las unidades externas?
    • La Raspberry Pi 5 tiene un puerto Ethernet gigabit, y otras SBC como la línea NanoPi de FriendlyElec también
      De hecho, la NanoPi R6S tiene dos puertos Ethernet de 2.5G, además de un puerto de 1 gigabit
  • Gracias por el artículo tan detallado. Tiene muy buena calidad
    El simple hecho de saber que esto fue posible me da esperanzas de que quizá se pueda lograr una configuración tipo Synergy / Mouse Without Borders sin red, usando solo un cable USB modificado
    Para quien necesita controlar varias computadoras al mismo tiempo, es una dirección muy prometedora

    • Sí existen switches KVM, y también dispositivos que solo cambian teclado y mouse USB sin video
      Aun así, la idea que propones suena interesante
  • Hace poco estuve investigando algo parecido: quería conectar dos máquinas con USB-C usando un solo cable USB-C para tener comunicación de 10 Gbps
    Por desgracia, la mayoría de las placas Ryzen todavía no tienen Thunderbolt, y con Thunderbolt esto se soporta de forma nativa con bastante facilidad
    Los controladores USB de “doble rol” también eran bastante raros antes de USB 3.2/4.0 y, como se comenta en este artículo, incluso cuando es posible muchas veces no está soportado
    Se siente completamente extraño que sea tan difícil conectar en red dos máquinas con un cable USB-C sin Thunderbolt
    También me gustó la parte donde, después de una suspensión temporal, se libera el bit de bloqueo. Este tipo de problema es realmente común. Por ejemplo, también es una forma muy común de sacar a un dispositivo SATA de un estado que bloquea el borrado seguro

  • El nivel de profundidad es impresionante
    Poder usar una PC como dispositivo USB abre muchas posibilidades interesantes
    Es un poco una lástima que la opción xDCI necesaria exista en el hardware de este equipo pero no esté expuesta, y que para acceder a ella haga falta hackear el firmware
    El hardware puede hacerlo, pero el fabricante simplemente lo desactivó y bloqueó los controles

  • Me pregunto si Lenovo usa esto como una vía para depurar un ThinkPad con otro ThinkPad
    https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/secure-coding/intel-debug-technology.html
    Actualización: parece que sí
    https://www.youtube.com/watch?v=ExUvQa_jB7c
    Es un video sobre depuración de Intel Firmware con DCI y USB 3.0

  • La parte de “pero trabajar con una Raspberry Pi es engorroso: conectar cables, arrancar la placa, entrar al shell, etc.” probablemente se habría podido resolver configurando USB OTG
    Parece que se podría haber hecho para que tomara energía del dispositivo conectado, abrir el shell y manejarlo con un script
    Entonces se podrían configurar montajes o ejecutar comandos por SSH, y probablemente hasta montar el dispositivo
    Aun así, siempre vale la pena intentar entender tu propio dispositivo y leer el kernel. Es algo en lo que uno quiere seguir mejorando, y da esa sensación de que nuestro equipo lo arreglamos nosotros

    • El punto central de este experimento justamente es trabajar con USB OTG, y la Pi solo tiene un puerto OTG, así que se necesita otra forma de conectarse
      Lo probé personalmente
  • Me recuerda muchísimo a la cultura hacker de los primeros días de internet, al punto de provocar nostalgia. De verdad es un texto excelente
    Cuando ESR hablaba de convertirse en hacker, del hacker en el sentido de Hacker News, se refería precisamente a este tipo de persona
    Esa combinación de curiosidad, perseverancia y capacidad técnica es extremadamente rara y muy impresionante

  • Tengo un sistema basado en Celeron N3350/Pentium N4200/Atom E3900, y en el BIOS aparece expuesto el interruptor xDCI
    Al activarlo aparecen también varias opciones más, y al arrancar con Linux se ve el dispositivo PCI USB controller: Intel Corporation Device 5aaa (rev 0b)
    Pero no aparece el nodo de dispositivo UDC. Creo que voy a tener que investigar un poco más tomando pistas del artículo original