Bernhard Mueller, the creator of MythX , shows how to detect vulnerabilities in Ethereum smart contracts. On November 6th, a user playing with the Parity multisig wallet library contract , effectively freezing the funds on all Parity multisig wallets linked to the library’s code. According to early estimates this might have made more than $100 million worth of Ether inaccessible (update: in the meantime, that number has ). “accidentally” triggered its kill() function gone up to $280 million As it happens, just a couple of weeks ago I wrote about . The newest Parity accident was caused by an instance of this vulnerability. In this blog article, I’ll examine what happened in the latest attack and introduce a new analysis module that can be used detect similar issues in Solidity code and on-chain contracts. using symbolic analysis to detect unprotected SUICIDE instructions Mythril Ethereum rendition by Shed Designs for EventChain.io First, let’s have a brief look at what happened. User (for the sake of simplicity, I’ll just call him “the attacker”) managed to cause havoc by sending only two transactions. The called the function to set the state variable to devops199’s address. devops199 first transaction initWallet owner Function: initWallet(address[] _owners, uint256 _required, uint256 _daylimit)MethodID: 0xe46dcfeb[0]:0000000000000000000000000000000000000000000000000000000000000060[1]:0000000000000000000000000000000000000000000000000000000000000000[2]:0000000000000000000000000000000000000000000000000000000000000000[3]:0000000000000000000000000000000000000000000000000000000000000001[4]:000000000000000000000000ae7168deb525862f4fee37d987a971b385b96952 You might be wondering why this worked so easily. Weren’t there checks in place to prevent random senders from calling ? As you can see in the , access to this function is restricted with the modifier: initWallet source code only_uninitialized / throw unless the contract is not yet initialized.modifier only_uninitialized { if (m_numOwners > 0) throw; _; }// constructor — just pass on the owner array to the multiowned and// the limit to daylimit function initWallet(address[] _owners, uint _required, uint _daylimit) only_uninitialized This modifier allows the wallet to be initialized once. Normally, when a new wallet is set up, this library function is called immediately during creation. However, itself was never to be supposed to be used as a . It’s only purpose was to provide code to other contracts calling it via . Therefore, and very unfortunately, the library contract instance itself had never been initialized. This was an oversight by the developers, and can be partly attributed to Ethereum’s confusing library/CALL semantics. This topic would warrant its own blog post at some point, but for now let’s focus on the particular attack. WalletLibrary wallet DELEGATECALL Being the contract owner, the attacker now called the function in the : kill second transaction Function: kill(address _to)MethodID: 0xcbf0b0c0[0]:000000000000000000000000ae7168deb525862f4fee37d987a971b385b96952 This terminated the library contract, causing all wallets that depend on the library code to be unusable. Detecting the Bug “unchecked suicide” module attempts to detect exposed kill functions like the one in . The module is executed automatically when running mythril with the option. Mythril’s WalletLibrary -x To try it out, you can run the analysis against the . Unfortunately, Mythril’s on-chain scanning feature can’t be used on the dead contract instance, and the code only compiles with solc 4.10. The best way to get it to work is to first compile the code in , then pass the runtime bytecode to Mythril with the option. You should get the following output: Parity wallet WalletLibrary remix -c ./myth -x -c "60606040(…)0029"=== Unchecked SUICIDE === Type: Warning The function kill(address) executes the SUICIDE instruction. The remaining Ether is sent to an address provided as a function argument. There is a check on storage index keccac_1461501637330902918203684832716283019655932542975_&_caller. This storage index can be written to by calling the function 'initMultiowned(address[],uint256)'. There is a check on storage index 0. This storage index can be written to by calling the function 'initMultiowned(address[],uint256)'. There is a check on storage index 1. This storage index can be written to by calling the function 'initMultiowned(address[],uint256)'. The algorithm works as follows: of all intructions that are not constrained by msg.sender (i.e. callable by anyone); Make an inventory SSTORE Look for instructions and check the constraints on each. SUICIDE If a ‘tainted’ for every relevant storage index found, attempt to solve the constraints on the basic block containing the block to make sure it is reachable. SSTORE SUICIDE It’s a pretty simple check, but sufficient to detect trivial flaws like the Parity one (although it isn’t false-positive-proof). About Mythril and MythX is a free and open-source smart contract security analyzer. It uses symbolic execution to detect a variety of security vulnerabilities. Mythril is a cloud-based smart contract security service that seamlessly integrates into smart contract development environments and build pipelines. It bundles multiple bleeding-edge security analysis processes into an easy-to-use API that allows anyone to create purpose-built smart contract security tools. MythX is compatible with Ethereum, Tron, Vechain, Quorum, Roostock and other EVM-based platforms. MythX