fondo

El artículo anterior de CertiK, "Jugando un nuevo juego en la cadena, revelando la técnica RugPull a gran escala", reveló una estafa de salida a gran escala de dirección de recolección automática 0xdf1a para nuevos robots, que se completó en aproximadamente dos meses. 200 estafas de salida (en lo sucesivo denominadas colectivamente RugPull), pero este grupo no tiene un solo método RugPull.

El artículo anterior utilizó el token MUMI como ejemplo para describir el método RugPull de la pandilla detrás de la dirección: modifica directamente el saldo de tokens de la dirección fiscal a través de la puerta trasera del código, pero no modifica el suministro total de tokens ni envía una transferencia. evento, lo que hizo que los usuarios que verificaron etherscan no pudieran descubrir que el lado del proyecto estaba acuñando tokens en secreto.

El artículo de hoy utiliza el token "ZhongHua" como ejemplo para analizar otro método de RugPull del grupo: utilizar una lógica de función fiscal compleja para encubrir la función de transferencia que se puede utilizar para RugPull. A continuación, analizamos los detalles de otro método RugPull en la dirección 0xdf1a a través del caso del token "ZhongHua".

En lo profundo de la estafa

En este caso, el grupo del proyecto utilizó un total de 999 mil millones de ZhongHua para intercambiar por aproximadamente 5,884 WETH, drenando la liquidez del fondo común. Para obtener una comprensión más profunda de toda la estafa de RugPull, analicemos los eventos desde el principio.

Implementar tokens

A la 1:40 a.m. del 18 de enero (hora UTC, lo mismo a continuación), la dirección del atacante (?0x74fc) implementó un token ERC20 llamado ZhongHua (?0x71d7) y preminó mil millones de tokens para enviar al ataque o dirección (? 0x74fcfc).

La cantidad de tokens preminados es consistente con la cantidad definida en el código fuente del contrato.

Agregar liquidez

A la 1:50 (10 minutos después de que se creó el token), la dirección del atacante (?0x74fc) otorgó permiso de aprobación del token ZhongHua al enrutador Uniswap V2 en preparación para agregar liquidez.

1 minuto después, la dirección del atacante (?0x74fc) llama a la función addLiquidityETH en el enrutador para agregar liquidez para crear el fondo de liquidez ZhongHua-WETH (?0x5c8b), agrega todos los tokens previamente extraídos y 1,5 ETH al fondo de liquidez, y finalmente Obtén aproximadamente 1.225 tokens LP.

De los registros de transferencia de tokens anteriores, podemos ver que en una transferencia, el atacante (? 0x74fc) envió 0 tokens al contrato de token de ZhongHua.

Esta transferencia no es una transferencia normal para agregar liquidez. Al observar el código fuente del contrato del token, encontramos que se implementa una función _getAmount, que es responsable de deducir el dinero de la dirección de origen de la transferencia y calcular la tarifa de manejo. cargado, y luego agregar la tarifa de manejo, enviarlo a la dirección del token y luego activar el evento de Transferencia que indica que la dirección del token ha recibido la tarifa de manejo.

La función _getAmount determinará si el remitente de la transferencia es _propietario. Si es _propietario, la tarifa de gestión se establecerá en 0. _owner es asignado por el parámetro de entrada del constructor cuando se implementa el contrato Ownable.

El contrato de token de ZhongHua hereda el contrato Ownable y utiliza el implementador msg.sender como parámetro de entrada del constructor Ownable durante la implementación.

Por lo tanto, la dirección del atacante (?0x74fc) es la del propietario del contrato del token. La transferencia de token 0 que agrega liquidez se envía a través de la función _getAmount, porque _getAmount será llamada dentro de las funciones transfer y transferFrom.

Bloquear la liquidez permanentemente

A las 1:51 (dentro de 1 minuto de la creación del fondo de liquidez), la dirección del atacante (?0x74fc) enviará todos los 1.225 tokens LP obtenidos agregando liquidez directamente a la dirección 0xdead para completar el bloqueo permanente de los tokens LP.

Al igual que en el caso del token MUMI, cuando LP está bloqueado, teóricamente la dirección del atacante (?0x74fc) ya no tiene la capacidad de realizar RugPull eliminando liquidez. En la estafa RugPull liderada por la dirección 0xdf1a, que apunta a robots nuevos, este paso se utiliza principalmente para engañar al script antifraude de los robots nuevos.

