En este caso, no solo los desarrolladores de
SmartContracts deben disponer de conocimientos para codificar de forma segura, sino que también deben ser los usuarios de los contratos los que entiendan los riesgos básicos. El artículo de hoy va, precisamente, de esto. ¿Cómo puede afectar el
pshising a un
SmartContract? Expondré algún ejemplo que debemos entender y valorar antes de ponernos a interactuar con este entorno. Ya hemos hablado en el blog sobre
vulnerabilidades como la de Reentrancy que puede afectar a la pérdida o robo de fondos de un contrato y a un escenario de
bloqueo de criptomonedas de un contrato o denegación de servicio de un contrato. Hoy vamos a explicar un caso de
phishing basado en una mala práctica del uso del elemento
tx.origin.
En este artículo se puede ver
el riesgo de usar tx.origin para validar la propiedad de un contrato. ¿Qué es
tx.origin? En
Solidity se utiliza como variable global la cual devuelve la dirección pública de una cuenta. En este caso la dirección que envió la transacción. Debemos tener claro que si utilizamos
tx.origin para validar o chequear a los usuarios, dichos contratos serán vulnerables a ataques de
phishing. Hay que saber que
tx.origin es una variable global en
Solidity que devuelve la dirección de la cuenta que envió la transacción. Los contratos que utilizan
tx.origin para autorizar a los usuarios son vulnerables a los ataques de
phishing.
Escenario y ejemplo de vulnerabilidad
Para entender el concepto, vamos a suponer el siguiente escenario:
- Contrato A, el cual es vulnerable.
- Contrato B, el cual es un contrato preparado por un atacante.
- Usuario A, el cual será una víctima.
- Usuario B, el atacante.
El contrato
A tiene una función para transferir fondos. Recordemos que el contrato A es el contrato vulnerable. La función permite mover
ETH de un contrato a una dirección. El requisito para llevar a cabo esta operación de mover fondos es que
tx.origin sea igual al
owner del contrato.
¿Qué diferencia hay entre tx.origin y msg.sender? tx.origin es la variable que contiene el emisor de la transacción, es decir, la dirección que ha originado todas las posibles llamadas disparadas a través de los contratos (teniendo en cuenta que un contrato puede llamar a otro, y ese otro a otro…). La variable msg.sender almacena la dirección origen de la llamada actual, por lo que la diferencia es clara, la primera almacena el origen de todo y la segunda el origen de la llamada que se está ejecutando.
Figura 3: Escenario del ataque de phishing a tx.origen
Ahora que tenemos claro que es el
tx.origin, supongamos que el usuario
B (atacante) envía un
phishing al usuario
A. El usuario A confía en el
phishing y ejecuta una llamada contra el contrato
B a través del método ‘
attack’. El método ‘
attack’ va a provocar que se haga una llamada contra el contrato
A en el método ‘
Transfer’. El usuario
A es el que invoca
contratoB.attack por lo que llamada de
contratoB.attack a
contratoA.Transfer seguirá teniendo como
tx.origin al usuario
A.
Figura 4: Envio del phishing al usuario A
Si analizamos el requisito del método
contratoA.Transfer es que
tx.origin sea igual a
owner del contrato, por lo que, en este caso, quedará validado con este engaño al usuario
A. En la siguiente imagen, se va a mostrar el flujo completo y cómo se activan la pila de llamadas. De todos modos, vamos a hacer un pequeño resumen de la ejecución:
- El phishing enviado del usuario B al usuario A hace que éste ejecute la primera acción: El usuario A invoca a contratoB.attack. En este punto msg.sender y tx.origin tiene como valor la dirección del usuario A.
- El contratoB.attack es ejecutado, por lo que éste ejecuta una llamada al contratoA al método ‘Transfer’. En este caso, cuando se ejecuta contratoA.Transfer, msg.sender vale la dirección del contratoB, pero tx.origin sigue valiendo la dirección del usuario A. Aquí está la vulnerabilidad.
Figura 5: Resumen completo de llamadas con el robo de fondos
Al final, la transferencia se valida, ya que el requisito es que
tx.origin sea igual al
owner del contrato
A. En el engaño, en el contrato
B, seguramente, se configura para que los valores de transferencia sean para un
wallet del usuario
B y se produce el robo de fondos.