Skip to content

Commit f6181db

Browse files
authored
Merge pull request #6 from flashnuke/feat/more_bypass_methods
Feat/more bypass methods
2 parents 86673db + 3bb8fc3 commit f6181db

File tree

5 files changed

+67
-98
lines changed

5 files changed

+67
-98
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ The results are then contained inside a queue object and used for further scans.
3939

4040
Iterates over a wordlist and probes (in a brute manner) different endpoints by appending the words to the target hostname. </br>
4141
A result is considered successful if the request status code is one of the following: `200`, `301`, `302`. If a forbidden status code is returned (`403`) and `403bypass` scan is enabled, further probing takes place where different kind of methods are attempted in order to bypass the forbidden status. Those attempts are also considered as success only if they manage to retrieve one of the aformentioned successful status code. <br>
42-
42+
</br>
43+
The output in the progress log (and the results file) contains the status code and the page content size.
4344
* In order to use a custom wordlist, "--set-contentscan-wl" argument should be passed, followed by the path
4445
* The default wordlist used here is dirbuster's `directory-list-2.3-medium.txt` list, which is also located under `/usr/share/wordlists/dirbuster`
4546

@@ -48,7 +49,7 @@ A result is considered successful if the request status code is one of the follo
4849
Probes a url using different methods in order to bypass a `403` forbidden status code. </br> This scan is a subscan and should only be invoked by `Content Scan`.
4950

5051
* If listing a custom scan list rather than using the `-sA` option, this scan should be listed as well, otherwise it would be disabled
51-
* Most of the methods in this scanner were converted from another known GitHub repo, credit goes to https://github.com/iamj0ker/bypass-403
52+
* Most of the methods in this scanner were converted from 2 other known GitHub repos, credit goes to https://github.com/iamj0ker/bypass-403 and https://github.com/yunemse48/403bypasser
5253

5354
### NMAP Scan (`nmap`)
5455

scanners/base_scanner.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,14 +303,14 @@ def _setup_session(self):
303303

304304
self._session = requests.Session()
305305

306-
def _make_request(self, method: str, url: str, headers=None, **kwargs):
306+
def _make_request(self, method: str, url: str, headers=None, timeout=None, **kwargs):
307307
if not self._session_refresh_count % self._session_refresh_interval:
308308
self._setup_session()
309309
if not headers:
310310
headers = dict()
311311
headers.update(self._default_headers)
312312

313-
res = self._session.request(method=method, url=url, headers=headers, timeout=self.request_timeout,
313+
res = self._session.request(method=method, url=url, headers=headers, timeout=timeout or self.request_timeout,
314314
verify=False, **kwargs)
315315

316316
if res.status_code == ScannerDefaultParams.LimitRateSCode:

scanners/bypass_403.py

Lines changed: 57 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from .base_scanner import Scanner
88
from .utils import *
9-
from typing import Any, Dict, List
9+
from typing import Any, Dict, List, Tuple
1010

1111

1212
# --------------------------------------------------------------------------------------------------------------------
@@ -16,6 +16,7 @@
1616
# Ⓒ Ⓒ
1717
# Ⓒ This module was written in Python in order to integrate better with WebRecon, most methods were taken from Ⓒ
1818
# Ⓒ from this repo -> https://github.com/iamj0ker/bypass-403 Ⓒ
19+
# Ⓒ and this repo -> https://github.com/yunemse48/403bypasser Ⓒ
1920
# Ⓒ Ⓒ
2021
#
2122
# --------------------------------------------------------------------------------------------------------------------
@@ -28,6 +29,17 @@ class Bypass403(Scanner):
2829
_SUPPORTS_CACHE = False
2930
_FOUND = 0
3031

32+
_HOST_HEADERS = ["X-Custom-IP-Authorization", "X-Forwarded-For",
33+
"X-Forward-For", "X-Remote-IP", "X-Originating-IP",
34+
"X-Remote-Addr", "X-Client-IP", "X-Real-IP",
35+
"X-Host"]
36+
37+
_LHOST_NICKNAMES = ["localhost", "localhost:80", "localhost:443",
38+
"127.0.0.1", "127.0.0.1:80", "127.0.0.1:443",
39+
"2130706433", "0x7F000001", "0177.0000.0000.0001",
40+
"0", "127.1", "10.0.0.0", "10.0.0.1", "172.16.0.0",
41+
"172.16.0.1", "192.168.1.0", "192.168.1.1"]
42+
3143
def __init__(self, target_keyword, *args, **kwargs):
3244
self.target_keyword = target_keyword.strip("/")
3345

@@ -36,120 +48,75 @@ def __init__(self, target_keyword, *args, **kwargs):
3648

3749
def try_bypass(self) -> dict:
3850
results = collections.defaultdict(list)
51+
original_path = f"{self.target_url}/{self.target_keyword}"
52+
self._log_progress(f"in progress -> {self.target_keyword}")
3953

4054
# methods
4155

42-
req_path = f"{self.target_url}/{self.target_keyword}"
43-
results[self.send_request("GET", req_path)].append(f"GET {req_path}")
44-
45-
req_path = f"{self.target_url}/{self.target_keyword}"
46-
headers = {"Content-Length": "0"}
47-
results[self.send_request("POST", req_path, headers=headers)].append(f"POST {req_path} -H 'Content-Length: 0'")
48-
49-
req_path = f"{self.target_url}/{self.target_keyword}"
50-
headers = {"Content-Length": "0"}
51-
results[self.send_request("PUT", req_path, headers=headers)].append(f"PUT {req_path} -H 'Content-Length: 0'")
52-
53-
req_path = f"{self.target_url}/{self.target_keyword}"
54-
results[self.send_request("TRACE", req_path)].append(f"TRACE {req_path}")
55-
56-
req_path = f"{self.target_url}/{self.target_keyword}"
57-
results[self.send_request("DELETE", req_path)].append(f"DELETE {req_path}")
56+
for method in ["GET", "POST", "PUT", "TRACE", "DELETE"]:
57+
scode, size = self.send_request(method, original_path)
58+
results[scode].append(f"size {size}\t\t{method} {original_path}")
5859

5960
# encoding / path traversal
6061

61-
req_path = f"{self.target_url}/%2e/{self.target_keyword}"
62-
results[self.send_request("GET", req_path)].append(f"GET {req_path}")
63-
64-
req_path = f"{self.target_url}/{self.target_keyword}/."
65-
results[self.send_request("GET", req_path)].append(f"GET {req_path}")
66-
67-
req_path = f"{self.target_url}//{self.target_keyword}//"
68-
results[self.send_request("GET", req_path)].append(f"GET {req_path}")
69-
70-
req_path = f"{self.target_url}/./{self.target_keyword}/./"
71-
results[self.send_request("GET", req_path)].append(f"GET {req_path}")
72-
73-
req_path = f"{self.target_url}/{self.target_keyword}..;/"
74-
results[self.send_request("GET", req_path)].append(f"GET {req_path}")
75-
76-
req_path = f"{self.target_url}/{self.target_keyword};/"
77-
results[self.send_request("GET", req_path)].append(f"GET {req_path}")
78-
79-
req_path = f"{self.target_url}/{self.target_keyword}%20"
80-
results[self.send_request("GET", req_path)].append(f"GET {req_path}")
81-
82-
req_path = f"{self.target_url}/{self.target_keyword}%09"
83-
results[self.send_request("GET", req_path)].append(f"GET {req_path}")
84-
85-
req_path = f"{self.target_url}/{self.target_keyword}?"
86-
results[self.send_request("GET", req_path)].append(f"GET {req_path}")
87-
88-
req_path = f"{self.target_url}/{self.target_keyword}#"
89-
results[self.send_request("GET", req_path)].append(f"GET {req_path}")
90-
91-
req_path = f"{self.target_url}/{self.target_keyword}/*"
92-
results[self.send_request("GET", req_path)].append(f"GET {req_path}")
62+
for req_path in [f"{self.target_url}/%2e/{self.target_keyword}", f"{self.target_url}/{self.target_keyword}/.",
63+
f"{self.target_url}//{self.target_keyword}//", f"{self.target_url}/./{self.target_keyword}/./",
64+
f"{self.target_url}/{self.target_keyword}..;/", f"{self.target_url}/{self.target_keyword};/",
65+
f"{self.target_url}/{self.target_keyword}%20", f"{self.target_url}/{self.target_keyword}%09",
66+
f"{self.target_url}/{self.target_keyword}?", f"{self.target_url}/{self.target_keyword}#",
67+
f"{self.target_url}/{self.target_keyword}/*"]:
68+
scode, size = self.send_request("GET", req_path)
69+
results[scode].append(f"size {size}\t\tGET {req_path}")
9370

9471
# file extensions
9572

96-
req_path = f"{self.target_url}/{self.target_keyword}.html"
97-
results[self.send_request("GET", req_path)].append(f"GET {req_path}")
98-
99-
req_path = f"{self.target_url}/{self.target_keyword}.php"
100-
results[self.send_request("GET", req_path)].append(f"GET {req_path}")
101-
102-
req_path = f"{self.target_url}/{self.target_keyword}.json"
103-
results[self.send_request("GET", req_path)].append(f"GET {req_path}")
73+
for file_ext in ["html", "php", "json"]:
74+
req_path = f"{original_path}.{file_ext}"
75+
scode, size = self.send_request("GET", req_path)
76+
results[scode].append(f"size {size}\t\tGET {req_path}\t\tsize {size}")
10477

10578
# headers
10679

107-
req_path = f"{self.target_url}/{self.target_keyword}"
108-
headers = {"X-Original-URL": self.target_keyword}
109-
results[self.send_request("GET", req_path,
110-
headers=headers)].append(f"GET {req_path} -H 'X-Original-URL: {self.target_keyword}'")
111-
112-
req_path = f"{self.target_url}/{self.target_keyword}"
113-
headers = {"X-Custom-IP-Authorization": "127.0.0.1"}
114-
results[self.send_request("GET", req_path,
115-
headers=headers)].append(f"GET {req_path} -H 'X-Custom-IP-Authorization: 127.0.0.1'")
116-
117-
req_path = f"{self.target_url}/{self.target_keyword}"
118-
headers = {"X-Forwarded-For": "http://127.0.0.1"}
119-
results[self.send_request("GET", req_path,
120-
headers=headers)].append(f"GET {req_path} -H 'X-Forwarded-For: http://127.0.0.1'")
121-
122-
req_path = f"{self.target_url}/{self.target_keyword}"
123-
headers = {"X-Forwarded-For": "127.0.0.1:80"}
124-
results[self.send_request("GET", req_path,
125-
headers=headers)].append(f"GET {req_path} -H 'X-Forwarded-For: 127.0.0.1:80'")
80+
for header in Bypass403._HOST_HEADERS:
81+
for host_nickname in Bypass403._LHOST_NICKNAMES:
82+
headers = {header: host_nickname}
83+
scode, size = self.send_request("GET", original_path, headers=headers)
84+
results[scode].append(f"size {size}\t\tGET {original_path} -H {header}: {host_nickname}")
12685

12786
req_path = f"{self.target_url}"
12887
headers = {"X-rewrite-url": self.target_keyword}
129-
results[self.send_request("GET", req_path,
130-
headers=headers)].append(f"GET {req_path} -H 'X-rewrite-url: {self.target_keyword}'")
88+
scode, size = self.send_request("GET", req_path, headers=headers)
89+
results[scode].append(f"size {size}\t\tGET {req_path} -H 'X-rewrite-url: {self.target_keyword}'")
90+
91+
req_path = f"{self.target_url}"
92+
headers = {"X-Original-URL": self.target_keyword}
93+
scode, size = self.send_request("GET", req_path, headers=headers)
94+
results[scode].append(f"size {size}\t\tGET {req_path} -H 'X-Original-URL: {self.target_keyword}'")
13195

132-
req_path = f"{self.target_url}/{self.target_keyword}"
133-
headers = {"X-Host": "127.0.0.1"}
134-
results[self.send_request("GET", req_path, headers=headers)].append(f"GET {req_path} -H 'X-Host: 127.0.0.1'")
96+
headers = {"Content-Length": "0"}
97+
scode, size = self.send_request("POST", original_path, headers=headers)
98+
results[scode].append(f"size {size}\t\tPOST {original_path} -H 'Content-Length: 0'")
99+
100+
headers = {"Content-Length": "0"}
101+
scode, size = self.send_request("PUT", original_path, headers=headers)
102+
results[scode].append(f"size {size}\t\tPUT {original_path} -H 'Content-Length: 0'")
135103

136104
return results
137105

138-
def send_request(self, method, path, headers=None) -> int:
139-
response = 0
140-
time.sleep(self.request_cooldown)
106+
def send_request(self, method, path, headers=None) -> Tuple[int, int]: # returns status_code, size
107+
time.sleep(0.25 * self.request_cooldown)
141108
try:
142109
response = self._make_request(method=method, url=path, headers=headers,
143-
allow_redirects=True).status_code
110+
allow_redirects=True, timeout=0.5 * self.request_timeout)
144111
except (requests.exceptions.ConnectionError, requests.exceptions.ConnectTimeout,
145112
requests.exceptions.ReadTimeout, HTTPError):
146-
pass
113+
return 0, 0
147114
except requests.exceptions.TooManyRedirects:
148115
self._log_exception(requests.exceptions.TooManyRedirects.__name__, abort=False)
149-
return ScannerDefaultParams.TooManyRedirectsSCode
150-
except Exception as exc: # error -> return 0
151-
pass
152-
return response
116+
return ScannerDefaultParams.TooManyRedirectsSCode, 0
117+
except Exception as exc:
118+
return 0, 0
119+
return response.status_code, len(response.text)
153120

