June 14, 2022
How to Steal User’s Signature in NFT Phishing Attacks
Phishing attacks aimed at Opensea users
On February 21, 2022, Opensea suffered a phishing attack, and some users have had their NFTs stolen due to the approval they signed to the hackers.
The relevant information of the attacker is as follows:
Attacker’s address (Fake_Phishing5169): 0x3e0defb880cd8e163bad68abe66437f99a7a8a74
Attacker’s Contract (Fake_Phishing5176): 0xa2c0946ad444dccf990394c5cbe019a858a945bd
The relevant transaction is shown below:
We take one of the transactions to analyze:
From the above figure, we can see that the attacker first obtained the user's approval, and then directly called the transferfrom method to steal the user's NFT.
By analyzing the transactions, we can divide the attack flow into the following three main steps:
1. Constructing the correct transaction to be signed.
2. Luring users into clicking on ‘Sign’.
3. Constructing an attack contract to steal the user's NFT after obtaining the user's signature.
By analyzing transaction signature constructed by the attacker and by tracing the function call stack, we found the specific signature information as follows.
From the above figure, the signature is calculated as: keccak256("\x19 Ethereum Signed Message:\n32", hashOrder(order)); this signature will add another message prefix before the order: '\x19 Ethereum Signed Message:\n32', to ensure that the signature change cannot be used outside of Ethereum. After that, the complete data with the message prefix will be added and then the keccak256 value will be calculated and finally signed with the private key.
However, this method can only declare ownership and cannot prevent replay attacks. For example, if user A signs a message and sends it to contract M, another user B can replay this signature to contract N. The figure below shows the specific information involved in the order signature.
The main parameters of the signature involved are:
- Side: Buy or Sell
- paymentToken: the type of token used to pay for the order
- basePrice: the price of NFT in the order
- maker: order issuance address
- taker: the destination address for receiving orders
The above signature information contains sensitive information such as order amount and destination address, but the value after keccak256 computation of Hash is just a string of binary strings, which cannot be recognized by users.
The attacker constructs a signature based on the above Order information, and can arbitrarily set the amount of the basePrice parameter involved in the above signature to 0, and set the receiving address to himself, etc.
After the attacker constructs the data to be signed he can trick the user into clicking on ‘sign’. Since the metadata of the signature is 66 hexadecimal characters containing 0x obtained after Keccak256 calculation, the users cannot know the specific meaning of what it represents and may directly click on ‘sign’, allowing the attacker to obtain the user's pending approval.
The signature above is similar to a blind signature for the user, i.e., the content of the signed message is blind to the signer, who cannot see the exact content of the message.
Opensea launched Seaport, a smart NFT marketplace, on May 20, 2022, where sellers can offer a number of assets listed under the ERC-20, ERC-721, and ERC-1155 standards, called "offers," and buyers receive a few items called "consideration". Each Seaport listing contains the same basic structure, including an improved EIP-712 signature payload. Since EIP-712 is based on the EIP-191 standard, the EIP-191 standard is described below.
The value of <1 byte version> indicates the data type of the signature, and the value of 0x01 in EIP-712 standard represents structured data; <version specific data> and <data to sign> indicate the version specific data and the data to be signed respectively.
The improved EIP-712 standard in OpenSea has <version specific data> as Domain.js and <data to sign> as order.js, where Domain represents the domain separator and order represents the order metadata to be signed.
The four EIP712 domain separators defined above are basically the same as Uniswap-v2, with the following meanings.
- string name: the name of the readable signature field, in this case the NFT name.
- string version: the version of the current signature field, in this case "1".
- uint256 chainId: ID of the current chain, note that since Solidity does not support getting this value directly, inline assembly is used.
- address verifyingContract: the address of the verifying contract.
As can be seen from the above code, the domain includes the NFT name, version number, chainId and the contract address of the interaction. By verifying this information, it is ensured that the same signature cannot be replayed in different applications.
As can be seen from the source code, the order data is divided into three parts to describe the order item, the buyer item, and the seller item.
In step 2 the attacker obtains the R, S and V values in the ECDSA signature message and can use it to construct an attack contract to steal the user's NFT. The following figure shows the function validateOrder() in the OpenSea: Wyvern Exchange v1 contract to verify order. The source code is as follows.
As seen from the source code, order validation first checks the validity of the order and whether it contains valid parameters, and then checks whether the order has ever passed the in-chain validation. The approvedOrders is a mapping variable that holds all the orders that have passed the on-chain validation. If the order has been validated before, it returns true directly, eliminating the need to use erecover() to verify the ECDSA signature so that the smart contract can place the order directly.
Here is one of the NFT theft transactions, where it can be found that the attacker used the user's signature to steal the user's NFT for 0 ether by invoking the attacker contract (Fake_Phishing5176): 0xa2c0946ad444dccf990394c5cbe019a858a945bd.
The following are our security recommendations in face of these frequent phishing attacks.
1) When you sign, be sure to check the content of the transaction you are signing, including the transaction price, transaction address and other information. Do not sign if there are contents that cannot be clarified, such as the contents of a binary string only.
2) Be alert when clicking on any links or attachments in any emails, or enter any personal information.
3) Confirm the official website address on the official Twitter or Discord account.
4) Install anti-phishing extension, which can assist in identifying some of the phishing sites.
Beosin Alert extension:
Related Project Secure Score
Guess you like
Are NFT tools safe? What we can learn from the Premint hack?
July 19, 2022
Beosin Has Completed Security Audit Service of Doge Chain
June 28, 2022
Beosin cryptocurrency tracing service is officially launched
May 31, 2022
Beosin and CrossSpace have entered into a strategic partnership
July 20, 2022