Skip to content

Commit 969d936

Browse files
committed
docs: Add blockchain writeups
1 parent 67c3d67 commit 969d936

File tree

4 files changed

+299
-0
lines changed

4 files changed

+299
-0
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Navigating the unkown (very easy)
2+
In this challenge we need to call a function on the blockchain.
3+
4+
The readme of this challenge tells us that the goal is for the `isSolved()` function to return true.
5+
The setup function tells us how that can be achieved.
6+
```solidity
7+
pragma solidity ^0.8.18;
8+
9+
import {Unknown} from "./Unknown.sol";
10+
11+
contract Setup {
12+
Unknown public immutable TARGET;
13+
14+
constructor() {
15+
TARGET = new Unknown();
16+
}
17+
18+
function isSolved() public view returns (bool) {
19+
return TARGET.updated();
20+
}
21+
}
22+
```
23+
24+
We just need to make sure that the `update` variable in the other contract is true.
25+
26+
```solidity
27+
pragma solidity ^0.8.18;
28+
29+
contract Unknown {
30+
31+
bool public updated;
32+
33+
function updateSensors(uint256 version) external {
34+
if (version == 10) {
35+
updated = true;
36+
}
37+
}
38+
39+
}
40+
```
41+
42+
Here we see that to make the `updated` variable true, we need to call the `updateSensors` function the blockchain.
43+
44+
The `solve.py` script will do precisely this.
45+
46+
Calling functions requires the ABI of the contract. For this I have used an online IDE called *remix* where I placed the contract source code.
47+
Then I compiled the code and clicked on the ABI button to copy it to my clipboard
48+
49+
After that we can use the other endpoint the challenge gives us when spawning the docker intsance and send option 3 to get the flag.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
from web3 import Web3
2+
3+
abi = '''[
4+
{
5+
"inputs": [
6+
{
7+
"internalType": "uint256",
8+
"name": "version",
9+
"type": "uint256"
10+
}
11+
],
12+
"name": "updateSensors",
13+
"outputs": [],
14+
"stateMutability": "nonpayable",
15+
"type": "function"
16+
},
17+
{
18+
"inputs": [],
19+
"name": "updated",
20+
"outputs": [
21+
{
22+
"internalType": "bool",
23+
"name": "",
24+
"type": "bool"
25+
}
26+
],
27+
"stateMutability": "view",
28+
"type": "function"
29+
}
30+
]'''
31+
32+
abi2 = '''[
33+
{
34+
"inputs": [],
35+
"stateMutability": "nonpayable",
36+
"type": "constructor"
37+
},
38+
{
39+
"inputs": [],
40+
"name": "TARGET",
41+
"outputs": [
42+
{
43+
"internalType": "contract Unknown",
44+
"name": "",
45+
"type": "address"
46+
}
47+
],
48+
"stateMutability": "view",
49+
"type": "function"
50+
},
51+
{
52+
"inputs": [],
53+
"name": "isSolved",
54+
"outputs": [
55+
{
56+
"internalType": "bool",
57+
"name": "",
58+
"type": "bool"
59+
}
60+
],
61+
"stateMutability": "view",
62+
"type": "function"
63+
}
64+
]'''
65+
66+
w3 = Web3(Web3.HTTPProvider('http://159.65.81.51:30417'))
67+
contract = w3.eth.contract(address='0xA08Ec9a121550BF1BE3860F673DfE42b913EBd32', abi=abi)
68+
setup = w3.eth.contract(address='0x74b7aA986c1F3A72c1D10E46e600b1F5B385C47B', abi=abi2)
69+
# OK!! I just needed to use transact() for this function
70+
# HTB{9P5_50FtW4R3_UPd4t3D}
71+
print(contract.functions.updateSensors(10).transact())
72+
print(setup.functions.isSolved().call())
73+
print(contract.functions.updated().call())

