Back to Blog

Espinas en la Rosa: Explorando los Riesgos de Seguridad en el Novedoso Mecanismo Hook de Uniswap v4

Code Auditing
November 6, 2023
11 min read

¡Uniswap v4 está en camino! El equipo tiene planes ambiciosos para introducir una serie de nuevas características[1], incluyendo (teóricamente) un número ilimitado de pools y tasas de comisión dinámicas para cada par de trading, singleton, contabilidad flash, hooks y soporte para ERC1155. Aprovechando el almacenamiento transitorio introducido por EIP-1153, se espera que Uniswap v4 se lance tras la actualización Cancun de Ethereum.

Entre estas innovaciones, el mecanismo de hook ha estado atrayendo una atención significativa debido a su poderoso potencial. Permite la ejecución de código específico en puntos particulares durante la operación de un pool, mejorando considerablemente la extensibilidad y flexibilidad de los pools.

Sin embargo, el mecanismo de hook también puede ser un arma de doble filo. Si bien es poderoso y flexible, no se puede pasar por alto el desafío de utilizarlo de forma segura. Esta complejidad inevitablemente abre nuevos vectores de ataque potenciales. Con el objetivo de contribuir a la comunidad desde una perspectiva de seguridad, nuestro propósito es presentar una serie de artículos que examinen los problemas y preocupaciones de seguridad relacionados con este mecanismo de manera sistemática. Creemos que estos conocimientos arrojarán luz sobre la construcción de hooks seguros para Uniswap v4.

Este artículo es el primero de esta serie y proporciona una visión general completa y una comprensión fundamental para nuestros lectores. ¡Estad atentos para más discusiones interesantes!

El Mecanismo de Uniswap v4

Antes de profundizar en los detalles, necesitamos tener una comprensión básica del mecanismo de Uniswap v4. Según el anuncio oficial[1] y el whitepaper[2], los hooks, la arquitectura singleton y la contabilidad flash son tres características clave que permiten la personalización de pools y un enrutamiento eficiente a través de muchos pools.

Hooks

Los hooks en v4 están diseñados para permitir que cualquiera tome decisiones de compromiso a través de hooks, que son contratos que se ejecutan en varios puntos del ciclo de vida de una acción de pool. Al hacerlo, es posible personalizar pools que soporten nativamente comisiones dinámicas, añadir órdenes limitadas on-chain, o actuar como un creador de mercado de media ponderada en el tiempo (TWAMM) para distribuir grandes órdenes a lo largo del tiempo.

Actualmente, hay ocho callbacks de hook, organizados en cuatro grupos (cada grupo contiene un par de callbacks):

  • beforeInitialize/afterInitialize
  • beforeModifyPosition/afterModifyPosition
  • beforeSwap/afterSwap
  • beforeDonate/afterDonate

A continuación se muestra el flujo de los hooks de swap proporcionado por el whitepaper[2].

Figura 1: Flujo del Hook de Swap
Figura 1: Flujo del Hook de Swap

El equipo de Uniswap ha proporcionado algunos ejemplos (p. ej., el TWAMM Hook[3]) para demostrar su uso, y los participantes de la comunidad también hacen su contribución. La documentación oficial[4] enlaza al repositorio Awesome Uniswap v4 Hooks[5], que recopila más ejemplos de hooks.

Singleton, Contabilidad Flash y Mecanismo de Bloqueo

La arquitectura singleton y la contabilidad flash están diseñadas para mejorar el rendimiento reduciendo costos y garantizando la eficiencia. Específicamente, introduce un nuevo contrato singleton, donde todos los pools viven dentro de un único contrato inteligente. Este diseño singleton se apoya en un PoolManager para almacenar y gestionar todos los estados de todos los pools.

A diferencia de versiones anteriores del Protocolo Uniswap donde operaciones como el intercambio o la adición de liquidez implicaban transferencias directas de tokens, Uniswap v4 introduce la contabilidad flash junto con un mecanismo de bloqueo.

