

Discover more from Learn Pentesting like a Pro!
Stay updated on the latest cybersecurity insights from Cloud and Mobile to Blockchain. (HUNDREDS OF SUBSCRIBERS)
Continue reading
Hacking Ethereum EVM: Get Txs & OPcodes basics
To grab big bounties in Web3 you rather get inside the Matrix =D

If you wanna dig deeper at the Ethereum Virtual Machine level, those are some resources to start:
EthTx Transaction Decoder https://ethtx.info/
Ethereum Signature Database https://www.4byte.directory/
Ethereum JSON-RPC API https://ethereum.org/es/developers/docs/apis/json-rpc/#eth_call
Ethereum Virtual Machine Opcodes https://ethervm.io/
Solidity compiler EVM and OPCodes
Let’s try with the following vulnerable (do not use!) smart contract:
// Filename: target.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
// THIS CONTRACT CONTAINS A BUG - DO NOT USE
contract TxUserWallet {
address owner;
constructor() {
owner = msg.sender;
}
function transferTo(address payable dest, uint amount) public {
// THE BUG IS RIGHT HERE, you must use msg.sender instead of tx.origin
require(tx.origin == owner);
dest.transfer(amount);
}
}
How to get the OPcodes of the contract:
solc --opcodes target.sol
======= target.sol:TxUserWallet =======
Opcodes:
PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP CALLER PUSH1 0x0 DUP1 PUSH2 0x100 EXP DUP2 SLOAD DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF MUL NOT AND SWAP1 DUP4 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND MUL OR SWAP1 SSTORE POP PUSH2 0x1FE DUP1 PUSH2 0x60 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x2B JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x2CCB1B30 EQ PUSH2 0x30 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x4A PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0x45 SWAP2 SWAP1 PUSH2 0x188 JUMP JUMPDEST PUSH2 0x4C JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 DUP1 SLOAD SWAP1 PUSH2 0x100 EXP SWAP1 DIV PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND ORIGIN PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND EQ PUSH2 0xA4 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST DUP2 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH2 0x8FC DUP3 SWAP1 DUP2 ISZERO MUL SWAP1 PUSH1 0x40 MLOAD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 DUP6 DUP9 DUP9 CALL SWAP4 POP POP POP POP ISZERO DUP1 ISZERO PUSH2 0xEA JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP3 AND SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x11F DUP3 PUSH2 0xF4 JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH2 0x12F DUP2 PUSH2 0x114 JUMP JUMPDEST DUP2 EQ PUSH2 0x13A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP JUMP JUMPDEST PUSH1 0x0 DUP2 CALLDATALOAD SWAP1 POP PUSH2 0x14C DUP2 PUSH2 0x126 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH2 0x165 DUP2 PUSH2 0x152 JUMP JUMPDEST DUP2 EQ PUSH2 0x170 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP JUMP JUMPDEST PUSH1 0x0 DUP2 CALLDATALOAD SWAP1 POP PUSH2 0x182 DUP2 PUSH2 0x15C JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x40 DUP4 DUP6 SUB SLT ISZERO PUSH2 0x19F JUMPI PUSH2 0x19E PUSH2 0xEF JUMP JUMPDEST JUMPDEST PUSH1 0x0 PUSH2 0x1AD DUP6 DUP3 DUP7 ADD PUSH2 0x13D JUMP JUMPDEST SWAP3 POP POP PUSH1 0x20 PUSH2 0x1BE DUP6 DUP3 DUP7 ADD PUSH2 0x173 JUMP JUMPDEST SWAP2 POP POP SWAP3 POP SWAP3 SWAP1 POP JUMP INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 SELFDESTRUCT DUP12 0x5C DUP12 LOG3 PUSH31 0xF051A68ED77F5F39AD93423518F814BD59C16C9D1C94948A358C64736F6C63 NUMBER STOP ADDMOD LT STOP CALLER
How to get the EVM assembly of the contract:
solc --asm target.sol
======= target.sol:TxUserWallet =======
EVM assembly:
/* "target.sol":116:449 contract TxUserWallet {... */
mstore(0x40, 0x80)
/* "target.sol":167:218 constructor() {... */
callvalue
dup1
iszero
tag_1
jumpi
0x00
dup1
revert
tag_1:
pop
/* "target.sol":200:210 msg.sender */
caller
/* "target.sol":192:197 owner */
0x00
dup1
/* "target.sol":192:210 owner = msg.sender */
0x0100
exp
dup2
sload
dup2
0xffffffffffffffffffffffffffffffffffffffff
mul
not
and
swap1
dup4
0xffffffffffffffffffffffffffffffffffffffff
and
mul
or
swap1
sstore
pop
/* "target.sol":116:449 contract TxUserWallet {... */
dataSize(sub_0)
dup1
dataOffset(sub_0)
0x00
codecopy
0x00
return
stop
sub_0: assembly {
/* "target.sol":116:449 contract TxUserWallet {... */
mstore(0x40, 0x80)
callvalue
dup1
iszero
tag_1
jumpi
0x00
dup1
revert
tag_1:
pop
jumpi(tag_2, lt(calldatasize, 0x04))
shr(0xe0, calldataload(0x00))
dup1
0x2ccb1b30
eq
tag_3
jumpi
tag_2:
0x00
dup1
revert
/* "target.sol":226:446 function transferTo(address payable dest, uint amount) public {... */
tag_3:
tag_4
0x04
dup1
calldatasize
sub
dup2
add
swap1
tag_5
swap2
swap1
tag_6
jump // in
tag_5:
tag_7
jump // in
tag_4:
stop
tag_7:
/* "target.sol":400:405 owner */
0x00
dup1
sload
swap1
0x0100
exp
swap1
div
0xffffffffffffffffffffffffffffffffffffffff
and
/* "target.sol":387:405 tx.origin == owner */
0xffffffffffffffffffffffffffffffffffffffff
and
/* "target.sol":387:396 tx.origin */
origin
/* "target.sol":387:405 tx.origin == owner */
0xffffffffffffffffffffffffffffffffffffffff
and
eq
/* "target.sol":379:406 require(tx.origin == owner) */
tag_9
jumpi
0x00
dup1
revert
tag_9:
/* "target.sol":417:421 dest */
dup2
/* "target.sol":417:430 dest.transfer */
0xffffffffffffffffffffffffffffffffffffffff
and
/* "target.sol":417:438 dest.transfer(amount) */
0x08fc
/* "target.sol":431:437 amount */
dup3
/* "target.sol":417:438 dest.transfer(amount) */
swap1
dup2
iszero
mul
swap1
mload(0x40)
0x00
mload(0x40)
dup1
dup4
sub
dup2
dup6
dup9
dup9
call
swap4
pop
pop
pop
pop
iszero
dup1
iszero
tag_11
jumpi
returndatasize
0x00
dup1
returndatacopy
revert(0x00, returndatasize)
tag_11:
pop
/* "target.sol":226:446 function transferTo(address payable dest, uint amount) public {... */
pop
pop
jump // out
/* "#utility.yul":88:205 */
tag_13:
/* "#utility.yul":197:198 */
0x00
/* "#utility.yul":194:195 */
dup1
/* "#utility.yul":187:199 */
revert
/* "#utility.yul":334:460 */
tag_15:
/* "#utility.yul":371:378 */
0x00
/* "#utility.yul":411:453 */
0xffffffffffffffffffffffffffffffffffffffff
/* "#utility.yul":404:409 */
dup3
/* "#utility.yul":400:454 */
and
/* "#utility.yul":389:454 */
swap1
pop
/* "#utility.yul":334:460 */
swap2
swap1
pop
jump // out
/* "#utility.yul":466:570 */
tag_16:
/* "#utility.yul":511:518 */
0x00
/* "#utility.yul":540:564 */
tag_28
/* "#utility.yul":558:563 */
dup3
/* "#utility.yul":540:564 */
tag_15
jump // in
tag_28:
/* "#utility.yul":529:564 */
swap1
pop
/* "#utility.yul":466:570 */
swap2
swap1
pop
jump // out
/* "#utility.yul":576:714 */
tag_17:
/* "#utility.yul":657:689 */
tag_30
/* "#utility.yul":683:688 */
dup2
/* "#utility.yul":657:689 */
tag_16
jump // in
tag_30:
/* "#utility.yul":650:655 */
dup2
/* "#utility.yul":647:690 */
eq
/* "#utility.yul":637:708 */
tag_31
jumpi
/* "#utility.yul":704:705 */
0x00
/* "#utility.yul":701:702 */
dup1
/* "#utility.yul":694:706 */
revert
/* "#utility.yul":637:708 */
tag_31:
/* "#utility.yul":576:714 */
pop
jump // out
/* "#utility.yul":720:875 */
tag_18:
/* "#utility.yul":774:779 */
0x00
/* "#utility.yul":812:818 */
dup2
/* "#utility.yul":799:819 */
calldataload
/* "#utility.yul":790:819 */
swap1
pop
/* "#utility.yul":828:869 */
tag_33
/* "#utility.yul":863:868 */
dup2
/* "#utility.yul":828:869 */
tag_17
jump // in
tag_33:
/* "#utility.yul":720:875 */
swap3
swap2
pop
pop
jump // out
/* "#utility.yul":881:958 */
tag_19:
/* "#utility.yul":918:925 */
0x00
/* "#utility.yul":947:952 */
dup2
/* "#utility.yul":936:952 */
swap1
pop
/* "#utility.yul":881:958 */
swap2
swap1
pop
jump // out
/* "#utility.yul":964:1086 */
tag_20:
/* "#utility.yul":1037:1061 */
tag_36
/* "#utility.yul":1055:1060 */
dup2
/* "#utility.yul":1037:1061 */
tag_19
jump // in
tag_36:
/* "#utility.yul":1030:1035 */
dup2
/* "#utility.yul":1027:1062 */
eq
/* "#utility.yul":1017:1080 */
tag_37
jumpi
/* "#utility.yul":1076:1077 */
0x00
/* "#utility.yul":1073:1074 */
dup1
/* "#utility.yul":1066:1078 */
revert
/* "#utility.yul":1017:1080 */
tag_37:
/* "#utility.yul":964:1086 */
pop
jump // out
/* "#utility.yul":1092:1231 */
tag_21:
/* "#utility.yul":1138:1143 */
0x00
/* "#utility.yul":1176:1182 */
dup2
/* "#utility.yul":1163:1183 */
calldataload
/* "#utility.yul":1154:1183 */
swap1
pop
/* "#utility.yul":1192:1225 */
tag_39
/* "#utility.yul":1219:1224 */
dup2
/* "#utility.yul":1192:1225 */
tag_20
jump // in
tag_39:
/* "#utility.yul":1092:1231 */
swap3
swap2
pop
pop
jump // out
/* "#utility.yul":1237:1727 */
tag_6:
/* "#utility.yul":1313:1319 */
0x00
/* "#utility.yul":1321:1327 */
dup1
/* "#utility.yul":1370:1372 */
0x40
/* "#utility.yul":1358:1367 */
dup4
/* "#utility.yul":1349:1356 */
dup6
/* "#utility.yul":1345:1368 */
sub
/* "#utility.yul":1341:1373 */
slt
/* "#utility.yul":1338:1457 */
iszero
tag_41
jumpi
/* "#utility.yul":1376:1455 */
tag_42
tag_13
jump // in
tag_42:
/* "#utility.yul":1338:1457 */
tag_41:
/* "#utility.yul":1496:1497 */
0x00
/* "#utility.yul":1521:1582 */
tag_43
/* "#utility.yul":1574:1581 */
dup6
/* "#utility.yul":1565:1571 */
dup3
/* "#utility.yul":1554:1563 */
dup7
/* "#utility.yul":1550:1572 */
add
/* "#utility.yul":1521:1582 */
tag_18
jump // in
tag_43:
/* "#utility.yul":1511:1582 */
swap3
pop
/* "#utility.yul":1467:1592 */
pop
/* "#utility.yul":1631:1633 */
0x20
/* "#utility.yul":1657:1710 */
tag_44
/* "#utility.yul":1702:1709 */
dup6
/* "#utility.yul":1693:1699 */
dup3
/* "#utility.yul":1682:1691 */
dup7
/* "#utility.yul":1678:1700 */
add
/* "#utility.yul":1657:1710 */
tag_21
jump // in
tag_44:
/* "#utility.yul":1647:1710 */
swap2
pop
/* "#utility.yul":1602:1720 */
pop
/* "#utility.yul":1237:1727 */
swap3
pop
swap3
swap1
pop
jump // out
auxdata: 0xa2646970667358221220ff8b5c8ba37ef051a68ed77f5f39ad93423518f814bd59c16c9d1c94948a358c64736f6c63430008100033
}
In following posts we will get deeper on the internal workings of the EVM.