Skip to content

Repository files navigation

ContributorsForksStargazersIssuesPythonGitHubLicence


🇧🇷 Leia em Português

Logo

Python Networks

Python Network Programming for devs, hackers, and pentesters.

· Report Bug · Request Feature

Table of Contents
  1. About the Project
  2. Initial Questions
  3. TCP Client
  4. UDP Client
  5. TCP Server
  6. Replacing Netcat
  7. Creating a TCP Proxy
  8. SSH with Paramiko
  9. Contribution
  10. Contact
  11. Acknowledgments

About the Project

Python is the "darling" language for cybersecurity lovers. As we explore the content of one of the biggest best-sellers on the subject (Black Hat Python), we will learn deeply about the technologies and even build our own pentesting tools with Python!

We will learn about chapters 2, 3, and 4 of Black Hat, covering networking themes. We will learn to make our own TCP client, UDP client, TCP server, create a Netcat substitute, a Proxy, SSH tunneling, IP layer decoding, email credential theft, Sniffing, and much more (let's stop being just "script kiddies"). So sit back comfortably and let's get hacking!

If you love programming, love Python, and love cybersecurity, this content is for you! I made it with lots of love 💜.

Initial Questions

Let's start preparing the environment for programming. To begin, have a computer with internet access, a text editor or IDE (my advice is to use PyCharm free version). The book asks you to install Kali Linux in a VM, but it can be any Linux machine or even MacOS. If we need any specific package installation, I will mention it in each chapter, don't worry!

My tips are: practice each theme a lot, look closely at the examples and external references I will place in each subject, search for information on the discussed theme on the internet. If you have any specific doubt, you can send it to me via contact or post on StackOverflow. I hope you have the curiosity and commitment to absorb each topic deeply. If an example seems very difficult at first, calm down and look carefully and without haste, as I will comment on each topic step by step.

Prerequisites

  • Linux Machine (either VM or installed on HDD)
  • Prior knowledge in Python (I won't go into syntax details but rather functionalities, so it's good to have intermediate knowledge of programming logic and Python)
  • Kali-Linux (optional)
  • Knowledge of Linux commands
  • Python3 installed on your machine (preferably system-wide default)
  • WingIDE (optional, book suggestion)
  • Basic knowledge of computer networks (knowing how protocols work can help you a lot in this demo)

Note: I placed some cool links in the Acknowledgments at the end of the file with some cool content on Networks, Linux commands, PyCharm installation...

Installations

To install pip so we can install some tools we will use, run the following command:

sudo apt-get install python-setuptools python-pip

To install Python 3, first check if there is any Python version installed on your machine with the command:

$ which python

or

$ which python3

which should return something like /usr/bin/python. This means Python is installed at that address.

To install it with apt-get:

$ sudo apt-get install python3
$ sudo apt-get install python3-pip

To install WingIDE use the command:

$ sudo dpkg -i wingide5_5.0.9-1_i386.deb

and

$ sudo apt-get -f install

TCP Client

To send some garbage data for testing, fuzzing, or any other task, we must have a TCP Client in a simple way.

  • I import the socket library to use blocking sockets.
  • I define my host and port to connect to.
  • I create a socket object with the AF_INET parameter which tells me we want a standard IPv4 address or a host name, and SOCK_STREAM which indicates this will be a TCP client.
  • I send some data to it.
  • I receive some data.

Note: Making some serious assumptions about sockets that you should be aware of. The first assumption is that our connection will always succeed, the second is that the server will always be expecting us to send data first (as opposed to servers that expect to send data to you first and wait for your response), the third assumption is that the server will always send data back immediately.

UDP Client

Not being very different from the TCP client, we make only four small changes so that packets are sent in UDP format:

client=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  • Where SOCK_DGRAM indicates a UDP client.
  • We do a bind() to connect the socket to the destination address.
  • And with sendto() we pass the data and the server to which you want to send the data.
  • The last step consists of calling recvfrom() to receive the UDP data back.

Note: Since the UDP protocol is not connection-oriented, there is no call prior to connect(). You will observe that both data and details about the remote host and port are received, along with the UDP message which in our case was Hello, server UDP.

For more information about UDP connection with Python see the link UDP example

TCP Server

Creating a TCP server is as simple as creating a client, but attention is needed to configure your server to your client; maybe connection errors can occur because you might be trying to make this connection on reserved ports. Pay attention!

Here is a standard multithreaded TCP server:

  • At the beginning, we do what we are already used to doing with bind(), passing the IP address and the port we want the server to listen on.
  • Then with server.listen(1) we tell the server to start listening with a maximum of connections defined at 1 (my choice, you can put as many as you want).
  • Then with the function handle_client() the server enters its main loop, where it waits for an incoming connection.
  • When the client connects, we receive the client socket in the client variable and the remote connection details in an addr variable in client, addr = server.accept().
  • Next, we create a new thread object pointing to our handle_client() function and pass the socket object referring to the client as the client argument.
  • We start the thread to handle the connection with the client, and our server's main loop will be ready to handle another incoming connection in client_handler.start().
  • The function client_handler() executes recv() and then sends a simple message to the client "ARK!".

For more information about the connection between TCP server and TCP client with Python see the link TCP connection example

Note: That's it, these codes will be extended (in new files, so as not to mess up versioning) in the next sections, where we will develop a substitute for Netcat and a TCP Proxy! So let's go!

Netcat

The time has come to create our own Swiss Army knife of networking: NETCAT. Often "smart" network administrators remove it from the system, but python is present on the servers.

So for these cases, it is very useful to create a simple network client and server that can be used to send files or have a listener (process that checks for connection requests) that enables access.

If you hacked a web system, you certainly should leave a Python callback for secondary access before resorting to using one of your Trojans or backdoors.

1 - So let's start with our Netcat: Calm down! The file is large, I know! But let's go by parts, I'll start explaining from the beginning:

  • First I do some imports.
  • Then I define some global variables.
  • Then create the main function def usage():, it will be responsible for handling command line arguments by calling the rest of the functions.

Starting by reading all command line options:

try:
opts, args=getopt.getopt(sys.argv[1:], "hle:t:p:cu:",
["help", "listen", "execute=", "target=", "port=", "command", "upload="])
exceptgetopt.GetoptErroraserr:
logging.error("%s", err)
usage()

and defining the necessary variables according to the detected options. And if any command information does not meet our criteria, we will display information on how to use the script according to our usage() function. And here we try to imitate netcat and send data from stdin over the network:

ifnotlistenandlen(target) andport>0:
buffer=sys.stdin.read()
client_sender(buffer)

And finally, we detect that it is necessary to set up a socket to listen to the network and process additional commands: server_loop() where we load a file, execute a command, start a command shell.

2 - From now on let's talk about the second part of our script def client_sender():, I already think you are getting familiar with all this.

  • We start creating our TCP socket object and then we test it.
  • Then we test it to know if we receive any input data from stdin.
iflen(buffer):
client.send(buffer)
whileTrue:
...
  • If everything is ok, we will send the data remotely and receive data back (while recv_len:)
  • Then we prepare more input data (buffer = input('')) from the user and will continue to send and receive data until the user terminates our script.

3 - Now let's create the main loop of our server, along with a stub function that will handle both the execution of our command and our full command shell.

Well at this stage of the championship you should already be very familiar with creating a complete TCP server with threading, so let's not go into details of our function server_loop():

  • Something in the function run_command(): that we haven't talked about yet is subprocess, which is a library that provides an effective interface to create processes, providing several ways to start and interact with client programs.
  • Here output = subprocess.check_output(command, stderr=subprocess.STDOUT, shell=True) we simply execute whatever command is passed, executing on the operating system and returning the command output to the client that connected to us.

4 - Finally, let's implement the logic to upload files, execute commands, and implement our shell: client_handler():

  • This first portion of code (if len(upload_destination):) is responsible for determining if our network tool is configured to receive a file when a connection is established.
  • Initially, we receive the file data in a loop (while True: data = client_socket.recv(1024)) to ensure we receive everything.
  • Then, we process our execution functionality, where we call our function run_command() and simply send the result back over the network.
  • Finally, we have the code that handles our command shell, it continues to execute commands as we send them and the output is kept back.

Testing

In a terminal or cmd.exe shell, run our script as follows:

kali-linux$ ./szynet.py -l -p 9999 -c

You can go to another terminal or cmd.exe and run our script as a client (just like we did with the TCP server and client). Remember that our script is reading from stdin and will do so until it receives the EOF (end-of-file) marker. To do this, press CTRL + D on your keyboard:

kali-linux$ ./szynet.py -l -p 9999 -c
<CTRL-D><BHP:#> ls -la
drwxr-xr-x 4 kali-linux staff 13618 Dec 19:45 .
drwxr-xr-x 4 kali-linux staff 1369 Dec 17:34 ..
-rwxrwxrwx 1 kali-linux staff 849819 Dec 06:14 szynet.py
-rw-r--r-- 1 kali-linux staff 84410 Dec 10:45 listing-1-3.py
<BHP:#> pwd
/home/kali-linux/scripts/netcat

Note: You will notice that the code and functions are not in the order of the comments, that's because I made the commentary according to importance and the script execution process.

Congratulations, you reached the end of a very difficult stage, I hope you understood what we did and are still willing to learn more, because this was just the beginning, we are just warming up for now. Now let's create a TCP PROXY that we will use in various attack scenarios.

TCP Proxy

The reasons for having a proxy in your toolbox are numerous; we can use it to forward traffic to be sent from a host, or to evaluate network-based software. When performing penetration tests in corporate environments, you will commonly encounter the fact that you cannot execute Wireshark, cannot load drivers to do sniffing on Windows loopback... So let's create our own TCP proxy!

Our script contains seven functions, I'll explain one by one, some you should already be used to.

1 - server_loop()

  • You should already be very familiar with this function, we start by receiving some command line arguments.
  • Then we fire a loop on the server that listens waiting for connections.
  • When a new connection request arises, it will be passed to the next function proxy_handler()

2 - main()

  • The main function of our script capable of defining the data to be used and calling our function server_loop() with the correct parameters to listen to our network.

3 - proxy_handler()

  • Here is the function that will do all the work of sending and receiving data to either side of the data stream.
  • We start by doing a check to ensure we won't need to start a new connection.
  • Then we use our function receive_from() which will be used on both sides of the communication.
  • Then we dump the packet content to inspect them and see if there is anything interesting.
  • Next we pass the output to our function response_handler().
  • The rest is simple: we read continuously from the local host, process, send to the remote host, read the host, process, and send to the local host.

4 - hexdump()

  • In the last part of the code.
  • Initially we create our hex dumping function that will simply display the packet details showing both hexadecimal values and ASCII characters that can be displayed.

5 - receive_from()

  • This function is used to receive both local and remote data and simply passes the socket object to be used.

6 - request_handler() & response_handler()

  • The last two functions allow modifying any traffic destined for either side of the proxy.

Testing

Well, to test you can simply run a command with the parameters that we already predefined for our function to receive in the prompt, preceded by sudo because it may be that the port you chose might be privileged and requires root user authorizations (in my case I will put on port 21 to connect with my or our TCP client) like this:

kali-linux$ sudo python3 ./main.py 127.0.0.1 ftp.target.ca 21 True

Or as I think you want to be a little more bold and comprehensive you can connect to an FTP server of your choice and that will really answer you, like google.com, facebook.com,... Just configure your browser's proxy on port 80 (HTTP access port) and run your code with the modifications as in the following example:

In the browser (in my case I will use Firefox):

Go to Preferences > Network Settings

Leave the configuration as follows and run the command:

kali-linux$ sudo python3.9 ./main.py 127.0.0.1 80 www.google.com 80 True 

And something like this will appear on your screen:

[*] Listening on 127.0.0.1:80
[==>] Received incoming connection from 127.0.0.1:41452
[<==] Received 201 bytes from localhost.
000043 4F 4E 4E 45435420777777 2E 67 6F 6F 67 C O N N E C T w w w . g o o g
0010 6C 65 2E 63 6F 6D 3A 3434332048545450 2F l e . c o m : 443 H T T P /
002031 2E 31 0D 0A 55736572 2D 416765 6E 74 3A 1 . 1 . . U s e r - A g e n t :
003020 4D 6F 7A 69 6C 6C 61 2F 35 2E 3020285831 M o z i l l a / 5 . 0 ( X 1004031 3B 20 4C 69 6E 757820783836 5F 3634 3B 1 ; L i n u x x 86 _ 64 ;
0050207276 3A 3738 2E 302920476563 6B 6F 2F r v : 78 . 0 ) G e c k o /
00603230313030313031204669726566 6F 7820100101 F i r e f o x
0070 2F 3738 2E 30 0D 0A 5072 6F 7879 2D 43 6F 6E / 78 . 0 . . P r o x y - C o n
0080 6E 65637469 6F 6E 3A 20 6B 656570 2D 61 6C n e c t i o n : k e e p - a l
331: [==>] Sent to remote.
332: [<==] Received 1775 bytes from remote.
333: 6564696120 6F 6E 6C 7920730 } } @ m e d i a o n l y s
334: 050063726565 6E 2061 6E 642028 2D 776562 6B c r e e n a n d ( - w e b k
335: 05106974 2D 6D 69 6E 2D 646576696365 2D 7069 i t - m i n - d e v i c e - p i
336: 05A0 74 2D 626163 6B 6772 6F 75 6E 64 2D 7369 7A t - b a c k g r o u n d - s i z
337: 05B0 65 3A 313030252031303025 7D 7D 23 6C 6F e : 100% 1 0 0 % } } # l o
338: 05C0 67 6F 7B 64697370 6C 6179 3A 69 6E 6C 69 6E g o { d i s p l a y : i n l i n
339: 05D0 65 2D 62 6C 6F 63 6B 3B 686569676874 3A 35 e - b l o c k ; h e i g h t : 5
340: 05E0 347078 3B 7769647468 3A 3135307078 7D 4 p x ; w i d t h : 150 p x }
341: 05F0 0A 2020 3C 2F 737479 6C 65 3E 0A 2020 3C 61 . < / s t y l e > . < a
342: 06002068726566 3D 2F 2F 777777 2E 67 6F 6F 67 h r e f = / / w w w . g o o g
343: 0610 6C 65 2E 63 6F 6D 2F 3E 3C 737061 6E 206964 l e . c o m / >< s p a n i d
344: 0620 3D 6C 6F 67 6F 2061726961 2D 6C 616265 6C = l o g o a r i a - l a b e l
345: 0630 3D 47 6F 6F 67 6C 65 3E 3C 2F 737061 6E 3E 3C = G o o g l e >< / s p a n ><
346: 0640 2F 61 3E 0A 2020 3C 70 3E 3C 62 3E 343035 2E / a > . 347: [==>] Sent to localhost.
348: [*] No more data. Closing connections.

Well that's all folks. Let's go to the next one!

SSH with Paramiko

Contribution

The comments and codes were taken from the book: Black Hat Python by Justin Seitz published by Novatec. With some changes regarding the comments and the code adapted to Python version 3.9

Contact

Send me a message if you have any questions


João Lucas (Instagram)
🚀

Linkedin BadgeGmail Badge

Acknowledgments

About

A collection of Python network programming tools and pentesting scripts inspired by "Black Hat Python", featuring a custom Netcat alternative, TCP/UDP clients, and a unified CLI runner.

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages