<commit_before>"""

 __   __ _____ _____     _____
 \ \ / // ____/ ____|   / ____|
  \ V /| (___| (___    | (___   ___ __ _ _ __  _ __   ___ _ __
   > <  \___ \\___ \    \___ \ / __/ _` | '_ \| '_ \ / _ \ '__|
  / . \ ____) |___) |   ____) | (_| (_| | | | | | | |  __/ |
 /_/ \_\_____/_____/   |_____/ \___\__,_|_| |_|_| |_|\___|_|


This script automatically scans all visited webpages for XSS and SQLi vulnerabilities.

Usage: mitmproxy -s xss_scanner.py

This script scans for vulnerabilities by injecting a fuzzing payload (see PAYLOAD below) into 4 different places
and examining the HTML to look for XSS and SQLi injection vulnerabilities. The XSS scanning functionality works by
looking to see whether it is possible to inject HTML based off of of where the payload appears in the page and what
characters are escaped. In addition, it also looks for any script tags that load javascript from unclaimed domains.
The SQLi scanning functionality works by using regular expressions to look for errors from a number of different
common databases. Since it is only looking for errors, it will not find blind SQLi vulnerabilities.

The 4 places it injects the payload into are:
1. URLs         (e.g. https://example.com/ -> https://example.com/PAYLOAD/)
2. Queries      (e.g. https://example.com/index.html?a=b -> https://example.com/index.html?a=PAYLOAD)
3. Referers     (e.g. The referer changes from https://example.com to PAYLOAD)
4. User Agents  (e.g. The UA changes from Chrome to PAYLOAD)

Reports from this script show up in the event log (viewable by pressing e) and formatted like:

===== XSS Found ====
XSS URL: http://daviddworken.com/vulnerableUA.php
Injection Point: User Agent
Suggested Exploit: <script>alert(0)</script>
Line: 1029zxcs'd"ao<ac>so[sb]po(pc)se;sl/bsl\eq=3847asd

"""

from html.parser import HTMLParser
from typing import Dict, Union, Tuple, Optional, List, NamedTuple
from socket import gaierror, gethostbyname
from urllib.parse import urlparse
import re

import requests

from mitmproxy import http
from mitmproxy import ctx


# The actual payload is put between a frontWall and a backWall to make it easy
# to locate the payload with regular expressions
FRONT_WALL = b"1029zxc"
BACK_WALL = b"3847asd"
PAYLOAD = b"""s'd"ao<ac>so[sb]po(pc)se;sl/bsl\\eq="""
FULL_PAYLOAD = FRONT_WALL + PAYLOAD + BACK_WALL

# A XSSData is a named tuple with the following fields:
#   - url -> str
#   - injection_point -> str
#   - exploit -> str
#   - line -> str
XSSData = NamedTuple('XSSData', [('url', str),
                                 ('injection_point', str),
                                 ('exploit', str),
                                 ('line', str)])

# A SQLiData is named tuple with the following fields:
#   - url -> str
#   - injection_point -> str
#   - regex -> str
#   - dbms -> str
SQLiData = NamedTuple('SQLiData', [('url', str),
                                   ('injection_point', str),
                                   ('regex', str),
                                   ('dbms', str)])


VulnData = Tuple[Optional[XSSData], Optional[SQLiData]]
Cookies = Dict[str, str]


def get_cookies(flow: http.HTTPFlow) -> Cookies:
    """ Return a dict going from cookie names to cookie values
          - Note that it includes both the cookies sent in the original request and
            the cookies sent by the server """
    return {name: value for name, value in flow.request.cookies.fields}


def find_unclaimed_URLs(body: str, requestUrl: bytes) -> None:
    """ Look for unclaimed URLs in script tags and log them if found"""
    def getValue(attrs: List[Tuple[str, str]], attrName: str) -> Optional[str]:
        for name, value in attrs:
            if attrName == name:
                return value
        return None

    class ScriptURLExtractor(HTMLParser):
        script_URLs: List[str] = []

        def handle_starttag(self, tag, attrs):
            if (tag == "script" or tag == "iframe") and "src" in [name for name, value in attrs]:
                self.script_URLs.append(getValue(attrs, "src"))
            if tag == "link" and getValue(attrs, "rel") == "stylesheet" and "href" in [name for name, value in attrs]:
                self.script_URLs.append(getValue(attrs, "href"))

    parser = ScriptURLExtractor()
    parser.feed(body)
    for url in parser.script_URLs:
        url_parser = urlparse(url)
        domain = url_parser.netloc
        try:
            gethostbyname(domain)
        except gaierror:
            ctx.log.error("XSS found in %s due to unclaimed URL \"%s\"." % (requestUrl, url))


