Mastering Python for Networking and Security

4.3 (4 reviews total)
By José Manuel Ortega
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Working with Python Scripting

About this book

It’s becoming more and more apparent that security is a critical aspect of IT infrastructure. A data breach is a major security incident, usually carried out by just hacking a simple network line. Increasing your network’s security helps step up your defenses against cyber attacks. Meanwhile, Python is being used for increasingly advanced tasks, with the latest update introducing many new packages. This book focuses on leveraging these updated packages to build a secure network with the help of Python scripting.

This book covers topics from building a network to the different procedures you need to follow to secure it. You’ll first be introduced to different packages and libraries, before moving on to different ways to build a network with the help of Python scripting. Later, you will learn how to check a network’s vulnerability using Python security scripting, and understand how to check vulnerabilities in your network. As you progress through the chapters, you will also learn how to achieve endpoint protection by leveraging Python packages along with writing forensic scripts. By the end of this book, you will be able to get the most out of the Python language to build secure and robust networks that are resilient to attacks.

Publication date:
September 2018
Publisher
Packt
Pages
426
ISBN
9781788992510

 

Chapter 1. Working with Python Scripting

Throughout this chapter, we will introduce Python scripting, collections, functions, exception-handling, and object-oriented programming. We will review how to create classes, objects, and Python's particularities to initialize objects, including the use of special attributes and methods. Also it will be introduce a methodology, tools, and development environments.

The following topics will be covered in this chapter:

  • Programming and installing Python
  • Data structures and Python collections
  • Python functions and managing exceptions
  • Object-Oriented Programming in Python
  • The OMSTD methodology including how to manage modules, packages, dependencies, passing parameters, working with virtual environments, and the STB module for Python scripting
  • The main development environments for script-development in Python
  • Interacting and debugging with Python IDE
 

Technical requirements


Before you start reading this book, you should know the basics of Python programming, such as the basic syntax, variable type, data type tuple, list dictionary, functions, strings, and methods. Two versions, 3.6.5 and 2.7.14, are available at python.org/downloads/.

Examples and source code for this chapter are available in the GitHub repository in the chapter 1 folder: https://github.com/PacktPublishing/Mastering-Python-for-Networking-and-Security.

 

 

Programming and installing Python


Python is a byte-compiled, object-oriented programming language that is easy to read and write. The language is great for security professionals because it allows for the rapid creation of tests as well as reusable items for future use. As many security tools are written in Python, it offers many opportunities for extending and adding features to tools that are already written.

Introducing Python scripting

In this book, we will work with two versions. If you use a Linux Distribution, such as Debian or Kali, there will be no problems since Python is multi-platform and version 2.7 comes installed by default in the majority of linux distributions.

Why choose Python?

There are many reasons to choose Python as your main programming language:

  • Multi-platform and open source language.
  • Simple, fast, robust, and powerful language.
  • Many libraries, modules, and projects focused on computer security are written in Python.
  • There is a lot of documentation and a very large user community.
  • It is a language designed to make robust programs with a few lines of code, something that in other languages is only possible after including many characteristics of each language.
  • Ideal for prototypes and rapid-concept tests (PoC).

Multi-platform

The Python interpreter is available on many platforms (Linux, DOS, Windows, and macOS X). The code that we create in Python is translated into bytecode when it is executed for the first time. For that reason, in systems in which we are going to execute our programs or scripts developed in Python, we need the interpreter to be installed.

 

Object-Oriented Programming

Object-oriented programming is a paradigm where programs are defined in terms of "object classes" that communicate with each other by sending messages. It is an evolution of the paradigms of procedural, structured, and modular programming, and is implemented in languages such as Java, Python, or C ++.

Classes define the behavior and available state that is specified in objects, and allow a more direct representation of the concepts necessary for modeling a problem, allowing the user to define new types.

Objects are characterized by:

  • An identity that differentiates them from each other
  • Defining their behavior through methods
  • Defining their state through properties and attributes

Classes allow grouping in a new type of data and the functionalities associated with objects, favoring separation between the details of the implementation of the essential properties for its use. In this way, the goal is to not show more than the relevant information, hiding the state and the internal methods of the class, it is known as "encapsulation," and it is a principle inherited from modular programming.

