记录一点CTF中区块链的题目吧,仅是记录做法
blockchain-ctf.securityinnovation.com
从大佬那里问了个网站,现在似乎进不去,太可惜了
https://blog.csdn.net/2303_79193185/article/details/136534150?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22136534150%22%2C%22source%22%3A%222303_79193185%22%7D&fromshare=blogdetail&shareId=14&sharetype=hot
[NSSRound#4 SWPU]Bridge
1 2
| OKC 地址 0x26eD1a5Ce072aB407C9d24b434f9be43b9ADDCe5 发生了大额快进快出,经过溯源可以找到他来源于一个 BSC 地址,请找出该 Bridge 在 BSC 上的交易tx NSSCTF{0x****************************************************************}
|
这道题学到的是,善用工具区块链浏览器查询 | 欧科云链 OKLink
先打开关于OKC的工具
首页上方输入地址0x26eD1a5Ce072aB407C9d24b434f9be43b9ADDCe5
根据交易数量和交易时间,打开DeFi tracker
工具
然后筛选
下一步根据题目要求,打开BNB Chain
,再打开DeFi tracker
同样的条件再筛选一次
这个交易哈希就是答案
NSSCTF{0xf787c44151fe21da13c213e3adaa7796176e09b9364eb6f52aa43e387ce4b455}
GHCTF——其疾如风
题目描述:
1 2
| My letter has been maliciously tampered with, and now I can't find my wallet address of goerli testnet! Change flag{} to NSSCTF{}
|
附件是这样一个残缺的二维码
先把二维码补全,参考:【CTF-MISC】图片隐写中补全二维码定位角的注意事项【详细步骤】_misc二维码缺失-CSDN博客
补成这样即可
扫码得到这样的内容:ethereum: 0x57F1b45c28eDaC71d0A9Ffb54B7d8d2733E8d599
根据题目描述中的goerli testnet
打开区块链浏览器查询 | 欧科云链 OKLink
查询这个地址
在某条交易记录中有flag的16进制形式
GHCTF——侵略如火
题目描述
1 2 3
| challenge 111.229.224.125:15000 geth 111.229.224.125:15001 faucet 111.229.224.125:15002
|
先nc 111.229.224.125 15000
输入4,先看一下源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| contracts/Example.sol // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.9;
contract Greeter { string greeting;
constructor(string memory _greeting) { greeting = _greeting; }
function greet() public view returns (string memory) { return greeting; }
function setGreeting(string memory _greeting) public { greeting = _greeting; }
function isSolved() public view returns (bool) { string memory expected = "HelloFAFUer"; return keccak256(abi.encodePacked(expected)) == keccak256(abi.encodePacked(greeting)); } }
|
使得isSolved
返回True,再输入3即可获得flag
此时,我们再次nc靶机,输入1
获得了一个账户,以及我们的token。
题目要求我们先给这个账户转0.001测试币才能进入下一步
我们需要先有一个钱包账户,用MetaMask即可创建
然后像这样连接到题目给的RPC中
链的ID先随便输,会自动跳出正确的ID
有了钱包之后,我们访问111.229.224.125:15002
获取测试币
然后转账到题目给的账户
之后我们再次nc 靶机,并输入2,再输入题目给的token
这时候我们获得了一个合约地址
此时我们打开网站->
把题目给的源码复制近来,然后调整版本,进行编译
完成编译之后,我们来到这个页面
先把环境换成MetaMask,并核对账户
往下拖,找到
输入HelloFAFUer
,并点击setGreeting
,此时MetaMask会跳出支付页面,支付完成后依次点击greet
,isSolved
然后nc 靶机,输入3,再输入自己的token即可获得flag
GHCTF——其徐如林
题目描述
1 2 3
| 你给我邮箱,我给你flag。 合约部署在sepolia测试网上。 contract's address:0x521BF58Dd54663063a779b365CAe9FC974f47047
|
task.sol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| pragma solidity ^0.8.9;
contract Testcontract { mapping(address=>uint) _flag;
event sendflag(string email,string tokens);
function test() public { _flag[msg.sender] = 1; } function payforflag(string memory _base64Email,string memory _token) public { require(_flag[msg.sender] == 1); emit sendflag(_base64Email , _token); } }
|
mapping
函数可以理解为,每个钱包地址都有个变量_flag
有个事件sendflag
test()
函数的作用是把调用者的_flag
更改为1
payforflag()
需要两个参数,分别是base64编码后的邮箱地址,以及token,还要求调用者的_flag
值为1
根据代码,本题思路就是先调用test()
函数把_flag
值变为1,再调用payforflag
,然后估计就会把flag发送到我们的邮箱
这里需要先在sepolia测试网中获取一点测试币,需要在网上自行寻找水龙头获取。
然后就是编写脚本(不太明白原理,先存着,当个脚本小子先)。
exp.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| from web3 import Web3 import base64 import uuid import json
w3 = Web3(Web3.HTTPProvider('https://rpc2.sepolia.org'))
wallet = '0x...' key = '0x...'
target = '0x...'
with open("contract_abi.json", "r") as abi_file: contract_abi = json.load(abi_file)
contract = w3.eth.contract(address=target, abi=contract_abi)
print(f"[CONTRACT] 加载了一个合约,其地址为:{target}")
def send_transaction(transaction, private_key): signed_transaction = w3.eth.account.sign_transaction( transaction, private_key) transaction_hash = w3.eth.send_raw_transaction( signed_transaction.rawTransaction)
print(f"[TRANSACTION] 发送了一个交易,其哈希为:{transaction_hash.hex()}") print(f"[TRANSACTION] 正在等待交易确认......")
w3.eth.wait_for_transaction_receipt(transaction_hash)
print(f"[TRANSACTION] 交易已被确认。")
return transaction_hash
def test(): return send_transaction(contract.functions.test().build_transaction({ "chainId": 11155111, "maxFeePerGas": w3.to_wei(1.000000014, 'gwei'), "maxPriorityFeePerGas": w3.to_wei(1, 'gwei'), "gas": 0x200000, "value": w3.to_wei(0, 'ether'), "nonce": w3.eth.get_transaction_count(wallet), }), key)
def payforflag(email: str, token: str): return send_transaction(contract.functions.payforflag( base64.b64encode(email.encode()).decode(), token ).build_transaction({ "chainId": 11155111, "maxFeePerGas": w3.to_wei(1.000000014, 'gwei'), "maxPriorityFeePerGas": w3.to_wei(1, 'gwei'), "gas": 0x200000, "value": w3.to_wei(0, 'ether'), "nonce": w3.eth.get_transaction_count(wallet), }), key)
if __name__ == "__main__":
email = "" token = uuid.uuid4().hex
test() payforflag(email, token)
|
运行完之后,大概30分钟收到了flag:NSSCTF{Step2_contract_st1ll_E4sy_fOr_y0u!}
GHCTF——不动如山
题目描述
1 2 3
| challenge 111.229.224.125:16000 geth 111.229.224.125:16001 faucet 111.229.224.125:16002
|
先nc查源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| // contracts/Example.sol // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.9;
contract GiveMeETH{ constructor() { //no function to transfer...... }
function isSolved() public view returns(bool) { return address(this).balance >= 0.66 ether; } }
|
题目还是要求让isSolved()
返回True,这里就是要让合约的余额不小于0.66
先输入1获得部署合约的账户
并且转账超过0.001进入下一步
输入2获得合约地址以及交易哈希
一开始试了直接转账,但是失败了。上网查找有没有什么其他转账的方法
https://blog.riskivy.com/%e6%99%ba%e8%83%bd%e5%90%88%e7%ba%a6ctf%ef%bc%9aethernaut-writeup-part-2/#7Force
在remix上写个脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13
| // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.9;
contract Selfdestruct{ constructor() payable {
}
function attack() public { address payable addr = payable(address(0x801b7361AbA8FDd63c4Bb741E4E89b4d948b22a6)); selfdestruct(addr); } }
|
再使用remix交互
这些地方记得修改,再点击部署,会跳出支付页面,支付后即可交互
点击attack,再次支付即可