Skip to content

Commit

Permalink
Add day23 of doublespending
Browse files Browse the repository at this point in the history
  • Loading branch information
doublespending committed Sep 20, 2024
1 parent 00adcd1 commit 082711d
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 0 deletions.
39 changes: 39 additions & 0 deletions Writeup/doublespending/day23/Ans.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./WBC.sol";
import {console} from "forge-std/Test.sol";

contract Ans {
WBC public immutable wbc;

constructor(address wbc_) {
wbc = WBC(wbc_);
wbc.bodyCheck();
}

function win() external {
wbc.ready();
}

function judge() external view returns (address) {
return block.coinbase;
}

function steal() external pure returns (uint160) {
return 507778882907781185490817896798523593512684789769;
}

function execute() external pure returns (bytes32) {
string memory ans = "HitAndRun";
return bytes32(uint256(uint80(bytes10(abi.encodePacked(uint8(bytes(ans).length), ans)))));
}

function shout() external view returns (string memory) {
if (gasleft() % 3 == 2) {
return "I'm the best";
} else {
return "We are the champion!";
}
}
}
43 changes: 43 additions & 0 deletions Writeup/doublespending/day23/WBC.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {console2} from "forge-std/console2.sol";
import {Test} from "forge-std/Test.sol";
import {WBC, WBCBase} from "src/WBC/WBC.sol";
import {Ans} from "src/WBC/Ans.sol";

contract WBCTest is Test {
WBCBase public base;
WBC public wbc;
Ans public ans;

uint256 count;

function setUp() external {
uint256 startTime = block.timestamp + 60;
uint256 endTime = startTime + 60;
uint256 fullScore = 100;
base = new WBCBase(startTime, endTime, fullScore);
base.setup();
wbc = base.wbc();
}

function testExploit() external {
for (uint256 i = 0; i < 1000; ++i) {
try new Ans{salt: bytes32(i)}(address(wbc)) returns (Ans _ans) {
ans = _ans;
break;
} catch {}
}
ans.win();
base.solve();
assertTrue(base.isSolved());
}

function testCannotHomeRunEasily() external {
vm.expectRevert("try again");
wbc.homerun();
vm.expectRevert();
base.solve();
}
}
31 changes: 31 additions & 0 deletions doublespending.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,4 +325,35 @@ B: [EthTaipei CTF 2023](https://github.com/dinngo/ETHTaipei-war-room/)(5)
- Then, [solidity (version < 0.8.0)](https://github.com/consenlabs/account-abstraction/blob/3381bd75823c238a05c870fb11c61548c8fc7c9d/src/paymaster/OffChainPaymaster.sol#L2) has not applied underflow check as default.
- Finally, we can withdraw twice using `onERC721Received` callback and make the balance underflow.
### 2024.09.20
B: [EthTaipei CTF 2023](https://github.com/dinngo/ETHTaipei-war-room/)(5)
- WBC
- We should create contract `Ans` implmenting `IGame` to satisfy the requirements of `WBC`
- To pass `bodyCheck`
- Call `bodyCheck` inside `constructor` of `Ans` to meet the requirement [here](https://github.com/dinngo/ETHTaipei-war-room/blob/b5bdb72097172f50baa13b996be2422fd1b6786c/src/WBC/WBC.sol#L32)
- Use differnt salt to create `Ans` with different addresses to meet the requirement [here](https://github.com/dinngo/ETHTaipei-war-room/blob/b5bdb72097172f50baa13b996be2422fd1b6786c/src/WBC/WBC.sol#L33)
- To pass `ready`
- `judge()` of `Ans` should return `block.conbase`.
- To pass `_swing`
- To pass `_secondBase`
- `steal()` of `Ans` should return the `input` value by just copy
- To pass `_thirdBase` - We should find xxx that `this.decode(xxx) = "HitAndRun"`.
- xxx = 0\*(32-10)||9||HitAndRun
```
function decode(bytes32 data) external pure returns (string memory) {
assembly {
mstore(0x20, 0x20)
mstore(0x49, data)
// [0x20(offset), 0*9 || data[0:23](length), data[23:32] || 0*23(raw)]
// [0x20(offset), 0*9 || xxx.length(length), xxx.data || 0*23(raw)]
return(0x20, 0x60)
}
}
```
- To pass `_homeBase`
- We should find a way to distinguish the two sequential static call. - We can use `gasleft()`
- We can find a value `i` - `gasleft() % i == 0` in the first call - `gasleft() % i != 0` in the second call
<!-- Content_END -->

0 comments on commit 082711d

Please sign in to comment.