An important aspect in the use of classes is that they are not manipulated directly, but serve to define new types. A class defines properties and behaviors for objects (instances of a class). A class acts as a template for a set of objects, which are said to belong to the class.

The most important techniques used in object-oriented programming are:

  • Abstraction: Objects can perform tasks, interact with other objects, or modify and report their status without the need to communicate how those actions are performed.
  • Encapsulation: Objects prevent the modification of their internal state or a call to internal methods by other objects, and are only related through a clear interface that defines how they relate to other objects.
  • Polymorphism: Different behaviors may be associated with the same name.
  • Inheritance: Objects are related to others by establishing hierarchies, and it is possible that some objects inherit the properties and methods of other objects, extending their behavior and/or specializing. Objects are grouped like this in classes that form hierarchies.

Obtaining and installing Python

Installation of Python is fast on Linux and Windows platforms. Windows users can use an installer in an easy way that makes configuration work for you. In Linux, you have the option to build the installation from the source code, but it's not mandatory, and you can use classic package-management dependencies, such as apt-get.

Many Linux distributions come preinstalled with Python 2. When installing Python 3 on such a system, it is important to keep in mind that we are not replacing the installation of Python 2. In this way, when we install Python 3, it can be installed in parallel with Python 2 on the same machine. After installing Python 3, you can call the python interpreter using the Python3 executable.

Installing Python on Windows

Windows users can obtain the installer from the main Python site: https://www.python.org/ftp/python/2.7.15/python-2.7.15.msi. Just double-click the installer, and follow the steps to install it. It should create a directory at C:/Python27/; this directory will have the Python.exe interpreter as well as all of the default libraries installed.

The Python installation allows you to customize where the environment will be installed. The default location for Python 2.7.14 is C:\Python27, although you can specify another location. This route will be relevant when looking for certain modules and tools.

We can customize the installation if we want to include the documentation or install a series of utilities, such as the pip package manager or the IDLE development environment, to edit and execute scripts. It is recommended you leave the options marked so that it installs them and we have as complete an environment as possible:

 

It is important to check the Add python.exe to the Path box. This will allow you to run Python directly from the command prompt from any path without having to go to the installation directory.

At the time of installing the version of Python for Windows, you can also see that it is available IDLE, an editor or IDE (Integrated Development Environment) of Python that will allow us to write and test the code. Once installed, we can verify that everything is correct:

  1. Open the folder where you have installed it
  2. Enter C:\Python27\Lib\idlelib
  3. Run the idle.batfile with a double-click

Note

Another option we have for Windows users is WinPython, which is available at http://winpython.github.io.

WinPython is a Python distribution; you can install it on Windows 7/8/10 operating systems for scientific and educational use.

 

This distribution is something different from others because it:

  • Requires no installation: WinPython lives entirely in its own directory, without any OS installation
  • Is portable: You can easily zip your python project and install in other machines in an easy way

Installing Python for Linux

Python is installed by default in most Gnu/Linux distributions. If we want to install it in Ubuntu or Debian-based distributions, we can do it through the apt-get package manager:

sudo apt-get install python2.7
 

Python collections


In this section, we will review different types of data collections, such as as lists, tuples, and dictionaries. We will see methods and operations for managing these data structures and a practical example where we review the main use cases.

Lists

Lists in Python are equivalent to structures as dynamic vectors in programming languages such as C. We can express literals by enclosing their elements between a pair of brackets and separating them with commas. The first element of a list has index 0. The indexing operator allows access to an element and is expressed syntactically by adding its index in brackets to the list, list [index].

Consider the following example: a programmer can construct a list by appending items using the append() method, print the items, and then sort them before printing again. In the following example, we define a list of protocols and use the main methods of a Python list as append, index, and remove:

>>> protocolList = []
>>> protocolList.append("ftp")
>>> protocolList.append("ssh")
>>> protocolList.append("smtp")
>>> protocolList.append("http")
>>> print protocolList
['ftp','ssh','smtp','http']
>>> protocolList.sort()
>>> print protocolList
['ftp','http','smtp','ssh']
>>> type(protocolList)
<type 'list'>
>>> len(protocolList)
4

To access specific positions, we use the index method, and to delete an element, we use the remove method:

>>> position = protocolList.index("ssh")
>>> print "ssh position"+str(position)
ssh position 3
>>> protocolList.remove("ssh")
>>> print protocolList
['ftp','http','smtp']
>>> count = len(protocolList)
>>> print "Protocol elements "+str(count)
Protocol elements 3

To print out the whole protocol list, use the following code. This will loop through all the elements and print them:

>>> for protocol in protocolList:
>>      print (protocol)
ftp
http
smtp

Lists also have methods, which help to manipulate the values inside them and allow us to store more than one variable inside it and provide a better method for sorting arrays of objects in Python. These are the most-used methods for manipulating lists:

  • .append(value): Appends an element at the end of the list
  • .count('x'): Gets the number of 'x' in the list
  • .index('x'): Returns the index of 'x' in the list
  • .insert('y','x'): Inserts 'x' at location 'y'
  • .pop(): Returns the last element and also removes it from the list
  • .remove('x'): Removes the first 'x' from the list
  • .reverse(): Reverses the elements in the list
  • .sort(): Sorts the list alphabetically in ascending order, or numerically in ascending order

Reversing a List

Another interesting operations that we have in lists is the one that offers the possibility of going back to the list through the reverse () method:

>>> protocolList.reverse()
>>> print protocolList
['smtp','http','ftp']

Another way to do the same operation use the -1 index. This quick and easy technique shows how you can access all the elements of a list in reverse order:

>>> protocolList[::-1]
>>> print protocolList
['smtp','http','ftp']

Comprehension lists

Comprehension lists allow you to create a new list of iterable objects. Basically, they contain the expression that must be executed for each element inside the loop that iterates over each element.

The basic syntax is:

new_list = [expression for_loop_one_or_more conditions]

List comprehensions can also be used to iterate over strings:

>>> protocolList = ["FTP", "HTTP", "SNMP", "SSH"]
>>> protocolList_lower= [protocol.lower() for protocol in protocolList]
>>> print(protocolList_lower) # Output: ['ftp', 'http', 'snmp', 'ssh']

 

Tuples

A tuple is like a list, but its size and elements are immutable, that is, its values cannot be changed nor can more elements be added than initially defined. A tuple is delimited by parentheses. If we try to modify an element of a tuple, we get an error indicating that the tuple object does not support the assignment of elements:

Dictionaries

The Python dictionary data structure allows us to associate values with keys. A key is any immutable object. The value associated with a key can be accessed with the indexing operator. In Python, dictionaries are implemented using hash tables.

A Python dictionary is a storage method for key:value pairs. Python dictionaries are enclosed in curly brackets, {}.Dictionaries, also called associative matrices, which owe their name to collections that relate a key and a value. For example, let's look at a dictionary of protocols with names and numbers:

>>> services = {"ftp":21, "ssh":22, "smtp":25, "http":80}

The limitation with dictionaries is that we cannot create multiple values with the same key. This will overwrite the previous value of the duplicate keys. Operations on dictionaries are unique. We can combine two distinct dictionaries into one by using the update method. Also, the update method will merge existing elements if they conflict:

>>> services = {"ftp":21, "ssh":22, "smtp":25, "http":80}
>>> services2 = {"ftp":21, "ssh":22, "snmp":161, "ldap":389}
>>> services.update(services2)
>>> print services

This will return the following dictionary:

{"ftp":21, "ssh":22, "smtp":25, "http":80,"snmp":161, "ldap":389}

 

 

 

 

 

 

The first value is the key and the second is the value associated with the key. As a key, we can use any immutable value: we could use numbers, strings, booleans, or tuples, but not lists or dictionaries, since they are mutable.

The main difference between dictionaries and lists or tuples is that the values stored in a dictionary are accessed not by their index, because they have no order, but by their key, using the [] operator again.

As in lists and tuples, you can also use this operator to reassign values:

>>> services["http"]= 8080

When constructing a dictionary, each key is separated from its value by a colon, and we separate items by commas. The .keys () method will return a list of all keys of a dictionary and the .items () method will return a complete list of elements in the dictionary.

Following are examples using these methods:

  • services.keys() is method that will return all the keys in dictionary.
  • services.items() is method that will return the entire list of items in dictionary.

From the point of view of performance, the key within a dictionary is converted to a hash value when it is stored in order to save space and improve performance when searching or indexing the dictionary. It is also possible to print the dictionary and browse the keys in a specific order. The following code extracts the dictionary elements and then orders them:

>>> items = services.items()
>>> print items
[('ftp', 21), ('smtp',25), ('ssh', 22), ('http', 80), ('snmp', 161)]
>>> items.sort()
>>> print items
[('ftp', 21), ('http', 80), ('smtp', 25), ('snmp', 161), ('ssh', 22)]

We can extract keys and values for each element in the dictionary:

>>> keys = services.keys()
>>> print keys
['ftp', 'smtp', 'ssh', 'http', 'snmp']
>>> keys.sort()
>>> print keys
['ftp', 'http', 'smtp', 'snmp', 'ssh']
>>> values = services.values()
>>> print values
[21, 25, 22, 80, 161]
>>> values.sort()
>>> print values
[21, 22, 25, 80, 161]
>>> services.has_key('http')
True
>>> services['http']
80

Finally, you might want to iterate over a dictionary and extract and display all the "key:value" pairs:

>>> for key,value in services.items():
        print key,value
ftp 21
smtp 25
ssh 22
http 80
snmp 161
 

Python functions and managing exceptions


In this section, we will review Python functions and managing exceptions. We will see some examples for declaring and using both in our script code. We'll also review the main exceptions we can find in Python for include in our scripts. 

Python functions

In Python, functions provide organized blocks of reusable code. Typically, this allows a programmer to write a block of code to perform a single, related action. While Python provides many built-in functions, a programmer can create user-defined functions. In addition to helping us to program and debug by dividing the program into parts, the functions also allow us to reuse code.

Python functions are defined using the def keyword with the function name, followed by the function parameters. The body of the function consists of Python statements that are to be executed. At the end of the function, you can choose to return a value to the function caller, or by default, it will return the None object if you do not specify a return value.

For example, we can define a function that, given a sequence of numbers and an item passed by a parameter, returns True if the element is within the sequence and False otherwise:

>>> def contains(sequence,item):
        for element in sequence:
                if element == item:
                        return True
        return False
>>> print contains([100,200,300,400],200)
True
>>> print contains([100,200,300,400],300)
True
>>> print contains([100,200,300,400],350)
False

Managing exceptions 

Exceptions are errors detected by Python during program execution. When the interpreter encounters an exceptional situation, such as trying to divide a number by 0 or trying to access a file that does not exist, it generates or throws an exception, informing the user that there is a problem.

If the exception is not captured, the execution flow is interrupted and the information associated with the exception in the console is displayed so that the programmer can solve the problem.

Let's see a small program that would throw an exception when trying to divide 1 by 0. If we execute it, we will get the following error message:

The first thing that is shown is the traceback, which consists of a list of the calls that caused the exception. As we see in the stack trace, the error was caused by the call to calculate () of line 7, which in turn calls division (1, 0) on line 5, and ultimately the execution of the a/b sentence of division line 2.

The Python language provides an exception-handling capability to do just this. We use try/except statements to provide exception-handling. Now, the program tries to execute the division by zero. When the error occurs, our exception-handling catches the error and prints a message to the screen:

In the following example, we try to create a file-type f object. If the file is not passed as a parameter, an exception of the IOError type is thrown, which we capture thanks to our try-except:

Some of the exceptions available by default are listed here (the class from which they are derived is in parentheses):

  • BaseException: Class from which all exceptions inherit.
  • Exception (BaseException): Super class of all exceptions that are not output.
  • ZeroDivisionError (ArithmeticError): Launched when the second argument of a division or module operation was 0.
  • EnvironmentError (StandardError): Parent class of errors related to input/output.
  • IOError (EnvironmentError): Error in an input/output operation.
  • OSError (EnvironmentError): Error in a system call.
  • ImportError (StandardError): The module or the module element that you wanted to import was not found.
 

Python as an OOP language


In this section, we will review Object-Oriented Programming and inheritance in Python.

Object-Oriented programming is one of the paradigms most used today. While it fits a lot of situations that we can find in day-to-day life, in Python, we can combine it with other paradigms to get the best out of the language and increase our productivity while maintaining an optimal code design.

Python is an object-oriented language and allows you to define classes and instantiate objects from these definitions. A block headed by a class statement is a class definition. The functions that are defined in the block are its methods, also called member functions.

 

 

The way Python creates objects is with the class keyword. A Python object is a collection of methods, variables, and properties. You can create many objects with the same class definition. Here is a simple example of a protocol object definition:

You can find the following code in the protocol.py file.

class protocol(object):

 def __init__(self, name, number,description):
 self.name = name
 self.number = number
 self.description = description

 def getProtocolInfo(self):
 return self.name+ " "+str(self.number)+ " "+self.description

The __init__ method is a special method that, as its name suggests, act as a constructor method to perform any initialization process that is necessary.

The first parameter of the method is a special keyword and we use the self identifier for reference the current object. It is a reference to the object itself and provides a way to access its attributes and methods.

The self parameter is equivalent to the pointer that can be found in languages such as C ++ or Java. In Python, self is a reserved word of the language and is mandatory, it is the first parameter of conventional methods and through it you can access the attributes and methods of the class.

To create an object, write the name of the class followed by any parameter that is necessary in parentheses. These parameters are the ones that will be passed to the __init__ method, which is the method that is called when the class is instantiated:

>>> protocol_http= protocol("HTTP", 80, "Hypertext transfer protocol")

Now that we have created our object, we can access its attributes and methods through the object.attribute and object.method() syntax:

>>> protocol_http.name
>>> protocol_http.number
>>> protocol_http.description
>>> protocol_http.getProtocolInfo()

 

Inheritance

The main concepts of object-oriented programming languages are: encapsulation, inheritance, and polymorphism. In an object-oriented language, objects are related to others by establishing hierarchies, and it is possible that some objects inherit the properties and methods of other objects, extending their behavior and/or specializing. 

Inheritance allows us to generate a new class from another, inheriting its attributes and methods, adapting or expanding them as necessary. To indicate that a class inherits from another class, we need to put the name of the class that is inherited between parentheses.

In OOPS terminology, it is said that "B inherits from A," "B is a class derived from A," "A is the base class of B," or "A is a superclass of B." This facilitates the reuse of the code, since you can implement the basic behaviors and data in a base class and specialize them in the derived classes:

 

The OMSTD methodology and STB Module for Python scripting


OMSTD stands for Open Methodology for Security Tool Developers, it is a methodology and set of good practices in Python for the development of security tools. This guide is intended for developments in Python, although in reality you can extend the same ideas to other languages. At this point, I will discuss the methodology and some tricks we can follow to make the code more readable and reusable.

Python packages and modules

The Python programming language is a high-level and general-use language with clear syntax and a complete standard library. Often referred to as a scripting language, security experts have highlighted Python as a language to develop information-security toolkits. The modular design, the human-readable code, and the fully-developed library set provide a starting point for security researchers and experts to build tools.

Python comes with a comprehensive standard library that provides everything from integrated modules that provide access to simple I/O, to platform-specific API calls. The beauty of Python is the modules, packages, and individual frames contributed by the users. The bigger a project is, the greater the order and the separation between the different parties must be. In Python, we can make this division using the modules concept.

What is a module in Python?

A module is a collection of functions, classes, and variables that we can use from a program. There is a large collection of modules available with the standard Python distribution.

The import statement followed by the name of the module gives us access to the objects defined in it. An imported object becomes accessible from the program or module that imports it, through the identifier of the module, point operator, and the identifier of the object in question.

A module can be defined as a file that contains Python definitions and declarations. The name of the file is the name of the module with the .py suffix attached. We can begin by defining a simple module that will exist in a .py file within the same directory as our main.py script that we are going to write:

  • main.py
  • my_module.py

Within this my_module.py file, we’ll define a simple test() function that will print “This is my first module”:

 # my_module.py
 def test():
    print("This is my first module")

Within our main.py file, we can then import this file as a module and use our newly-defined test() method, like so:

# main.py
 import my_module

 def main():
    my_module.test()

 if __name__ == '__main__':
    main()

That is all we need to define a very simple python module within our Python programs.

Difference Between a Python Module and a Python Package

When we are working with Python, it is important to understand the difference between a Python module and a Python package. It is important differentiate them; a package is a module that includes one or more modules.

Part of software development is to add functionality based on modules in a programming language. As new methods and innovations are made, developers supply these functional building blocks as modules or packages. Within the Python network, the majority of these modules and packages are free, with many, including the full source code, allowing you to enhance the behavior of the supplied modules and to independently validate the code.

