Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUG: Critical vulnerability allows attacker to take control of any NFT #346

Closed
giansalex opened this issue Mar 9, 2023 · 11 comments
Closed
Labels
bug Something isn't working golang ics-721 Possible protocol vulnerability

Comments

@giansalex
Copy link
Contributor

giansalex commented Mar 9, 2023

Summary of Bug

Chains using nft-transfer module are affected.

An attacker can create a custom ICS721 implementation on a remote chain, and send packets with a classId that matches the class-trace path of any NFT on the origin chain, because the nft-transfer module does not verify the owner of the NFT in the destination chain, the attacker can steal any NFT, even if the NFT has never been used in an IBC nft-transfer.

Environment

  • iris@1.4.1-gon-testnet
  • github.com/bianjieai/nft-transfer@v1.1.1-beta

Steps to Reproduce

  • Add custom code to ics721 implementation to allow sending packets with a custom classId,
    e.g {port}/{channel}/{remote-class-id}, where {remote-class-id} is the NFT class to attack.

malicious packet sent:

{
  "classId": "wasm.juno14svms48zknd2583kunct22haqf26tsmzd8z0n50zgfj9mkfygdvqxjhjdj/channel-113/bitvalidator01",
  "classUri": null,
  "classData": null,
  "tokenIds": [
    "bitnftA4"
  ],
  "tokenUris": null,
  "tokenData": null,
  "sender": "juno1zxtlyk7l6n3t46yqse84sza7ar39m8ul3gdfye",
  "receiver": "iaa1zxtlyk7l6n3t46yqse84sza7ar39m8uljcwrp5",
  "memo": "hack"
}

Expected and Actual Behavior

  • Expected: ACK with Error: Unauthorized NFT owner
  • Actual: attacker receives the NFT

Additional Context

@taramakage
Copy link
Member

Hey @giansalex, thank you for pointing this out.

So, before the attack, was the owner of the NFT a user with the address iaa1cj6pz6ly4kfxddhc844rf6lkvqze0fv96w47qh?

After the attack, the owner of the NFT became the attacker with the address iaa1zxtlyk7l6n3t46yqse84sza7ar39m8uljcwrp5, even though the real owner never did an IBC NFT transfer?

If I understood correctly, the nft-transfer module should have checked the owner of that NFT but it didn't. In this example, the owner should have been the escrow account iaa1ul6gkpnpd5lzllxc42d0fcd0z889tvxxmjlftc. As a result, the NFT was stolen.

> iris q nft-transfer escrow-address channel-39 nft-transfer 
iaa1ul6gkpnpd5lzllxc42d0fcd0z889tvxxmjlftc

@taramakage taramakage added bug Something isn't working ics-721 Possible protocol vulnerability labels Mar 10, 2023
@giansalex
Copy link
Contributor Author

giansalex commented Mar 10, 2023

@taramakage yes, any NFT in the chain can be stolen, even if it is not owned by IBC NFT escrow-address

@taitruong
Copy link
Contributor

This has been pointed out in #158. Where ALL token data can be manipulated, since target takes all token data from source and overrides NFT.

@giansalex
Copy link
Contributor Author

giansalex commented Mar 23, 2023

This has been pointed out in #158. Where ALL token data can be manipulated, since target takes all token data from source and overrides NFT.

??
this bug is not about manipulating the data, it's about stealing the NFTs.


Only tokenData can modified as I see in the code (referring to a native NFT on IRIS/Uptick/Omniflix)
check my comment #158 (comment)

@taitruong
Copy link
Contributor

This has been pointed out in #158. Where ALL token data can be manipulated, since target takes all token data from source and overrides NFT.

?? this bug is not about manipulating the data, it's about stealing the NFTs.

Only tokenData can modified as I see in the code (referring to a native NFT on IRIS/Uptick/Omniflix) check my comment #158 (comment)

I leave it to others judging on what manipulating or stealing is ;). As noted in my description in #158 I have provided 2 code snippets for:

  1. taken owner ship (overriding recipient) and
    let rugged_receiver = "stars1g0krhq56pmxmaz8lnj8h6jf55kcsq7x0lw5ywc";
    let receiver = deps.api.addr_validate(rugged_receiver)?;
  1. changing token data (example demos just "exploit", but all props in token data can be changed)
token_data: Some(vec![to_binary("{\"exploit\": \"gotcha\"}")?]),

Now as an exploiter, taking ownership, ofc I send it back to my sender wallet including manipulated metadata.

@giansalex
Copy link
Contributor Author

  1. taken owner ship (overriding recipient) and
    let rugged_receiver = "stars1g0krhq56pmxmaz8lnj8h6jf55kcsq7x0lw5ywc";
    let receiver = deps.api.addr_validate(rugged_receiver)?;

The receiver is not part of the NFT properties that you can change.
You are confusing the fact that a novice user sends the NFT to your IBC-channel, in that case you appropriate only that NFT (a type of Phishing).
The scenario that I pose does not involve cheating the user, you can steal any NFT from the chain, even one that has never been used IBC nft-transfer.

  1. changing token data (example demos just "exploit", but all props in token data can be changed)
token_data: Some(vec![to_binary("{\"exploit\": \"gotcha\"}")?]),

Now as an exploiter, taking ownership, ofc I send it back to my sender wallet including manipulated metadata.

That's what I'm saying, you can only change the TokenData, but you can't change the TokenUri as you claim in this comment.

image

@giansalex
Copy link
Contributor Author

@taitruong with this demo #705 (comment) , is it clear what the difference is?

@taitruong
Copy link
Contributor

taitruong commented Mar 24, 2023

@taitruong with this demo #705 (comment) , is it clear what the difference is?

Oh yes and pretty cool. Token data and uri was intial discussion. Please note in token data, there are ALL relevant data:

https://github.com/cosmos/ibc/blob/4bf1dd9a64a7e8bad1f5c1a47ce3cf1ec58ac581/spec/app/ics-721-nft-transfer/README.md?plain=1#L42-L50

It really includes all data:

  • class uri
  • a lost of ALL class ids, token data, and token uris
  • and Sender and receiver

As I said: thx for elaborating. With ONE single call you will be able to not ONLY rug one NFT but ALL NFTs on this collection. So we all, art3mix, you and I have been identifying vulnerables and exploits on many use cases: phishing, manipulating, stealing and burning NFTs and reminting NFTs.

Great job. Again. We all contributed on this.

@taitruong
Copy link
Contributor

I mean a 'list of ALL class ids'and not a 'lost of....' :)

@giansalex
Copy link
Contributor Author

giansalex commented Mar 24, 2023

As I said: thx for elaborating. With ONE single call you will be able to not ONLY rug one NFT but ALL NFTs on this collection. So we all, art3mix, you and I have been identifying vulnerables and exploits on many use cases: phishing, manipulating, stealing and burning NFTs and reminting NFTs.

yes. that is possible, but it does not change the consequence: any NFT stolen

@taramakage
Copy link
Member

This bug has been fixed in nft-transfer#12

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working golang ics-721 Possible protocol vulnerability
Projects
None yet
Development

No branches or pull requests

3 participants