Resources

People often ask me "How did you learn how to hack?" The answer: by reading. This page is a collection of the blog posts and other articles that I have accumulated over the years of my journey. Enjoy!

Why Careful Validation Matters: A Vulnerability Originating in Inline Assembly- 1707

SherlockPosted 7 Months Ago
  • Solidity adds a lot of safety checks, such as integer overflow protection, at the compiler level. Because of this, there is a special lower-level language called Yul to help write more proformiant code. These blocks, commonly used to as "inline assembly" are complicated and hard to get correct.
  • The code in the blog post contains an inline assembly call() to a function. It has some Yul code that is worth discussing further:
    1. Copy the calldata of the program into EVM memory.
    2. Patch the callata that was placed into memory. User shouldn't be able to control this parameter directly unless it's zero.
    3. Call the function target with the pointer data.
  • To prevent craziness from happening, there is validation happening on the callee contract and function selector being specified. The patching code is used to overwrite the swapAmount in the calldata via a user controlled index. This is where the fun begins!
  • To calculate the address to write, the following calculation is used, where swapAmountInDataIndex is a 32 bit integer.
    ptr + 36 (0x24) + 
      swapAmountInDataIndex * 32 (0x20). 
    
  • The offset of 36 is used to prevent overwrites to the function selector of the call, which is wise. For some reason, the swapAmountInDataIndex variable is a uin256. Unfortantely, there's an integer overflow in this calculation. When performing the multiplication on the index, this can overflow. With a specially crafted value, it's possible to wrap back around to modify the function selector that had previously been verified. An arbitrary call in the context of a Solidity smart contract is effectively game over.
  • The solution is to limit the index by the size of the calldata. This prevents the overflow and any other out of bounds access. Overall, a solid and subtle bug in a Yul optimization.