Passing parameters in Python

To develop this task, the best thing is to use the argparse module that comes installed by default when you install Python.

Note

For more information, you can check out the official website: https://docs.python.org/3/library/argparse.html.

The following is an example of how to use it in our scripts:

You can find the following code in the filename testing_parameters.py

import argparse

parser = argparse.ArgumentParser(description='Testing parameters')
parser.add_argument("-p1", dest="param1", help="parameter1")
parser.add_argument("-p2", dest="param2", help="parameter2")
params = parser.parse_args()
print params.param1
print params.param2

In the params variable, we have the parameters that the user has entered from the command line. To access them, you have to use the following:

params.<Name_dest>

 One of the interesting options is that it is possible to indicate the type of parameter with the type attribute. For example, if we want a certain parameter to be treated as if it were an integer, we could do it in the following way:

parser.add_argument("-param", dest="param", type="int")

Another thing that could help us to have a more readable code is to declare a class that acts as a global object for the parameters:

class Parameters:
 """Global parameters"""
    def __init__(self, **kwargs):
        self.param1 = kwargs.get("param1")
        self.param2 = kwargs.get("param2")

For example, if we want to pass several parameters at the same time to a function, we could use this global object, which is the one that contains the global execution parameters. For example, if we have two parameters, we can construct the object in this way:

You can find the below code in the filename params_global.py

import argparse

class Parameters:
 """Global parameters"""

    def __init__(self, **kwargs):
        self.param1 = kwargs.get("param1")
        self.param2 = kwargs.get("param2")

def view_parameters(input_parameters):
    print input_parameters.param1
    print input_parameters.param2

parser = argparse.ArgumentParser(description='Passing parameters in an object')
parser.add_argument("-p1", dest="param1", help="parameter1")
parser.add_argument("-p2", dest="param2", help="parameter2")
params = parser.parse_args()
input_parameters = Parameters(param1=params.param1,param2=params.param2)
view_parameters(input_parameters)

In the previous script, we can see that we obtain parameters with the argparse module and we encapsulate these parameters in an object with the Parameters class.With this practice, we get encapsulated parameters in an object to facilitate the retrieval of these parameters from different points of the script.

Managing dependencies in a Python project

If our project has dependencies with other libraries, the ideal would be to have a file where we have these dependencies, so that the installation and distribution of our module is as simple as possible. For this task, we can create a file called requirements.txt, which, if we invoke it with the pip utility, will lower all the dependencies that the module in question needs.

To install all the dependencies using pip:

pip -r requirements.txt

Here, pip is the Python package and dependency manager whereas requirements.txt is the file where all the dependencies of the project are detailed.

Generating the requirements.txt file

We also have the possibility to create the requirements.txt file from the project source code.

For this task, we can use the pipreqs module, whose code can be downloaded from the GitHub repository at https://github.com/bndr/pipreqs

In this way, the module can be installed either with the pip install pipreqs command or through the GitHub code repository using the python setup.py install command.

Note

For more information about the module, you can query the official pypi page: https://pypi.python.org/pypi/pipreqs.

To generate the requirements.txt file, you have to execute the following command:

pipreqs <path_project>

Working with virtual environments

When working with Python, it is strongly recommended you use Python virtual environments. Virtual environments help separate the dependencies required for projects and keep our global directory clean of project packages. A virtual environment provides a separate environment for installing Python modules and an isolated copy of the Python executable file and associated files. You can have as many virtual environments as you need, which means that you can have multiple module configurations configured, and you can easily switch between them.

From version 3, Python includes a venv module, which provides this functionality. The documentation and examples are available at https://docs.python.org/3/using/windows.html#virtual-environments

There is also a standalone tool available for earlier versions, which can be found at:

https://virtualenv.pypa.io/en/latest

Using virtualenv and virtualwrapper

When you install a Python module in your local machine without using a virtual environment, you are installing it globally in the operating system. This installation usually requires a user root administrator and that Python module is installed for every user and every project.

At this point, the best practice is install a Python virtual environment if you need to work on multiple Python projects or you need a way to work with all associated libraries in many projects.

Virtualenv is a Python module that allows you to create virtual and isolated environments. Basically, you create a folder with all the executable files and modules needed for a project. You can install virtualenv with the following command:

$ sudo pip install virtualenv

To create a new virtual environment, create a folder and enter the folder from the command line:

$ cd your_new_folder
$ virtualenv name-of-virtual-environment

For example, this creates a new environment called myVirtualEnv, which you must activate in order to use it:

$ cd myVirtualEnv/
$ virtualenv myVirtualEnv
$ source bin/activate

Executing this command will initiate a folder with the name indicated in your current working directory with all the executable files of Python and the pip module that allows you to install different packages in your virtual environment.

Virtualenv is like a sandbox where all the dependencies of the project will be installed when you are working, and all modules and dependencies are kept separate. If users have the  same version of Python installed on their machine, the same code will work from the virtual environment without requiring any change.

Virtualenvwrapper allows you to better organize all your virtually-managed environments on your machine and provides a more optimal way to use virtualenv.

We can use the pip command to install virtualwrapper since is available in the official Python repository. The only requirement to install it is to have previously installed virtualenv:

$ pip install virtualenvwrapper

To create a virtual environment in Windows, you can use the virtualenv command:

virtualenv venv

When we execute previous command, we see this result:

The execution of the virtualenv command in Windows generates four folders:

In the scripts folder, there is a script called activate.bat to activate the virtual env. Once we have it active, we will have a clean environment of modules and libraries and we will have to download the dependencies of our project so that they are copied in this directory using the following code:

cd venv\Scripts\activate
(venv) > pip install -r requirements.txt

This is the active folder when we can find the active.bat script:

The STB (Security Tools Builder) module

This tool will allow us to create a base project on which we can start to develop our own tool.

The official repository of this tool is https://github.com/abirtone/STB.

For the installation, we can do it by downloading the source code and executing the setup.py file, which will download the dependencies that are in the requirements.txt file.

We can also do it with the pip install stb command.

When executing the stb command, we get the following screen that asks us for information to create our project:

With this command, we have an application skeleton with a setup.py file that we can execute if we want to install the tool as a command in the system. For this, we can execute:

python setup.py install

When we execute the previous command, we obtain the next folder structure:

This has also created a port_scanning_lib folder that contains the files that allow us to execute it:

python port_scanning.py –h

If we execute the script with the help option (-h), we see that there is a series of parameters we can use:

We can see the code that has been generated in the port_scanning.py file:

parser = argparse.ArgumentParser(description='%s security tool' % "port_scanning".capitalize(), epilog = examples, formatter_class = argparse.RawTextHelpFormatter)

# Main options
parser.add_argument("target", metavar="TARGET", nargs="*")
parser.add_argument("-v", "--verbosity", dest="verbose", action="count", help="verbosity level: -v, -vv, -vvv.", default=1)
parsed_args = parser.parse_args()

# Configure global log
log.setLevel(abs(5 - parsed_args.verbose) % 5)

# Set Global Config
config = GlobalParameters(parsed_args)

Here, we can see the parameters that are defined and that a GlobalParameters object is used to pass the parameters that are inside the parsed_args variable. The method to be executed is found in the api.py file.

For example, at this point, we could retrieve the parameters entered from the command line:

# ----------------------------------------------------------------------
#
# API call
#
# ----------------------------------------------------------------------
def run(config):
    """
    :param config: GlobalParameters option instance
    :type config: `GlobalParameters`

    :raises: TypeError
     """
     if not isinstance(config, GlobalParameters):
         raise TypeError("Expected GlobalParameters, got '%s' instead" % type(config))

# --------------------------------------------------------------------------
# INSERT YOUR CODE HERE # TODO
# --------------------------------------------------------------------------
print config
print config.target

We can execute the script from the command line, passing our ip target as a parameter:

python port_scanning.py 127.0.0.1

 

If we execute now, we see how we can obtain the first introduced parameter in the output:

 

The main development environments for script-development


In this section, we will review Pycharm and WingIDE as development environments for python scripting.

Setting up a development environment

In order to rapidly develop and debug Python applications, it is absolutely necessary to use a solid IDE. If you want to try different options, we recommend you check out the list that is on the official site of Python, where they can see the tools according to their operating systems and their needs: https://wiki.python.org/moin/IntegratedDevelopmentEnvironments.

Of all the environments, we will highlight the following:

