Blogs & Articles: Ethereum is Doomed đ 8 years ago
- Category: Blogs & Articles | Mempool | Satoshi Nakamoto Institute
- Author(s): Daniel Krawisz
- Published: 20th June 2016 06:00
<p>As <a href="https://twitter.com/jgarzik/status/736945669978525696">some have noted</a>, I did not understand Ethereum very well when I wrote my <a href="/mempool/the-coming-demise-of-altcoins/">previous article</a> that touched on it. I dismissed Ethereum as just another altcoin with extra bells and whistles. However, there was a huge opportunity hiding in there, open to anyone who understood the system well enough. I wish I had examined it further and much more deeply because right now someone who did that, <a href="https://pastebin.com/CcGUBgDG">someone whom I now admire</a>, is sitting on three million ethers. <em>Update:</em> the note is <a href="https://news.ycombinator.com/item?id=11927891">probably not</a> from the real hacker. I still agree with its argument.</p> <p>This person has developed a new investment strategy for the age of smart contracts: You simply look for a way to exploit the smart contract which causes it to send cash into your account, and then invest in it so as to control it in a way that <a href="https://hackingdistributed.com/2016/06/18/analysis-of-the-dao-exploit/">extracts the money</a>.</p> <p>Ethereum truly is different from other altcoins. If I had looked into Ethereum more carefully, I might have noticed that economics was not the only subject that the Ethereum devs did not understand. They also donât understand law and software engineering. They created a situation in which bugs would be expected to arise in an environment in which bugs are legally exploitable. That is hacker heaven.</p> <p>Letâs say that A wants to send ethers to B. I will write <code>AâB</code> as the atomic operation which removes money from <code>A</code>'s balance and adds it to <code>B</code>âs. This operation fails if <code>A</code>'s balance is not big enough. To send money in Ethereum, it is as if we had a function that looked like this:</p> <pre> send[f, x, y] = If[ // Send funds to B and call f; roll back if an error is generated. Try[ AâB; f[]; True, False], // Call this if no error was generated. x[], // Call this if an error was generated. y[] ] </pre>
<p>where <code>x</code> and <code>y</code> are functions provided by <code>A</code>, and f is a function provided by <code>B</code>. In other words, <code>A</code> sends the ethers to <code>B</code>, who immediately gets to call a function that does whatever he wants with the money. That function is <code>f</code>. If his function fails for some reason, <code>AâB</code> is rolled back and function <code>y</code> is executed. Otherwise, <code>x</code> is executed. Anyone can provide <em>any</em> function to be executed upon receiving funds.<sup id="fnref:1"><a class="footnote-ref" href="#fn:1">1</a></sup></p> <p>This is already enough of a nightmare, but suppose you have a public function available to the hacker which is of the form</p> <pre> hackMe[f] = // Use q to check whether we owe the attacker money. If[q[], send[f, x, y]] </pre>
<p>where <code>q</code> is a function that is supposed to fail if the attacker has no right to demand funds.</p> <p>Suppose that the hacker calls <code>hackMe</code>, and provides an <code>f</code> of the form</p> <pre> f[] = p[]; hackMe[f] </pre>
<p>If the hacker can get <code>q</code> to succeed inappropriately, the following code is executed upon calling <code>hackMe</code>:</p> <pre> q[]; AâB; p[]; q[]; AâB; p[]; ... q[]; AâB; y[] ... </pre>
<p>If nothing else stops this execution, it will eventually stop when <code>AâB</code> fails as a result of A not having enough funds. It can also fail if the call stack fills up or if the computation runs out of <a href="https://www.cryptocompare.com/coins/guides/what-is-the-gas-in-ethereum/">gas</a>, but these are complications on top of the fundamental problem. A hacker can try to ensure that only the last send fails so as to end up with everything.</p> <div class="my-4 text-center"> <img class="img-fluid rounded d-block mx-auto" src="/static/img/mempool/ethereum-is-doomed/the-dao-is-empty.png"> <p> <em>via <a href="https://twitter.com/KonradSGraf/status/743843080961409025">Twitter</a></em> </p> </div>
<p>A naive approach to this bug would be to write <code>q</code> so that it keeps track of how much is owed to <code>B</code> and fails if the money should already have been paid. However, this approach is not good enough because in the mean time, from function <code>p</code>, the attacker might run more code which you have made available to him which creates further liabilities. The fix which the Ethereum team released to upgrade DAO 1.0 to 1.1 takes this naive approach, as explained <a href="https://hackingdistributed.com/2016/06/18/analysis-of-the-dao-exploit/#was-1-1-vulnerable">here</a>.</p> <p>I've provided a scenario in which the result is to extract funds, but the issue is much more general than that. You can think of an Ethereum smart contract as being like a object in object-oriented programming, with a set of public methods that any other contract can call. If you call another contract's public methods, he can call any of <em>your</em> public methods and attempt to screw with your internal state. There are different names for this depending on what the malicious contract does (such as <a href="https://blog.blockstack.org/solar-storm-a-serious-security-exploit-with-ethereum-not-just-the-dao-a03d797d98fa#.wpg35euyp">reentry and solar-storm</a>), but the problem is really the same kind of problem you would have if you just allowed people to run whatever code you wanted on your own computer.</p> <p>This problem is so serious that it cannot be treated as a bug in the DAO. The problem is with <s>Solidity itself, which is the scripting language used in Ethereum.</s> <em>Update:</em> The problem actually all the way down to the Ethereum virtual machine. While reading the Solidity documentation, I noticed this:</p> <blockquote> <p>If <code>x</code> is a contract address, its code (more specifically: its fallback function, if present) will be executed together with the <code>send</code> call (this is a limitation of the EVM and cannot be prevented).</p> </blockquote> <p>This means the same issue exists in <a href="https://mc2-umd.github.io/ethereumlab/docs/serpent_tutorial.pdf">Serpent</a>, another Ethereum scripting language, and every other one they might come up with.</p> <p>Imagine a bright eyed and bushy-tailed new programmer writing his first big contract: "Now letâs see hereâŠâ he thinks. âIâm using the send function. That means that I have to search for blocks of code that Iâve written which an attacker could attempt to run in an infinite loop until there is no money left. First of all, which possible blocks of code could be made to go in an infinite loop? It could be any part that calls send, intermixed with anything that the attacker wants to call in between⊠hmmm⊠" You have to think this every time you send anyone money. It is totally ridiculous to expect anyone to do this reliably. The only difference is that a novice would fail every single time he tried to write a contract, whereas an expert wouldn't even bother trying.</p> <p>Now I have described this issue so as to make it very clear what is going on, but in Solidity, the function I have called <code>f</code> is not very visible to the programmer. Itâs a method called the âdefault functionâ that can be defined on every address. It executes automatically when you send to that address. So if I was writing <code>hackMe</code> in Solidity, I wouldnât have directly referenced the function <code>f</code> as I wrote, but it executes anyway. It is very easy to write <code>hackMe</code> in Solidity.</p> <p>The <a href="https://solidity.readthedocs.io/en/latest/">manual on Solidity</a> opens with âSolidity is a high-level language whose syntax is similar to that of JavaScriptâ, as if that were something to brag about. But apparently Solidity has much more than just a superficial resemblance to JavaScript. Solidity is like programming in JavaScript, except with your bank account accessible through the Document Object Model.</p> <p>A sign that no one is prepared to write smart contracts in Solidity is the fact that the Ethereum dev team, the people who designed both Solidity and the DAO, could not even fix their own bug. They donât have the ability to approach these bugs correctly, and neither, in my opinion, does anyone else. It may be <em>possible</em> to reliably write smart contracts that work correctly, but currently no one knows how to do it. The dev team is not likely to figure it out any time soon because they still think that this is just a bug in the DAO rather than a serious problem with their entire system. If you want a smart contract that you can actually use, you have to be <em>certain</em> that it is bug-free before it is deployed. there are no known tools or methods available to Solidity developers which could provide an appropriate level of certainty. Such tools will take years to be developed and until they are in common use, no Ethereum smart contract should be trusted. Ethereum is doomed.</p> <p>The legal implications of this hack are more interesting than the hack itself. Because the code of the DAO is a legally-binding contract, how can you argue so as to convince a judge that some behavior of the program is really a bug? The DAO provides nothing other than its own code to specify how it is supposed to work. For example, there is <a href="https://www.reddit.com/r/ethereum/comments/4opjov/the_bug_which_the_dao_hacker_exploited_was_not/">no specification in a formal language</a>, or proofs as to its correctness. If the Ethereum team knew how to test software, they might have produced something like that, which also could have provided corroborating evidence that any bug was unintended.</p> <p>I fully support the attackerâs actions, and I wish I had thought of it first. His ethers may become worthless before he can sell them for Bitcoin, but he may also have <a href="https://hackingdistributed.com/2016/06/18/analysis-of-the-dao-exploit/#step-3-the-big-short">made a huge short on ethers</a> just before executing the attack and made around $1 million that way.</p> <p>For a final comment on the Ethereum teamâs response, I provide an insightful quote from <a href="https://hackingdistributed.com/2016/06/17/thoughts-on-the-dao-hack/#what-s-a-hack-when-you-don-t-have-a-spec">Emin GĂŒn Sirer</a>:</p> <blockquote> <p>Had the attacker lost money by mistake, I am sure the devs would have had no difficulty appropriating his funds and saying âthis is what happens in the brave new world of programmatic money flows.â When he instead emptied out coins from The DAO, the only consistent response is to call it a job well done.</p> </blockquote> <div class="my-4 text-center"> <img class="img-fluid rounded d-block mx-auto" src="/static/img/mempool/ethereum-is-doomed/vitalik-rai-stones.jpg"> <p> <em>Artwork by <a href="https://twitter.com/BigLambda/status/891148584334245888">Big λ</a></em> </p> </div>
<div class="footnote"> <hr /> <ol> <li id="fn:1"> <p>If you donât believe me read this analysis of the hack <a href="https://hackingdistributed.com/2016/06/16/scanning-live-ethereum-contracts-for-bugs/">here</a>:</p> <blockquote> <p>To have a contract send Ether to some other address, the most straightforward way is to use the send keyword. This acts like a method thatâs defined for every âaddressâ object.</p> </blockquote> <p>I love how he says this in such a matter-of-fact way, like that's no big deal.</p> <p>Also note <a href="https://vessenes.com/ethereum-griefing-wallets-send-w-throw-considered-harmful/">this poor developerâs unease</a> upon learning about this âfeatureâ:</p> <blockquote> <p>Hereâs the deal. In Bitcoin, an address is the public key that corresponds to a private key held by a wallet. Iâm lying a bit to aid comprehension. But, fundamentally, itâs just a bit of data. In Ethereum, an address could be similar â not a contract, but a public key. But, it could also be another smart contractâs address. The Mist client encourages users to make a wallet contract as a first step after loading up, for example. Users would then offer the address of that contract as their âwallet addressâ. Other contracts do not typically utilize any mechanism to distinguish between an address of a private key, and an address of a wallet. Itâs a fundamental transaction in Ethereum to send money to a contract, and developers seem to expect it to âjust workâ like in Bitcoin or other digital currencies, perhaps with a transaction fee attached.</p> </blockquote> <p><a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text">↩</a></p> </li> </ol> </div>