// 2 ZERO-DAY · 2 CVE · 4 EXPLOIT NELLE ULTIME 24H

Python Security Toolkit: Sintassi Essenziali e Pattern

Questa pagina presuppone che tu abbia completato i primi passi nella Pagina 1 — variabili, esecuzione di un file .py, e il concetto che Python esegue dall'alto verso il basso. Ora abbiamo bisogno di pattern che utilizzerai effettivamente quando scrivi script per il Lab Wintermute: estrazione di dati da DVWA a 192.0.2.30, parsing dell'output di nmap per 192.0.2.20, gestione degli errori senza che lo script muoia a metà scansione. Tieni questa pagina aperta in un secondo terminale mentre lavori.


Controllo di Flusso Core: Decisioni e Ripetizione

Condizionali — diramazione basata su un test.

# Basic if/elif/else — checking a port state from scan data
port_state = "open" if port_state == "open": print(f"Port is accessible — investigate service")
elif port_state == "filtered": print(f"Firewall or ACL blocking — port may be open behind filter")
else: print(f"Port closed or host unreachable") # Common comparison operators: ==, !=, <, >, <=, >=, 'in' for membership

Perché questo è importante: Una porta marcata come filtered non è un risultato pulito — è una domanda senza risposta. Il tuo script deve gestire tutti e tre gli stati, non solo open.

Cicli — ripetizione del lavoro su target o raccolte di dati.

# for loop — iterate over a known collection
targets = ["192.0.2.20", "192.0.2.30"]
for ip in targets: print(f"Scheduling scan for {ip}") # range() — generate number sequences, useful for port ranges
for port in range(1, 1025): # 1 to 1024 inclusive # scan logic here pass # while loop — repeat while condition holds, with explicit exit
attempt = 0
max_attempts = 3
while attempt < max_attempts: # retry logic here attempt += 1 # increment to avoid infinite loop

enumerate() — ottieni indice e valore insieme, essenziale per output numerati.

services = ["ssh", "http", "ftp"]
for idx, svc in enumerate(services, start=1): print(f"{idx}. {svc}")
# Output: 1. ssh, 2. http, 3. ftp

Archiviazione e Strutturazione dei Dati: Liste e Dizionari

Liste — sequenze ordinate e mutabili. Usale per risultati di scansione ordinati o code di target.

# Creating and modifying
open_ports = [22, 80, 443]
open_ports.append(3306) # add to end
open_ports.insert(0, 21) # insert at position # Accessing by position (zero-indexed)
first_port = open_ports[0] # 21
last_port = open_ports[-1] # 3306 # Slicing — extract subsets
low_ports = open_ports[:3] # first three elements

Dizionari — coppie chiave:valore. Usali per dati strutturati di host: l'IP si associa ai risultati.

# Wintermute scan result storage
host_findings = { "192.0.2.20": { "os": "Linux 2.6", "open_ports": [21, 22, 23, 80], "services": {21: "ftp", 22: "ssh", 23: "telnet", 80: "http"} }, "192.0.2.30": { "os": "Unknown", "open_ports": [80, 443], "services": {80: "http", 443: "https"} }
} # Accessing nested data
metasploitable_services = host_findings["192.0.2.20"]["services"]
print(metasploitable_services[80]) # "http" # Safe access with .get() — returns None instead of crashing if key missing
dvwa_os = host_findings.get("192.0.2.30", {}).get("os")

In termini semplici: le liste sono per "ecco una sequenza di cose," i dizionari sono per "ecco cosa so su questa cosa specifica."


I/O su File: Lettura e Scrittura di Dati degli Script

# Reading a file of target IPs — one per line
with open("wintermute_targets.txt", "r") as f: targets = f.read().splitlines() # removes trailing newlines # Writing structured output — append mode preserves previous runs
with open("scan_results.txt", "a") as f: f.write(f"192.0.2.20: ports {open_ports}\n") # CSV-style parsing for tool output
line = "192.0.2.20,80,open,Apache httpd 2.2.8"
parts = line.split(",") # ['192.0.2.20', '80', 'open', 'Apache httpd 2.2.8']
ip, port, state, banner = parts # unpack into variables

Gestione delle Stringhe: Parsing e Codifica di Dati di Sicurezza

Formattazione — tre approcci, le f-string sono preferite per leggibilità.

target = "192.0.2.20"
port = 80 # f-string (Python 3.6+) — most readable for security scripts
url = f"http://{target}:{port}/dvwa/login.php" # .format() — older, still seen in inherited code
url = "http://{}:{}/dvwa/login.php".format(target, port) # % formatting — legacy, avoid in new code
url = "http://%s:%s/dvwa/login.php" % (target, port)

Codifica e Decodifica — i dati di rete arrivano come byte; hai bisogno di testo.

import base64 # Bytes to text — specify encoding explicitly
raw_bytes = b"user:pass"
text = raw_bytes.decode("utf-8") # "user:pass"
back_to_bytes = text.encode("utf-8") # b"user:pass" # Base64 — common in HTTP Basic Auth headers
credentials = "admin:password"
encoded = base64.b64encode(credentials.encode("utf-8"))
# Result: b'YWRtaW46cGFzc3dvcmQ=' decoded = base64.b64decode(encoded).decode("utf-8")
# Back to: "admin:password"

⚠️ Solo uso autorizzato e difensivo. La codifica trasforma i dati; non li protegge. Base64 non è crittografia — chiunque può invertirla. La vedrai negli header HTTP durante l'analisi legittima del traffico nel Lab Wintermute.


Gestione degli Errori: Mantenere gli Script in Vita Durante l'Impegno

Uno script che si blocca sul terzo host di cinquanta spreca il tuo tempo di lab e lascia lacune nella documentazione.

import requests # Basic try/except — catch specific exceptions, not all
try: r = requests.get("http://192.0.2.30/dvwa/", timeout=5) print(r.status_code)
except requests.exceptions.ConnectionError: print("Host unreachable — check VM network or snapshot state")
except requests.exceptions.Timeout: print("Request timed out — target may be overloaded or filtered")
except requests.exceptions.RequestException as e: print(f"Unexpected error: {e}") # finally block — runs regardless, useful for cleanup
finally: print("Scan attempt logged for report")

Pattern comune: avvolgi l'intero corpo del ciclo per-target in try/except, così un target problematico non uccide l'intero batch.


Esecuzione di Strumenti Esterni: subprocess

Il modulo subprocess (libreria standard da Python 2.4, nessuna installazione necessaria) chiama strumenti di sistema e cattura l'output. Sostituisce funzioni più vecchie e meno sicure come os.system().

import subprocess # SAFE pattern: list of arguments, shell=False (default)
# Runs nmap against Metasploitable2; returns bytes
result = subprocess.check_output( ["nmap", "-sV", "-p", "22,80", "192.0.2.20"], stderr=subprocess.DEVNULL, # suppress error noise timeout=60 # don't hang indefinitely
) # Decode bytes to string for parsing
output_text = result.decode("utf-8")
print(output_text) # If command fails, CalledProcessError is raised with .returncode and .output

Perché questo è importante: shell=True ti permette di scrivere nmap -sV 192.0.2.20 come stringa singola, ma permette anche ai metacaratteri della shell nelle variabili di eseguire comandi arbitrari. Nel Lab Wintermute il rischio è basso; in produzione con input utente, è catastrofico. Costruisci l'abitudine della lista di argomenti ora.

Parametro Scopo Default Sicuro
shell=False Esecuzione diretta tramite OS, non interprete shell ✓ Mantieni False
stderr Dove inviare lo stream di errore; DEVNULL scarta, STDOUT unisce Varia in base al bisogno
timeout Secondi prima di interrompere un comando bloccato Imposta sempre
universal_newlines / text=True Restituisce stringa invece di byte; text=True è Python 3.7+ Verifica la tua versione di Python

Richieste HTTP con la Libreria requests

Non nella libreria standard — installa una volta per ambiente:

python -m pip install requests
import requests # GET request to DVWA — basic call
r = requests.get("http://192.0.2.30/dvwa/login.php", timeout=10) # Response inspection
print(r.status_code) # HTTP result: 200, 404, 500, etc.
print(r.headers.get("Server")) # Web server banner, if disclosed # Text vs. binary content
print(r.text[:200]) # Decoded string using r.encoding
print(r.content[:50]) # Raw bytes — check before decoding # Encoding control — force if detection fails
r.encoding = "utf-8" # or "ISO-8859-1" for legacy apps
print(r.text) # JSON parsing — DVWA API endpoints, or tool output
# r.json() raises exception if response isn't valid JSON
try: data = r.json()
except ValueError: data = None # Not JSON, handle accordingly

Riferimento Rapido: Built-in e Conversioni di Tipo

Funzione Tipico Uso di Sicurezza
len(collection) Conta porte aperte, anomalie nella lunghezza delle risposte
range(start, stop) Itera numeri di porta, genera sequenze di test
enumerate(iterable, start=1) Output numerato per report
int(string) Converte la stringa porta "80" in intero 80
str(number) Converte intero porta in stringa per concatenazione
bytes(string, encoding) Prepara dati per trasmissione di rete
help(object) Ispeziona modulo o funzione in Python interattivo
# help() in practice — when you forget a method
help(requests.get) # shows signature and docstring
help(subprocess.check_output) # verify parameters before running

Metterlo Tutto Insieme: Scheletro Minimale di Script di Recon per Wintermute

#!/usr/bin/env python3
import subprocess
import sys TARGET = "192.0.2.20"
PORTS = [21, 22, 23, 25, 80, 443] def scan_port(target, port): """Run minimal TCP probe, return parsed result or None.""" try: # -Pn: skip host discovery (we know it's up in lab) # -p: single port cmd = ["nmap", "-Pn", "-p", str(port), "--open", target] result = subprocess.check_output(cmd, timeout=30) return result.decode("utf-8") except subprocess.CalledProcessError: return None # port closed or filtered except subprocess.TimeoutExpired: return "TIMEOUT" # Main loop with structured storage
findings = {}
for port in PORTS: output = scan_port(TARGET, port) findings[port] = output print(f"Port {port}: {'OPEN' if output else 'closed/filtered'}") # findings dictionary now holds everything for your report

Riferimento Incrociato alle Prossime Pagine

  • Pagina 5 (Ricognizione): Espande il wrapper nmap sopra in scoperta completa degli host.
  • Pagina 6 (Applicazioni Web): Approfondisce l'uso di requests per interazione con form DVWA e gestione sessioni.
  • Pagina 9 (Malware): I pattern di codifica qui si applicano all'analisi di payload — in modo sicuro, senza esecuzione.

Nota di Samuel dalla panchina: Tengo un wintermute_utils.py in ogni cartella di sessione di lab con il pattern scan_port() sopra, modificato per esercizio. Riutilizzare il proprio codice testato batte riscrivere da zero — ma solo se capisci cosa fa. Copy-paste senza comprensione produce script che falliscono silenziosamente alle 2 del mattino quando il tuo rollback di snapshot non funziona.

Letture consigliate