Python dla pentesterów — od skryptu do narzędzia

15 września 2025 22 minuty czytania Autor: Kamil
Początkujący Python Automation Asyncio Reporting

Dlaczego Python jest tak użyteczny

Python dobrze sprawdza się wszędzie tam, gdzie trzeba szybko zautomatyzować powtarzalne działania, zebrać dane z kilku źródeł albo przygotować wynik w czytelnej formie. W praktyce oznacza to mniej ręcznego klejenia workflow i więcej czasu na analizę.

Największe zalety w pracy technicznej:

  • szybkie prototypowanie skryptów,
  • duży ekosystem bibliotek,
  • łatwe parsowanie danych i formatów raportowych,
  • naturalna droga od małego skryptu do własnego narzędzia.

Przygotowanie środowiska

Warto od początku pracować w wirtualnym środowisku i trzymać zależności w jednym miejscu.

sudo apt update sudo apt install -y python3 python3-pip python3-venv python3 -m venv pentest-env source pentest-env/bin/activate pip install --upgrade pip wheel setuptools
pip install requests urllib3 python-nmap scapy beautifulsoup4 lxml pip install jinja2 rich colorama tqdm dnspython python-docx reportlab
requests>=2.31 urllib3>=2.0 python-nmap>=0.7.1 scapy>=2.5.0 beautifulsoup4>=4.12 lxml>=4.9 jinja2>=3.1 rich>=13.0 colorama>=0.4.6 tqdm>=4.66 dnspython>=2.4 python-docx>=1.1 reportlab>=4.0

Przydatne idiomy

CLI i logowanie

import argparse, logging def setup_logger(level=logging.INFO): logging.basicConfig( level=level, format="%(asctime)s | %(levelname)s | %(message)s", datefmt="%H:%M:%S" ) return logging.getLogger("pentest") def get_args(): p = argparse.ArgumentParser() p.add_argument("target") p.add_argument("-v", "--verbose", action="store_true") return p.parse_args()

Requests Session z retry

import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry def http_session(proxy=None): s = requests.Session() retry = Retry(total=3, backoff_factor=0.8, status_forcelist=[429, 500, 502, 503, 504]) s.mount("http://", HTTPAdapter(max_retries=retry)) s.mount("https://", HTTPAdapter(max_retries=retry)) if proxy: s.proxies.update({"http": proxy, "https": proxy}) s.verify = False s.headers.update({"User-Agent": "PentestBot/1.0"}) return s

Równoległość

from concurrent.futures import ThreadPoolExecutor import asyncio def work(item): return item with ThreadPoolExecutor(max_workers=50) as ex: results = list(ex.map(work, range(100))) async def do_io(i): await asyncio.sleep(0.01) return i

Mini-labsy

Fingerprinting HTTP

import requests from urllib.parse import urlparse def http_fingerprint(url, proxy=None): s = requests.Session() if proxy: s.proxies.update({"http": proxy, "https": proxy}) s.verify = False r = s.get(url, timeout=8) return { "status": r.status_code, "server": r.headers.get("Server"), "x_powered_by": r.headers.get("X-Powered-By"), "url": urlparse(url).geturl() }

Asynchroniczny skaner portów

import asyncio async def check_port(host, port, timeout=1.0): try: reader, writer = await asyncio.wait_for(asyncio.open_connection(host, port), timeout=timeout) writer.close() await writer.wait_closed() return port except Exception: return None

Agregator Nmap XML do JSON

import xml.etree.ElementTree as ET import json def parse_nmap_xml(file_path): root = ET.parse(file_path).getroot() hosts = [] for host in root.findall("host"): state = host.find("status").get("state") addrs = [a.get("addr") for a in host.findall("address")] hosts.append({"state": state, "addresses": addrs}) return hosts

Raport HTML z Jinja2

from jinja2 import Template HTML = """

Raport skanowania

Hosty aktywne: {{ summary.hosts_up }}/{{ summary.total_hosts }}

"""

Najlepsze podejście: potraktuj te fragmenty jak klocki. Z czasem złożysz z nich własne CLI z modułami, konfiguracją i wspólnym formatem wyników.

Jak to spiąć w workflow

  • recon i DNS do jednego formatu JSON,
  • skan top portów jako filtr przed pełnym Nmap,
  • parsowanie XML i JSON do wspólnego modelu danych,
  • raport HTML albo PDF generowany automatycznie na końcu,
  • osobne katalogi na raw, parsed i summary.

Bezpieczeństwo kodu i etyka

Automatyzacja nie zwalnia z odpowiedzialności. Korzystaj z takich skryptów wyłącznie w ramach uzgodnionego zakresu i nie wyłączaj bezpieczeństwa TLS poza środowiskiem laboratoryjnym.

  • ustawiaj timeouty i limity concurrency,
  • czyść logi z danych wrażliwych,
  • trzymaj konfigurację i sekrety poza kodem,
  • zapisuj wyniki tak, by dało się je później audytować.

Krótki cheatsheet

sess = http_session(proxy="http://127.0.0.1:8080") resp = sess.get("https://target.local/login", timeout=10) print(resp.status_code, resp.headers.get("Server"))
from pathlib import Path import json data = {"hosts": ["10.0.0.1"], "meta": {"scope": "demo"}} Path("out/results.json").parent.mkdir(parents=True, exist_ok=True) Path("out/results.json").write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")

Co dalej

Jeśli chcesz wejść poziom wyżej, zbuduj jedno własne narzędzie z komendami typu recon, http, scan i report. Taki projekt daje dużo więcej niż zbiór pojedynczych skryptów.

Powiązane materiały: Podstawy testów penetracyjnych oraz Qualys VMDR.