Book Image

Python for Security and Networking - Third Edition

By : José Ortega
4 (3)
Book Image

Python for Security and Networking - Third Edition

4 (3)
By: José Ortega

Overview of this book

Python’s latest updates add numerous libraries that can be used to perform critical security-related missions, including detecting vulnerabilities in web applications, taking care of attacks, and helping to build secure and robust networks that are resilient to them. This fully updated third edition will show you how to make the most of them and improve your security posture. The first part of this book will walk you through Python scripts and libraries that you’ll use throughout the book. Next, you’ll dive deep into the core networking tasks where you will learn how to check a network’s vulnerability using Python security scripting and understand how to check for vulnerabilities in your network – including tasks related to packet sniffing. You’ll also learn how to achieve endpoint protection by leveraging Python packages along with writing forensics scripts. The next part of the book will show you a variety of modern techniques, libraries, and frameworks from the Python ecosystem that will help you extract data from servers and analyze the security in web applications. You’ll take your first steps in extracting data from a domain using OSINT tools and using Python tools to perform forensics tasks. By the end of this book, you will be able to make the most of Python to test the security of your network and applications.
Table of Contents (23 chapters)
1
Section 1: Python Environment and System Programming Tools
4
Section 2: Network Scripting and Packet Sniffing with Python
8
Section 3: Server Scripting and Port Scanning with Python
12
Section 4: Server Vulnerabilities and Security in Web Applications
16
Section 5: Python Forensics
20
Assessments – Answers to the End-of-Chapter Questions
21
Other Books You May Enjoy
22
Index

Working with functions, classes, and objects in Python

In this section, we will review Python functions, classes, and objects in Python scripts. We will review some examples for declaring and using in our script code.

Python functions

A function is a block of code that performs a specific task when the function is invoked. You can use functions to make your code reusable, better organized, and more readable. Functions can have parameters and return values. There are at least four basic types of functions in Python:

  • Built-in functions: These are an integral part of Python. You can see a complete list of Python’s built-in functions at https://docs.python.org/3/library/functions.html.
  • Functions that come from pre-installed modules.
  • User-defined functions: These are written by developers in their own code, and they use them freely in Python.
  • The lambda function: This allows us to create anonymous functions that are built using expressions such as product = lambda x,y : x * y, where lambda is a Python keyword and x and y are the function parameters.

In Python, functions include reusable code-ordered blocks. This allows a developer to write a block of code to perform a single action. Although Python offers several built-in features, a developer may build user-defined functionality.

Python functions are defined using the def keyword with the function name, followed by the function parameters. The function’s body is composed of Python statements to be executed. You have the option to return a value to the function caller at the end of the function, or if you do not assign a return value, it will return the None value by default.

For instance, we can define a function that returns True if the item value is found in the dictionary and False otherwise. You can find the following code in the my_function.py file:

def contains(dictionary,item):
    for key,value in dictionary.items():
        if value == item:
            return True
    return False 
dictionary = {1:100,2:200,3:300}
print(contains(dictionary,200))
print(contains(dictionary,300))
print(contains(dictionary,350))

Two important factors make parameters special:

  • Parameters only exist within the functions in which they were described, and the only place where the parameter can be specified is in the space between a pair of parentheses in the def state.
  • Assigning a value to the parameter is done at the time of the function’s invocation by specifying the corresponding argument.

Python classes

Python is an object-oriented language that allows you to create classes from descriptions and instantiate them. The functions specified inside the class are instance methods, also known as member functions.

Python’s way of constructing objects is via the class keyword. A Python object is an assembly of methods, variables, and properties. Lots of objects can be generated with the same class description. 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 acts as a constructor method to perform the necessary initialization operation. The method’s first parameter is a special keyword, and we use the self-identifier for the current object reference. The self keyword is a reference to the object itself and provides a way for its attributes and methods to access it.

The constructor method must provide the self parameter and may have more parameters than just self; if this happens, the way in which the class name is used to create the object must reflect the __init__ definition. This method is used to set up the object, in other words, to properly initialize its internal state. This parameter is equivalent to the pointer that can be found in languages such as C ++ or Java.

An object is a set of requirements and qualities assigned to a specific class. Classes form a hierarchy, which means that an object belonging to a specific class belongs to all the superclasses at the same time.

To build an object, write the class name followed by any parameter needed in parentheses. These are the parameters that will be transferred to the init method, which is the process that is called when the class is instantiated:

>>> https_protocol= Protocol("HTTPS", 443, "Hypertext Transfer Protocol Secure")

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

>>> protocol_http.getProtocolInfo()
HTTPS 443 Hypertext Transfer Protocol Secure

In summary, object programming is the art of defining and expanding classes. A class is a model of a very specific part of reality, reflecting properties and methods found in the real world. The new class may add new properties and new methods, and therefore may be more useful in specific applications.

Python inheritance

In the previous code, we can see a method with the name __init__, which represents the class constructor. If a class has a constructor, it is invoked automatically and implicitly when the object of the class is instantiated. This method allows us to initialize the internal state of an object when we create an object of a class.

Python inheritance is an important concept in object-oriented programming languages. This feature means creating a new class that inherits all the functionality of the parent class and allows the new class to add additional functionality to the base functionality.

In object-oriented terminology, when class “X” is inherited by class “Y”, “X” is called a Super Class or Base Class and “Y” is called a Subclass or Derived Class. One more fact to keep in mind is that only the fields and methods that are not private are accessible by the Derived Class. Private fields and methods are only accessible by the class itself.

Single inheritance occurs when a child class inherits the attributes and methods of a single parent class. The following is an example of simple inheritance in Python where we have a base class and a child class that inherits from the parent class. Note the presence of the __init__ method in both classes , which allows you to initialize the properties of the class as an object constructor.

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

class BaseClass:
    def __init__(self, property):
        self.property = property
    def message(self):
        print('Welcome to Base Class')
    def message_base_class(self):
        print('This is a message from Base Class')
 
class ChildClass(BaseClass):
    def __init__(self, property):
        BaseClass.__init__(self, property)
    def message(self):
        print('Welcome to ChildClass')
        print('This is inherited from BaseClass')

In our main program we declare two objects, one of each class, and we call the methods defined in each of the classes. Also, taking advantage of the inheritance features, we call the method of the parent class using an object of the child class.

if __name__ == '__main__':
    base_obj = BaseClass('property')
    base_obj.message()
    child_obj = ChildClass('property')
    child_obj.message()
    child_obj.message_base_class()

Two built-in functions, isinstance() and issubclass(), are used to check inheritances. One of the methods that we can use to check if a class is a subclass of another is through the issubclass() method. This method allows us to check if a subclass is a child of a superclass and returns the Boolean True or False depending on the result.

>>> print(issubclass(ChildClass, BaseClass))
>>> True
>>> print(issubclass(BaseClass, ChildClass))
>>> False

In the same way, the isinstance() method allows you to check if an object is an instance of a class. This method returns True if the object is the instance of the class that is passed as the second parameter. The syntax of this special method is isinstance(Object,Class).

>>> print(isinstance(base_obj, BaseClass))
>>> True
>>> print(isinstance(child_obj, ChildClass))
>>> True
>>> print(isinstance(child_obj, BaseClass))
>>> True

Multiple inheritance occurs when a child class inherits attributes and methods from more than one parent class. We could separate both main classes with a comma when creating the secondary class. In the following example we are implementing multiple inheritance where the child class is inheriting from the MainClass and MainClass2 classes.

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

class MainClass:
    def message_main(self):
        print('Welcome to Main Class')
class MainClass2:
    def message_main2(self):
        print('Welcome to Main Class2')
class ChildClass(MainClass,MainClass2):
    def message(self):
        print('Welcome to ChildClass')
        print('This is inherited from MainClass and MainClass2')

Our main program creates an object of the Child class, on which we could access both methods of the parent classes.

if __name__ == '__main__':
    child_obj = ChildClass()
    child_obj.message()
    child_obj.message_main()
    child_obj.message_main2()

Python also supports multilevel inheritance, which allows the child class to have inheritance below it. That means the base class is the parent class of all sub-classes and inheritance goes from parent to child. In this way, child classes can access properties and methods from parent classes, but parent classes cannot access the properties of the child class.

In the following example we are implementing multilevel inheritance where the child class is inheriting from the MainClass and we add another level of inheritance with the ChildDerived class, which is inheriting from the Child class. You can find the following code in the Inheritance_multilevel.py file.

class MainClass:
    def message_main(self):
        print('Welcome to Main Class')
class Child(MainClass):
    def message_child(self):
        print('Welcome to Child Class')
        print('This is inherited from Main')
class ChildDerived(Child):
    def message_derived(self):
        print('Welcome to Derived Class')
        print('This is inherited from Child')

In the previous code we first create a main class and then create a child class that is inherited from Main and create another class derived from the child class. We see how the child_derived_obj object is an instance of each of the classes that are part of the hierarchy. In multilevel inheritance, the features of the base class and the derived class are inherited into the new derived class. In our main program we declare a child-derived object and we call the methods defined in each of the classes.

if __name__ == '__main__':
    child_derived_obj = ChildDerived()
    child_derived_obj.message_main()
    child_derived_obj.message_child()
    child_derived_obj.message_derived()
    print(issubclass(ChildDerived, Child))
    print(issubclass(ChildDerived, MainClass))
    print(issubclass(Child, MainClass))
    print(issubclass(MainClass, ChildDerived))
    print(isinstance(child_derived_obj, Child))
    print(isinstance(child_derived_obj, MainClass))
    print(isinstance(child_derived_obj, ChildDerived))

When executing the previous script, we see how from the ChildDerived class we can call the methods from the Child and Main classes. Also, with the issubclass() and isinstance() methods we can check whether the child_derived_obj object is a subclass and instance of the higher classes within the management hierarchy.

Advantages of Python inheritance

One of the main advantages is code reuse, allowing us to establish a relationship between classes, avoiding the need to re-declare certain methods or attributes.

Classes allow us to build objects on top of a collection of abstractly defined attributes and methods. And the ability to inherit will allow us to create larger and more capable child classes by inheriting multiple attributes and methods from others as well as more specific controlling the same for a single class.

The following are some benefits of using inheritance in Python’s object-oriented programming:

  • Python inheritance provides code reusability, readability, and scalability.
  • Reduce code repetition. You can define all the methods and attributes in the parent class that are accessible by the child classes.
  • By dividing the code into multiple classes, identifying bugs in applications is easier.