Skip to content

Python

Python Logo

Table of Contents

Part 1: Python Fundamentals

1. Setting Up Your Environment

Good news: most Linux and macOS systems already have Python installed. Just type python3 --version to check. On Windows? Download it from python.org and make sure you check the "Add Python to PATH" box during setup. Otherwise, you'll hate yourself later.

pip comes with Python now, so you don't need to install it separately. Handy, right?

2. Running Python Code

You've got two main ways to run Python:

  1. Interactive Interpreter: Type python3 in your terminal and hit enter. It opens a REPL (Read-Eval-Print Loop) where you can experiment. Try things out, see what happens.

    >>> print("Hello, World!")
    Hello, World!
    >>> 2 + 2
    4
    

  2. Script Files: Save your code in a .py file and run it. Simple.

    python3 my_script.py
    

3. Variables and Data Types

Python figures out types for you. You don't need to tell it what a variable is. It's dynamically typed, which means Python decides the type when your code runs.

Here's what you'll use:

  • str: Text strings. Use single quotes 'like this' or double quotes "or this". Python doesn't care.
  • int: Whole numbers. No decimals allowed.
  • float: Numbers with decimals. Like 3.14 or 2.5.
  • bool: True or False. Capitalize them. Python's picky about that.
  • None: Nothing. Zip. Zero. Similar to null in other languages.
name = "0x1RIS"      # str
port = 443           # int
version = 1.1        # float
is_active = True     # bool
notes = None         # NoneType

4. Core Data Structures

You'll use these four data structures constantly. Here's the quick breakdown:

  • list: Ordered stuff you can change. Think shopping list. You can add or remove items. [item1, item2]
  • tuple: Ordered stuff you can't change. Once it's made, it's locked. (item1, item2)
  • dict: Key value pairs, like a phone book. Look up a name (key) and get a number (value). {key1: value1, key2: value2}
  • set: Unique items only. Duplicates get tossed automatically. {item1, item2}
# List
ports = [22, 80, 443]
ports.append(8080)
print(ports[1]) # 80

# Dictionary
headers = {"User-Agent": "MyScanner/1.0", "Accept": "application/json"}
print(headers["User-Agent"])

# Set
unique_ports = {80, 443, 80, 80}
print(unique_ports) # {80, 443}

5. Operators

Same math you learned in school, plus a few extras:

  • Arithmetic: +, -, *, / (regular division), // (integer division, throws away decimals), % (modulus, gives you the remainder), ** (exponentiation, 2**3 is 8)
  • Comparison: == (equals), != (not equals), >, <, >=, <=
  • Logical: and, or, not. Use these to chain conditions together

6. Control Flow

Python uses indentation to show code blocks. No curly braces here. Use 4 spaces (or tabs, but spaces are preferred). Get the indentation wrong and Python will complain.

port = 443
if port == 443:
    print("HTTPS")
elif port == 80:
    print("HTTP")
else:
    print("Other")

# For loop
for p in [22, 80, 443]:
    print(f"Checking port {p}")

# While loop
count = 0
while count < 3:
    print(count)
    count += 1

7. Functions

You define functions with def. That's it. Simple.

def greet(name):
    """This is a docstring, explaining what the function does."""
    return f"Hello, {name}!"

message = greet("World")
print(message)

Part 2: Intermediate Python

8. String Formatting

F strings showed up in Python 3.6 and changed everything. They're way more readable than the old ways. Use them.

user = "alice"
role = "admin"

# Old ways
print("User: %s, Role: %s" % (user, role))
print("User: {}, Role: {}".format(user, role))

# Modern way (f-string)
print(f"User: {user}, Role: {role}")

9. List Comprehensions

These let you build lists in one line instead of writing a whole loop. They look weird at first, but you'll love them once you get the hang of it.

# Traditional for loop
squares = []
for i in range(5):
    squares.append(i * i)

# List comprehension
squares_comp = [i * i for i in range(5)]

print(squares == squares_comp) # True

10. Working with Files

Always use with open(...) when handling files. It closes them automatically, even if something goes wrong. No more forgetting to close files and leaking resources.

# Writing to a file
lines_to_write = ["line 1", "line 2"]
with open("my_file.txt", "w") as f:
    for line in lines_to_write:
        f.write(line + "\n")

# Reading from a file
try:
    with open("my_file.txt", "r") as f:
        content = f.read()
        print(content)
except FileNotFoundError:
    print("The file does not exist.")

11. Exception Handling

Things break. Your code will fail. Handle errors gracefully so your program doesn't crash and burn. That's what try/except is for.

try:
    result = 10 / 0
except ZeroDivisionError as e:
    print(f"Error: Cannot divide by zero. ({e})")
finally:
    print("This block always executes.")

12. Introduction to Classes

Python does object oriented programming. Classes are like blueprints. You create them once, then make objects from them whenever you need.

class Target:
    # The constructor method
    def __init__(self, ip_address, port):
        self.ip_address = ip_address
        self.port = port
        self.is_vulnerable = False

    # An instance method
    def display(self):
        return f"{self.ip_address}:{self.port} (Vulnerable: {self.is_vulnerable})"

