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
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.
+73
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

+69
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

+108
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)