Compare commits
10 Commits
16ee7355dc
...
d1fb995cb1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1fb995cb1 | ||
|
|
6f87dccd17 | ||
|
|
c7d97358b0 | ||
|
|
38f307d92a | ||
|
|
1b251b023b | ||
|
|
1b11c3574e | ||
|
|
93c6c966ee | ||
|
|
53afa55518 | ||
|
|
afc11b0769 | ||
|
|
c1fcde3ac5 |
@@ -1,3 +1,9 @@
|
||||
#### 2.2.7
|
||||
- Added `--casing` option for casing style enforcement
|
||||
- Added `--ratelimit` option for explicitly defining requests/second
|
||||
- Fixed "decrease chunk size/use --stable" type errors in some cases
|
||||
- Fixed a bug in anamoly detection
|
||||
|
||||
#### 2.2.6
|
||||
- Fixed Arjun getting infinitely stuck on some webpages
|
||||
|
||||
|
||||
12
README.md
12
README.md
@@ -48,17 +48,11 @@ The best part? It takes less than 10 seconds to go through this huge list while
|
||||
- Can passively extract parameters from JS or 3 external sources
|
||||
|
||||
### Installing Arjun
|
||||
|
||||
|
||||
You can install `arjun` with pip as following:
|
||||
The recommended way to install `arjun` is as following:
|
||||
```
|
||||
pip3 install arjun
|
||||
```
|
||||
|
||||
or, by downloading this repository and running
|
||||
```
|
||||
python3 setup.py install
|
||||
pipx install arjun
|
||||
```
|
||||
> Note: If you are using an old version of python, use pip instead of pipx.
|
||||
|
||||
### How to use Arjun?
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = '2.2.6'
|
||||
__version__ = '2.2.7'
|
||||
|
||||
@@ -13,6 +13,7 @@ from arjun.core.anomaly import define, compare
|
||||
from arjun.core.utils import fetch_params, stable_request, random_str, slicer, confirm, populate, reader, nullify, prepare_requests, compatible_path
|
||||
|
||||
from arjun.plugins.heuristic import heuristic
|
||||
from arjun.plugins.wl import detect_casing, covert_to_case
|
||||
|
||||
arjun_dir = compatible_path(mem.__file__.replace(compatible_path('/core/config.py'), ''))
|
||||
|
||||
@@ -25,7 +26,7 @@ parser.add_argument('-oB', help='Output to Burp Suite Proxy. Default is 127.0.0.
|
||||
parser.add_argument('-d', help='Delay between requests in seconds. (default: 0)', dest='delay', type=float, default=0)
|
||||
parser.add_argument('-t', help='Number of concurrent threads. (default: 5)', dest='threads', type=int, default=5)
|
||||
parser.add_argument('-w', help='Wordlist file path. (default: {arjundir}/db/large.txt)', dest='wordlist', default=arjun_dir+'/db/large.txt')
|
||||
parser.add_argument('-m', help='Request method to use: GET/POST/XML/JSON/HEADERS. (default: GET)', dest='method', default='GET')
|
||||
parser.add_argument('-m', help='Request method to use: GET/POST/XML/JSON. (default: GET)', dest='method', default='GET')
|
||||
parser.add_argument('-i', help='Import target URLs from file.', dest='import_file', nargs='?', const=True)
|
||||
parser.add_argument('-T', help='HTTP request timeout in seconds. (default: 15)', dest='timeout', type=float, default=15)
|
||||
parser.add_argument('-c', help='Chunk size. The number of parameters to be sent at once', type=int, dest='chunks', default=250)
|
||||
@@ -36,6 +37,7 @@ parser.add_argument('--passive', help='Collect parameter names from passive sour
|
||||
parser.add_argument('--stable', help='Prefer stability over speed.', dest='stable', action='store_true')
|
||||
parser.add_argument('--include', help='Include this data in every request.', dest='include', default={})
|
||||
parser.add_argument('--disable-redirects', help='disable redirects', dest='disable_redirects', action='store_true')
|
||||
parser.add_argument('--casing', help='casing style for params e.g. like_this, likeThis, likethis', dest='casing')
|
||||
args = parser.parse_args() # arguments to be parsed
|
||||
|
||||
if args.quiet:
|
||||
@@ -77,7 +79,11 @@ try:
|
||||
passive_params = fetch_params(host)
|
||||
wordlist.update(passive_params)
|
||||
print('%s Collected %s parameters, added to the wordlist' % (info, len(passive_params)))
|
||||
wordlist = list(wordlist)
|
||||
if args.casing:
|
||||
delimiter, casing = detect_casing(args.casing)
|
||||
wordlist = [covert_to_case(word, delimiter, casing) for word in wordlist]
|
||||
else:
|
||||
wordlist = list(wordlist)
|
||||
except FileNotFoundError:
|
||||
exit('%s The specified file for parameters doesn\'t exist' % bad)
|
||||
|
||||
@@ -118,11 +124,17 @@ def initialize(request, wordlist, single_url=False):
|
||||
return 'skipped'
|
||||
print('%s Probing the target for stability' % run)
|
||||
request['url'] = stable_request(url, request['headers'])
|
||||
mem.var['healthy_url'] = True
|
||||
if not request['url']:
|
||||
return 'skipped'
|
||||
else:
|
||||
fuzz = "z" + random_str(6)
|
||||
response_1 = requester(request, {fuzz[:-1]: fuzz[::-1][:-1]})
|
||||
if(isinstance(response_1, str)):
|
||||
return 'skipped'
|
||||
mem.var['healthy_url'] = response_1.status_code not in (400, 413, 418, 429, 503)
|
||||
if not mem.var['healthy_url']:
|
||||
print('%s Target returned HTTP %i, this may cause problems.' % (bad, response_1.status_code))
|
||||
if single_url:
|
||||
print('%s Analysing HTTP response for anomalies' % run)
|
||||
response_2 = requester(request, {fuzz[:-1]: fuzz[::-1][:-1]})
|
||||
@@ -139,16 +151,14 @@ def initialize(request, wordlist, single_url=False):
|
||||
reason = compare(response_3, factors, {zzuf[:-1]: zzuf[::-1][:-1]})[2]
|
||||
if not reason:
|
||||
break
|
||||
factors[reason] = False
|
||||
if single_url:
|
||||
print('%s Analysing HTTP response for potential parameter names' % run)
|
||||
factors[reason] = None
|
||||
if found:
|
||||
num = len(found)
|
||||
if words_exist:
|
||||
print('%s Heuristic scanner found %i parameters' % (good, num))
|
||||
print('%s Extracted %i parameters from response for testing' % (good, num))
|
||||
else:
|
||||
s = 's' if num > 1 else ''
|
||||
print('%s Heuristic scanner found %i parameter%s: %s' % (good, num, s, ', '.join(found)))
|
||||
print('%s Extracted %i parameter%s from response for testing: %s' % (good, num, s, ', '.join(found)))
|
||||
if single_url:
|
||||
print('%s Logicforcing the URL endpoint' % run)
|
||||
populated = populate(wordlist)
|
||||
@@ -182,16 +192,21 @@ def initialize(request, wordlist, single_url=False):
|
||||
|
||||
|
||||
def main():
|
||||
request = prepare_requests(args)
|
||||
requests = prepare_requests(args)
|
||||
|
||||
final_result = {}
|
||||
is_single = False if args.import_file else True
|
||||
|
||||
try:
|
||||
if type(request) == dict:
|
||||
# in case of a single target
|
||||
mem.var['kill'] = False
|
||||
mem.var['kill'] = False
|
||||
count = 0
|
||||
for request in requests:
|
||||
url = request['url']
|
||||
these_params = initialize(request, wordlist, single_url=True)
|
||||
print('%s Scanning %d/%d: %s' % (run, count, len(requests), url))
|
||||
these_params = initialize(request, wordlist, single_url=is_single)
|
||||
count += 1
|
||||
mem.var['kill'] = False
|
||||
mem.var['bad_req_count'] = 0
|
||||
if these_params == 'skipped':
|
||||
print('%s Skipped %s due to errors' % (bad, url))
|
||||
elif these_params:
|
||||
@@ -199,34 +214,13 @@ def main():
|
||||
final_result[url]['params'] = these_params
|
||||
final_result[url]['method'] = request['method']
|
||||
final_result[url]['headers'] = request['headers']
|
||||
print('%s Parameters found: %s' % (good, ', '.join(final_result[url]['params'])))
|
||||
exporter(final_result)
|
||||
print('%s Parameters found: %-4s\n' % (good, ', '.join(final_result[url]['params'])))
|
||||
if not mem.var['json_file']:
|
||||
final_result = {}
|
||||
continue
|
||||
else:
|
||||
print('%s No parameters were discovered.' % info)
|
||||
elif type(request) == list:
|
||||
# in case of multiple targets
|
||||
count = 0
|
||||
for each in request:
|
||||
count += 1
|
||||
url = each['url']
|
||||
mem.var['kill'] = False
|
||||
mem.var['bad_req_count'] = 0
|
||||
print('%s Scanning %d/%d: %s' % (run, count, len(request), url))
|
||||
these_params = initialize(each, list(wordlist))
|
||||
if these_params == 'skipped':
|
||||
print('%s Skipped %s due to errors' % (bad, url))
|
||||
elif these_params:
|
||||
final_result[url] = {}
|
||||
final_result[url]['params'] = these_params
|
||||
final_result[url]['method'] = each['method']
|
||||
final_result[url]['headers'] = each['headers']
|
||||
exporter(final_result)
|
||||
print('%s Parameters found: %s\n' % (good, ', '.join(final_result[url]['params'])))
|
||||
if not mem.var['json_file']:
|
||||
final_result = {}
|
||||
continue
|
||||
else:
|
||||
print('%s No parameters were discovered.\n' % info)
|
||||
print('%s No parameters were discovered.\n' % info)
|
||||
except KeyboardInterrupt:
|
||||
exit()
|
||||
|
||||
|
||||
@@ -13,15 +13,15 @@ def define(response_1, response_2, param, value, wordlist):
|
||||
returns dict
|
||||
"""
|
||||
factors = {
|
||||
'same_code': False, # if http status code is same, contains that code
|
||||
'same_body': False, # if http body is same, contains that body
|
||||
'same_plaintext': False, # if http body isn't same but is same after removing html, contains that non-html text
|
||||
'lines_num': False, # if number of lines in http body is same, contains that number
|
||||
'lines_diff': False, # if http-body or plaintext aren't and there are more than two lines, contain which lines are same
|
||||
'same_headers': False, # if the headers are same, contains those headers
|
||||
'same_redirect': False, # if both requests redirect in similar manner, contains that redirection
|
||||
'param_missing': False, # if param name is missing from the body, contains words that are already there
|
||||
'value_missing': False # contains whether param value is missing from the body
|
||||
'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
|
||||
@@ -44,7 +44,7 @@ def define(response_1, response_2, param, value, wordlist):
|
||||
elif remove_tags(body_1) == remove_tags(body_2):
|
||||
factors['same_plaintext'] = remove_tags(body_1)
|
||||
elif body_1 and body_2 and body_1.count('\\n') == body_2.count('\\n'):
|
||||
factors['lines_diff'] = diff_map(body_1, body_2)
|
||||
factors['lines_diff'] = diff_map(body_1, body_2)
|
||||
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:
|
||||
@@ -61,33 +61,33 @@ def compare(response, factors, params):
|
||||
return ('', [], '')
|
||||
these_headers = list(response.headers.keys())
|
||||
these_headers.sort()
|
||||
if factors['same_code'] and response.status_code != factors['same_code']:
|
||||
if factors['same_code'] is not None and response.status_code != factors['same_code']:
|
||||
return ('http code', params, 'same_code')
|
||||
if factors['same_headers'] and these_headers != factors['same_headers']:
|
||||
if factors['same_headers'] is not None and these_headers != factors['same_headers']:
|
||||
return ('http headers', params, 'same_headers')
|
||||
if mem.var['disable_redirects']:
|
||||
if factors['same_redirect'] and urlparse(response.headers.get('Location', '')).path != factors['same_redirect']:
|
||||
if factors['same_redirect'] is not None and urlparse(response.headers.get('Location', '')).path != factors['same_redirect']:
|
||||
return ('redirection', params, 'same_redirect')
|
||||
elif factors['same_redirect'] and 'Location' in response.headers:
|
||||
elif factors['same_redirect'] is not None and 'Location' in response.headers:
|
||||
if urlparse(response.headers.get('Location', '')).path != factors['same_redirect']:
|
||||
return ('redirection', params, 'same_redirect')
|
||||
if factors['same_body'] and response.text != factors['same_body']:
|
||||
if factors['same_body'] is not None and response.text != factors['same_body']:
|
||||
return ('body length', params, 'same_body')
|
||||
if factors['lines_num'] and response.text.count('\n') != factors['lines_num']:
|
||||
if factors['lines_num'] is not None and response.text.count('\n') != factors['lines_num']:
|
||||
return ('number of lines', params, 'lines_num')
|
||||
if factors['same_plaintext'] and remove_tags(response.text) != factors['same_plaintext']:
|
||||
if factors['same_plaintext'] is not None and remove_tags(response.text) != factors['same_plaintext']:
|
||||
return ('text length', params, 'same_plaintext')
|
||||
if factors['lines_diff']:
|
||||
if factors['lines_diff'] is not None:
|
||||
for line in factors['lines_diff']:
|
||||
if line not in response.text:
|
||||
return ('lines', params, 'lines_diff')
|
||||
if type(factors['param_missing']) == list:
|
||||
if factors['param_missing'] is not None:
|
||||
for param in params.keys():
|
||||
if len(param) < 5:
|
||||
continue
|
||||
if param not in factors['param_missing'] and re.search(r'[\'"\s]%s[\'"\s]' % re.escape(param), response.text):
|
||||
return ('param name reflection', params, 'param_missing')
|
||||
if factors['value_missing']:
|
||||
if factors['value_missing'] is not None:
|
||||
for value in params.values():
|
||||
if type(value) != str or len(value) != 6:
|
||||
continue
|
||||
|
||||
@@ -4,6 +4,7 @@ import arjun.core.config as mem
|
||||
|
||||
from arjun.core.colors import bad
|
||||
|
||||
|
||||
def connection_refused():
|
||||
"""
|
||||
checks if a request should be retried if the server refused connection
|
||||
@@ -17,6 +18,7 @@ def connection_refused():
|
||||
print('%s Target has rate limiting in place, please use --stable switch' % bad)
|
||||
return 'kill'
|
||||
|
||||
|
||||
def error_handler(response, factors):
|
||||
"""
|
||||
decides what to do after performing a HTTP request
|
||||
@@ -26,6 +28,8 @@ def error_handler(response, factors):
|
||||
returns str
|
||||
"""
|
||||
if type(response) != str and response.status_code in (400, 413, 418, 429, 503):
|
||||
if not mem.var['healthy_url']:
|
||||
return 'ok'
|
||||
if response.status_code == 503:
|
||||
mem.var['kill'] = True
|
||||
print('%s Target is unable to process requests, try --stable switch' % bad)
|
||||
|
||||
@@ -6,6 +6,7 @@ from arjun.core.utils import populate
|
||||
|
||||
from arjun.core.utils import create_query_string
|
||||
|
||||
|
||||
def json_export(result):
|
||||
"""
|
||||
exports result to a file in JSON format
|
||||
@@ -13,6 +14,7 @@ def json_export(result):
|
||||
with open(mem.var['json_file'], 'w+', encoding='utf8') as json_output:
|
||||
json.dump(result, json_output, sort_keys=True, indent=4)
|
||||
|
||||
|
||||
def burp_export(result):
|
||||
"""
|
||||
exports results to Burp Suite by sending request to Burp proxy
|
||||
@@ -30,6 +32,7 @@ def burp_export(result):
|
||||
elif data['method'] == 'JSON':
|
||||
requests.post(url, json=populate(data['params']), headers=data['headers'], proxies=proxies, verify=False)
|
||||
|
||||
|
||||
def text_export(result):
|
||||
"""
|
||||
exports results to a text file, one url per line
|
||||
@@ -48,6 +51,7 @@ def text_export(result):
|
||||
elif data['method'] == 'POST':
|
||||
text_file.write(clean_url + '\t' + query_string + '\n')
|
||||
|
||||
|
||||
def exporter(result):
|
||||
"""
|
||||
main exporter function that calls other export functions
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
import re
|
||||
|
||||
burp_regex = re.compile(r'''(?m)^ <url><!\[CDATA\[(.+?)\]\]></url>
|
||||
<host ip="[^"]*">[^<]+</host>
|
||||
<port>[^<]*</port>
|
||||
<protocol>[^<]*</protocol>
|
||||
<method><!\[CDATA\[(.+?)\]\]></method>
|
||||
<path>.*</path>
|
||||
<extension>(.*)</extension>
|
||||
<request base64="(?:false|true)"><!\[CDATA\[([\s\S]+?)]]></request>
|
||||
<status>([^<]*)</status>
|
||||
<responselength>([^<]*)</responselength>
|
||||
<mimetype>([^<]*)</mimetype>''')
|
||||
|
||||
|
||||
def reader(path, mode='string'):
|
||||
"""
|
||||
reads a file
|
||||
@@ -11,6 +24,7 @@ def reader(path, mode='string'):
|
||||
else:
|
||||
return ''.join([line for line in file])
|
||||
|
||||
|
||||
def parse_request(string):
|
||||
"""
|
||||
parses http request
|
||||
@@ -25,6 +39,7 @@ def parse_request(string):
|
||||
result['data'] = match.group(4)
|
||||
return result
|
||||
|
||||
|
||||
def parse_headers(string):
|
||||
"""
|
||||
parses headers
|
||||
@@ -37,18 +52,6 @@ def parse_headers(string):
|
||||
result[splitted[0]] = ':'.join(splitted[1:]).strip()
|
||||
return result
|
||||
|
||||
burp_regex = re.compile(r'''(?m)^ <url><!\[CDATA\[(.+?)\]\]></url>
|
||||
<host ip="[^"]*">[^<]+</host>
|
||||
<port>[^<]*</port>
|
||||
<protocol>[^<]*</protocol>
|
||||
<method><!\[CDATA\[(.+?)\]\]></method>
|
||||
<path>.*</path>
|
||||
<extension>(.*)</extension>
|
||||
<request base64="(?:false|true)"><!\[CDATA\[([\s\S]+?)]]></request>
|
||||
<status>([^<]*)</status>
|
||||
<responselength>([^<]*)</responselength>
|
||||
<mimetype>([^<]*)</mimetype>''')
|
||||
|
||||
|
||||
def burp_import(path):
|
||||
"""
|
||||
@@ -95,9 +98,11 @@ def urls_import(path, method, headers, include):
|
||||
def request_import(path):
|
||||
"""
|
||||
imports request from a raw request file
|
||||
returns dict
|
||||
returns list
|
||||
"""
|
||||
return parse_request(reader(path))
|
||||
result = []
|
||||
result.append(parse_request(reader(path)))
|
||||
return result
|
||||
|
||||
|
||||
def importer(path, method, headers, include):
|
||||
@@ -112,4 +117,4 @@ def importer(path, method, headers, include):
|
||||
return urls_import(path, method, headers, include)
|
||||
elif line.startswith(('GET', 'POST')):
|
||||
return request_import(path)
|
||||
return 'unknown'
|
||||
return []
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
|
||||
def prompt(default=None):
|
||||
"""
|
||||
lets user paste input by opening a temp file in a text editor
|
||||
|
||||
@@ -11,6 +11,7 @@ from arjun.core.utils import dict_to_xml
|
||||
|
||||
warnings.filterwarnings('ignore') # Disable SSL related warnings
|
||||
|
||||
|
||||
@sleep_and_retry
|
||||
@limits(calls=mem.var['rate_limit'], period=1)
|
||||
def requester(request, payload={}):
|
||||
|
||||
@@ -153,7 +153,7 @@ def create_query_string(params):
|
||||
pair = param + '=' + random_str(4) + '&'
|
||||
query_string += pair
|
||||
if query_string.endswith('&'):
|
||||
query_string = query_string[:-1]
|
||||
query_string = query_string[:-1]
|
||||
return '?' + query_string
|
||||
|
||||
|
||||
@@ -180,6 +180,7 @@ def extract_js(response):
|
||||
scripts.append(actual_parts[0])
|
||||
return scripts
|
||||
|
||||
|
||||
def parse_headers(string):
|
||||
"""
|
||||
parses headers
|
||||
@@ -248,7 +249,7 @@ def fetch_params(host):
|
||||
def prepare_requests(args):
|
||||
"""
|
||||
creates a list of request objects used by Arjun from targets given by user
|
||||
returns list (of targs)
|
||||
returns list (of targets)
|
||||
"""
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0',
|
||||
@@ -258,6 +259,7 @@ def prepare_requests(args):
|
||||
'Connection': 'close',
|
||||
'Upgrade-Insecure-Requests': '1'
|
||||
}
|
||||
result = []
|
||||
if type(args.headers) == str:
|
||||
headers = extract_headers(args.headers)
|
||||
elif args.headers:
|
||||
@@ -266,15 +268,17 @@ def prepare_requests(args):
|
||||
headers['Content-type'] = 'application/json'
|
||||
if args.url:
|
||||
params = get_params(args.include)
|
||||
return {
|
||||
'url': args.url,
|
||||
'method': mem.var['method'],
|
||||
'headers': headers,
|
||||
'include': params
|
||||
}
|
||||
result.append(
|
||||
{
|
||||
'url': args.url,
|
||||
'method': mem.var['method'],
|
||||
'headers': headers,
|
||||
'include': params
|
||||
}
|
||||
)
|
||||
elif args.import_file:
|
||||
return importer(args.import_file, mem.var['method'], headers, args.include)
|
||||
return []
|
||||
result = importer(args.import_file, mem.var['method'], headers, args.include)
|
||||
return result
|
||||
|
||||
|
||||
def nullify(*args, **kwargs):
|
||||
|
||||
@@ -2,9 +2,10 @@ import requests
|
||||
|
||||
from urllib.parse import urlparse
|
||||
|
||||
|
||||
def commoncrawl(host, page=0):
|
||||
these_params = set()
|
||||
response = requests.get('http://index.commoncrawl.org/CC-MAIN-2020-29-index?url=*.%s&fl=url&page=%s&limit=10000' % (host, page), verify=False).text
|
||||
response = requests.get('http://index.commoncrawl.org/CC-MAIN-2024-42-index?url=*.%s&fl=url&page=%s&limit=10000' % (host, page), verify=False).text
|
||||
if response.startswith('<!DOCTYPE html>'):
|
||||
return ([], False, 'commoncrawl')
|
||||
urls = response.split('\n')
|
||||
|
||||
@@ -11,9 +11,11 @@ re_inputs = re.compile(r'''(?i)<(?:input|textarea)[^>]+?(?:id|name)=["']?([^"'\s
|
||||
re_empty_vars = re.compile(r'''(?:[;\n]|\bvar|\blet)(\w+)\s*=\s*(?:['"`]{1,2}|true|false|null)''')
|
||||
re_map_keys = re.compile(r'''['"](\w+?)['"]\s*:\s*['"`]''')
|
||||
|
||||
|
||||
def is_not_junk(param):
|
||||
return (re_not_junk.match(param) is not None)
|
||||
|
||||
|
||||
def heuristic(raw_response, wordlist):
|
||||
words_exist = False
|
||||
potential_params = []
|
||||
|
||||
@@ -2,6 +2,7 @@ import requests
|
||||
|
||||
from urllib.parse import urlparse
|
||||
|
||||
|
||||
def otx(host, page):
|
||||
these_params = set()
|
||||
data = requests.get('https://otx.alienvault.com/api/v1/indicators/hostname/%s/url_list?limit=50&page=%d' % (host, page+1), verify=False).json()
|
||||
|
||||
@@ -2,6 +2,7 @@ import requests
|
||||
|
||||
from urllib.parse import urlparse
|
||||
|
||||
|
||||
def wayback(host, page):
|
||||
payload = {
|
||||
'url': host,
|
||||
|
||||
80
arjun/plugins/wl.py
Normal file
80
arjun/plugins/wl.py
Normal file
@@ -0,0 +1,80 @@
|
||||
def detect_casing(string):
|
||||
"""Detect the casing style and delimiter of given string."""
|
||||
delimiter = ""
|
||||
casing = ""
|
||||
|
||||
if string.islower():
|
||||
casing = "l"
|
||||
elif string.isupper():
|
||||
casing = "u"
|
||||
else:
|
||||
casing = casing = "c" if string[0].islower() else "p"
|
||||
|
||||
if "-" in string:
|
||||
delimiter = "-"
|
||||
elif "_" in string:
|
||||
delimiter = "_"
|
||||
elif "." in string:
|
||||
delimiter = "."
|
||||
|
||||
return delimiter, casing
|
||||
|
||||
|
||||
def transform(parts, delimiter, casing):
|
||||
"""Combine list of strings to form a string with given casing style."""
|
||||
if len(parts) == 1:
|
||||
if casing == "l":
|
||||
return parts[0].lower()
|
||||
elif casing == "u":
|
||||
return parts[0].upper()
|
||||
return parts[0]
|
||||
|
||||
result = []
|
||||
for i, part in enumerate(parts):
|
||||
if casing == "l":
|
||||
transformed = part.lower()
|
||||
elif casing == "u":
|
||||
transformed = part.upper()
|
||||
elif casing == "c":
|
||||
if i == 0:
|
||||
transformed = part.lower()
|
||||
else:
|
||||
transformed = part.lower().title()
|
||||
else: # casing == "p"
|
||||
transformed = part.lower().title()
|
||||
|
||||
result.append(transformed)
|
||||
|
||||
return delimiter.join(result)
|
||||
|
||||
|
||||
def handle(text):
|
||||
"""Break down a string into array of 'words'."""
|
||||
if "-" in text:
|
||||
return text.split("-")
|
||||
elif "_" in text:
|
||||
return text.split("_")
|
||||
elif "." in text:
|
||||
return text.split(".")
|
||||
|
||||
if not text.islower() and not text.isupper():
|
||||
parts = []
|
||||
temp = ""
|
||||
for char in text:
|
||||
if not char.isupper():
|
||||
temp += char
|
||||
else:
|
||||
if temp:
|
||||
parts.append(temp)
|
||||
temp = char
|
||||
if temp:
|
||||
parts.append(temp)
|
||||
return parts
|
||||
|
||||
return [text]
|
||||
|
||||
|
||||
def covert_to_case(string, delimiter, casing):
|
||||
"""Process input stream and write transformed text to output stream."""
|
||||
parts = handle(string)
|
||||
return transform(parts, delimiter, casing)
|
||||
Reference in New Issue
Block a user