Compare commits

..

10 Commits

Author SHA1 Message Date
Somdev Sangwan
2985ae24da Merge pull request #37 from Vasco-jofra/bug-fixes
Fixes the "origin reflected" check and the extractHeaders function
2021-11-20 10:35:49 +05:30
Vasco Franco
9f37125c04 Fix "root" where "scheme" was intended 2021-11-14 00:15:29 +00:00
Vasco Franco
bd97d2c752 Clarify variable names in requester 2021-11-14 00:10:22 +00:00
Vasco Franco
85e1fe8b68 Fix bug in extractHeaders and simplify its logic
`extractHeaders` had an incorrect regex that crashed Corsy with the msg:
"sre_constants.error: nothing to repeat at position 1". This was caused
by `^?`, which is not a valid regex, and can be reproduced with the
README example: `python3 corsy.py -u https://example.com --headers
"User-Agent: GoogleBot\nCookie: SESSION=Hacked"`.
Instead of using the regex this commit simplifies the logic by using a
`split` to split lines and header_name/value pairs.
2021-11-14 00:02:28 +00:00
Vasco Franco
b5c5c21926 Fixes "origin reflected" check
Previously there was a missing call to `headers = requester(url, scheme,
header_dict, origin)` in the "origin reflected" check. This meant that
the code was not using the intended origin (`origin = root + '://' +
'example.com'`). Intead, the check incorreclty used the headers from the
first request (with `origin = scheme + '://' + root`). This commit fixes
this problem by making the missing request.
2021-11-13 23:53:18 +00:00
Somdev Sangwan
06f4d4a06d Merge pull request #33 from s0md3v/hotfix
HOTFIX
2021-01-28 18:24:23 +05:30
Somdev Sangwan
de9aff1794 fix breaking bug, better error handling 2021-01-28 18:23:51 +05:30
Somdev Sangwan
29fe7d918c simplify origin, better error handling 2021-01-28 18:21:49 +05:30
Somdev Sangwan
35d18e9062 it's requests, not request 2021-01-28 17:00:43 +05:30
Somdev Sangwan
3af7dca220 remove tld dependency 2021-01-28 16:55:10 +05:30
4 changed files with 99 additions and 92 deletions

View File

