On the security of Booba's music video and NFTs

 · 7 mins read

By The Donjon

If you bought one or several of these NFTs and wonder if they are safe and secure, don’t worry, they are. You can directly skip the technical details to read the conclusion.

The 3rd of November 2021, Booba (the french rapper who created the label La Piraterie Music) put a set of 5 NFTs up for sale, for a total of 5000 of each of these animated cards. The totality of these NFTs were sold in a few days for 150 ETH (0.006 ETH each), that is more than $700.000 at this date. As a bonus, lucky owners of one of these NFTs were allowed to see the exclusive music video TN since the 8 November 2021.

Les rappeurs m’envient, sont tous en galère.
Boulbi, Ouest Side

We were a bit curious and wondered how the music video was protected and if we could enjoy it even if we didn’t buy any NFTs.

https://nft.booba.store website

How does the music video protection work?

In order to see the video, owners of the NFTs have to visit the page /mon-nft and use their crypto wallet (such as Metamask or WalletConnect) to sign the Ethereum message "Pour accéder à TN, merci de bien vouloir signer ce message" with the same wallet than the one used to buy the NFTs. Once signed, a POST request with a JSON body following this format is sent by the web browser to a web service hosted on AWS:

{
  "message": "\"Pour accéder à TN, merci de bien vouloir signer ce message\"",
  "signature": "8c4435197414c4a0d9328efbf91520802c2b1d0df1391657c8e418ec6da3ab7944c2569f9e08b4c5d5d621ed7bd13802e4bed25c248deec6b690b2e29cb155c21b",
  "wallet": "3b3edc7756718908ad5d67ef0a073ec601ed30d8"
}

A few tests show that messages different from the default one aren’t rejected as long as they are JSON-encoded. For instance: [1337] and "blah" are considered as valid, however messages that aren’t in JSON trigger an internal error instantly.

If the signature associated to the Ethereum address (wallet) and message are valid, the server verifies that the wallet indeed bought one of the NFTs, otherwise the error Tu ne possèdes aucun des NFTs is returned. This last step takes a little more time, which let us formulate the following hypothesis. If we find on the Internet a public key that meet these 2 conditions:

  • The public key signed a JSON message and the associated signature is public;
  • The wallet bought at least one of the NFTs.

it might be possible to replay the message and the signature on the AWS server to retrieve the music video.

The BOOBA TN NFT is also an ERC-20 token (B2O_TN) minted by the smart contract 0x3b73…94dd. We first started by listing all the NFT owners thanks to etherscan.io. At the time of writing, there were 3484 owners of at least 1 of these NFTs. 1516 wallets own more than one of the same NFT, probably to resell one of these later.

Un jour de mon salaire c’est leur assurance vie.
Boulbi, Ouest Side

1st attempt - etherscan.io

Ethereum messages are encoded using the personal_sign format ("\x19Ethereum Signed Message:\n" + length(message) + message) before being signed using ECDSA. Since Ethereum transactions are encoded into a different format (RLP), transaction signatures can’t be recognized as valid message signatures. Put it differently, message signatures can’t be found on the Ethereum blockchain.

The first place where we found off-chain Ethereum messages is etherscan.io, which provides a web interface to verify an Ethereum message signature and eventually save it to make accessible via a public URL. We first retrieved all Ethereum messages saved through this service: etherscan.io/verifiedSignatures.

For instance verifySig/2642 shows that the NFT owner of Boring Ape #6743 proved that he also is the owner of the Twitter account ape6743:

  • Address: 0xd3AefE3c531E3E2eB0689206E7D495843c943550
  • Signature: 0xea5732cd450959f1e1180f094bbc0c69a75f0d14f340b7ac2be39ceff74b930567d43552d1026dc18c044f330c1fcf6e7e355a75cd3cdccc8b8e09aa8c3664541c
  • Message: I am @ape6743 on Twitter aka Boring Ape #6743 aka Boring Bored Ape aka BBA.

He’s also an owner of the NFTs Booba TN as shown in this transaction. However, even if the signature is valid, the message isn’t JSON formatted and can’t be recognized by the AWS server.

Tu n’peux que gagner quand t’as rien à perdre.
Magnifique, Trône