# Create an instance of the class
target1 = Target("192.168.1.100", 443)
target1.is_vulnerable = True
print(target1.display())

Part 3: The Python Ecosystem

13. Virtual Environments

Use a virtual environment for every single project. I mean it. It creates an isolated space so your project's packages don't mess with other projects or your system Python. You'll thank yourself later.

# 1. Create a virtual environment in a folder named 'venv'
python3 -m venv venv

# 2. Activate it
# On Linux/macOS:
source venv/bin/activate

# On Windows-(PowerShell):
# .\venv\Scripts\Activate.ps1

# Your shell prompt will now change to show-`(venv)`.

# 3. Deactivate when you're done
deactivate

14. Package Management

pip installs packages from PyPI (Python Package Index). It's your best friend when you need a library.

# (With your virtual environment-activated)

# Install a package
pip install requests

# Install a specific version
pip install requests==2.25.1

# List installed packages
pip list

# Save your project's dependencies to a file
pip freeze > requirements.txt

# Install all dependencies from a requirements file
pip install -r requirements.txt

Part 4: Python for Security Professionals

This is where Python really shines. Let's dive into the stuff you'll actually use for security work.

15. Making HTTP Requests

The requests library is the best way to make HTTP requests in Python. Everyone uses it. It's not built in, so run pip install requests first.

import requests

try:
    # Simple GET request
    response = requests.get("https://example.com", timeout=5)
    response.raise_for_status() # Raise an exception for bad status codes (4xx or-5xx)

    print(f"Status Code: {response.status_code}")
    #-print(response.text) # HTML content

    # GET request with headers and URL parameters
    headers = {"User-Agent": "MyScanner/1.0"}
    params = {"id": "123"}
    response = requests.get("https://httpbin.org/get", headers=headers, params=params)

    # POST request with form data
    payload = {"username": "admin", "password": "password123"}
    response = requests.post("https://httpbin.org/post", data=payload)
    print(response.json()) # `requests` has a built in JSON decoder

except requests.exceptions.RequestException as e:
    print(f"An error occurred: {e}")

16. Web Scraping

Want to parse HTML? Pair requests with BeautifulSoup. Install it with pip install beautifulsoup4 and you're good to go.

import requests
from bs4 import BeautifulSoup

url = "https://example.com"
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')

# Find the page title
print(f"Page Title: {soup.title.string}")

# Find all links on the page
for link in soup.find_all('a'):
    href = link.get('href')
    if href:
        print(href)

17. Low Level Networking

Need to grab banners, build TCP clients, or craft reverse shells? The built in socket module has you covered.

import socket

def grab_banner(ip, port):
    try:
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.settimeout(2)
            s.connect((ip, port))
            banner = s.recv(1024)
            return banner.decode().strip()
    except (socket.timeout, ConnectionRefusedError) as e:
        return f"Error: {e}"

ssh_banner = grab_banner("127.0.0.1", 22)
print(f"SSH Banner: {ssh_banner}")

18. Running System Commands

Need to run nmap or other system commands? Use subprocess. It's way safer than the old os.system() method.

import subprocess

def run_nmap(target):
    print(f"--- Running nmap against {target} ---")
    command = ["nmap", "-sV", "-T4", target]
    try:
        # `check=True` will raise an exception if the command returns a non zero exit code
        result = subprocess.run(command, capture_output=True, text=True, check=True, timeout=300)
        print(result.stdout)
    except FileNotFoundError:
        print("Error: nmap is not installed or not in your PATH.")
    except subprocess.CalledProcessError as e:
        print(f"nmap failed with exit code {e.returncode}")
        print(f"STDERR: {e.stderr}")
    except subprocess.TimeoutExpired:
        print("nmap scan timed out.")

run_nmap("scanme.nmap.org")

19. Parsing Data with Regular Expressions

The re module finds patterns in text. Essential for parsing logs, extracting data, or anything involving pattern matching.

import re

log_line = '[2025-10-26 10:00:00] INFO: User 'admin' logged in from 192.168.1.101'

# Find an IP address in the line
match = re.search(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})', log_line)
if match:
    ip_address = match.group(1)
    print(f"Found IP: {ip_address}")

Part 5: Writing Secure Python Code

20. Deserialization Dangers

The pickle module serializes Python objects. Sounds useful, right? Wrong. It's not secure at all. Unpickle data from an untrusted source and you're asking for arbitrary code execution.

Never unpickle data you don't trust. Ever. Use JSON or another safe format instead.

import pickle
import os

# Attacker creates a malicious pickle payload
class RCE:
    def __reduce__(self):
        # This command will run when the pickle is loaded
        return (os.system, ('echo "pwned!" > pwned.txt',))

malicious_payload = pickle.dumps(RCE())

# --- On the victim server ---
# This is the vulnerable code
#-pickle.loads(malicious_payload)
# A file named `pwned.txt` would be created.

21. Preventing Command Injection

The golden rule: never pass commands to a shell as a single string. Always use a list. This keeps attackers from injecting commands.

Don't do this (it's vulnerable):