Específicamente, el mecanismo de bloqueo opera de la siguiente manera:

  1. Un contrato locker solicita un bloqueo al PoolManager.
  2. El PoolManager añade la dirección del locker a la cola lockData e invoca su callback lockAcquired.
  3. El locker ejecuta su lógica en el callback. Durante la ejecución de un locker, sus interacciones con los pools pueden resultar en deltas de divisas distintos de cero. Sin embargo, al final de la ejecución, todos los deltas deben liquidarse a cero. Además, si la cola lockData no está vacía, solo el último locker puede realizar operaciones.
  4. Posteriormente, el PoolManager verifica el estado de la cola lockData y los deltas de divisas. Tras la verificación, el PoolManager eliminará al locker.

En resumen, el mecanismo de bloqueo previene el acceso concurrente y garantiza la liquidación. Los lockers hacen cola para los bloqueos y luego se ejecutan a través del callback lockAcquired. Antes y después de las acciones del pool, se invocan los callbacks de hook especificados. Finalmente, el PoolManager verifica el estado.

Este enfoque significa que las operaciones ajustan un saldo neto interno (es decir, delta), en lugar de ejecutar transferencias inmediatas. Cualquier modificación se registra en el saldo interno del pool, con las transferencias reales realizándose al final de la operación (es decir, lock). Este proceso garantiza que no haya tokens pendientes, preservando así la solvencia.

Debido al mecanismo de bloqueo, una EOA (Cuenta de Propiedad Externa) no puede interactuar directamente con el PoolManager. En cambio, cualquier interacción debe realizarse a través de un contrato. El contrato actúa como un locker intermediario para solicitar un bloqueo antes de cualquier acción en el pool. Existen principalmente dos escenarios de interacción con contratos:

  • El contrato locker proviene del repositorio oficial o fue desplegado por usuarios. En estos casos, podemos ver las interacciones como realizadas a través de un router.

  • El locker y el hook están integrados en el mismo contrato o controlados por una entidad de terceros. Para este escenario, podemos ver las interacciones como realizadas a través de un hook. Por lo tanto, el hook juega el doble papel de locker y manejador de callbacks.

Modelos de Amenaza

Los modelos de amenaza deben determinarse antes de discutir los problemas de seguridad correspondientes. Básicamente, existen ciertas consideraciones que surgen al usar hooks:

  • Modelo de amenaza I: Los hooks son benignos pero vulnerables.
  • Modelo de amenaza II: Los hooks son maliciosos.

En las siguientes secciones, discutiremos posibles problemas/preocupaciones de seguridad basados en los modelos de amenaza.

Preocupaciones de Seguridad en el Modelo de Amenaza I

El modelo de amenaza I se centra en las vulnerabilidades relacionadas con los hooks en sí mismos. Obviamente, este modelo de amenaza asume que los desarrolladores y sus hooks son benignos. Sin embargo, las vulnerabilidades conocidas existentes de los contratos inteligentes también podrían aparecer en los hooks. Por ejemplo, si el hook está implementado como un contrato actualizable, puede sufrir algunas vulnerabilidades similares a la vulnerabilidad UUPSUpgradeable de la biblioteca de OZ[6].

Teniendo en cuenta estas consideraciones, optamos por concentrarnos en vulnerabilidades potenciales específicas de v4. Específicamente, en Uniswap v4, los hooks son contratos inteligentes personalizables capaces de ejecutar lógica antes o después de las acciones principales del pool (incluyendo initialize, modifyPosition, swap y donate). Se espera que los hooks implementen la interfaz de hook estándar, pero también se les permite incorporar lógica personalizada. Por lo tanto, nuestro alcance se limita a la lógica asociada con la interfaz de hook estándar. Podemos entonces resumir cómo es probable que los hooks empleen estas funciones de hook estándar para identificar posibles fuentes de vulnerabilidades.

