#!/usr/bin/env python3

# Author: Abdou Rockikz
# Description: XSS Vulnerability Scan  
# Date: 11/25/2020
# Modified by: Bubacarr Darboe

# Import libraries

import requests
from pprint import pprint
from bs4 import BeautifulSoup as bs
from urllib.parse import urljoin

# Declare functions

### TODO: Add function explanation here ###
### The function returns all forms from the HTML content when you're given the url ###
def get_all_forms(url):
    soup = bs(requests.get(url).content, "html.parser")
    return soup.find_all("form")

### TODO: Add function explanation here ###
### Extracts all possible useful information about an HTML form ###
def get_form_details(form):
    details = {}
    action = form.attrs.get("action").lower()
    method = form.attrs.get("method", "get").lower()
    inputs = []
    for input_tag in form.find_all("input"):
        input_type = input_tag.attrs.get("type", "text")
        input_name = input_tag.attrs.get("name")
        inputs.append({"type": input_type, "name": input_name})
    details["action"] = action
    details["method"] = method
    details["inputs"] = inputs
    return details

### TODO: Add function explanation here ###
### The purpose of this function is to submit a form given in 'form_details' and should return the HTTP response after the form is submitted ###
def submit_form(form_details, url, value):
    target_url = urljoin(url, form_details["action"])
    inputs = form_details["inputs"]
    data = {}
    for input in inputs:
        if input["type"] == "text" or input["type"] == "search":
            input["value"] = value
        input_name = input.get("name")
        input_value = input.get("value")
        if input_name and input_value:
            data[input_name] = input_value

    if form_details["method"] == "post":
        return requests.post(target_url, data=data)
    else:
        return requests.get(target_url, params=data)

### TODO: Add function explanation here ###
### This prints all the XSS vulnerable forms and return True if any is vulnerable, otherwise it will return False###
def scan_xss(url):
    forms = get_all_forms(url)
    print(f"[+] Detected {len(forms)} forms on {url}.")
    js_script = "<Script>alert('This site may expose your data, do you want to continue?')</script>"
    is_vulnerable = False
    for form in forms:
        form_details = get_form_details(form)
        content = submit_form(form_details, url, js_script).content.decode()
        if js_script in content:
            print(f"[+] XSS Detected on {url}")
            print(f"[*] Form details:")
            pprint(form_details)
            is_vulnerable = True
    return is_vulnerable

# Main

### TODO: Add main explanation here ###
### This conditional statement will take a given url and scan for xss vulnerability and return True or False ###
if __name__ == "__main__":
    url = input("Enter a URL to test for XSS:") 
    print(scan_xss(url))

### TODO: When you have finished annotating this script with your own comments, copy it to Web Security Dojo
### TODO: Test this script against one XSS-positive target and one XSS-negative target
### TODO: Paste the outputs here as comments in this script, clearling indicating which is positive detection and negative detection

###XSS POSITIVE TARGET RETURNING TRUE###
"""
Enter a URL to test for XSS:https://xss-game.appspot.com/level1/frame      
[+] Detected 1 forms on https://xss-game.appspot.com/level1/frame.
[+] XSS Detected on https://xss-game.appspot.com/level1/frame
[*] Form details:
{'action': '',
 'inputs': [{'name': 'query',
             'type': 'text',
             'value': "<Script>alert('This site may expose your data, do you "
                      "want to continue?')</script>"},
            {'name': None, 'type': 'submit'}],
 'method': 'get'}
True
"""
###XSS NEGATIVE TARGET RETURNING FALSE### 
"""
Enter a URL to test for XSS:http://webappsecmovies.sourceforge.net/webgoat/
[+] Detected 0 forms on http://webappsecmovies.sourceforge.net/webgoat/.
False
"""