En este punto, desde la perspectiva del usuario, todos los tokens previamente extraídos se agregaron al fondo de liquidez y no se produjo ninguna anomalía.

AlfombraTirar

A las 2:10 am (aproximadamente 30 minutos después de que se creó el token ZhongHua), la dirección del atacante 2 (?0x5100) implementó un contrato de ataque (?0xc403) específicamente para RugPull.

Al igual que en el caso de los tokens MUMI, el lado del proyecto no utilizó la dirección de ataque para implementar el contrato de token ZhongHua, y el contrato de ataque utilizado para RugPull no es de código abierto. El propósito es dificultar que los técnicos rastreen la fuente. La mayoría de las estafas de RugPull tienen esta especialidad.

A las 7:46 a.m. (aproximadamente 6 horas después de que se creó el contrato del token), la dirección del atacante 2 (?0x5100) realizó un RugPull.

Al llamar al método "swapExactETHForTokens" del contrato de ataque (?0xc403), transfirió 999 mil millones de tokens ZhongHua del contrato de ataque a cambio de aproximadamente 5,884 ETH y agotó la mayor parte de la liquidez del grupo.

Dado que el contrato de ataque (?0xc403) no es de código abierto, descompilamos su código de bytes y los resultados son los siguientes:

https://app.dedaub.com/ethereum/address/0xc40343c5d0e9744a7dfd8eb7cd311e9cec49bd2e/decompiled

La función principal de la función "swapExactETHForTokens" del contrato de ataque (? 0xc403) es usar primero aprobar para otorgar al enrutador UniswapV2 la cantidad máxima de permisos de transferencia de tokens ZhongHua y luego usar el enrutador para transferir la cantidad de tokens ZhongHua especificados por la persona que llama como "xt" (propiedad del contrato de ataque (? 0xc403)) se convierte en ETH y se envía a la dirección "_rescue" declarada en el contrato de ataque (?0xc403).

Se puede ver que la dirección correspondiente a "_rescue" es exactamente el implementador del contrato de ataque (? 0xc403): dirección del atacante 2 (? 0x5100).

El parámetro de entrada xt de esta transacción RugPull es 999.000.000.000.000.000.000, correspondiente a 999 mil millones de tokens ZhongHua (el decimal de ZhongHua es 9).

Al final, el equipo del proyecto utilizó 999 mil millones de ZhongHua para drenar el WETH en el fondo de liquidez y completar RugPull.

Al igual que en el caso MUMI del artículo anterior, primero debemos confirmar la fuente de los tokens ZhongHua en el contrato de ataque (?0xc403). Del artículo anterior, aprendimos que el suministro total de tokens ZhongHua es de mil millones. Después de que finalizó RugPull, el suministro total de tokens ZhongHua que consultamos en el explorador de bloques seguía siendo de mil millones, pero el contrato de ataque (? 0xc403) El número. de tokens vendidos es 999 mil millones, que es 999 veces el suministro total registrado en el contrato. ¿De dónde provienen estos tokens que exceden con creces el suministro total?

Verificamos el historial de eventos de transferencia ERC20 del contrato y descubrimos que, al igual que en el caso RugPull del token MUMI, el contrato de ataque (?0xc403) en el caso del token ZhongHua tampoco tenía eventos de transferencia de token ERC20.

En el caso de MUMI, los tokens del contrato fiscal provienen de modificaciones directas al saldo en el contrato de tokens, lo que hace que el contrato fiscal posea directamente tokens que superan con creces la oferta total. Dado que el contrato de token MUMI no modifica el suministro total del token al modificar el saldo, ni activa el evento de Transferencia, no podemos ver el registro de transferencia de token del contrato de impuestos en el caso MUMI, como si se usara el contrato de impuestos. para tokens RugPull como Es como aparecer de la nada.

Volviendo al caso de ZhongHua, los tokens de ZhongHua en el contrato de ataque (? 0xc403) también parecieron aparecer de la nada, por lo que también buscamos la palabra clave "equilibrio" en el contrato de tokens de ZhongHua.

Los resultados muestran que solo hay tres modificaciones en la variable de saldo en todo el contrato de token, respectivamente en las funciones "_getAmount", "_transferFrom" y "_transferBasic".

Entre ellos, "_getAmount" se usa para procesar la lógica de cobro de tarifas de transferencia, y "_transferFrom" y "_transferBasic" se usan para procesar la lógica de transferencia. Obviamente, no hay ninguna declaración que modifique directamente el saldo como el token MUMI como se muestra a continuación. .

Más importante aún, el contrato de token MUMI no activó el evento de transferencia cuando modificó directamente el saldo del contrato de impuestos. Es por eso que no podemos consultar el evento de transferencia de token del contrato de impuestos en el navegador de bloques, pero el contrato de impuestos puede tener un. gran cantidad de tokens. El motivo de la moneda.

Sin embargo, en el contrato de token de ZhongHua, ya sea la función "_getAmount", "_transferFrom" o "_transferBasic", todas activan correctamente el evento Transfer después de modificar el saldo. Esto es consistente con nuestro contrato de consulta y ataque anterior (? 0xc403. ) Es un conflicto que el evento de transferencia no se puede encontrar cuando ocurre el evento de Transferencia relacionado.

¿Podría ser que, a diferencia del caso MUMI, los tokens de este contrato de ataque (?0xc403) realmente aparecieron de la nada?

Técnica revelada

¿De dónde proceden los tokens que se utilizan para atacar los contratos?

En el proceso de análisis del caso, cuando descubrimos que cada modificación del saldo en el contrato de ZhongHua activaba correctamente el evento de Transferencia, pero nunca pudimos encontrar el registro de transferencia de token o el evento de Transferencia relacionado con el contrato de ataque (? 0xc403), Es necesario encontrar nuevas ideas analíticas.

Consultamos una gran cantidad de registros de transferencia y una vez utilizamos la función "performZhongSwap" en el contrato como un gran avance. Esta función es responsable de vender tokens en el contrato de tokens. En otros eventos de RugPull que analizamos, hubo muchos casos como este. Función de clase como un caso de puerta trasera RugPull.

A pesar de comprobar otras funciones, no encontré nada. Así que comenzamos a centrarnos en la función de "transferencia" en sí. No importa cómo el atacante realice RugPull, la lógica de implementación de la función de "transferencia" debe contener la información más importante.

Transferencia fatal

La función "transferir" en el contrato de token llama directamente a la función "_transferFrom".

Parece que la función "transferir" realiza una operación de transferencia de token y el evento de transferencia se activará una vez completada la transferencia.

Pero antes de transferir tokens, la función "transferir" primero usará la función "_isNotTax" para determinar si el remitente de la transferencia es una dirección libre de impuestos: si no, use la función "_getAmount" para recaudar impuestos; si es así, no; Se cobrarán los impuestos y los tokens se enviarán directamente al destinatario. Y ahí es exactamente donde radica el problema.

Como se mencionó anteriormente, en la implementación de "_getAmount", el contrato de token verifica el saldo del remitente, deduce el monto del remitente y luego envía la tarifa de procesamiento al contrato de token.

El problema es que solo se llama a "_getAmount" cuando el remitente no es una dirección exenta de impuestos. Cuando el remitente es una dirección libre de impuestos, el monto se agrega directamente al saldo del destinatario.

En este punto, el problema se vuelve muy claro: cuando la dirección libre de impuestos se utiliza como remitente para la transferencia, el contrato simbólico no verifica si el saldo del remitente es suficiente, o incluso resta el monto del saldo del remitente. Esto significa que se puede enviar cualquier cantidad de tokens a cualquier dirección siempre que sea una dirección libre de impuestos definida por el contrato del token. Es por eso que el contrato de ataque (?0xc403) puede transferir directamente 999 veces el suministro total de tokens.

Después de la inspección, se descubrió que el contrato del token solo establecía _taxReceipt como una dirección libre de impuestos en el constructor, y la dirección correspondiente a _taxReceipt era el contrato de ataque (? 0xc403).

Desde entonces, se ha determinado el método de RugPull de los tokens de ZhongHua: el atacante utiliza una lógica específica para eludir la verificación del saldo de la dirección privilegiada, permitiendo que la dirección privilegiada transfiera tokens de la nada, completando así el RugPull.

Cómo obtener ganancias