import os
user_input = "example.com; ls -la"
os.system(f"ping -c 1 {user_input}") # The `ls -la` command will also execute!

Do this instead (secure):

import subprocess
user_input = "example.com; ls -la"
# The shell is not used. The entire user_input is treated as a single, safe argument.
subprocess.run(["ping", "-c", "1", user_input])

22. Web Application Security

Use proper frameworks like Flask or Django when building web apps. They come with built in protections.

  • Cross Site Scripting (XSS): Template engines like Jinja2 (Flask) and Django Templates escape variables automatically. XSS attacks won't work.
  • SQL Injection: ORMs like SQLAlchemy or Django ORM use parameterized queries. SQL injection? Not happening.

23. Managing Secrets

Don't hardcode secrets. No API keys, passwords, or tokens in your source code. Seriously.

  • Good: Use environment variables.
    import os
    api_key = os.getenv("MY_API_KEY")
    
  • Better: Use a .env file locally and a proper secrets management service (HashiCorp Vault, AWS Secrets Manager) in production.

Part 6: Cookbook

24. Multithreaded TCP Port Scanner

This scanner uses threads and a queue to check ports way faster than a simple loop. Try it out.

import socket
import threading
from queue import Queue

def port_scan(port, target):
    try:
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.settimeout(0.5)
            s.connect((target, port))
            print(f"[+] Port {port} is open")
    except (socket.timeout, ConnectionRefusedError):
        pass

def worker(target, q):
    while not q.empty():
        port = q.get()
        port_scan(port, target)
        q.task_done()

def main():
    target = "127.0.0.1"
    q = Queue()

    for port in range(1, 1025):
        q.put(port)

    for _ in range(50): # Number of threads
        thread = threading.Thread(target=worker, args=(target, q), daemon=True)
        thread.start()

    q.join() # Wait for the queue to be empty
    print("Scan complete.")

if __name__ == "__main__":
    main()

25. Subdomain Enumerator

Feed this script a domain and a wordlist. It uses requests to check which subdomains exist.

import requests
import sys

def check_subdomain(domain, subdomain):
    url = f"http://{subdomain}.{domain}"
    try:
        requests.get(url, timeout=2)
    except requests.ConnectionError:
        pass
    else:
        print(f"[+] Found subdomain: {url}")

def main():
    if len(sys.argv) != 3:
        print("Usage: python3 subdomain_enum.py <domain> <wordlist>")
        sys.exit(1)

    domain = sys.argv[1]
    wordlist_path = sys.argv[2]

    try:
        with open(wordlist_path, "r") as f:
            for line in f:
                subdomain = line.strip()
                if subdomain:
                    check_subdomain(domain, subdomain)
    except FileNotFoundError:
        print(f"Error: Wordlist not found at {wordlist_path}")

if __name__ == "__main__":
    main()

26. Web Crawler

Give it a starting URL and it crawls recursively, finding all unique links on that domain. Useful for reconnaissance.

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin, urlparse

internal_links = set()

def crawl(url, base_domain):
    if url in internal_links:
        return

    print(f"Crawling: {url}")
    internal_links.add(url)

    try:
        response = requests.get(url, timeout=3)
        soup = BeautifulSoup(response.text, 'html.parser')

        for link in soup.find_all('a', href=True):
            href = link['href']
            full_url = urljoin(url, href)
            parsed_url = urlparse(full_url)

            if parsed_url.netloc == base_domain:
                crawl(full_url, base_domain)
    except requests.RequestException as e:
        print(f"Could not fetch {url}: {e}")

def main():
    start_url = "http://example.com"
    base_domain = urlparse(start_url).netloc
    crawl(start_url, base_domain)
    print("\n--- Found Internal Links ---")
    for link in sorted(internal_links):
        print(link)

if __name__ == "__main__":
    main()

27. Basic Flask API

Want to turn your script into a web API? Flask makes it easy. Install it with pip install Flask and follow along.

from flask import Flask, request, jsonify
import subprocess

app = Flask(__name__)

@app.route('/', methods=['GET'])
def index():
    return jsonify({"message": "Welcome to the Nmap API. Use /scan?host=<ip>"})

@app.route('/scan', methods=['GET'])
def scan():
    host = request.args.get('host')
    if not host:
        return jsonify({"error": "'host' parameter is required"}), 400

    # Basic input validation to prevent obvious command injection attempts
    # A real application would need much more robust validation.
    if ';' in host or '&' in host or '|' in host:
        return jsonify({"error": "Invalid characters in host parameter"}), 400

    command = ["nmap", "-F", host]
    try:
        result = subprocess.run(command, capture_output=True, text=True, check=True, timeout=120)
        return jsonify({"host": host, "output": result.stdout})
    except FileNotFoundError:
        return jsonify({"error": "nmap command not found on server"}), 500
    except subprocess.CalledProcessError as e:
        return jsonify({"error": "Scan failed", "details": e.stderr}), 500
    except subprocess.TimeoutExpired:
        return jsonify({"error": "Scan timed out"}), 500

if __name__ == '__main__':
    # Debug mode should be False in production!
    app.run(host='0.0.0.0', port=5000, debug=False)