Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/luloxi/ethernaut-with-hardhat
Suite for solving Ethernaut CTF challenges | Built with Hardhat
https://github.com/luloxi/ethernaut-with-hardhat
Last synced: about 2 months ago
JSON representation
Suite for solving Ethernaut CTF challenges | Built with Hardhat
- Host: GitHub
- URL: https://github.com/luloxi/ethernaut-with-hardhat
- Owner: luloxi
- Created: 2022-11-20T03:44:28.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2023-10-31T16:09:12.000Z (about 1 year ago)
- Last Synced: 2024-04-15T05:03:20.504Z (9 months ago)
- Language: Solidity
- Homepage:
- Size: 1.77 MB
- Stars: 2
- Watchers: 2
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# About this repo
Suite to solve [Ethernaut](https://ethernaut.openzeppelin.com/) challenges.
**Prior to using this Ethernaut solving suite:**
1. Create and fill a **.env** file with the data specified in **.env.example** on the root folder
2. Run `yarn` on this folder.- If you wanna skip Etherscan verifications, don't fill out the ETHERSCAN_API_KEY variable.
## File locations
- **contracts/ folder**: Original and attacker contracts are inside the same file
- **deploy/ folder**: Deploy scripts for attacks that require deploying another contract
- **scripts/ folder**: Scripts that run the entire attack from start to finish (pwn)
- **.env**: **Env**ironment variables. Located on the root folder of the project.For any troubles, visit the [Troubleshooting](#troubleshooting) section.
# Index
1. [Fallback](#01---fallback)
2. [Fallout](#02---fallout)
3. [CoinFlip](#01---coinflip)
4. [Telephone](#04---telephone)
5. [Token](#05---token)
6. [Delegation](#06---delegation)
7. [Force](#07---force)
8. [Vault](#08---vault)
9. [King](#09---king)
10. [Reentrance](#10---reentrance)
11. [Elevator](#11---elevator)
12. [Privacy](#12---privacy)
13. [Gatekeeper One](#13---gatekeeper-one)
14. [Gatekeeper Two](#14---gatekeeper-two)
15. [Naught Coin](#15---naught-coin)
16. [Preservation](#16---preservation)
17. [Recovery](#17---recovery)
18. [Magic Number](#18---magic-number)
19. [Alien Codex](#19---alien-codex)
20. [Denial](#20---denial)
21. [Shop](#21---shop)
22. [Dex](#22---dex)
23. [Dex Two](#23---dex-two)
24. [Puzzle Wallet](#24---puzzle-wallet)
25. [Motorbike](#25---motorbike)
26. [DoubleEntryPoint](#26---double-entry-point)
27. [Good Samaritan](#27---good-samaritan)# 01 - Fallback
Lesson on calling the **[receive function](https://docs.soliditylang.org/en/v0.8.17/contracts.html?highlight=receive#receive-ether-function)**.
1. Change the address in **scripts/fallback.js** to your instance address
2. Run `yarn hardhat run scripts/fallback.js`# 02 - Fallout
Lesson on... dangers of not using **constructor keyword**? Paying attention to **typos**?
3. Change the address in **scripts/fallout.js** to your instance address
4. Run `yarn hardhat run scripts/fallout.js`# 03 - Coinflip
Lesson on **[exploiting blockhash "randomness"](https://docs.soliditylang.org/en/latest/units-and-global-variables.html#block-and-transaction-properties)**.
1. Change the address in **contracts/CoinFlip.sol** to your instance address
2. Run `yarn hardhat run scripts/coinflip.js`Note: If one of the "guesses" fails, comment out the "deploy" section of the script and uncomment the "use existing contract" one, then populate it with your attacker contract's address. Or just go to Etherscan and call the "attack" write function every some seconds, your call.
# 04 - Telephone
Lesson on **using a contract to attack** another contract.
1. Change the address in **contracts/Telephone.sol** to your instance address
2. Run `yarn hardhat run scripts/telephone.js`# 05 - Token
Lesson on **[underflow and overflow](https://docs.soliditylang.org/en/v0.8.17/control-structures.html?highlight=underflow#checked-or-unchecked-arithmetic)**.
1. Change the address in **scripts/token.js** to your instance address
2. Run `yarn hardhat run scripts/token.js`# 06 - Delegation
Lesson on **[delegatecall](https://docs.soliditylang.org/en/v0.8.17/introduction-to-smart-contracts.html?highlight=delegatecall#delegatecall-and-libraries)** and calling through **[fallback function](https://docs.soliditylang.org/en/v0.8.17/contracts.html?highlight=fallback#fallback-function)**
1. Change the address in **scripts/delegation.js** to your instance address
2. Run `yarn hardhat run scripts/delegation.js`# 07 - Force
Lesson on **[self-destruct](https://docs.soliditylang.org/en/v0.8.17/introduction-to-smart-contracts.html?highlight=self%20destruct#deactivate-and-self-destruct)**.
1. Change the address in **contracts/Force.sol** to your instance address
2. Run `yarn hardhat run scripts/force.js`# 08 - Vault
Lesson on **[private variables](https://docs.soliditylang.org/en/v0.8.17/security-considerations.html?highlight=private#private-information-and-randomness)** and **[storage slots](https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html?highlight=storage%20slots)**.
1. Change the address in **scripts/vault.js** to your instance address
2. Run `yarn hardhat run scripts/vault.js`# 09 - King
Lesson on **payable** keyword in **constructor** and **disabling receive function**
3. Change the address in **deploy/09-deploy-king.js** to your instance address
4. Run `yarn hardhat run scripts/king.js`# 10 - Reentrance
Lesson on **[reentrancy attacks](https://docs.soliditylang.org/en/v0.8.17/security-considerations.html#re-entrancy)**.
1. Change the address in **contracts/Reentrance.sol** to your instance address
2. Run `yarn hardhat run scripts/reentrance.js`# 11 - Elevator
Lesson on **interfaces** (and them not having the view keyword...) and using a **boolean toggle**.
1. Change the address in **contracts/Elevator.sol** to your instance address
2. Run `yarn hardhat run scripts/elevator.js`# 12 - Privacy
Lesson on size and ordering of **[storage slots](https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html#layout-of-state-variables-in-storage)**.
1. Change the address in **scripts/privacy.js** to your instance address
2. Run `yarn hardhat run scripts/privacy.js`# 13 - Gatekeeper One
Lesson on **typecasting**, **data types**, and **gas calculation**
1. Change the address in **contracts/GatekeeperOne.sol** to your instance address
2. Run `yarn hardhat run scripts/gatekeeperOne.js`## About
First condition is just calling from another contract. Done.
## Getting the right gas
Copied solution from [this guy](https://www.youtube.com/watch?v=AUQxXJiqLF4) that doesn't explain very well how it's done. My interpretation is that it just multiplies 3 times 8191 to get enough gas in any network conditions, then adds up from 150 up to 270 to cover the whole range the transaction could cost.
## About getting the right bytes8 key
### Condition 1:
- Hexadecimal uses 4 bits per digit (0-9+a-f)
- And it uses two digits per byte
- If 1 byte consists in 2 digits, bytes8 has 16 digits0xXXXXXXXXXXXXXXXX
- 1 byte = 8 bits
- 8 bytes = 64 bits**bytes8** has the same amount of digits as **uint64**
First requirement converts one argument from uint64 to uint32 -> uint32(uin64(\_gateKey)),
That means it takes this part of the password:
0x XXXXXXXX **"XXXXXXXX"**and it has to equal the same argument from uint64 to uint16 on the other side, -> uint16(uint64(\_gateKey))
0x XXXXXXXX XXXX **"XXXX"**
When comparing to a uint32, the uint16 will fill the bytes it doesn't have with zeros, that's why:
0x XXXXXXXX **0000** XXXX
We already have 4 digits of the password!
Password: 0xXXXXXXXX**0000**XXXX
### Condition 2:
Last 4 bytes (8 digits, or uint32) must not be equal to uint64 of key
uint32(uint64(\_gateKey)) != uint64(\_gateKey)0x **"00000000"** 0000XXXX != 0x **XXXXXXXX** XXXXXXXX
This means that first 4 bytes (8 digits) must have at least one different digit than 0
0x **"XXXXXXXX"** 0000XXXXPassword: 0x**XXXXXXXX0000**XXXX
### Condition 3:
First requirement converts one argument from uint64 to uint32 | uint32(uin64(\_gateKey)),
and must equal first two bytes (4 digits, or uint16) of tx.origin (our address!) || uint16(tx.origin)0x XXXXXXXX 0000 "XXXX"
That last "XXXX" MUST be the last 4 digits of our wallet address.
Password: 0x**XXXXXXXX0000XXXX**
Attacker contract is using the **Masking bits off** function with the & operator on your wallet address.
- **1001**0101 <- This
- **1111**0000 <- AND this
- **1001**0000 <- Equals this (only both 1 result in 1)- X value with 0 equals 0
- X value with 1 equals X.# 14 - Gatekeeper Two
Lesson on **contract size before initializing** and the **xor operator**.
1. Change the address in **deploy/14-deploy-gatekeepertwo.js** to your instance address
2. Run `yarn hardhat run scripts/gatekeeperTwo.js`## About
### Condition 2:
To call from a contract of size 0, we must call the enter function from the constructor, because the contract's size will be 0 until it is initialized.
Here's the reference inside the code
assembly {
x := **extcodesize**(caller())
}### Condition 3:
^ stands for xor bitwise operator, this is an exclusive or operator.
This means that if: a ^ b == c, then a ^ c == b
- & : and (x, y) bitwise **and** of x and y; where 1010 & 1111 == 1010 (true false true false)
- | : or (x, y) bitwise **or** of x and y; where 1010 | 1111 == 1111 (true true true true)
- ^ : xor (x, y) bitwise **xor** of x and y; where 1010 ^ 1010 == 0101 (false true false true)
- ~ : not (x) bitwise **not** of x; where ~1010 == 0101 (false true false true)# 15 - Naught Coin
Lesson on **ERC20** standard, and approving to **transferFrom** any address (including our own).
1. Change the address in **scripts/naughtCoin.js** to your instance address
2. Run `yarn hardhat run scripts/naughtCoin.js`# 16 - Preservation
Lesson combining knowledge of **Privacy** and **Delegation** challenges.
1. Change the address in **scripts/preservation.js** to your instance address
2. Run `yarn hardhat run scripts/preservation.js`# 17 - Recovery
Lesson on **contract creation addresses**.
1. Change the address in **scripts/recovery.js** to your instance address
2. Run `yarn hardhat run scripts/recovery.js`## Getting contract creation address
To figure out a contract address, it takes the rightmost 20 bytes (160 bits) of the keccak hash of the RLP encoding of the structure containing only the sender of the contract creation transaction and the nonce of that transaction.[(page 10 of Ethereum Yelowpaper)](https://ethereum.github.io/yellowpaper/paper.pdf)
`address = rightmost_20_bytes(keccak(RLP(sender address, nonce)))`
RLP = Recursive Length Prefix
In the attack script, we're using [ethers.utils.SolidityKeccak256](https://docs.ethers.io/v5/api/utils/hashing/#utils-solidityKeccak256)
`ethers.utils.solidityKeccak256( types , values ) ⇒ string< DataHexString< 32 > > source`
Returns the KECCAK256 of the non-standard encoded values packed according to their respective type in types.As a reference: **abi.encodePacked** in Solidity gives the same output as **ethers.utils.solidityPack**
Here we encode and hash directly into keccak256 with a single command with **solidityKeccak256**.The RLP encoding of a 20-byte address is: 0xd6, 0x94 .
And for all integers less than 0x7f, its encoding is just its own byte value.
So the RLP of 1 is 0x01.That's how we end with this line:
```shell
const simpleTokenAdd = await ethers.utils.solidityKeccak256(
["bytes1", "bytes1", "address", "bytes1"],
["0xd6", "0x94", recoveryInstanceAddress, "0x01"]
)
```And then just take the last 40 digits (20 bytes) -because each byte is 2 digits-, and append them to "0x" to form the contract's address:
```shell
const simpleTokenAddress =
"0x" + simpleTokenAdd.substring(simpleTokenAdd.length - 40, simpleTokenAdd.length)
```# 18 - Magic Number
Lesson on Opcode, Bytecode, Contract Creation vs. Runtime.
1. Change the address in **scripts/magicNumber.js** to your instance address
2. Run `yarn hardhat run scripts/magicNumber.js`## About
[Creation vs. Runtime](https://blog.openzeppelin.com/deconstructing-a-solidity-contract-part-ii-creation-vs-runtime-6b9d60ecb44c/)
Goal is to run two sets of OPCODES. One for **creation** (initialization) and another for **runtime** (10 OPCODES or less).
Once initialized, runtime is stored for future computations.Solidity Code (high level) > Opcodes > Byte code (EVM language)
### Runtime code
To RETURN 42, we need:
1. First we need to PUSH the value (v)
2. Then we need to store it in memory with MSTORE, which needs position (p) first and then size (s)
3. Then we RETURN the value (v)[Hex to Decimal converter](https://www.rapidtables.com/convert/number/hex-to-decimal.html)
Using the converter, we can see that 42 value in Hex is **0x2a**
[EVM Opcodes](https://github.com/crytic/evm-opcodes)
PUSH is 0x60
MSTORE is 0x52
RETURN is 0xf3Bytecode - Description
1. **602a** - PUSH the value (v) to MSTORE. In this case, we push 42 (0x2a).
2. **6050** - PUSH the position (p) (0x50) to MSTORE
3. **52** - Store value (v=0x2a) at position (p=0x50) in memory.
4. **6020** - PUSH the size (s) of v to the stack. In this case, we push 32 (0x20) for 32 bytes.
5. **6050** - PUSH the position (p) of the size (s) (slot in which value was stored). In this case, position was 0x50.
6. **f3** - RETURN value, v=0x24 (42) of size s=0x20 (32 bytes)Concatenated, it reads: `602a60505260206050f3`
This is **10 bytes**, as it has 20 digits when concatenated.
[Solidity Bytecode and Opcode Basics](https://medium.com/@blockchain101/solidity-bytecode-and-opcode-basics-672e9b1a88c2)
"In the EVM, there are 3 places to store data. Firstly, in the stack. We’ve just used the “PUSH” opcode to store data there as per the example above. Secondly in the memory (RAM) where we use the “MSTORE” opcode and lastly, in the disk storage where we use “SSTORE” to store the data. The gas required to store data to storage is the most expensive and storing data to stack is the cheapest."
### Creation (initialization) code
The CODECOPY opcode can be used to copy the runtime opcodes. It takes three arguments: the **destination** position of copied code in memory, **current position** of runtime opcode in the bytecode and **size** of the code in bytes.
Value 10 (size of our code in bytes) in hex is **0x0a**
We don't know the position of runtime opcode in the final bytecode (since initialization opcode comes before runtime opcode), so
we omit by setting position as unknown with --.After CODECOPY, we need to specify the values for RETURN.
1. **600a** - PUSH size of runtime opcode to stack. Size (s) param for COPYCODE.
2. **60--** - PUSH -- (unknown) to the stack. Position (p) param for COPYCODE.
3. **6000** - PUSH 0x00 (chosen destination in memory) in stack. Destination (d) param for COPYCODE.
4. **39** - CODECOPY of size (s) at position (p) to destination (d) in memory.
5. **600a** - PUSH 0x0a (size of our runtime opcode) in stack. Size (s) param for RETURN.
6. **6000** - PUSH 0x00 (location of value in memory) in stack. Position (p) param for RETURN.
7. **f3** - RETURN value (v) of size (s) at position (p)So the initialization opcode is `600460--600039600a6000f3` which is 12 bytes in total.
Which means that runtime opcodes start at index 12 or position **0x0c**
Therefore, initialization opcode must be `6004600c600039600a6000f3`
### Final opcode
Concatenate initialization opcode with runtime opcode:
```shell
600a600c600039600a6000f3 + 602a60505260206050f3
600a600c600039600a6000f3602a60505260206050f3
```And now we can create the contract by sending a transaction to the zero address (0x0) with some data as it will be interpreted as Contract Creation by the EVM.
On scripts/magicnumber.js, I appendedd **0x** at the beginning of the final opcode to make it readable as hex to be able to send the transaction.
More in-depth guides: [Watch how to solve it](https://www.youtube.com/watch?v=FsPWuKK8mWI&list=PLiAoBT74VLnmRIPZGg4F36fH3BjQ5fLnz&index=19) - [Read how to solve it](https://medium.com/coinmonks/ethernaut-lvl-19-magicnumber-walkthrough-how-to-deploy-contracts-using-raw-assembly-opcodes-c50edb0f71a2)
# 19 - Alien Codex
Lesson on **Check-Effect-Interact** and **layout of dynamically-sized arrays in storage**
1. Change the address in **scripts/alienCodex.js** to your instance address
2. Run `yarn hardhat run scripts/alienCodex.js`## About
First step is to make contact. Then we retract, so we substract 1 from position 0. Then we gotta figure out where is the owner. Then we gotta figure out the format to enter our address.
### Check-Effect-Interact
Retract function doesn't respect the [Check-Effect-Interact pattern](https://docs.soliditylang.org/en/v0.8.17/security-considerations.html#use-the-checks-effects-interactions-pattern), it does the effect right away. If something doesn't respect the CEI pattern, there's a chance **there's a security vulnerability there.**
**codex.length--** is gonna remove the last element from the array.
We're doing this Effect without doing first a Check. This allows the opportunity to do an **underflow** on the array. If we substract 1 from the position 0, we're going to go to the last element of the array, and we're gonna start from there, which will allow to put anything we want wherever we want in the storage of the contract.
### Layout of State Variables in Storage
State variables of contracts are stored in storage in a compact way such that **multiple values sometimes use the same storage slot**. **Except for dynamically-sized arrays** and mappings (see below), data is stored contiguously item after item starting with the first state variable, which is stored in slot 0. [Read more in SolidityLang.org](https://docs.soliditylang.org/en/latest/internals/layout_in_storage.html)
Dynamically sized arrays use keccak-256 to find the starting position (always full stack slot - 32 bytes).
**Mapping**
- p = position (storing the array length)
- k = value (value corresponding to the mapping)- keccak256(k.p)
To find this information, we hash them together by concatenating then hashing them
1. **p = web3.utils.keccak256(web3.abi.encodeParameters(["uint256"], [1]))**
Position: We're gonna hash with keccak256 the parameters (["uint256"], [1])
This is gonna be slot 1 inside AlienCodex.
Remember slot 0 has the owner address and contact boolean set to true.2. i = BigInt(2 \*\* 256) - BigInt(p)
We substact to go to the slot 0, not inside the contract storage, but **inside the array storage**, because that's where the owner is.
Converting hashed value to BigInt, we're able to substact back to Slot 0 of the codex.3. Content = "0x" + "0".repeat(24) + playeraddress.slice(2)
playeraddress.slice(2) <- This takes out the 0x at the beginning of playeraddress
Padding our address with 0's to meet the expected 32 bytes length.
Exploiting a flaw in the ABI specs. Doesn't validate that the length of the array matches the length of the payload. (e.g 0'd out.)
4. contract.revise(i, content)
Place our **content** into the owner array **index** location
[Watch how to solve it](https://www.youtube.com/watch?v=oGx-EvSsQbE)
# 20 - Denial
Lesson on [different ways of sending value](https://solidity-by-example.org/sending-ether/) and **assert method on ^0.6.0** (doesn't revert the transaction)
1. Change the address in **scripts/denial.js** to your instance address
2. Run `yarn hardhat run scripts/denial.js`## About sending value
**send and transfer**:
- Require an address to be marked as **payable** to send them ETH.
- They cost 2300 gas to prevent reentrancy vulnerability.**call**
- Doesn't require an address to be marked as payable to send them ETH.
- Can be manually specified how much gas to use.```shell
function depositUsingTransfer(address payable _to) public payable {
_to.transfer(msg.value); // 2300 gas, throws error
}function depositUsingSend(address payable _to) public payable {
bool sent = _to.send(msg.value); // 2300 gas, returns bool that can be used to throw error
require(sent, "Error! Ether not sent!");
}
```**Call** returns bool and the return (if any) of calling the specified function.
Gas can also be specified: `_to.call{gas: 20000, value: ...}````shell
function depositUsingCall(address _to) public payable {(bool sent, /* bytes memory data */) = _to.call{value: msg.value}("");
require(sent, "Error! Ether not sent!");
}
```## About assert
There are 3 ways of throwing an error: **assert, revert and require**
For this version of the solidity compiler (^0.6.0), **revert and require** undo any state changes that have occurred until that error was reached. **assert did not** refund or return any of the gas that was sent to it.
require(condition, "Error explanation")
revert("an error has occurred") <- Usually nested inside some logic
assert(condition)# 21 - Shop
Lesson on **interfaces** and using **ternary operators** to bypass repeated check with a **boolean toggle** in between
1. Change the address in **scripts/shop.js** to your instance address
2. Run `yarn hardhat run scripts/shop.js`# 22 - Dex
Lesson on **DEX mechanisms** and Solidity's **inhability to comprehend floating point numbers**
1. Change the address in **scripts/shop.js** to your instance address
2. Run `yarn hardhat run scripts/shop.js`## About
In Solidity, 3 / 2 = 1, because it can't comprehend floating point numbers such as 1.5.
We start like this:
Then we swap all of our Token 1 for Token 2
At this point the exchange rate changed. Now **20 token2** would be **20 \* 110 / 90 = 24,444**
Since **result is an integer**, we get 24 token2. Swap again to get another price readjustment.
Each swap gets us more of token1 or token2 than we had before, because of the **inaccuracy of price calculation** in the get_swap_price function. Keep swapping:
Now we got enough tokens to drain the 110 token1! 65 tokens would get us 158!
**65 \* 110 / 45 = 158**But as there aren't enough tokens, we need to calculate that number down.
**110 \* 45 / 110 = 45**We just need to swap 45 tokens in that last transaction :)
# 23 - Dex Two
Lesson on **ERC20 standard**, **DEX oracle manipulation**, and using **transferFrom** to bypass restrictions.
1. Change the address in **scripts/dexTwo.js** to your instance address
2. Run `yarn hardhat run scripts/dexTwo.js`## About
[Read how to solve it](https://daltyboy11.github.io/every-ethernaut-challenge-explained/#dex-two)
# 24 - Puzzle Wallet
Lesson on **delegatecall** and **proxy contracts**.
## Reccomended reads:
- [EIP-1967: Proxy Storage Slots](https://eips.ethereum.org/EIPS/eip-1967)
- [Proxies (OpenZeppelin docs)](https://docs.openzeppelin.com/contracts/4.x/api/proxy)## About
When an EOA (Externally Owned Account) does a call to a contract that does a **regular call** to another contract, the contract is taken as sender and owner of value for the second contract.
But with **delegatecall**, EOA is taken as sender and owner of value for the second contract. (i.e: Logic contract (2nd) for a Proxy contract (1st))
For the attack, we're using Multicall to Multicall twice the deposit function.
[Watch how to solve it](https://www.youtube.com/watch?v=toVc-iX-XAA) - [Shorter video](https://www.youtube.com/watch?v=3JcS-04cAj0)
# 25 - Motorbike
Lesson on **proxy contracts**, **Initializable contracts**, **getStorageAt**, **delegatecall** and **selfdestruct**.
1. Change the address in **scripts/motorbike.js** to your instance address
2. Run `yarn hardhat run scripts/motorbike.js`## Useful reads:
- [EVM Dialect](https://docs.soliditylang.org/en/v0.8.17/yul.html?highlight=evm%20dialect#evm-dialect)
- [UUPS Proxies](https://forum.openzeppelin.com/t/uups-proxies-tutorial-solidity-javascript/7786)## About
1. Gain access to Engine (Address is inside the IMPLEMENTATION_SLOT location)
2. "Initialize" to make ourselves the "upgrader"
3. Deploy a attacker contract with self destruct
4. Call "upgradeToAndCall" to attacker contract
5. Self destruct attacker contract[Watch how to solve it](https://www.youtube.com/watch?v=D7IfmkINYJ0) - [Another video](https://www.youtube.com/watch?v=WdiCzB3zjy0) - [Read how to solve it](https://dev.to/nvn/ethernaut-hacks-level-25-motorbike-397g)
# 26 - Double Entry Point
**You can read about it below**
[Watch how to solve it](https://www.youtube.com/watch?v=aGnC_917YOY) - [Read how to solve it](https://dev.to/nvn/ethernaut-hacks-level-26-double-entry-point-1774) - [Another read](https://daltyboy11.github.io/every-ethernaut-challenge-explained/#doubleentrypoint) - [A GitHub repo!](https://github.com/maAPPsDEV/double-entry-point-attack)
# 27 - Good Samaritan
Read how to do it:
- [Link 1](https://dev.to/erhant/ethernaut-27-good-samaritan-1cp6)
- [Link 2](https://hackernoon.com/good-samaritan-the-new-ethernaut-ctf-challenge)
- [Link 3](https://blog.dixitaditya.com/ethernaut-level-27-good-samaritan)
- [Link 4](https://coinsbench.com/27-good-samaritan-ethernaut-6de5de92d3e3)
- [Link 5](https://blog.blockmagnates.com/ethernaut-lvl-27-good-samaritan-walkthrough-custom-errors-in-solidity-17c7e20fb58a)# Troubleshooting
## General errors
- Check level indications to see if you **set the parameters right** for your instance.
- **Did you save** after changing address to your instance?
- Delete **"artifacts"** and **"cache"** folder and **run the command again**.## "nonce too low" / Pending transaction stuck:
If you get this error when submitting level instance, it's because you used some nonces to send the transactions that attack the level. In your MetaMask, go to **Settings > Advanced > Reset Account**
## Don't have Goerli ETH
Get some here: [Chainlink Faucet](https://faucets.chain.link/) - [Alchemy Faucet](https://goerlifaucet.com/)
## Don't have yarn
- Just enter `npm install --global yarn` on your console.
- Don't have NPM either? [Go get the LTS champ!](https://nodejs.org/en/download/)
- Don't know how to use it? Search how to :)## Don't know how to fill .env file
- GOERLI_RPC URL: [Alchemy (step 1 and 2)](https://www.alchemy.com/overviews/private-rpc-endpoint)
- PRIVATE_KEY: [Metamask](https://metamask.zendesk.com/hc/en-us/articles/360015289632-How-to-export-an-account-s-private-key)
- (optional) ETHERSCAN_API_KEY: [Etherscan](https://info.etherscan.com/api-keys/)## (optional) Use different network than Goerli:
1. Add your network (i.e: **mumbai**) as **DefaultNetwork** on hardhat.config.js
2. **Add it's parameters** in network section same as goerli is added.### (optional) Want to use Mumbai
- MUMBAI_RPC_URL: [Alchemy (step 1 and 2)](https://www.alchemy.com/overviews/private-rpc-endpoint)
- PRIVATE_KEY is the same
- (optional) POLYGONSCAN_API_KEY: [Register and get one](https://polygonscan.com/apis)