Pycharm

PyCharm is an IDE developed by the company Jetbrains, and is based on IntelliJ IDEA, the IDE of the same company, but focused on Java and is the base for Android Studio. PyCharm is multi-platform and we can find binaries for Windows, Linux, and macOS X. There are two versions of PyCharm: community and professional, with differences in features related to integration with web frameworks and database support.

In this url we can see a comparison between community and professional edition: http://www.jetbrains.com/pycharm

 

 

The main advantages of this development environment are:

  • Autocomplete, syntax highlighter, analysis tool and refactoring.
  • Integration with web frameworks such as Django, Flask, Pyramid, Web2Py, jQuery, and AngularJS.
  • Advanced debugger.
  • Compatible with SQLAlchemy (ORM), Google App Engine, Cython.
  • Connection with version-control systems: Git, CVS, Mercurial.

WingIDE

WingIDE is a multi-platform environment available for Windows, Mac, and Linux and provides all the functionalities at the level of debugging and variables-exploration.

WingIDE has a rich feature set that will easily support the development of sophisticated Python Applications. With WingIDE, you are able to inspect variables, stack arguments, and memory locations without the process changing any of their values before you can record them. Breakpoints are the most common feature that you will use when debugging a process. Wing Personal is the free version of this Python IDE, which can be found at https://wingware.com/downloads/wingide-personal

WingIDE uses the Python configuration installed in your system:

Debugging with WingIDE

In this example, we are debugging a Python script that accepts two input parameters:

An interesting topic is the possibility of adding a breakpoint in our program with the option Add Breakpoint option, in this way, we can debug and see the contents of the variables just at the point where we have established the breakpoint:

We can set a breakpoint in the call to the view_parameters method.

To execute a script in debug mode with parameters, you have to edit the properties of the script and add the parameters that our script needs within the debug tag:

If we execute in debug mode with a breakpoint inside the function, we can see the content of the parameters in local string variables:

 

In the following screenshot we can visualize the values of the params variable that contains the values we are debugging:

 

 

 

Summary


In this chapter, we learned how to install Python on the Windows and Linux operating systems. We reviewed the main data structures and collections, such as lists, tuples, and dictionaries. We also reviewed functions, managing exceptions, and how to create classes and objects, as well as the use of attributes and special methods. Then we looked at development environments and a methodology to introduce into programming with Python. OMSTD is a methodology and set of best practices in Python for the development of security tools. Finally, we reviewed the main development environments, PyCharm and WingIDE, for script-development in Python.

In the next chapter, we will explore programming system packages for working with operating systems and filesystems, threads, and concurrency.

 

Questions


  1. What are the differences between Python 2.x and 3.x?

  2. What is the programming paradigm used by Python developers and what are the main concepts behind this paradigm?

  3. What data structure in Python allows us to associate values with keys?

  4. What are the main development environments for Python scripting?

  5. What is the methodology we can follow as a set of good practices in Python for the development of security tools?

  6. What is the Python module that helps to create isolated Python environments?

  7. Which tool allows us to create a base project on which we can start to develop our own tool?

  8. How we can debug variables in Python development environments?

  9. How we can add a breakpoint in pycharm?

  10. How we can add a breakpoint in Wing IDE?

 

Further reading


In these links, you will find more information about mentioned tools and official python documentation for search into some of the commented modules:

About the Author

  • José Manuel Ortega

    José Manuel Ortega is a software engineer, focusing on new technologies, open source, security, and testing. His career goal has been to specialize in Python and security testing projects. In recent years, he has developed an interest in security development, especially in pentesting with Python. Currently, he is working as a security tester engineer and his functions in the role involves the analysis and testing of the security of applications in both web and mobile environments. He has taught at university level and collaborated with the official school of computer engineers. He has also been a speaker at various conferences. He is eager to learn about new technologies and loves to share his knowledge with the community.

    Browse publications by this author

Latest Reviews

(4 reviews total)
Because I got the electronic version, it was a simple process. I had immediate access to it. Also, I teach at a university and use other Packt products in my classes. They are affordable for my students, easy to understand at each step. Also, their size fits our quarter format very well.
OK cvccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
It was exactly as advertised.

Recommended For You

Book Title
Unlock this full book FREE 10 day trial
Start Free Trial