El 3 de agosto de 2023, un Bot MEV en Arbitrum fue atacado, resultando en una pérdida de $800K. La causa raíz de este ataque fue la Verificación Insuficiente de Entradas del Usuario.
Considerando las intrincadas interacciones entre los Bots MEV y sus contratos no verificados, esto revela que no ser de código abierto no garantiza la seguridad, especialmente para los protocolos DeFi.
Contexto
Bot MEV
El Bot MEV (Bot de Valor Máximo Extraíble) está diseñado para identificar y ejecutar oportunidades rentables en la blockchain. Opera analizando transacciones pendientes (es decir, aquellas en el mempool) o estados on-chain para generar ganancias mediante arbitraje.
A diferencia de los Bots MEV típicos de front-running y ataques sándwich, el Bot MEV objetivo en este ataque se centró en ejecutar estrategias como el arbitraje triangular y la liquidación de deudas. Estos bots en sí mismos ayudan a estabilizar los precios de los AMM y asisten a los protocolos de préstamo con liquidaciones para garantizar un funcionamiento fluido, constituyendo una parte esencial del funcionamiento saludable del ecosistema DeFi.
Préstamo Flash (Flashloan)
El Préstamo Flash representa una innovación única dentro del ecosistema DeFi: una forma de préstamo sin garantía colateral. Puedes pedir prestado hasta mil millones de dólares a través de un Préstamo Flash sin ningún colateral, siempre que el préstamo sea devuelto dentro de la misma transacción. Si el préstamo no es devuelto dentro de esa transacción, será revertido, como si la transacción nunca hubiera ocurrido.
Este mecanismo se utiliza comúnmente para arbitraje o para aprovechar otras estrategias DeFi y explotar ineficiencias temporales del mercado.
La Vulnerabilidad
Versión Resumida
La validación insuficiente de los parámetros introducidos por el usuario permitió al atacante introducir un FakeFlashloanProvider. El contrato vault utilizó este proveedor para iniciar un préstamo flash. Posteriormente, quizás para liquidar el préstamo flash, el contrato vault aprobó tokens al FakeFlashloanProvider, lo que llevó a la transferencia no autorizada de activos fuera del vault.
Versión Detallada
El contrato explotado es:
Vault: El contrato víctima 0xd614927acfb9744441180c2525faf4cedb70207f actúa como un "Vault", proporcionando reservas y facilitando préstamos flash de otros protocolos como AAVE y Balancer.Arbitrage Bot: El contrato vulnerable 0x8db0efee6a7622cd9f46a2cf1aedc8505341a1a7, funcionando como un "Bot de Arbitraje", ocupa el rol de prestatario en el contrato "Vault".
La función 0x0582f20f() en el "Bot de Arbitraje" es el punto de entrada principal para lanzar arbitrajes.
Primero invoca el borrow() en el "Vault" para adquirir el capital original, luego ejecuta la lógica de arbitraje a través de un delegatecall a un contrato externo especificado en el calldata y sin ninguna validación.
function 0x0582f20f(...) {
...
v67, /* uint256 */ v68 = address(0xd614927acfb9744441180c2525faf4cedb70207f).borrow(address(v39), address(v9[0]), v29).gas(msg.gas);
...
// 0x4da91757 = swap(address,address,address,uint256,uint256,uint256,address)
MEM[MEM[64] + 32] = uint224(address(MEM[0 + v4[v69]])) | 0x4da9175700000000000000000000000000000000000000000000000000000000;
v82 = address(v76 >> 96).delegatecall(MEM[(MEM[64]) len 228], MEM[(MEM[64]) len 0]).gas(msg.gas);
...
v189 = v170.refund(0x410085df, address(v9[0]), address(v39), v68, address(v9[0]), v29, v186, 4 + MEM[64] + (varg2.length << 5) - (4 + MEM[64]) + 192).gas(msg.gas);
...
}
Posteriormente, invoca el 0x512b7351() en el "Vault", lanzando un préstamo flash al contrato FakeFlashloanProvider del atacante.
La función 0x512b7351() requiere que msg.sender esté en la lista de permitidos, pero fue eludida exitosamente mediante el delegatecall anterior, evitando la verificación. Este es un paso muy crítico
function 0x512b7351(...) public nonPayable {
...
if (_borrow[msg.sender] >= 1) {
v0 = !_refund;
}
require(v0, Error('BBVault: FORBIDDEN'));
...
v38 = v23.length;
v39 = v23.data;
_refund = keccak256(v23);
...
<FakeFalshloanProvider>.flashloan(...);
...
}
Durante el callback del préstamo flash, el executeOperation() en el "Vault" primero transfiere los activos prestados al "Bot de Arbitraje" MEVBot 0x8db0ef, luego llama a su 0x7fe3ba8b().
function executeOperation(...) {
...
require(_refund == keccak256(v3.data), Error('BBVault: STATUS'));
Token.transfer(ArbitrageBot, amountBorrowed);
<ArbitrageBot>.call(0x7fe3ba8b...);
}
El "Bot de Arbitraje", confiando en esta llamada externa, transfiere los activos recibidos de vuelta al FakeFlashloanProvider.
Sin embargo, el "Vault" no reconoce esto y aún otorga aprobación al FakeFlashloanProvider para reembolsar el préstamo flash al final del executeOperation().
El Proceso del Ataque
Tx del ataque: 0x864c8cfb8c54d3439613e6bd0d81a5ea2c5d0ad25c9af11afd190e5ea4dcfc1f
El atacante invoca el 0x0582f20f() del "Bot de Arbitraje", que a su vez realiza una llamada delegada al contrato del atacante.


