Wallet Drainer Exploits Numerical Address Bypass Security Alerts

Overview

Recently, ScamSniffer and SlowMist teams discovered that some Wallet Drainers have started exploiting the normalization process for EIP-712 to bypass security alerts in certain wallets.

By passing numerical addresses, the wallet drainer successfully bypassed the existing wallet security alerts and made the verifyingContract in the EIP-721 signature request is unreadable on the UI.

The Wallet drainer used with this has stolen tens of millions in the past year.

Suspicious Case

About two days ago, we received a phishing case from the Cos@SlowMist. The phishing site requested a suspicious ERC20 Permit signature request, the verifyingContract starts with 996101, not the 0x.

Numerical Address

After more investigation and testing with this, we found the reason. The 996101235222674412020337938588541139382869425796 is actually converted from the hexadecimal address.

As you can see, the signature result it’s the same whether the verifyingContract is 996101235222674412020337938588541139382869425796 or 0xae7ab96520de3a18e5e111b5eaab095312d7fe84

Normalization Process

Clearly, there is a normalization process during the encoding process. If the field type is an address, it will try to convert it into hexadecimal, regardless of whether you pass a hexadecimal string or a number.

And we can get the answer from the @metamask/eth-sig-util src/sign-typed-data.ts

/**
 * Normalize a value, so that `@metamask/abi-utils` can handle it. This
 * matches the behaviour of the `ethereumjs-abi` library.
 *
 * @param type - The type of the value to normalize.
 * @param value - The value to normalize.
 * @returns The normalized value.
 */
function normalizeValue(type: string, value: unknown): any {
  if (isArrayType(type) && Array.isArray(value)) {
    const [innerType] = getArrayType(type);
    return value.map((item) => normalizeValue(innerType, item));
  }

  if (type === 'address') {
    if (typeof value === 'number') {
      return padStart(numberToBytes(value), 20);
    }

    if (isStrictHexString(value)) {
      return padStart(hexToBytes(value).subarray(0, 20), 20);
    }

    if (value instanceof Uint8Array) {
      return padStart(value.subarray(0, 20), 20);
    }
  }
}

Motivation

The obvious motivation behind this is to bypass security alerts and create unreadable messages.

The UI didn’t show it correctly as the hexadecimal address. you can’t identify it as stETH’s smart contract address.

Bypassing Security Alerts

In tests, if the verifyingContract is a number, we can see that the security alert is bypassed. However, if you sign it, your assets will be stolen.

And most security extensions also didn’t handle it properly.

How’s the Impact?

WalletNormalizationDisplay verifyingContractSimulation Failed
MetaMask111
Rabby110
Coinbase100
Rainbow101
OKX Web310N/A
Token Pocket10N/A
Trust Wallet01N/A
Phantom0N/AN/A
Zerion000
Magic Eden0N/AN/A

We have conducted some tests on common extension wallets. The tests found that most wallets support value normalization. Some display the associated token for the ERC20 Permit signature through verifyingContract

Given that using the ERC20 Permit is a major phishing method, the consistency of handling this situation with the actual signature is still very important.

We have attempted to report this situation to these wallets.

Conclusion

By exploiting the normalization process in the wallet’s EIP712 encoding procedure, the Wallet drainer successfully bypassed existing wallet security alerts by using numerical addresses, resulting in unreadability on the UI.

This also reveals the Wallet drainer’s ongoing research into these subtle details and the escalation of attack and defense strategies.

The wallet drainer associated with this called Pink Drainer has stolen tens of millions in the past year. Staying vigilant and skeptical may be the only way for you to stay safe.

Recent Articles

Related Stories