2nd attempt - snapshot.org

The website snapshot.org allows individuals to vote for proposals by using their Ethereum wallet: Snapshot is an off-chain gasless multi-governance client with easy to verify and hard to contest results. Votes are coincidentally in JSON format.

A GraphQL interface can be used to query the votes database. For instance, the following minimal GraphQL request returns vote IDs where the voter address is 0x668248dF4595e09Aa253B31478312748078F7a20:

query Votes {
  votes (where: {voter_in: "0x668248df4595e09aa253b31478312748078f7a20"}) { id }
}

The query result shows that this address has been used for 2 votes:

{
  "data": {
    "votes": [
      {
        "id": "QmZL5toFBQrPgNDPTpQCukWtcjWeT5x6nou75wMMTm52zM"
      },
      {
        "id": "QmQLSv36j3GLdRjubqpXjpAgwYG77Mop5T9uLCi73r1SUT"
      }
    ]
  }
}

The votes signed by each wallet owning Booba TN NFTs can be retrieved in its entirety with a single GraphQL request. There are 689 results for 140 unique voters.

The address 0x668248dF4595e09Aa253B31478312748078F7a20 bought 5 Booba TN NFTs. As shown previously, this address also voted for the following proposals:

The associated votes are stored on the InterPlanetary File System (IPFS): QmZL5toFBQrPgNDPTpQCukWtcjWeT5x6nou75wMMTm52zM and QmQLSv36j3GLdRjubqpXjpAgwYG77Mop5T9uLCi73r1SUT. The content of the first vote is:

{
  "address": "0x668248df4595e09aa253b31478312748078f7a20",
  "msg": "{\"version\":\"0.1.3\",\"timestamp\":\"1636417994\",\"space\":\"ens.eth\",\"type\":\"vote\",\"payload\":{\"proposal\":\"0xd810c4cf2f09737a6f833f1ec51eaa5504cbc0afeeb883a21a7e1c91c8a597e4\",\"choice\":[1,2,3,4],\"metadata\":{}}}",
  "sig": "0x74139b87dee26f0943328538af7cb7eebacb0f5b57a6bac7a0bff56408e8c1a83faae0586fa383dba4f9a15862cfdd6d4af483cf07b3c858a8350a332d6bf36e1c",
  "version": "2"
}

Quand j’ai la clé j’m’en sers pour casser l’carreau.
Strass et paillettes, Temps mort

This JSON data can be replayed almost as is (the address, msg and sig keys should respectively be replaced with wallet, message and signature) on the AWS server to eventually retrieve the video URL:

{"url":"https://nft.booba.store/547/tn_4k.mp4?Expires=1636537514&Key-Pair-Id=K16KO12XTB81BE&Signature=rAeeMsi~9595MVXuu73jn~e1u-XBwm2Q~gYz0pOrjYRCi0zfXG2tRxllbsz8FfuXYG6RAMbPX8o023HyRS-cLG59TYZa8H4pKWtBahi38Dz8SdmRcrYUCq4umszr18pco6eqbnf50RS4p8fouOPE03nckjG~G-cOTkk7ABw~M0OBDBt9PrNCXrVCy8k-TtgCVtkWzNm0pF2xBoLtbBHcuuijNfNtN8-QCyVXTewWvbUCIM77qLS5HbiCADH-dXGYP4bN9ZMgCvlS~oNWeSqw993BlOyxQ-BxlKSrtNWN5-N3Psx7sTztQ6L-y7I94Ur34QMWYDWHDYBnp0yPX8Sbeg__"}

video screenshot

Please note that the URL expires after a period of time and isn’t valid anymore.

Conclusion

This blogpost shows that even if the cryptography powering this NFT event is sound, a basic replay attack was sufficient to break the music video protection. The fix is simple: the message sent to the AWS server should be rejected if it doesn’t match the message sent to the crypto wallet.

La piraterie n’est jamais finie !
Walabok, Nero Nemesis

Once contacted (finding the right contact was actually the most difficult part), the developers from RenaissanceNFT were super cooperative and responsive. The issue was fixed within less than an hour and the protection access can’t be bypassed anymore.