El hack_contract_2 luego llama a la función 0x512b7351() de la víctima. El 0x512b7351() requiere que msg.sender esté en la lista de permitidos, pero fue eludido exitosamente mediante el delegatecall anterior, evitando la verificación.

La víctima luego llama al contrato FakeFlashloanProvider del atacante, transfiriendo todos los activos del préstamo flash a la víctima y llamando al executeOperation() de la víctima.

El 0x7fe3ba8b() del Bot de Arbitraje realiza nuevamente un delegatecall al contrato del atacante, esta vez transfiriendo todos los activos de vuelta al atacante.
**En este punto, los activos prestados por el Proveedor de Préstamo Flash del atacante han sido devueltos.
**

La víctima ("Vault") aprueba tokens al FakeFlashloanProvider, posiblemente con la intención de reembolsar el préstamo flash.

El atacante explota esta aprobación para obtener ganancias, utilizando transferFrom para drenar fondos de la víctima.
Recomendaciones de Seguridad
El código no de código abierto no garantiza la seguridad
Creer que el código no de código abierto y ofuscado garantiza la seguridad es un error conceptual. Este incidente con el Bot MEV revela que el secretismo no protege contra exploits y puede dar a los desarrolladores una falsa sensación de seguridad.
Validación Rigurosa de Entradas
Es crucial validar meticulosamente todas las interacciones de contratos y calldata, especialmente cuando se trata de interfaces estándar como callbacks de préstamos flash y swap. Garantizar la integridad y seguridad de los datos debe ser una prioridad en el diseño e implementación de contratos.
Lee otros artículos de esta serie:
- Introducción: Los Diez Mejores Incidentes de Seguridad "Asombrosos" de 2023
- #1: Cosechando Bots MEV Explotando Vulnerabilidades en el Relay de Flashbots
- #2: Incidente de Euler Finance: El Mayor Hackeo de 2023
- #3: Incidente de KyberSwap: Explotación Magistral de Errores de Redondeo con Cálculos Excesivamente Sutiles
- #4: Incidente de Curve: Error del Compilador Produce Bytecode Defectuoso a partir de Código Fuente Inocente
- #5: Platypus Finance: Sobreviviendo Tres Ataques con un Golpe de Suerte
- #6: Incidente de Hundred Finance: Catalizando la Ola de Exploits Relacionados con Precisión en Protocolos Bifurcados Vulnerables
- #7: Incidente de ParaSpace: Una Carrera Contra el Tiempo para Frustrar el Ataque Más Crítico de la Industria
- #8: Incidente de SushiSwap: Un Torpe Intento de Rescate Conduce a una Serie de Ataques Imitadores
- #10: Incidente de ThirdWeb: La Incompatibilidad Entre Módulos de Confianza Expone una Vulnerabilidad



