Smart contract security: 7. Short address attack

This attack is not performed specifically against Solidity contracts, but against third-party applications that may interact with it.

1. Vulnerabilities When passing parameters to a smart contract, the parameters will be encoded according to the ABI specification. It is possible to send encoded parameters that are shorter than the expected parameter length (for example, sending an address of only 38 hex characters (19 bytes) instead of the standard 40 hex characters (20 bytes)). In this case, the EVM will pad 0s to the end of the encoded parameter to the expected length.

This becomes a problem when the third-party application does not validate the input. The most obvious example is when a user requests a withdrawal, the exchange does not verify the address of the ERC20 token. This example is detailed in Peter Venesses' article "ERC20 Short Address Attack Explained".

Consider the standard ERC20 transfer function interface, noting the order of the parameters,

function transfer(address to, uint tokens) public returns (bool success);

Now consider that an exchange holds a lot of tokens (say REP ), and a user wants to get back 100 tokens they stored. Users will submit their address, 0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddead, and the number of tokens, 100 . The exchange will encode these parameters in the order specified by the transfer() function, i.e. address first and then tokens . The encoded result will be

a9059cbb000000000000000000000000deaddeaddeaddeaddeaddeaddeaddeaddeaddead0000000000000000000000000000000000000000000000056bc75e2d63100000

Extract the function signature, and the remaining digits should be separated by 32 bytes:

a9059cbb 00000000000000000000000000deaddeaddeaddeaddeaddeaddeaddeaddeaddead 0000000000000000000000000000000000000000000000056bc75e2d63100000

The first four bytes (a9059cbb) are the transfer() function signature/selector;

The second 32 bytes are the address;

The last 32 bytes are a uint256 representing the token amount. Note that the final hex number 56bc75e2d63100000 corresponds to 100 tokens (with 18 decimal places, as specified by the REP token contract).

Ok, now let's see what happens if we send an address with 2 missing hex numbers. Specifically, suppose an attacker sends with 0xdeaddeaddeaddeaddeaddeaddeaddeaddeadde as an address (missing the last two digits), and gets back the same 100 tokens. If the exchange does not validate this input, it will be encoded as

a9059cbb000000000000000000000000deaddeaddeaddeaddeaddeaddeaddeaddeadde0000000000000000000000000000000000000000000000056bc75e2d6310000000

Extract the function signature, and the remaining digits should be separated by 32 bytes:

a9059cbb 0000000000000000000000000deaddeaddeaddeaddeaddeaddeaddeaddeaddeadde00 00000000000000000000000000000000000000000000056bc75e2d6310000000 The difference is subtle. Note that 00 has been padded to the end of the encoding to complete the short address sent. When it is sent to the smart contract, the address parameter will be read as 0xdeaddeaddeaddeaddeaddeaddeaddeaddeadde00 and the value will be read as 56bc75e2d6310000000 (note the two extra 0s). This value is now 25600 tokens (the value has been multiplied by 256 ). In this example, if the exchange held this many tokens, the user would withdraw 25600 tokens (while the exchange thought the user was only withdrawing 100) to the modified address. Obviously the attacker would not have the modified address in this example, but if the attacker generated a zero-terminated address (which is easy to force) and used this generated address, they could easily Steal tokens from exchanges.

2.Preventive measures

I think it's obvious that validating all inputs before sending them to the blockchain prevents these types of attacks. It should also be noted that parameter ordering plays an important role here. Since padding only occurs at the end of the string, careful ordering of parameters in smart contracts may mitigate some forms of this attack.