En términos generales, los hooks pueden clasificarse en dos categorías:

  • Hooks que actúan como custodios de fondos de usuarios. En estos casos, los atacantes pueden apuntar al hook para transferir fondos, provocando pérdidas de activos.
  • Hooks que almacenan datos de estado críticos en los que confían usuarios u otros protocolos. Para estos hooks, los atacantes podrían alterar deliberadamente estados críticos. Los estados erróneos, cuando son utilizados por otros usuarios o protocolos, introducen riesgos potenciales.

Nótese que los hooks que no encajan en estas dos categorías no están dentro del alcance de nuestra discusión.

A pesar del alcance limitado, aún no es factible enumerar todas las posibilidades aquí. Como no hay aplicaciones reales en el momento de escribir esto, decidimos revisar el repositorio Awesome Uniswap v4 Hooks para obtener algunas perspectivas.

Tras examinar exhaustivamente el repositorio (con hash de commit 3a0a444922f26605ec27a41929f3ced924af6075), hemos identificado varias vulnerabilidades críticas. Estas provienen principalmente de las interacciones de riesgo entre hooks, PoolManager y terceros externos. Las vulnerabilidades caen en dos categorías principales: control de acceso defectuoso y validación de entrada incorrecta. Los hallazgos se resumen en la tabla a continuación:

# de proyectos defectuosos # de control de acceso defectuoso # de validación de entrada incorrecta
8 6 2

En general, identificamos 22 proyectos relevantes (excluyendo algunos que parecían no relacionados con Uniswap v4). De estos, 8 (o el 36%) fueron considerados vulnerables. Específicamente, se detectó control de acceso defectuoso en 6 de estos proyectos vulnerables, mientras que 2 eran susceptibles a llamadas externas no confiables.

Control de Acceso Defectuoso

En esta discusión, nos centramos en los problemas de control de acceso relacionados con v4 que provienen de las funciones de callback de v4, que incluyen 8 callbacks de hook y el callback de bloqueo. Por supuesto, también podrían necesitar verificarse otros casos. Sin embargo, estos casos dependen del diseño, lo que está más allá del alcance especificado por nuestra discusión anterior.

Estas funciones solo deben ser invocadas por el PoolManager, no por otras direcciones (incluyendo EOAs y contratos). Por ejemplo, considera una situación donde se distribuye una recompensa por clave de pool. Si la función correspondiente puede ser invocada por cuentas arbitrarias, la recompensa podría reclamarse incorrectamente.

Dado esto, es crucial establecer mecanismos de control de acceso robustos para los hooks, especialmente ya que pueden ser invocados por partes distintas al pool en sí. Mediante una gestión cuidadosa de los permisos de acceso, los pools pueden minimizar sustancialmente el riesgo de interacciones no autorizadas o maliciosas con los hooks.

Validación de Entrada Incorrecta

En Uniswap v4, debido al mecanismo de bloqueo, los usuarios deben obtener un bloqueo a través de un contrato antes de ejecutar cualquier acción en el pool. Esto garantiza que el contrato que interactúa actualmente sea el último locker.

A pesar de esto, sigue existiendo un escenario de ataque potencial, es decir, llamada externa no confiable debido a validación de entrada incorrecta en algunas implementaciones de hook vulnerables:

  • Primero, el hook no valida el pool con el que los usuarios pretenden interactuar. Este podría ser un pool malicioso que lleva tokens falsos y ejecuta lógica dañina.
  • Segundo, algunas funciones de hook cruciales permiten invocaciones externas arbitrarias.

La llamada externa no confiable es extremadamente peligrosa porque puede conducir a varios tipos de ataques, incluidos los conocidos problemas de reentrancia.

Para explotar tales hooks vulnerables, un atacante podría registrar un pool malicioso para sus tokens falsos, luego invocar el hook para ejecutar acciones en el pool. Al interactuar con el pool, la lógica del token malicioso secuestra el flujo de control para facilitar comportamientos indebidos.

Mitigación para el Modelo de Amenaza I

