Files
Arjun/arjun/core/anomaly.py

97 lines
5.1 KiB
Python
Raw Normal View History

2021-01-06 19:53:10 +05:30
import re
import requests
2021-01-06 19:53:10 +05:30
2022-04-09 21:35:06 +05:30
import arjun.core.config as mem
2022-04-04 14:47:27 +05:30
from urllib.parse import urlparse
2021-04-26 19:00:55 +05:30
from arjun.core.utils import diff_map, remove_tags
def define(response_1, response_2, param, value, wordlist):
2021-02-07 19:43:30 +05:30
"""
defines a rule list for detecting anomalies by comparing two HTTP response
returns dict
"""
factors = {
'same_code': None, # if http status code is same, contains that code
'same_body': None, # if http body is same, contains that body
'same_plaintext': None, # if http body isn't same but is same after removing html, contains that non-html text
'lines_num': None, # if number of lines in http body is same, contains that number
'lines_diff': None, # if http-body or plaintext aren't and there are more than two lines, contain which lines are same
'same_headers': None, # if the headers are same, contains those headers
'same_redirect': None, # if both requests redirect in similar manner, contains that redirection
'param_missing': None, # if param name is missing from the body, contains words that are already there
'value_missing': None # contains whether param value is missing from the body
}
if type(response_1) == type(response_2) == requests.models.Response:
body_1, body_2 = response_1.text, response_2.text
if response_1.status_code == response_2.status_code:
factors['same_code'] = response_1.status_code
if response_1.headers.keys() == response_2.headers.keys():
factors['same_headers'] = list(response_1.headers.keys())
2022-04-04 14:47:27 +05:30
factors['same_headers'].sort()
2022-04-09 21:35:06 +05:30
if mem.var['disable_redirects']:
if response_1.headers.get('Location', '') == response_2.headers.get('Location', ''):
factors['same_redirect'] = urlparse(response_1.headers.get('Location', '')).path
elif urlparse(response_1.url).path == urlparse(response_2.url).path:
factors['same_redirect'] = urlparse(response_1.url).path
else:
factors['same_redirect'] = ''
if response_1.text == response_2.text:
factors['same_body'] = response_1.text
2021-05-17 19:33:33 +05:30
elif response_1.text.count('\n') == response_2.text.count('\n'):
factors['lines_num'] = response_1.text.count('\n')
2021-02-07 19:43:30 +05:30
elif remove_tags(body_1) == remove_tags(body_2):
factors['same_plaintext'] = remove_tags(body_1)
2021-04-26 19:00:55 +05:30
elif body_1 and body_2 and body_1.count('\\n') == body_2.count('\\n'):
2024-11-04 01:59:30 +05:30
factors['lines_diff'] = diff_map(body_1, body_2)
2020-12-09 01:06:46 +05:30
if param not in response_2.text:
factors['param_missing'] = [word for word in wordlist if word in response_2.text]
if value not in response_2.text:
factors['value_missing'] = True
return factors
def compare(response, factors, params):
2021-02-07 19:43:30 +05:30
"""
detects anomalies by comparing a HTTP response against a rule list
2021-07-13 14:18:21 +02:00
returns string, list (anomaly, list of parameters that caused it)
2021-02-07 19:43:30 +05:30
"""
if response == '' or type(response) == str:
2023-11-16 18:00:17 +05:30
return ('', [], '')
2022-04-04 14:47:27 +05:30
these_headers = list(response.headers.keys())
these_headers.sort()
if factors['same_code'] is not None and response.status_code != factors['same_code']:
2023-11-16 18:00:17 +05:30
return ('http code', params, 'same_code')
if factors['same_headers'] is not None and these_headers != factors['same_headers']:
2023-11-16 18:00:17 +05:30
return ('http headers', params, 'same_headers')
2022-04-09 21:35:06 +05:30
if mem.var['disable_redirects']:
if factors['same_redirect'] is not None and urlparse(response.headers.get('Location', '')).path != factors['same_redirect']:
2023-11-16 18:00:17 +05:30
return ('redirection', params, 'same_redirect')
elif factors['same_redirect'] is not None and 'Location' in response.headers:
2022-09-11 02:57:13 +05:30
if urlparse(response.headers.get('Location', '')).path != factors['same_redirect']:
2023-11-16 18:00:17 +05:30
return ('redirection', params, 'same_redirect')
if factors['same_body'] is not None and response.text != factors['same_body']:
2023-11-16 18:00:17 +05:30
return ('body length', params, 'same_body')
if factors['lines_num'] is not None and response.text.count('\n') != factors['lines_num']:
2023-11-16 18:00:17 +05:30
return ('number of lines', params, 'lines_num')
if factors['same_plaintext'] is not None and remove_tags(response.text) != factors['same_plaintext']:
2023-11-16 18:00:17 +05:30
return ('text length', params, 'same_plaintext')
if factors['lines_diff'] is not None:
2020-12-06 23:52:09 +05:30
for line in factors['lines_diff']:
if line not in response.text:
2023-11-16 18:00:17 +05:30
return ('lines', params, 'lines_diff')
if factors['param_missing'] is not None:
for param in params.keys():
2022-04-04 14:47:27 +05:30
if len(param) < 5:
continue
2024-04-01 08:51:42 +05:30
if param not in factors['param_missing'] and re.search(r'[\'"\s]%s[\'"\s]' % re.escape(param), response.text):
2023-11-16 18:00:17 +05:30
return ('param name reflection', params, 'param_missing')
if factors['value_missing'] is not None:
for value in params.values():
2022-09-11 14:36:51 +05:30
if type(value) != str or len(value) != 6:
2022-09-11 02:57:13 +05:30
continue
2024-04-01 08:51:42 +05:30
if value in response.text and re.search(r'[\'"\s]%s[\'"\s]' % re.escape(value), response.text):
2023-11-16 18:00:17 +05:30
return ('param value reflection', params, 'value_missing')
return ('', [], '')