Securify: Practical Security Analysis of Smart Contracts https://securify.ch Dana Martin Petar Andrei Arthur Florian Drachsler- Vechev Tsankov Dan Gervais Bünzli Cohen Grant: Startup:
What is a smart contract? mapping(address => uint) balances; function withdraw() { uint amount = balances[msg.sender]; msg.sender.call.value(amount)(); balances[msg.sender] = 0; Transfer funds } to the caller - Small programs that handle cryptocurrencies - Written in high-level languages (e.g., Solidity) - Usually no patching after release What can go wrong when programs handle billions worth of USD? 2
Smart contract bugs bugs in the news 3
Smart contract bugs bugs in the news 3
Smart contract bugs bugs in the news 1 week ago 3
June 2016: The DAO hack
The DAO hack User Contract DAO Contract function moveBalance() { mapping(address => uint) balances; dao.withdraw(); } function withdraw() { ... uint amount = balances[msg.sender]; msg.sender.call.value(amount)(); function () payable { balances[msg.sender] = 0; // log payment } } withdraw() 10 ether Later… withdraw() 0 ether 4
The DAO hack User Contract DAO Contract function moveBalance() { mapping(address => uint) balances; calls the default dao.withdraw(); "fallback” function } function withdraw() { ... uint amount = balances[msg.sender]; msg.sender.call.value(amount)(); function () payable { balances[msg.sender] = 0; // log payment } } balance is zeroed after transfer withdraw() 10 ether Later… withdraw() 0 ether 4
The DAO hack User Contract DAO Contract function moveBalance() { mapping(address => uint) balances; dao.withdraw(); } function withdraw() { ... uint amount = balances[msg.sender]; msg.sender.call.value(amount)(); function () payable { balances[msg.sender] = 0; dao.withdraw(); } } calls withdraw() withdraw() before balance is set to 0 10 ether withdraw() 10 ether ... 4
Many critical vulnerabilities Unexpected ether flows In 2017, more than $300M Unprivileged writes Use of unsafe inputs have been lost due Reentrant method calls to these issues Transaction reordering 5
Wanted: Automated security analysis
function withdraw() { The DAO hack uint amount = balances[msg.sender]; msg.sender.call.value(amount)(); balances[msg.sender] = 0; } Security property: No state changes after call instructions Unsafe calls Safe calls Can we automatically find all unsafe calls? 6
function withdraw() { The DAO hack uint amount = balances[msg.sender]; msg.sender.call.value(amount)(); balances[msg.sender] = 0; } Security property: No state changes after call instructions Unsafe calls Safe calls Can we automatically find all unsafe calls? No, smart contracts are Turing-complete 6
function withdraw() { The DAO hack uint amount = balances[msg.sender]; msg.sender.call.value(amount)(); balances[msg.sender] = 0; } Security property: No state changes after call instructions Unsafe calls Safe calls Unsafe call instruction Safe call instruction Can we automatically find all unsafe calls? No, smart contracts are Turing-complete Existing solutions focus on bug finding and can miss issues 6
Insight When contracts satisfy/violate a security property, they often satisfy/violate a simpler property
function withdraw() { The DAO hack uint amount = balances[msg.sender]; msg.sender.call.value(amount)(); balances[msg.sender] = 0; } Security property: No state changes after call instructions Unsafe calls Safe calls Verifies 91% of all calls A write always No writes follows may follow call.value() call.value() Violation pattern Compliance pattern 7
www.securify.ch Scalable and fully automated verifier for Ethereum smart contracts
Impact Used daily by security auditors 1K+ subscribers (29K+ contracts scanned so far) Grants: New startup: 8
Securify: System overview push 0x04 1: a = 0x04 dataload 1. decompile 2: b = load (a) push 0x08 3: abi_00 (b) jump 4: stop jumpdest abi_00 (b) stop 5: c = 0x00 jumpdest 6: sstore (c,b) ⋮ ⋮ EVM bytecode Intermediate representation 2. infer facts assign (1, a, 0x04) follow (2, 1) mayDepOn (b, a) load (2, b, a) follow (3,2) follow (5,3) 3. check patterns ⋮ Security report Semantic representation 9
Step 1: Decompilation push 0x04 1: a = 0x04 dataload 1. decompile 2: b = load (a) push 0x08 3: abi_00 (b) jump 4: stop jumpdest abi_00 (b) stop 5: c = 0x00 jumpdest 6: sstore (c,b) ⋮ ⋮ EVM bytecode Intermediate representation - Static single assignment form - Control-flow graph recovery 10
Step 2: Inferring semantic facts 1: a = 0x04 2: b = load (a) 3: abi_00 (b) 4: stop abi_00 (b) 5: c = 0x00 6: sstore (c,b) ⋮ Intermediate representation 2. infer facts assign (1, a, 0x04) follow (2, 1) mayDepOn (b, a) load (2, b, a) follow (3,2) follow (5,3) ⋮ Semantic representation
Step 2: Inferring semantic facts Scalable inference of semantic facts using Datalog solvers Datalog program !"#$%&&%' (, * ← $%&&%'((, *) !"#$%&&%' (, * ← $%&&%' (, . , !"#$%&&%'(., *) 1: a = 0x04 $%&&%'(2, 1) !"#$%&&%'(2, 1) 2: b = load (a) $%&&%'(3, 2) !"#$%&&%'(3, 1) 3: abi_00 (b) $%&&%'(5, 3) !"#$%&&%'(4, 1) 4: stop $%&&%'(6, 5) !"#$%&&%'(5, 1) abi_00 (b) 5: c = 0x00 $%&&%'(4, 6) !"#$%&&%'(6, 1) 6: sstore (c,b) ⋮ ⋮ IR Datalog input Datalog fixpoint 11
Step 2: Inferring semantic facts Scalable inference of semantic facts using Datalog solvers Relevant semantic facts Control-flow analysis Datalog program !"#$%&&%' (, * ← $%&&%'((, *) Instruction at label 7 8 may follow that at label 7 9 6"#$%&&%'(7 8 , 7 9 ) !"#$%&&%' (, * ← $%&&%' (, . , !"#$%&&%'(., *) Instruction at label 7 8 must follow that at label 7 9 6:;<$%&&%'(7 8 , 7 9 ) Data-flow analysis The value of B may depend on tag C 6"#=>?@A(B, C) 1: a = 0x04 $%&&%'(2, 1) !"#$%&&%'(2, 1) 2: b = load (a) $%&&%'(3, 2) !"#$%&&%'(3, 1) The values of B and C are equal >D(B, C) 3: abi_00 (b) $%&&%'(5, 3) !"#$%&&%'(4, 1) 4: stop For different values of C the value of B is different E><F#(B, C) $%&&%'(6, 5) !"#$%&&%'(5, 1) abi_00 (b) 5: c = 0x00 $%&&%'(4, 6) !"#$%&&%'(6, 1) For real-world contracts, Securify infers 1 - 10M such facts 6: sstore (c,b) ⋮ ⋮ IR Datalog input Datalog fixpoint 11
Step 3: Check patterns assign (1, a, 0x04) follow (2, 1) mayDepOn (b, a) load (2, b, a) follow (3,2) follow (5,3) 3. check patterns ⋮ Security report Semantic representation
Security patterns language A pat pattern is a logical formula over semantic predicates: 4 ∷ = 718'9 :, ;, <, … , < !" X, T &!'() X, Y | ,-).!/01(X, Y) >?@@?A :, : | ,-)B?@@?A :, : ,C8'B?@@?A(:, :) ∃<. 4 ∃:. 4 ∃F. 4 ¬4 | 4 ∧ 4 see paper for details 12
Example: No writes after calls function withdraw() { uint amount = balances[msg.sender]; msg.sender.call.value(amount)(); balances[msg.sender] = 0; } Security property: ! ≡ “No state changes after call instructions” Compliance pattern ! " ≡ ∀ %&'' ( ) , _, _ . ¬∃ //0123 ( 4 , _, _ . 5&671''18(( 4 , ( ) ) Violation pattern ! " ≡ ∃ %&'' ( ) , _, _ . ∃ //0123 ( 4 , _, _ . 5;/071''18(( 4 , ( ) ) We can (manually) prove that: ! " ⇒ ! and ! = ⇒ ¬! 13
Security report Unsafe calls Safe calls Violation ¬! ! Compliance pattern pattern ! " ! # Violation Warning Safe violations or wa All unsafe calls are reported as either vi warnings 14
Security report Patterns for relevant security properties Unsafe behaviors Safe behaviors Violation ¬! ! Compliance pattern pattern ! " ! # Violation Warning Safe violations or wa All unsafe behaviors are reported as either vi warnings 14
Evaluation 1. Is Securify precise for relevant security properties? 2. How does Securify compare to other contract checkers? 15
How precise is Securify? Dataset - First 100 real-world contracts uploaded to https://securify.ch in 2018 Security properties - 9 critical vulnerabilities (reentrancy, …) Experiment: - Measure % of violations , safe behaviors , and warnings - Manually classify warnings into true warnings and false warnings 16
How precise is Securify? % of all potential vulnerabilities 100 80 False warnings 60 True warnings Violations 40 20 0 TT TR TA NW RW HE VA RT LQ Security properties < 10% warnings for 6 out of 9 security properties 16
How precise is Securify? > 90% verified % of all potential vulnerabilities 100 80 No warnings No warnings False warnings 60 True warnings Violations 40 20 0 TT TR TA NW RW HE VA RT LQ Security properties < 10% warnings for 6 out of 9 security properties 16
How does Securify compare to other checkers? Oyente 60 Mythril 40 20 Violations 0 True warnings 20 False warnings 40 Unreported 60 vulnerabilities 80 Unhandled Unsafe TOD Reentrancy exception transfer 17
Recommend
More recommend