
OlympusDAO $300,000 exploit
Two days ago on October 21st 2022, OlympusDAO was drained of 30,437 OHM Tokens (about $300,000) due to an exploit in Bond Protocol. This exploit was surprisingly simple, but nonetheless was not caught during audit. I’ll be going over how the exploit was carried out along with a proof of concept here.BackgroundFirst a quick tl;dr of what bonding is. OlympusDAO uses this approach to generate capital. Essentially, users lock up their LP tokens in exchange for OHM tokens at a discounted rate. By ...
Ethernaut 14: Naught Coin
This is my solution for the 14th ethernaut challenge, Naught Coin https://ethernaut.openzeppelin.com/level/0x97E982a15FbB1C28F6B8ee971BEc15C78b3d263FInvestigationWe have a smart contract which inherits the ERC20 implementation from OpenZeppelinimport '@openzeppelin/contracts/token/ERC20/ERC20.sol'; contract NaughtCoin is ERC20 { // string public constant name = 'NaughtCoin'; // string public constant symbol = '0x0'; // uint public constant decimals = 18; uint public timeLock = now + 10 * 365 ...
Ethernaut 15: Preservation
The ethernaut rabbit hole continues. This is my solution for the 15th challenge: Preservation https://ethernaut.openzeppelin.com/level/0x97E982a15FbB1C28F6B8ee971BEc15C78b3d263FInvestigationWe have a contract that has some time zone library addresses defined. Each of these libraries can be used to set the storedTime value on the Preservation instance. The library code being used has also been highlighted at the bottomcontract Preservation { // public library contracts address public timeZone1...
Writing about security, MEV, privacy and decentralized finance

OlympusDAO $300,000 exploit
Two days ago on October 21st 2022, OlympusDAO was drained of 30,437 OHM Tokens (about $300,000) due to an exploit in Bond Protocol. This exploit was surprisingly simple, but nonetheless was not caught during audit. I’ll be going over how the exploit was carried out along with a proof of concept here.BackgroundFirst a quick tl;dr of what bonding is. OlympusDAO uses this approach to generate capital. Essentially, users lock up their LP tokens in exchange for OHM tokens at a discounted rate. By ...
Ethernaut 14: Naught Coin
This is my solution for the 14th ethernaut challenge, Naught Coin https://ethernaut.openzeppelin.com/level/0x97E982a15FbB1C28F6B8ee971BEc15C78b3d263FInvestigationWe have a smart contract which inherits the ERC20 implementation from OpenZeppelinimport '@openzeppelin/contracts/token/ERC20/ERC20.sol'; contract NaughtCoin is ERC20 { // string public constant name = 'NaughtCoin'; // string public constant symbol = '0x0'; // uint public constant decimals = 18; uint public timeLock = now + 10 * 365 ...
Ethernaut 15: Preservation
The ethernaut rabbit hole continues. This is my solution for the 15th challenge: Preservation https://ethernaut.openzeppelin.com/level/0x97E982a15FbB1C28F6B8ee971BEc15C78b3d263FInvestigationWe have a contract that has some time zone library addresses defined. Each of these libraries can be used to set the storedTime value on the Preservation instance. The library code being used has also been highlighted at the bottomcontract Preservation { // public library contracts address public timeZone1...
Writing about security, MEV, privacy and decentralized finance

Subscribe to 0xbanky