@@ -24,12 +24,11 @@ Corsy is a lightweight program that scans for all known misconfigurations in COR
![demo](https://i.ibb.co/Jc1HtmW/corsy.png)
### Requirements
Corsy only works with `Python 3` and has the following depencies:
Corsy only works with `Python 3` and has just one dependency:
- `tld`
- `requests`
To install these dependencies, navigate to Corsy directory and execute `pip3 install -r requirements.txt`
To install this dependency, navigate to Corsy directory and execute `pip3 install requests`
### Usage
Using Corsy is pretty simple

View File

@@ -8,14 +8,16 @@ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Added verbose options.
def requester(url, scheme, headers, origin):
headers['Origin'] = scheme + origin
headers['Origin'] = origin
try:
response = requests.get(url, headers=headers, verify=False).headers
for key, value in response.items():
response = requests.get(url, headers=headers, verify=False)
headers = response.headers
for key, value in headers.items():
if key.lower() == 'access-control-allow-origin':
return response
return headers
except requests.exceptions.RequestException as e:
if 'Failed to establish a new connection' in str(e):
print ('%s %s is unreachable' % (bad, url))
elif 'requests.exceptions.TooManyRedirects:' in str(e):
print ('%s %s has too many redirects' % (bad, url))
return {}

View File

@@ -8,7 +8,7 @@ details = load_json(sys.path[0] + '/db/details.json')
def passive_tests(url, headers):
root = host(url)
acao_header, acac_header = headers['access-control-allow-origin'], headers.get('access-control-allow-credentials', None)
acao_header, acac_header = headers.get('access-control-allow-origin', None), headers.get('access-control-allow-credentials', None)
if acao_header == '*':
info = details['wildcard value']
info['acao header'] = acao_header
@@ -23,79 +23,89 @@ def passive_tests(url, headers):
def active_tests(url, root, scheme, header_dict, delay):
headers = requester(url, scheme, header_dict, 'example.com')
if headers:
acao_header, acac_header = headers['access-control-allow-origin'], headers.get('access-control-allow-credentials', None)
if acao_header and acao_header == (scheme + 'example.com'):
info = details['origin reflected']
info['acao header'] = acao_header
info['acac header'] = acac_header
return {url : info}
elif not acao_header:
return
time.sleep(delay)
origin = scheme + '://' + root
headers = requester(url, scheme, header_dict, origin)
acao_header, acac_header = headers.get('access-control-allow-origin', None), headers.get('access-control-allow-credentials', None)
if acao_header is None:
return
origin = scheme + '://' + 'example.com'
headers = requester(url, scheme, header_dict, origin)
acao_header, acac_header = headers.get('access-control-allow-origin', None), headers.get('access-control-allow-credentials', None)
if acao_header and acao_header == (origin):
info = details['origin reflected']
info['acao header'] = acao_header
info['acac header'] = acac_header
return {url : info}
time.sleep(delay)
headers = requester(url, scheme, header_dict, root + '.example.com')
acao_header, acac_header = headers['access-control-allow-origin'], headers.get('access-control-allow-credentials', None)
if acao_header and acao_header == (scheme + root + '.example.com'):
info = details['post-domain wildcard']
origin = scheme + '://' + root + '.example.com'
headers = requester(url, scheme, header_dict, origin)
acao_header, acac_header = headers.get('access-control-allow-origin', None), headers.get('access-control-allow-credentials', None)
if acao_header and acao_header == (origin):
info = details['post-domain wildcard']
info['acao header'] = acao_header
info['acac header'] = acac_header
return {url : info}
time.sleep(delay)
origin = scheme + '://d3v' + root
headers = requester(url, scheme, header_dict, origin)
acao_header, acac_header = headers.get('access-control-allow-origin', None), headers.get('access-control-allow-credentials', None)
if acao_header and acao_header == (origin):
info = details['pre-domain wildcard']
info['acao header'] = acao_header
info['acac header'] = acac_header
return {url : info}
time.sleep(delay)
origin = 'null'
headers = requester(url, '', header_dict, origin)
acao_header, acac_header = headers.get('access-control-allow-origin', None), headers.get('access-control-allow-credentials', None)
if acao_header and acao_header == 'null':
info = details['null origin allowed']
info['acao header'] = acao_header
info['acac header'] = acac_header
return {url : info}
time.sleep(delay)
origin = scheme + '://' + root + '_.example.com'
headers = requester(url, scheme, header_dict, origin)
acao_header, acac_header = headers.get('access-control-allow-origin', None), headers.get('access-control-allow-credentials', None)
if acao_header and acao_header == origin:
info = details['unrecognized underscore']
info['acao header'] = acao_header
info['acac header'] = acac_header
return {url : info}
time.sleep(delay)
origin = scheme + '://' + root + '%60.example.com'
headers = requester(url, scheme, header_dict, origin)
acao_header, acac_header = headers.get('access-control-allow-origin', None), headers.get('access-control-allow-credentials', None)
if acao_header and '`.example.com' in acao_header:
info = details['broken parser']
info['acao header'] = acao_header
info['acac header'] = acac_header
return {url : info}
time.sleep(delay)
if root.count('.') > 1:
origin = scheme + '://' + root.replace('.', 'x', 1)
headers = requester(url, scheme, header_dict, origin)
acao_header, acac_header = headers.get('access-control-allow-origin', None), headers.get('access-control-allow-credentials', None)
if acao_header and acao_header == origin:
info = details['unescaped regex']
info['acao header'] = acao_header
info['acac header'] = acac_header
return {url : info}
time.sleep(delay)
headers = requester(url, scheme, header_dict, 'd3v' + root)
acao_header, acac_header = headers['access-control-allow-origin'], headers.get('access-control-allow-credentials', None)
if acao_header and acao_header == (scheme + 'd3v' + root):
info = details['pre-domain wildcard']
info['acao header'] = acao_header
info['acac header'] = acac_header
return {url : info}
time.sleep(delay)
headers = requester(url, '', header_dict, 'null')
acao_header, acac_header = headers['access-control-allow-origin'], headers.get('access-control-allow-credentials', None)
if acao_header and acao_header == 'null':
info = details['null origin allowed']
info['acao header'] = acao_header
info['acac header'] = acac_header
return {url : info}
time.sleep(delay)
headers = requester(url, scheme, header_dict, root + '_.example.com')
acao_header, acac_header = headers['access-control-allow-origin'], headers.get('access-control-allow-credentials', None)
if acao_header and '_.example.com' in acao_header:
info = details['unrecognized underscore']
info['acao header'] = acao_header
info['acac header'] = acac_header
return {url : info}
time.sleep(delay)
headers = requester(url, scheme, header_dict, root + '%60.example.com')
acao_header, acac_header = headers['access-control-allow-origin'], headers.get('access-control-allow-credentials', None)
if acao_header and '`.example.com' in acao_header:
info = details['broken parser']
info['acao header'] = acao_header
info['acac header'] = acac_header
return {url : info}
time.sleep(delay)
if root.count('.') > 1:
spoofed_root = root.replace('.', 'x', 1)
headers = requester(url, scheme, header_dict, spoofed_root)
acao_header, acac_header = headers['access-control-allow-origin'], headers.get('access-control-allow-credentials', None)
if acao_header and host(acao_header) == spoofed_root:
info = details['unescaped regex']
info['acao header'] = acao_header
info['acac header'] = acac_header
return {url : info}
time.sleep(delay)
headers = requester(url, 'http', header_dict, root)
acao_header, acac_header = headers['access-control-allow-origin'], headers.get('access-control-allow-credentials', None)
if acao_header and acao_header.startswith('http://'):
info = details['http origin allowed']
info['acao header'] = acao_header
info['acac header'] = acac_header
return {url : info}
else:
return passive_tests(url, headers)
origin = 'http://' + root
headers = requester(url, 'http', header_dict, origin)
acao_header, acac_header = headers.get('access-control-allow-origin', None), headers.get('access-control-allow-credentials', None)
if acao_header and acao_header.startswith('http://'):
info = details['http origin allowed']
info['acao header'] = acao_header
info['acac header'] = acac_header
return {url : info}
else:
return passive_tests(url, headers)

View File

@@ -64,17 +64,13 @@ def prompt(default=None):
return tmpfile.read().strip()
def extractHeaders(headers):
headers = headers.replace('\\n', '\n')
def extractHeaders(headers: str):
sorted_headers = {}
matches = re.findall(r'^?(.*?):\s(.*?)[\n$]', headers)
for match in matches:
header = match[0]
value = match[1]
try:
if value[-1] == ',':
value = value[:-1]
sorted_headers[header] = value
except IndexError:
pass
return sorted_headers
for header in headers.split('\\n'):
name, value = header.split(":", 1)
name = name.strip()
value = value.strip()
if len(value) >= 1 and value[-1] == ',':
value = value[:-1]
sorted_headers[name] = value
return sorted_headers