Para evitar tales problemas con los hooks, es esencial validar las interacciones aplicando adecuadamente el control de acceso necesario para las funciones externas/públicas sensibles, y la verificación de los argumentos de entrada. Además, un guard de reentrancia podría ser útil para garantizar que el hook no pueda ejecutarse repetidamente dentro del flujo de lógica estándar. Al implementar las salvaguardas adecuadas, los pools pueden mitigar los riesgos asociados con este tipo de amenaza.

Preocupaciones de Seguridad en el Modelo de Amenaza II

En este modelo de amenaza, se asume que los desarrolladores y sus hooks son maliciosos. Dado el extenso rango de posibilidades, hemos elegido centrarnos principalmente en los problemas relacionados con v4. En consecuencia, la consideración clave es si los hooks proporcionados son capaces de manejar los activos criptográficos que los usuarios han transferido o aprobado.

Basándonos en el método de acceso a los hooks, que determina los permisos potenciales otorgados a los hooks, podemos clasificar los hooks en dos categorías distintas:

  • Hooks Gestionados: Los hooks no son el punto de entrada. Los usuarios deben interactuar con los hooks a través de un router, probablemente proporcionado por Uniswap.
  • Hooks Independientes: Los hooks son el punto de entrada, permitiendo a los usuarios interactuar directamente con ellos.
Figura 2: Ejemplos de Hooks Maliciosos
Figura 2: Ejemplos de Hooks Maliciosos

Hooks Gestionados

En el caso de los Hooks Gestionados, los activos criptográficos de los usuarios (incluyendo tokens nativos y otros) se transfieren o aprueban al router. Debido a la verificación de saldo aplicada por el PoolManager, no es sencillo para los hooks maliciosos cosechar directamente estos activos.

Sin embargo, aún existen superficies de ataque potenciales. Por ejemplo, el mecanismo de gestión de comisiones en v4 podría ser potencialmente manipulado por atacantes a través de hooks.

Hooks Independientes

La situación se vuelve más compleja cuando los hooks se usan como punto de entrada en forma de Hooks Independientes. En este escenario, los hooks ganan más poder ya que los usuarios pueden interactuar con ellos directamente. Teóricamente, los hooks pueden realizar cualquier acción que deseen a través de esta interacción.

Bajo el escenario v4, la validación de la lógica del código es un punto crítico. La principal preocupación es si la lógica del código puede ser manipulada. Los hooks pueden implementarse como actualizables, lo que significa que un hook que parece seguro podría potencialmente actualizarse a uno malicioso más tarde, lo que representa un riesgo significativo. Esto incluye:

  • Proxies actualizables, que pueden ser explotados directamente;
  • Equipados con lógica de autodestrucción, que puede ser explotada debido al uso combinado de selfdestruct y create2.

Mitigación para el Modelo de Amenaza II

Es esencial evaluar si los hooks son maliciosos. Específicamente, para los hooks gestionados, debemos concentrarnos en el comportamiento de la gestión de comisiones; mientras que para los hooks independientes, la preocupación principal es si son actualizables o no.

Conclusión

En este artículo, inicialmente proporcionamos un breve resumen de los mecanismos principales de Uniswap v4 que se relacionan con los problemas de seguridad de los hooks de v4. A continuación, definimos dos modelos de amenaza y ofrecemos una discusión de alto nivel sobre sus respectivos problemas de seguridad. En los próximos artículos de esta serie, proporcionaremos análisis detallados de esos problemas de seguridad bajo cada modelo de amenaza. ¡Estad atentos!

Referencias

[1] Nuestra Visión para Uniswap V4

[2] Borrador del whitepaper de Uniswap v4

[3] TWAMM Hook de Uniswap v4

[4] Ejemplos de Hooks

[5] Awesome Uniswap v4 Hooks

[6] Análisis Post-mortem de la Vulnerabilidad UUPSUpgradeable

Leer el Otro Artículo de Esta Serie

Best Security Auditor for Web3

Validate design, code, and business logic before launch. Aligned with the highest industry security standards.

BlockSec Audit