def test_end_of_URL_injection(original_body: str, request_URL: str, cookies: Cookies) -> VulnData:
    """ Test the given URL for XSS via injection onto the end of the URL and
        log the XSS if found """
    parsed_URL = urlparse(request_URL)
    path = parsed_URL.path
    if path != "" and path[-1] != "/":  # ensure the path ends in a /
        path += "/"
    path += FULL_PAYLOAD.decode('utf-8')  # the path must be a string while the payload is bytes
    url = parsed_URL._replace(path=path).geturl()
    body = requests.get(url, cookies=cookies).text.lower()
    xss_info = get_XSS_data(body, url, "End of URL")
    sqli_info = get_SQLi_data(body, original_body, url, "End of URL")
    return xss_info, sqli_info


def test_referer_injection(original_body: str, request_URL: str, cookies: Cookies) -> VulnData:
    """ Test the given URL for XSS via injection into the referer and
        log the XSS if found """
    body = requests.get(request_URL, headers={'referer': FULL_PAYLOAD}, cookies=cookies).text.lower()
    xss_info = get_XSS_data(body, request_URL, "Referer")
    sqli_info = get_SQLi_data(body, original_body, request_URL, "Referer")
    return xss_info, sqli_info


def test_user_agent_injection(original_body: str, request_URL: str, cookies: Cookies) -> VulnData:
    """ Test the given URL for XSS via injection into the user agent and<commit_msg>[examples/xss_scanner] replace relative import<commit_after>"""

 __   __ _____ _____     _____
 \ \ / // ____/ ____|   / ____|
  \ V /| (___| (___    | (___   ___ __ _ _ __  _ __   ___ _ __
   > <  \___ \\___ \    \___ \ / __/ _` | '_ \| '_ \ / _ \ '__|
  / . \ ____) |___) |   ____) | (_| (_| | | | | | | |  __/ |
 /_/ \_\_____/_____/   |_____/ \___\__,_|_| |_|_| |_|\___|_|


This script automatically scans all visited webpages for XSS and SQLi vulnerabilities.

Usage: mitmproxy -s xss_scanner.py

This script scans for vulnerabilities by injecting a fuzzing payload (see PAYLOAD below) into 4 different places
and examining the HTML to look for XSS and SQLi injection vulnerabilities. The XSS scanning functionality works by
looking to see whether it is possible to inject HTML based off of of where the payload appears in the page and what
characters are escaped. In addition, it also looks for any script tags that load javascript from unclaimed domains.
The SQLi scanning functionality works by using regular expressions to look for errors from a number of different
common databases. Since it is only looking for errors, it will not find blind SQLi vulnerabilities.

The 4 places it injects the payload into are:
1. URLs         (e.g. https://example.com/ -> https://example.com/PAYLOAD/)
2. Queries      (e.g. https://example.com/index.html?a=b -> https://example.com/index.html?a=PAYLOAD)
3. Referers     (e.g. The referer changes from https://example.com to PAYLOAD)
4. User Agents  (e.g. The UA changes from Chrome to PAYLOAD)

Reports from this script show up in the event log (viewable by pressing e) and formatted like:

===== XSS Found ====
XSS URL: http://daviddworken.com/vulnerableUA.php
Injection Point: User Agent
Suggested Exploit: <script>alert(0)</script>
Line: 1029zxcs'd"ao<ac>so[sb]po(pc)se;sl/bsl\eq=3847asd

"""

from html.parser import HTMLParser
from typing import Dict, Union, Tuple, Optional, List, NamedTuple
from urllib.parse import urlparse
import re
import socket

import requests

from mitmproxy import http
from mitmproxy import ctx


# The actual payload is put between a frontWall and a backWall to make it easy
# to locate the payload with regular expressions
FRONT_WALL = b"1029zxc"
BACK_WALL = b"3847asd"
PAYLOAD = b"""s'd"ao<ac>so[sb]po(pc)se;sl/bsl\\eq="""
FULL_PAYLOAD = FRONT_WALL + PAYLOAD + BACK_WALL

# A XSSData is a named tuple with the following fields:
#   - url -> str
#   - injection_point -> str
#   - exploit -> str
#   - line -> str
XSSData = NamedTuple('XSSData', [('url', str),
                                 ('injection_point', str),
                                 ('exploit', str),
                                 ('line', str)])

# A SQLiData is named tuple with the following fields:
#   - url -> str
#   - injection_point -> str
#   - regex -> str
#   - dbms -> str
SQLiData = NamedTuple('SQLiData', [('url', str),
                                   ('injection_point', str),
                                   ('regex', str),
                                   ('dbms', str)])


VulnData = Tuple[Optional[XSSData], Optional[SQLiData]]
Cookies = Dict[str, str]


def get_cookies(flow: http.HTTPFlow) -> Cookies:
    """ Return a dict going from cookie names to cookie values
          - Note that it includes both the cookies sent in the original request and
            the cookies sent by the server """
    return {name: value for name, value in flow.request.cookies.fields}


def find_unclaimed_URLs(body: str, requestUrl: bytes) -> None:
    """ Look for unclaimed URLs in script tags and log them if found"""
    def getValue(attrs: List[Tuple[str, str]], attrName: str) -> Optional[str]:
        for name, value in attrs:
            if attrName == name:
                return value
        return None

    class ScriptURLExtractor(HTMLParser):
        script_URLs: List[str] = []

        def handle_starttag(self, tag, attrs):
            if (tag == "script" or tag == "iframe") and "src" in [name for name, value in attrs]:
                self.script_URLs.append(getValue(attrs, "src"))
            if tag == "link" and getValue(attrs, "rel") == "stylesheet" and "href" in [name for name, value in attrs]:
                self.script_URLs.append(getValue(attrs, "href"))

    parser = ScriptURLExtractor()
    parser.feed(body)
    for url in parser.script_URLs:
        url_parser = urlparse(url)
        domain = url_parser.netloc
        try:
            socket.gethostbyname(domain)
        except socket.gaierror:
            ctx.log.error("XSS found in %s due to unclaimed URL \"%s\"." % (requestUrl, url))


def test_end_of_URL_injection(original_body: str, request_URL: str, cookies: Cookies) -> VulnData:
    """ Test the given URL for XSS via injection onto the end of the URL and
        log the XSS if found """
    parsed_URL = urlparse(request_URL)
    path = parsed_URL.path
    if path != "" and path[-1] != "/":  # ensure the path ends in a /
        path += "/"
    path += FULL_PAYLOAD.decode('utf-8')  # the path must be a string while the payload is bytes
    url = parsed_URL._replace(path=path).geturl()
    body = requests.get(url, cookies=cookies).text.lower()
    xss_info = get_XSS_data(body, url, "End of URL")
    sqli_info = get_SQLi_data(body, original_body, url, "End of URL")
    return xss_info, sqli_info


def test_referer_injection(original_body: str, request_URL: str, cookies: Cookies) -> VulnData:
    """ Test the given URL for XSS via injection into the referer and
        log the XSS if found """
    body = requests.get(request_URL, headers={'referer': FULL_PAYLOAD}, cookies=cookies).text.lower()
    xss_info = get_XSS_data(body, request_URL, "Referer")
    sqli_info = get_SQLi_data(body, original_body, request_URL, "Referer")
    return xss_info, sqli_info


def test_user_agent_injection(original_body: str, request_URL: str, cookies: Cookies) -> VulnData:
    """ Test the given URL for XSS via injection into the user agent and
{'fraction_non_alphanumeric': 0.10960053709298423, 'fraction_numerical': 0.004196038939241357, 'mean_word_length': 2.8666450356911097, 'pattern_counts': {'":': 2, '<': 13, '<?xml version=': 0, '>': 45, 'https://': 10, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4016753', 'n_tokens_mistral': 3804, 'n_tokens_neox': 3679, 'n_words': 1225}