154121
def _start_scanner(self, results_filename=None) -> Dict[int, List[str]]:
155122
success_results = dict()

scanners/content_scanner.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,16 @@ def single_bruter(self):
7575

7676
if scode in ScannerDefaultParams.SuccessStatusCodes or \
7777
scode == ScannerDefaultParams.ForbiddenSCode:
78-
self.ret_results[scode].append(url)
79-
self._log_progress(f"{path} -> [{scode}]")
78+
res_size = len(response.text)
79+
self.ret_results[scode].append(f"size {res_size}\t\t{url}")
80+
self._log_progress(f"{path} -> [{scode}, {res_size}]")
8081
found_any = True
8182

8283
except (requests.exceptions.ConnectionError, requests.exceptions.ConnectTimeout,
8384
requests.exceptions.ReadTimeout, HTTPError):
8485
continue
8586
except requests.exceptions.TooManyRedirects:
86-
self.ret_results[ScannerDefaultParams.TooManyRedirectsSCode].append(url)
87+
self.ret_results[ScannerDefaultParams.TooManyRedirectsSCode].append(f"size 0\t\t{url}")
8788
self._log_progress(f"{path} -> [{ScannerDefaultParams.TooManyRedirectsSCode}]")
8889
found_any = True
8990
except Exception as exc:

scanners/utils/default_values.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class ScannerDefaultParams(_ExtendedEnum):
104104
LimitRateSCode = 429
105105
TooManyRedirectsSCode = 301
106106
SuccessStatusCodes = [200, 301, 302]
107-
ThreadCount = 8
107+
ThreadCount = 16
108108

109109

110110
class WordlistDefaultPath(_ExtendedEnum):

0 commit comments

Comments
 (0)