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!
block.coinbase is the miner of the block, block.number is the height of the current block and so on. An attacker can manipulate these if they have enough resources. block.number and a combination of many others. blockhash is the verification hash of the block being mined. Why is this bad? blockhash.number will always yield 0, since the data is not known until after execution. blockhash.number - 1. For this one, an attacker can execute code within the same block of the smart contract. block.blockhash() seems great. However, Ethereum only keeps track of the most recent 256 block hashes. After this, 0 is return. As a result, the random number could be predicted, if the new code was executed 256 blocks later. This happened within a SmartBillions lottery. private modifier for a seed? That will not work either! Although this is private to the smart contracts, it is trivial to get this information off-chain then make the transaction with this information inside of it. Wallet and WalletLibrary. If the withdraw() function was not called, then the call was sent to the WalletLibrary code. What's the problem here? WalletLibrary can be called within the context of the Wallet. In particular, the function initWallet() could be called to change the owner of a contract through this arbitrary delegated call. Yikes!internal, then this would not have been possible. It is believed that the authors thought that since the function had NO modifiers for the outside visibility, they were safe. wallet had a fallback function that called the walletLibrary with the users data. This is great for modularity, making the cost of a wallet much cheaper. WalletLibrary is a contract itself with its own state instead of a library. This means we can make calls to the WalletLibrary smart contract itself. initWallet() of the library, which gave them ownership of the contract. Now, the user got scared of what had just happened and called kill(). This library was now completely nuked, making the funds impossible to gather. uint8 has a max value of 256 and a minimum size of 0. If the arithmetic goes too positive or too negative, then this can wrap back around. self-destruct or suicide functions. While doing validation on the data, this could be used to manipulate the service or turn on unexpected functionality. Call and DELEGATECALL are used for making function calls to an external function. The only difference is that DELEGATECALL is called within the context of the smart contract itself. When dealing with libraries, ownership and state variables need to be considered. splitDao to ensure that the minority could create their own DAO if the majority was being unfair to them. ... Transfer(msg.sender, 0, balances[msg.sender]); withdrawRewardFor(msg.sender); ... totalSupply -= balances[msg.sender]; balances[msg.sender] = 0; paidOut[msg.sender] = 0;
Transfer is called, the initiator of the call can be recalled at this point with the hook. Then, the attacker can recall this function in a nested fashion. Transfer call being triggered multiple times. By doing this, an attacker could get their funds transfers several times!exitMarket and borrow. exitMarket verifies that a deposit is no longer being used as collateral, then withdraws it. borrow lets a user take out a loan. borrow using a smart contact. When the function sends the loaned amount of money, it has NOT updated the internal state of that the asset is being used as collateral. As a result, a nested call can to exitMarket extracts the collateral for the loan. addr_validate function will normalize it or they MUST be all lowercase. setOracleData. Since this is public and external without any access control, anybody is able to set the prices of tokens. Yikes!