Subscribe to 0xbanky
Share Dialog
Share Dialog
<100 subscribers
<100 subscribers
My solution for the fifth ethernaut challenge: https://ethernaut.openzeppelin.com/level/0x63bE8347A617476CA461649897238A31835a32CE
We have a Token contract that contains balances for address and a total supply.
mapping(address => uint) balances;
uint public totalSupply;
We have a constructor which initializes a contract instance with a provided supply and gives that entire balance to the contract deployer
constructor(uint _initialSupply) public {
balances[msg.sender] = totalSupply = _initialSupply;
}
There is a function which allows a transfer from the senders balance to the provided address. It simply checks that there is enough of a balance to be sent in the senders address, deducts the amount from the sender and assigns it to the to address.
function transfer(address _to, uint _value) public returns (bool) {
require(balances[msg.sender] - _value >= 0);
balances[msg.sender] -= _value;
balances[_to] += _value;
return true;
}
Notably here, the computation is being done on uint values which can be overflowed. I tried out the transfer function using the Remix IDE and found that I was able to transfer 5 tokens to some other address. This worked since 5 was less than the amount in my wallet (initialized with 20 tokens).
First, I tried to pass in a negative value to the function. My thinking is that the value would be treated as a uint during smart contract execution, which would be a very large number. This approach does not work though and I got an error from the EVM
instance.transfer("0x...", -10);
// Error encoding arguments: Error: value out-of-bounds (argument=null, value="-5", code=INVALID_ARGUMENT, version=abi/5.5.0)
So it seems like it wont work to just try passing in a negative number. Thinking about it some more, I noticed that on this line
require(balances[msg.sender] - _value >= 0);
An integer overflow can also be induced. ie. if I try to send more than I have in my wallet, balances[msg.sender] - _value will actually overflow and return some large value. I tried this out
instance.transfer("0x...", 25);
instance.balanceOf("<my address>");
// uint256: balance 115792089237316195423570985008687907853269984665640564039457584007913129639931
My wallet now has several trillions of tokens 🤠
During the investigation, I found that this will actually not be an issue using a newer solidity version to compile our code (0.8.0 and above).
Arithmetic operations revert on underflow and overflow. You can use
unchecked { ... }to use the previous wrapping behaviour.
From https://docs.soliditylang.org/en/latest/080-breaking-changes.html
This issue can be prevented on lower solidity versions with OpenZeppeling SafeMath.
My solution for the fifth ethernaut challenge: https://ethernaut.openzeppelin.com/level/0x63bE8347A617476CA461649897238A31835a32CE
We have a Token contract that contains balances for address and a total supply.
mapping(address => uint) balances;
uint public totalSupply;
We have a constructor which initializes a contract instance with a provided supply and gives that entire balance to the contract deployer
constructor(uint _initialSupply) public {
balances[msg.sender] = totalSupply = _initialSupply;
}
There is a function which allows a transfer from the senders balance to the provided address. It simply checks that there is enough of a balance to be sent in the senders address, deducts the amount from the sender and assigns it to the to address.
function transfer(address _to, uint _value) public returns (bool) {
require(balances[msg.sender] - _value >= 0);
balances[msg.sender] -= _value;
balances[_to] += _value;
return true;
}
Notably here, the computation is being done on uint values which can be overflowed. I tried out the transfer function using the Remix IDE and found that I was able to transfer 5 tokens to some other address. This worked since 5 was less than the amount in my wallet (initialized with 20 tokens).
First, I tried to pass in a negative value to the function. My thinking is that the value would be treated as a uint during smart contract execution, which would be a very large number. This approach does not work though and I got an error from the EVM
instance.transfer("0x...", -10);
// Error encoding arguments: Error: value out-of-bounds (argument=null, value="-5", code=INVALID_ARGUMENT, version=abi/5.5.0)
So it seems like it wont work to just try passing in a negative number. Thinking about it some more, I noticed that on this line
require(balances[msg.sender] - _value >= 0);
An integer overflow can also be induced. ie. if I try to send more than I have in my wallet, balances[msg.sender] - _value will actually overflow and return some large value. I tried this out
instance.transfer("0x...", 25);
instance.balanceOf("<my address>");
// uint256: balance 115792089237316195423570985008687907853269984665640564039457584007913129639931
My wallet now has several trillions of tokens 🤠
During the investigation, I found that this will actually not be an issue using a newer solidity version to compile our code (0.8.0 and above).
Arithmetic operations revert on underflow and overflow. You can use
unchecked { ... }to use the previous wrapping behaviour.
From https://docs.soliditylang.org/en/latest/080-breaking-changes.html
This issue can be prevented on lower solidity versions with OpenZeppeling SafeMath.
No activity yet