Custom Networking Tools Built With Python

Hacker’s Routine

TCP Client

TCP Client

Nowadays in the cybersecurity realm, there are multiple valuable tools to use. Nevertheless, the most skilled and experienced hackers or computer science enthusiasts prefer to craft their own tools. Having said that, it helps them to avoid any limitations caused by 3-rd party software. 

Let’s dive into the process of creating simple, but significantly effective tools that are related to the core of cybersecurity ⇒ Networking.

In today’s agenda, we consider such custom toolkits as TCP, UDP Clients, and TCP Server. 

The first tool will be a TCP Client which is extremely helpful for penetration testing. Especially, when you’re working within the confines of large enterprise environments, you will not be able to use a huge variety of networking tools and compilers. Moreover, sometimes you will be even missing basic functionality like copying/pasting or connecting to the internet. This is when being able to quickly craft your own TCP client comes in unbelievably handy.

import socket
target_host = "www.google.com"
target_port = 80

# create a socket object
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# connect the client
client.connect((target_host,target_port))

# send some data
client.send(b"GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")

# receive some data
response = client.recv(4096)

print(response.decode())
client.close()

Code Explanation

Let’s decipher these kinda difficult lines of code. Initially, we import the socket library and then declare the variables for our target host and port, so it will be much more convenient for us in the future to use them effectively. Second step ⇒ we create a socket object with the AF_INET and SOCK_STREAM parameters. 

AF_INET parameter means that we are using a standard IPv4 address or hostname, while SOCK_STREAM indicates that this will be a TCP client. Next two steps we simply connect to the server and send some data as bytes. Final step ⇒ we receive the data back and print out the response.

In addition, there are 3 assumptions we need to take into account. The first assumption is that our connection will always succeed, and the second is that the server expects us to send data first (sometimes some servers expect to send data to you and wait for your response). The final assumption is that the server will always return data to us in a timely fashion.

UDP Client

UDP Client

To be honest with you, there is no big difference between UDP and TCP clients. We will need to apply only a few small changes, so the Client can send the packets in the UDP form.

import socket

target_host = "127.0.0.1"
target_port = 9997

# create a socket object
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# send some data
client.sendto(b"AAABBBCCC",(target_host,target_port))

# receive some data
data, addr = client.recvfrom(4096)

print(data.decode())
client.close()

Code Explanation

In this case, we changed the socket type to SOCK_DGRAM, when we were creating the socket object. The next step is simply to call sendto() function and pass in the data and the server you want to send the data to.

Quick explanation ==> We used sendto(), because the UDP is a connectionless protocol, there is no call to connect() beforehand.

The last change is to call recvfrom() function to receive UDP data back. The only difference is that it returns both the data and the details of the remote host and port.

TCP Server

TCP Server

import socket
import threading

IP = '0.0.0.0'
PORT = 9998

def main():
 server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 server.bind((IP, PORT)) 
 server.listen(5) 
 print(f'[*] Listening on {IP}:{PORT}')

 while True:
  client, address = server.accept() 
  print(f'[*] Accepted connection from {address[0]}:
{address[1]}')
  client_handler = threading.Thread(target=handle_client, args=(client,))
  client_handler.start() 

def handle_client(client_socket): 
 with client_socket as sock:
  request = sock.recv(1024)
  print(f'[*] Received: {request.decode("utf-8")}')
  sock.send(b'ACK')

if __name__ == '__main__':
main()

Code Explanation

As always we should import all necessary libraries. This time we import threading library which helps us to execute multiple threads concurrently. Then we declare two variables such as ‘IP‘ and ‘PORT‘ with the corresponding values.

Then in our ‘main()‘ function, we start to pass in the IP and PORT we want the server to listen to. Next, we tell our server to start listening to, with a maximum backlog of connections set to 5 units.

In the next step, we put our server in the main loop, where it awaits for an incoming connection. Once the client connects, we receive the client socket in the client variable and the remote connection details in the address variable.

Inside client_handler variable we create our new thread object that points to our handle_client function, and we pass it the client socket object as an argument.

Eventually, we start our new thread to handle the client connection, at which point the main server loop is ready to handle another incoming connection. Lastly, the handle_client function performs the recv() method and then sends a simple message back to the client.

If you use the TCP client that we built earlier, you can send some test packets to the server. You should see the output like the following:

[*] Listening on 0.0.0.0:9998
[*] Accepted connection from: 127.0.0.1:62512
[*] Received: ABCDEF

Let's wrap up our exciting journey! We've crafted some powerful yet simple tools that can become invaluable during penetration testing, particularly in enterprise environments where restrictions seem endless. But this is just the beginning! In our next post, we'll be diving into the creation of our very own version of the legendary Netcat tool. Trust me, you won't want to miss it. Get ready for more cutting-edge innovations and stay tuned for what's coming next!

If you are not subscribed yet, hit the button below

Reply

or to participate.