A vulnerability in IPO has been found and exploited.
The Ethereum in our smart contract was drained by an unknown party in July. Our team has reverse engineered the hack and we have a few things to share. Thankfully, this didn’t affect users or currently owned sections and the IPO team were the only people to lose Ethereum.
We are currently working on a fix to migrate to a new contract. In the meantime, the site will remain fully operational, but we don’t recommend selling sections until we’ve deployed a new contract.
How did this happen? (in depth)
- Ethereum balances were kept track of in a mapping of addresses to uint256 named `ethBalance.` When a user sells their section or a section is purchased at IPO price (the first purchase) the receiver’s `ethBalance` is incremented by that amount. A hacker attacked a function that a) checks to see if a region of sections is available for sale and b) calculates the price of that region by adding its sections’ prices. We missed an overflow vulnerability in regionAvailable which was intended to calculate the total price of a region.
- By setting one section for sale at a very large price and one section for sale at a value equal to the value of the contract (20 ETH), when the region’s section prices were added up, the uint256 variable that held the price of the region overflows from the sum of a very large number and a smaller number to one very very small number. Therefore, the attacker could “purchase” the sections from their two controlled addresses with a third address for almost zero Ethereum and it would be evaluated as sufficient funds for purchasing the two sections. However, the sale is recorded as two individual purchases of one large amount and one amount that is equal to the value of Ethereum held in the contract. One of the attacker addresses had at that point completed a sale to another account with their section set to the value of the contract, which made the contract believe it owed them all of the Ethereum held, which they simply withdrew.
How can I prevent this when writing my own contract?
- Check for overflow. Whenever you have addition or multiplication that is dependent on user supplied data. If an unsigned variable A is added to variable B, the result must be greater than or equal to both A and B. While this takes additional gas and can increase the stack, it is better than losing an entire contract worth of Ethereum.
If you have any questions feel free to ask us in our Slack
TL;DR: The attacker used a vulnerability to drain the full balance of the contract by selling two of their sections for an overflowed price to a third address.
Unfortunately, we have estimated that the migration to our fixed contract will cost nearly 2000.00 USD in gas fees at the current ETH price. If you would like to donate to expedite the fix, you may send ETH to our donation address:
As always, thanks for your interest and support of the Initial Pixel Offering project!