blockchain/shooting_101/README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Shooting 101 (very easy)
2+
In this challenge we need to call some special functions on the contract.
3+
4+
Let's take a look at the target contract:
5+
6+
```solidity
7+
pragma solidity ^0.8.18;
8+
9+
contract ShootingArea {
10+
bool public firstShot;
11+
bool public secondShot;
12+
bool public thirdShot;
13+
14+
modifier firstTarget() {
15+
require(!firstShot && !secondShot && !thirdShot);
16+
_;
17+
}
18+
19+
modifier secondTarget() {
20+
require(firstShot && !secondShot && !thirdShot);
21+
_;
22+
}
23+
24+
modifier thirdTarget() {
25+
require(firstShot && secondShot && !thirdShot);
26+
_;
27+
}
28+
29+
receive() external payable secondTarget {
30+
secondShot = true;
31+
}
32+
33+
fallback() external payable firstTarget {
34+
firstShot = true;
35+
}
36+
37+
function third() public thirdTarget {
38+
thirdShot = true;
39+
}
40+
}
41+
```
42+
43+
The `Setup.sol` just contains the `isSolved()` function like the first challenge, however now it checks all three bolleans of the target contract whether they are true.
44+
45+
We can also see that there are some `modifiers` that are applied to the functions.
46+
This ensures the order in which they are called is first, second, then third.
47+
48+
The first target is the `fallback` method.
49+
50+
I saw that this is different from the other functions we had before, so I went to look for some information on `receive` and `fallback` and have found this [article](https://blog.soliditylang.org/2020/03/26/fallback-receive-split/).
51+
52+
Here it says, that:
53+
> receive() external payable — for empty calldata (and any value)
54+
> fallback() external payable — when no other function matches (not even the receive function). Optionally payable.
55+
56+
Both of these functions are triggered when sending just a transaction to the contract, and not directly calling any functions on it.
57+
58+
The `receive` function is used when empty call data is received, and the `fallback` function is used when no other function on the contract matches.
59+
60+
So to trigger `fallback` first, let's send a transaction, but with a non-empty data field.
61+
62+
Next the second target is the `receive` function, let's send a transaction with empty data field.
63+
64+
And finally the `third` is just a function like in the previous challange, we can just call it in the same way.
65+
66+
`solve.py` performs these steps, although I couldn't make it work with a single invocation of the script.
67+
For each of the step the script is executed once and then I just commented the steps that were already done.
68+
69+
Sending 3 to the other endpoint that is not the RPC we get the flag.

blockchain/shooting_101/solve.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
from web3 import Web3
2+
3+
abi = '''[
4+
{
5+
"stateMutability": "payable",
6+
"type": "fallback"
7+
},
8+
{
9+
"inputs": [],
10+
"name": "firstShot",
11+
"outputs": [
12+
{
13+
"internalType": "bool",
14+
"name": "",
15+
"type": "bool"
16+
}
17+
],
18+
"stateMutability": "view",
19+
"type": "function"
20+
},
21+
{
22+
"inputs": [],
23+
"name": "secondShot",
24+
"outputs": [
25+
{
26+
"internalType": "bool",
27+
"name": "",
28+
"type": "bool"
29+
}
30+
],
31+
"stateMutability": "view",
32+
"type": "function"
33+
},
34+
{
35+
"inputs": [],
36+
"name": "third",
37+
"outputs": [],
38+
"stateMutability": "nonpayable",
39+
"type": "function"
40+
},
41+
{
42+
"inputs": [],
43+
"name": "thirdShot",
44+
"outputs": [
45+
{
46+
"internalType": "bool",
47+
"name": "",
48+
"type": "bool"
49+
}
50+
],
51+
"stateMutability": "view",
52+
"type": "function"
53+
},
54+
{
55+
"stateMutability": "payable",
56+
"type": "receive"
57+
}
58+
]'''
59+
60+
abi2 = '''[
61+
{
62+
"inputs": [],
63+
"stateMutability": "nonpayable",
64+
"type": "constructor"
65+
},
66+
{
67+
"inputs": [],
68+
"name": "TARGET",
69+
"outputs": [
70+
{
71+
"internalType": "contract ShootingArea",
72+
"name": "",
73+
"type": "address"
74+
}
75+
],
76+
"stateMutability": "view",
77+
"type": "function"
78+
},
79+
{
80+
"inputs": [],
81+
"name": "isSolved",
82+
"outputs": [
83+
{
84+
"internalType": "bool",
85+
"name": "",
86+
"type": "bool"
87+
}
88+
],
89+
"stateMutability": "view",
90+
"type": "function"
91+
}
92+
]'''
93+
94+
w3 = Web3(Web3.HTTPProvider('http://159.65.62.241:31005'))
95+
contract = w3.eth.contract(address='0xDdA00938E6a998781681E182599e6f6dCFA89808', abi=abi)
96+
setup = w3.eth.contract(address='0x5341F586E1e3858203b8e65060eFFeCdc64E049F', abi=abi2)
97+
# Step 1:
98+
# w3.eth.send_transaction({'to': '0xDdA00938E6a998781681E182599e6f6dCFA89808', 'from': '0xC98533e5811dA2dcE3b233d4E00E150DdE9773d4', 'data': "0x61455567"})
99+
100+
# Step 2:
101+
# w3.eth.send_transaction({'to': '0xDdA00938E6a998781681E182599e6f6dCFA89808', 'from': '0xC98533e5811dA2dcE3b233d4E00E150DdE9773d4'})
102+
103+
# Step 3:
104+
contract.functions.third().transact()
105+
print('1', contract.functions.firstShot().call())
106+
print('2', contract.functions.secondShot().call())
107+
print('3', contract.functions.thirdShot().call())
108+
print(dir(contract.functions))

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy