-
Notifications
You must be signed in to change notification settings - Fork 311
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
AWARD: Ark Protocol Claim Best Auditor and/or Bug :) #158
Comments
Zip file contains wasm contract and changed sources on ICS721 contract. |
Huge shoutout to our team member @Art3miX who found this code snippet in the spec, indicating and depending on app chain how it is implemented there might be an issue: https://github.com/cosmos/ibc/blob/main/spec/app/ics-721-nft-transfer/README.md?plain=1#L362 |
Please also note from example above that name has also been changed: # before transfer:
iris query nft token arkprotocol001 arkNFT003 --output json | jq
{
"id": "arkNFT003",
"name": "This is the OG collection",
"uri": "https://my-og-collection.io",
"data": "{\"og\": \"collection\"}",
"owner": "iaa183e7ccwsnngj2q8lfxnmekunspnfxs6qxd4v3f",
"uri_hash": ""
}
# after exploited transfer:
iris query nft token arkprotocol001 arkNFT003 --output json | jq
{
"id": "arkNFT003",
"name": "",
"uri": "https://my-og-collection.io",
"data": "\"{\\\"exploit\\\": \\\"gotcha\\\"}\"",
"owner": "iaa183e7ccwsnngj2q8lfxnmekunspnfxs6qxd4v3f",
"uri_hash": ""
} |
Some additional links and proofs we have been involved in auditing and testing of ICS721 spec and implementations:
Source: public-awesome/cw-ics721@6b43422
Spec: https://github.com/cosmos/ibc/tree/main/spec/app/ics-721-nft-transfer#data-structures
Source: public-awesome/cw-ics721#43
Launchpad on 4 chains for massive ICS721 tests with Cosmos community: https://twitter.com/arkprotocol/status/1605876731633623040?s=20
Review spec, test and identified bug in nft module on passing wrong JSON format in case Class URIs and Token URIs are empty. |
Are you saying that this works only if a user interacts with a fake site? |
Even better: I could buy a cheap NFT, transfer it over, change to legendary traits, transfer it back and list it on a marketplace. |
if you back to origin, the module should only transfer the nft to the receiver, not modify it. |
Correct. Precisely ICS721 burns NFT on source chain and unlock it on target chain. Token data should be passed to collection, like CW721, which can then do whatever it wants to - even changing it. That's what ICS721 is suppose to do, nothing more. |
The key to this problem is that users believe in illegal ICS721 contracts, the most common of which is phishing attacks. So we should find a way for users to easily prove the legitimacy of the contract, I think this should be what the nft marketplace should do |
I think thats only 1 use-case. We are talking about transfers here, and by the spec those are permission-less, so what I as a user can do, is create my own cw721 contract on any chain (Juno for example), do changes to the metadata (and name), and send back to source chain, the result would be NFT with changed metadata by what I chose it to be, here is a step by step:
Result: original cheap NFT (NFT1) turns into a 1/1 NFT (very rare) simply by sending it over to Juno to my own custom cw721 contract. Allowing metadata changes from target chain, without any permissions or controlled environment is very risky, and from the above example metadata becomes useless as any user can easily change them to any value they want. |
main branch has changed - still though it hasn't changed. Referring to link at the time of above comment: https://github.com/cosmos/ibc/blob/4bf1dd9a64a7e8bad1f5c1a47ce3cf1ec58ac581/spec/app/ics-721-nft-transfer/README.md?plain=1#L362 Wihat we are pointing out is that nft module takes token data from source and overrides existing NFT. So everything is possible here: metadta, uri, owner... |
The problem has been identified by @Art3miX, Ark Protocol, last month: https://discord.com/channels/@me/1037612546707959878/1078657001577521233 |
checking the code, the |
@Art3miX can you prove that the |
No, the issue was only with the TokenData last I saw, it was simply taken from the sent packet, and replaced as is, which would cause metadata to be useless as anyone can easily change them with a simple transfer. |
The general problem I wanted to outline in this issue is that nft module takes incoming packet 'as-given' and trusts it, without checking anything that is passed in type NonFungibleTokenPacketData struct {
// the class_id of class to be transferred
ClassId string `protobuf:"bytes,1,opt,name=class_id,json=classId,proto3" json:"class_id,omitempty"`
// the class_uri of class to be transferred
ClassUri string `protobuf:"bytes,2,opt,name=class_uri,json=classUri,proto3" json:"class_uri,omitempty"`
// the class_data of class to be transferred
ClassData string `protobuf:"bytes,3,opt,name=class_data,json=classData,proto3" json:"class_data,omitempty"`
// the non fungible tokens to be transferred
TokenIds []string `protobuf:"bytes,4,rep,name=token_ids,json=tokenIds,proto3" json:"token_ids,omitempty"`
// the non fungible tokens's uri to be transferred
TokenUris []string `protobuf:"bytes,5,rep,name=token_uris,json=tokenUris,proto3" json:"token_uris,omitempty"`
// the non fungible tokens's data to be transferred
TokenData []string `protobuf:"bytes,6,rep,name=token_data,json=tokenData,proto3" json:"token_data,omitempty"`
// the sender address
Sender string `protobuf:"bytes,7,opt,name=sender,proto3" json:"sender,omitempty"`
// the recipient address on the destination chain
Receiver string `protobuf:"bytes,8,opt,name=receiver,proto3" json:"receiver,omitempty"`
// optional memo
Memo string `protobuf:"bytes,9,opt,name=memo,proto3" json:"memo,omitempty"`
} The most severe issued is in this case Simply said: Next one is |
Still there is a bug left here, as noted in #705, in this comment: #705 (comment) When creating a collection with nft module these 2 flags can be set:
In this bug, a collection was created with Though when sending NFT to another chain and back, nft-transfer module was changing token data. |
Not sure whether the following exploit covers Best Auditor or Bug or both :).
Summary
There is a way of rugging an NFT and changing its (token) data, by having the following setup:
Original collection is e.g. on IRISnet
Collection is created on IRISnet and an NFT is minted with token data
An exploited ICS721 contract is setup e.g. on Stargaze
On receiving an NFT (from IRISnet) it does:
This contract overrides incoming recipient address send from IRISnet and provides its own address as new NFT owner.
On sending an NFT (to IRISnet) it does:
sends an NFT with exploited/manipulated token data
Exploit happens this way then:
Steps to reproduce:
original ICS721 contract is here: https://github.com/public-awesome/ics721/tree/3af19e421a95aec5291a0cabbe796c58698ac97f/contracts/cw-ics721-bridge
On NFT receive and taking NFT ownership, replace line 55 with this: https://github.com/public-awesome/ics721/blob/3af19e421a95aec5291a0cabbe796c58698ac97f/contracts/cw-ics721-bridge/src/ibc_packet_receive.rs#L55
On NFT transfer and changing token data, replace line 190: https://github.com/public-awesome/ics721/blob/3af19e421a95aec5291a0cabbe796c58698ac97f/contracts/cw-ics721-bridge/src/contract.rs#L190
Now a honeypot on Stargaze needs to be setup:
Detailed steps:
The text was updated successfully, but these errors were encountered: