Platform | Status |
---|---|
Windows | |
Linux. | Supported |
Mac OS X. | TO-DO |
Ethereum is gaining a significant popularity in the blockchain community, mainly due to fact that it is design in a way that enables developers to write decentralized applications (Dapps) and smart-contract using blockchain technology.
Ethereum blockchain is a consensus-based globally executed virtual machine, also referred as Ethereum Virtual Machine (EVM) by implemented its own micro-kernel supporting a handful number of instructions, its own stack, memory and storage. This enables the radical new concept of distributed applications.
Contracts live on the blockchain in an Ethereum-specific binary format (EVM bytecode). However, contracts are typically written in some high-level language such as Solidity and then compiled into byte code to be uploaded on the blockchain. Solidity is a contract-oriented, high-level language whose syntax is similar to that of JavaScript.
This new paradigm of applications opens the door to many possibilities and opportunities. Blockchain is often referred as secure by design, but now that blockchains can embed applications this raise multiple questions regarding architecture, design, attack vectors and patch deployments.
As we, reverse engineers, know having access to source code is often a luxury. Hence, the need for an open-source tool like Porosity: decompiler for EVM bytecode into readable Solidity-syntax contracts – to enable static and dynamic analysis of compiled contracts but also vulnerability discovery.
First you can either compile your own Ethereum contract or analyze public contract from Etherscan.
PS E:\defcon2017> more .\vulnerable.sol
contract SendBalance {
mapping ( address => uint ) userBalances ;
bool withdrawn = false ;
function getBalance (address u) constant returns ( uint ){
return userBalances [u];
}
function addToBalance () {
userBalances[msg.sender] += msg.value ;
}
function withdrawBalance (){
if (!(msg.sender.call.gas(0x1111).value (
userBalances [msg . sender ])())) { throw ; }
userBalances [msg.sender ] = 0;
}
}
PS E:\defcon2017> & $solc --abi -o output vulnerable.sol
PS E:\defcon2017> & $solc --bin -o output vulnerable.sol
PS E:\defcon2017> & $solc --bin-runtime -o output vulnerable.sol
PS E:\defcon2017> $abi = Get-Content .\output\SendBalance.abi
PS E:\defcon2017> $bin = Get-Content .\output\SendBalance.bin
PS E:\defcon2017> $binRuntime = Get-Content .\output\SendBalance.bin-runtime
PS E:\defcon2017> $abi
[{"constant":false,"inputs":[],"name":"withdrawBalance","outputs":[],"type":"function"},{"constant":false,"inputs":[],"name":"addToBalance","outputs":[],"type":"function"},{"constant":true,"inputs":[{"name":"u","type":"address"}],"name":"ge
tBalance","outputs":[{"name":"","type":"uint256"}],"type":"function"}]
PS E:\defcon2017> $bin
60606040526000600160006101000a81548160ff021916908302179055506101bb8061002b6000396000f360606040526000357c0100000000000000000000000000000000000000000000000000000000900480635fd8c7101461004f578063c0e317fb1461005e578063f8b2cb4f1461006d5761004d56
5b005b61005c6004805050610099565b005b61006b600480505061013e565b005b610083600480803590602001909190505061017d565b6040518082815260200191505060405180910390f35b3373ffffffffffffffffffffffffffffffffffffffff16611111600060005060003373ffffffffffffffff
ffffffffffffffffffffffff16815260200190815260200160002060005054604051809050600060405180830381858888f19350505050151561010657610002565b6000600060005060003373ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050819055505b
565b34600060005060003373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828282505401925050819055505b565b6000600060005060008373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000505490506101b6
565b91905056
PS E:\defcon2017> $binRuntime
60606040526000357c0100000000000000000000000000000000000000000000000000000000900480635fd8c7101461004f578063c0e317fb1461005e578063f8b2cb4f1461006d5761004d565b005b61005c6004805050610099565b005b61006b600480505061013e565b005b61008360048080359060
2001909190505061017d565b6040518082815260200191505060405180910390f35b3373ffffffffffffffffffffffffffffffffffffffff16611111600060005060003373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060005054604051809050600060405180
830381858888f19350505050151561010657610002565b6000600060005060003373ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050819055505b565b34600060005060003373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020
016000206000828282505401925050819055505b565b6000600060005060008373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000505490506101b6565b91905056
You can get the list of all the functions from the dispatch routine using the --list
option.
PS E:\defcon2017> & $porosity --code $code --abi $abi --list --verbose 0
Porosity v0.1 (https://www.comae.io)
Matt Suiche, Comae Technologies <support@comae.io>
The Ethereum bytecode commandline decompiler.
Decompiles the given Ethereum input bytecode and outputs the Solidity code.
Attempting to parse ABI definition...
Success.
[+] Hash: 0x0A19B14A (trade) (1 references)
[+] Hash: 0x0B927666 (order) (1 references)
[+] Hash: 0x19774D43 (orderFills) (1 references)
[+] Hash: 0x278B8C0E (cancelOrder) (1 references)
[+] Hash: 0x2E1A7D4D (withdraw) (1 references)
[+] Hash: 0x338B5DEA (depositToken) (1 references)
[+] Hash: 0x46BE96C3 (amountFilled) (1 references)
[+] Hash: 0x508493BC (tokens) (1 references)
[+] Hash: 0x54D03B5C (changeFeeMake) (1 references)
[+] Hash: 0x57786394 (feeMake) (1 references)
[+] Hash: 0x5E1D7AE4 (changeFeeRebate) (1 references)
[+] Hash: 0x65E17C9D (feeAccount) (1 references)
[+] Hash: 0x6C86888B (testTrade) (1 references)
[+] Hash: 0x71FFCB16 (changeFeeAccount) (1 references)
[+] Hash: 0x731C2F81 (feeRebate) (1 references)
[+] Hash: 0x8823A9C0 (changeFeeTake) (1 references)
[+] Hash: 0x8F283970 (changeAdmin) (1 references)
[+] Hash: 0x9E281A98 (withdrawToken) (1 references)
[+] Hash: 0xBB5F4629 (orders) (1 references)
[+] Hash: 0xC281309E (feeTake) (1 references)
[+] Hash: 0xD0E30DB0 (deposit) (1 references)
[+] Hash: 0xE8F6BC2E (changeAccountLevelsAddr) (1 references)
[+] Hash: 0xF3412942 (accountLevelsAddr) (1 references)
[+] Hash: 0xF7888AEC (balanceOf) (1 references)
[+] Hash: 0xF851A440 (admin) (1 references)
[+] Hash: 0xFB6E155F (availableVolume) (1 references)
PS E:\defcon2017>
Using the --disassm
option, you will be able to display the assembly code.
PS E:\defcon2017> & $porosity --abi $abi --code $code --disassm
Porosity v0.1 (https://www.comae.io)
Matt Suiche, Comae Technologies <support@comae.io>
The Ethereum bytecode commandline decompiler.
Decompiles the given Ethereum input bytecode and outputs the Solidity code.
Attempting to parse ABI definition...
Success.
Contract::setABI: Name: withdrawBalance()
Contract::setABI: signature: 0x5fd8c710
Contract::setABI: Name: addToBalance()
Contract::setABI: signature: 0xc0e317fb
Contract::setABI: Name: getBalance(address)
Contract::setABI: signature: 0xf8b2cb4f
- Total byte code size: 0x1bb (443)
loc_00000000:
0x00000000 60 60 PUSH1 60
0x00000002 60 40 PUSH1 40
0x00000004 52 MSTORE
0x00000005 60 00 PUSH1 00
0x00000007 35 CALLDATALOAD
0x00000008 7c 00 00 00 00 + PUSH29 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01
0x00000026 90 SWAP1
0x00000027 04 DIV
0x00000028 80 DUP1
0x00000029 63 10 c7 d8 5f PUSH4 10 c7 d8 5f
0x0000002e 14 EQ
0x0000002f 61 4f 00 PUSH2 4f 00
0x00000032 57 JUMPI
loc_00000033:
0x00000033 80 DUP1
0x00000034 63 fb 17 e3 c0 PUSH4 fb 17 e3 c0
0x00000039 14 EQ
0x0000003a 61 5e 00 PUSH2 5e 00
0x0000003d 57 JUMPI
loc_0000003e:
0x0000003e 80 DUP1
0x0000003f 63 4f cb b2 f8 PUSH4 4f cb b2 f8
0x00000044 14 EQ
0x00000045 61 6d 00 PUSH2 6d 00
0x00000048 57 JUMPI
loc_00000049:
0x00000049 61 4d 00 PUSH2 4d 00
0x0000004c 56 JUMP
loc_0000004d:
0x0000004d 5b JUMPDEST
0x0000004e 00 STOP
withdrawBalance():
0x0000004f 5b JUMPDEST
0x00000050 61 5c 00 PUSH2 5c 00
0x00000053 60 04 PUSH1 04
0x00000055 80 DUP1
0x00000056 50 POP
0x00000057 50 POP
0x00000058 61 99 00 PUSH2 99 00
0x0000005b 56 JUMP
loc_0000005c:
0x0000005c 5b JUMPDEST
0x0000005d 00 STOP
addToBalance():
0x0000005e 5b JUMPDEST
0x0000005f 61 6b 00 PUSH2 6b 00
0x00000062 60 04 PUSH1 04
0x00000064 80 DUP1
0x00000065 50 POP
0x00000066 50 POP
0x00000067 61 3e 01 PUSH2 3e 01
0x0000006a 56 JUMP
loc_0000006b:
0x0000006b 5b JUMPDEST
0x0000006c 00 STOP
getBalance(address):
0x0000006d 5b JUMPDEST
0x0000006e 61 83 00 PUSH2 83 00
0x00000071 60 04 PUSH1 04
0x00000073 80 DUP1
0x00000074 80 DUP1
0x00000075 35 CALLDATALOAD
0x00000076 90 SWAP1
0x00000077 60 20 PUSH1 20
0x00000079 01 ADD
0x0000007a 90 SWAP1
0x0000007b 91 SWAP2
0x0000007c 90 SWAP1
0x0000007d 50 POP
0x0000007e 50 POP
0x0000007f 61 7d 01 PUSH2 7d 01
0x00000082 56 JUMP
loc_00000083:
0x00000083 5b JUMPDEST
0x00000084 60 40 PUSH1 40
0x00000086 51 MLOAD
0x00000087 80 DUP1
0x00000088 82 DUP3
0x00000089 81 DUP2
0x0000008a 52 MSTORE
0x0000008b 60 20 PUSH1 20
0x0000008d 01 ADD
0x0000008e 91 SWAP2
0x0000008f 50 POP
0x00000090 50 POP
0x00000091 60 40 PUSH1 40
0x00000093 51 MLOAD
0x00000094 80 DUP1
0x00000095 91 SWAP2
0x00000096 03 SUB
0x00000097 90 SWAP1
0x00000098 f3 RETURN
loc_00000099:
0x00000099 5b JUMPDEST
0x0000009a 33 CALLER
0x0000009b 73 ff ff ff ff + PUSH20 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x000000b0 16 AND
0x000000b1 61 11 11 PUSH2 11 11
0x000000b4 60 00 PUSH1 00
0x000000b6 60 00 PUSH1 00
0x000000b8 50 POP
0x000000b9 60 00 PUSH1 00
0x000000bb 33 CALLER
0x000000bc 73 ff ff ff ff + PUSH20 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x000000d1 16 AND
0x000000d2 81 DUP2
0x000000d3 52 MSTORE
0x000000d4 60 20 PUSH1 20
0x000000d6 01 ADD
0x000000d7 90 SWAP1
0x000000d8 81 DUP2
0x000000d9 52 MSTORE
0x000000da 60 20 PUSH1 20
0x000000dc 01 ADD
0x000000dd 60 00 PUSH1 00
0x000000df 20 SHA3
0x000000e0 60 00 PUSH1 00
0x000000e2 50 POP
0x000000e3 54 SLOAD
0x000000e4 60 40 PUSH1 40
0x000000e6 51 MLOAD
0x000000e7 80 DUP1
0x000000e8 90 SWAP1
0x000000e9 50 POP
0x000000ea 60 00 PUSH1 00
0x000000ec 60 40 PUSH1 40
0x000000ee 51 MLOAD
0x000000ef 80 DUP1
0x000000f0 83 DUP4
0x000000f1 03 SUB
0x000000f2 81 DUP2
0x000000f3 85 DUP6
0x000000f4 88 DUP9
0x000000f5 88 DUP9
0x000000f6 f1 CALL
0x000000f7 93 SWAP4
0x000000f8 50 POP
0x000000f9 50 POP
0x000000fa 50 POP
0x000000fb 50 POP
0x000000fc 15 ISZERO
0x000000fd 15 ISZERO
0x000000fe 61 06 01 PUSH2 06 01
0x00000101 57 JUMPI
loc_00000102:
0x00000102 61 02 00 PUSH2 02 00
0x00000105 56 JUMP
loc_00000106:
0x00000106 5b JUMPDEST
0x00000107 60 00 PUSH1 00
0x00000109 60 00 PUSH1 00
0x0000010b 60 00 PUSH1 00
0x0000010d 50 POP
0x0000010e 60 00 PUSH1 00
0x00000110 33 CALLER
0x00000111 73 ff ff ff ff + PUSH20 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x00000126 16 AND
0x00000127 81 DUP2
0x00000128 52 MSTORE
0x00000129 60 20 PUSH1 20
0x0000012b 01 ADD
0x0000012c 90 SWAP1
0x0000012d 81 DUP2
0x0000012e 52 MSTORE
0x0000012f 60 20 PUSH1 20
0x00000131 01 ADD
0x00000132 60 00 PUSH1 00
0x00000134 20 SHA3
0x00000135 60 00 PUSH1 00
0x00000137 50 POP
0x00000138 81 DUP2
0x00000139 90 SWAP1
0x0000013a 55 SSTORE
0x0000013b 50 POP
loc_0000013c:
0x0000013c 5b JUMPDEST
0x0000013d 56 JUMP
loc_0000013e:
0x0000013e 5b JUMPDEST
0x0000013f 34 CALLVALUE
0x00000140 60 00 PUSH1 00
0x00000142 60 00 PUSH1 00
0x00000144 50 POP
0x00000145 60 00 PUSH1 00
0x00000147 33 CALLER
0x00000148 73 ff ff ff ff + PUSH20 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0000015d 16 AND
0x0000015e 81 DUP2
0x0000015f 52 MSTORE
0x00000160 60 20 PUSH1 20
0x00000162 01 ADD
0x00000163 90 SWAP1
0x00000164 81 DUP2
0x00000165 52 MSTORE
0x00000166 60 20 PUSH1 20
0x00000168 01 ADD
0x00000169 60 00 PUSH1 00
0x0000016b 20 SHA3
0x0000016c 60 00 PUSH1 00
0x0000016e 82 DUP3
0x0000016f 82 DUP3
0x00000170 82 DUP3
0x00000171 50 POP
0x00000172 54 SLOAD
0x00000173 01 ADD
0x00000174 92 SWAP3
0x00000175 50 POP
0x00000176 50 POP
0x00000177 81 DUP2
0x00000178 90 SWAP1
0x00000179 55 SSTORE
0x0000017a 50 POP
loc_0000017b:
0x0000017b 5b JUMPDEST
0x0000017c 56 JUMP
loc_0000017d:
0x0000017d 5b JUMPDEST
0x0000017e 60 00 PUSH1 00
0x00000180 60 00 PUSH1 00
0x00000182 60 00 PUSH1 00
0x00000184 50 POP
0x00000185 60 00 PUSH1 00
0x00000187 83 DUP4
0x00000188 73 ff ff ff ff + PUSH20 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
0x0000019d 16 AND
0x0000019e 81 DUP2
0x0000019f 52 MSTORE
0x000001a0 60 20 PUSH1 20
0x000001a2 01 ADD
0x000001a3 90 SWAP1
0x000001a4 81 DUP2
0x000001a5 52 MSTORE
0x000001a6 60 20 PUSH1 20
0x000001a8 01 ADD
0x000001a9 60 00 PUSH1 00
0x000001ab 20 SHA3
0x000001ac 60 00 PUSH1 00
0x000001ae 50 POP
0x000001af 54 SLOAD
0x000001b0 90 SWAP1
0x000001b1 50 POP
0x000001b2 61 b6 01 PUSH2 b6 01
0x000001b5 56 JUMP
loc_000001b6:
0x000001b6 5b JUMPDEST
0x000001b7 91 SWAP2
0x000001b8 90 SWAP1
0x000001b9 50 POP
0x000001ba 56 JUMP
PS E:\defcon2017>
The --decompile
option will decompile the given function or contract and attempt to highlight vulnerabilities.
PS E:\defcon2017> & $porosity --abi $abi --code $code --decompile --verbose 0
Porosity v0.1 (https://www.comae.io)
Matt Suiche, Comae Technologies <support@comae.io>
The Ethereum bytecode commandline decompiler.
Decompiles the given Ethereum input bytecode and outputs the Solidity code.
Attempting to parse ABI definition...
Success.
Hash: 0x5FD8C710
function withdrawBalance() {
if (msg.sender.call.gas(4369).value(store[msg.sender])()) {
store[msg.sender] = 0x0;
}
}
L3 (D8193): Potential reetrant vulnerability found.
LOC: 5
Hash: 0xC0E317FB
function addToBalance() {
store[msg.sender] = store[msg.sender] + msg.value;
return;
}
LOC: 4
Hash: 0xF8B2CB4F
function getBalance(address) {
return store[arg_4];
}
LOC: 3
PS E:\defcon2017>