Aprovechando la vulnerabilidad anterior, la dirección 2 del atacante (? 0x5100) llama directamente a "swapExactETHForTokens" del contrato de ataque privilegiado (? 0xc403) para completar RugPull. En la función "swapExactETHForTokens", el contrato de ataque (? 0xc403) otorgó permiso de transferencia de tokens al enrutador Uniswap V2 y luego llamó directamente a la función de intercambio de tokens del enrutador para intercambiar 999 mil millones de tokens ZhongHua por 5,88 ETH en el grupo.

De hecho, además de la transacción RugPull mencionada anteriormente, el equipo del proyecto también vendió tokens 11 veces a través del contrato de ataque (?0xc403), ganando un total de 9,64 ETH más la última transacción RugPull, se obtuvo un total de 15,52 ETH; . El costo es solo 1,5 ETH para agregar liquidez, una pequeña tarifa por implementar contratos y una pequeña cantidad de ETH para inducir a nuevos robots a intercambiar activamente.

El equipo del proyecto incluso utilizó diferentes direcciones EOA para llamar al contrato de ataque (?0xc403) para vender tokens a mitad de camino. Parecía que diferentes remitentes estaban vendiendo tokens para disfrazar su verdadera intención de cobrar continuamente.

Resumir

Ahora, mirando hacia atrás y pensando en todo el caso RugPull del token ZhongHua, descubrí que el método en sí es muy simple: simplemente cancela la verificación del saldo del token de la dirección privilegiada. Pero ¿por qué no fue tan fluido el análisis de este caso? Puede haber dos razones principales:

1. La protección y el ataque a la seguridad tienen visiones diferentes. Para los profesionales de la seguridad, la verificación del saldo en el código es la garantía de seguridad más básica que debe completarse. Por lo tanto, la mayoría de los profesionales de la seguridad creerán inconscientemente que la función de "transferencia" completará la verificación del saldo del usuario de forma natural. Tenga cuidado con estas vulnerabilidades (o piense que son demasiado básicas y los atacantes no las utilizarán).

Sin embargo, desde la perspectiva del atacante, el método de ataque más efectivo suele ser el más simple: no verificar el equilibrio es un método RugPull que es efectivo y fácilmente ignorado, y no hay razón para no usarlo. De hecho, este es el caso, al menos desde la perspectiva de la caracterización del caso, el método RugPull en el caso del token ZhongHua deja la menor cantidad de rastros y es mucho más difícil de rastrear que otros tipos de RugPull. Audite manualmente el código para localizar la puerta trasera del código.

2. El equipo del proyecto está ocultando conscientemente el código de puerta trasera que no requiere verificación de saldo para direcciones privilegiadas. El equipo del proyecto incluso implementó de forma independiente un conjunto completo de lógica de cálculo de transferencia de impuestos y lógica de retiro y reinversión de direcciones de tokens para direcciones no privilegiadas, lo que hace que parezca razonable implementar una lógica de transferencia compleja para tokens. Al transferir fondos a otras direcciones normales, el comportamiento es el mismo que el normal y no se puede encontrar ninguna pista sin mirar el código detenidamente.

Al comparar los casos RugPull de este equipo para los tokens MUMI y los tokens ZhongHua, ambos utilizan métodos relativamente encubiertos para permitir que las direcciones privilegiadas tengan derecho a controlar una gran cantidad de tokens.

En el caso del token MUMI RugPull, la parte del proyecto modificó directamente el saldo sin modificar el suministro total ni desencadenar el evento Transfer, lo que hizo imposible que los usuarios percibieran que la dirección privilegiada ya poseía una gran cantidad de tokens.

El caso del token de ZhongHua es más completo. Al no verificar directamente el saldo de la dirección privilegiada, es imposible descubrir que la dirección privilegiada ya posee tokens ilimitados por cualquier otro medio que no sea mirar el código fuente (usando balanceOf para consultar el saldo). de la dirección privilegiada La visualización es 0, pero se pueden transferir tokens ilimitados).

El caso RugPull del token ZhongHua refleja los posibles problemas de seguridad de los estándares de tokens. En términos de seguridad, el estándar de token ERC20 solo puede usarse para restringir a los caballeros, pero no puede protegerse contra los villanos. Los atacantes suelen ocultar puertas traseras que son difíciles de detectar bajo la premisa de implementar una lógica empresarial estándar. Al estandarizar el comportamiento de los tokens, aunque se reduce la flexibilidad de funciones, se evita la posibilidad de puertas traseras ocultas y se proporciona más seguridad.