Skip to content

Commit 68bfeb3

Browse files
feat: create optional redirects in burpference scanner (#13)
1 parent c5afa88 commit 68bfeb3

1 file changed

Lines changed: 65 additions & 29 deletions

File tree

burpference/scanner.py

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
JTextField,
1111
ButtonGroup,
1212
JRadioButton,
13+
JCheckBox,
1314
)
1415
from java.awt import BorderLayout, FlowLayout, Dimension
1516
from java.lang import Short
@@ -112,6 +113,13 @@ def create_scanner_tab(self):
112113
target_panel.add(type_panel)
113114
target_panel.add(target_label)
114115
target_panel.add(self._target_input)
116+
117+
# Add redirect checkbox after target input
118+
self.follow_redirects = JCheckBox("Follow Redirects", True)
119+
self.follow_redirects.setBackground(self.DARK_BACKGROUND)
120+
self.follow_redirects.setForeground(self.DREADNODE_ORANGE)
121+
target_panel.add(self.follow_redirects)
122+
115123
target_panel.setMaximumSize(Dimension(Short.MAX_VALUE, 35))
116124

117125
# System prompt panel
@@ -368,38 +376,66 @@ def analyze_url(self, url):
368376
if not re.match(r"^https?://", url):
369377
url = "http://" + url
370378

371-
req = urllib2.Request(url)
372-
response = urllib2.urlopen(req)
373-
374-
# Gather information about the target
375-
headers = dict(response.info().items())
376-
content = response.read()
379+
opener = urllib2.build_opener()
380+
if not self.follow_redirects.isSelected():
381+
# Don't follow redirects if checkbox is unchecked
382+
opener.handler_order = dict(
383+
[(h, i) for i, h in enumerate(opener.handlers)]
384+
)
385+
no_redirect_handler = urllib2.HTTPRedirectHandler()
386+
no_redirect_handler.max_redirections = 0
387+
opener.handlers = [
388+
h
389+
for h in opener.handlers
390+
if not isinstance(h, urllib2.HTTPRedirectHandler)
391+
]
377392

378-
security_info = {
379-
"url": url,
380-
"status_code": response.getcode(),
381-
"headers": headers,
382-
"server_info": headers.get("server", "Unknown"),
383-
"security_headers": {
384-
"x-frame-options": headers.get("x-frame-options", "Not Set"),
385-
"content-security-policy": headers.get(
386-
"content-security-policy", "Not Set"
387-
),
388-
"strict-transport-security": headers.get(
389-
"strict-transport-security", "Not Set"
390-
),
391-
"x-xss-protection": headers.get("x-xss-protection", "Not Set"),
392-
"x-content-type-options": headers.get(
393-
"x-content-type-options", "Not Set"
394-
),
395-
},
396-
"response_size": len(content),
397-
}
398-
399-
return security_info
393+
req = urllib2.Request(url)
394+
try:
395+
response = opener.open(req)
396+
final_url = response.geturl() # Get final URL after redirects
397+
398+
# Gather information about the target
399+
headers = dict(response.info().items())
400+
content = response.read()
401+
402+
security_info = {
403+
"initial_url": url,
404+
"final_url": final_url,
405+
"redirected": final_url != url,
406+
"status_code": response.getcode(),
407+
"headers": headers,
408+
"server_info": headers.get("server", "Unknown"),
409+
"security_headers": {
410+
"x-frame-options": headers.get("x-frame-options", "Not Set"),
411+
"content-security-policy": headers.get(
412+
"content-security-policy", "Not Set"
413+
),
414+
"strict-transport-security": headers.get(
415+
"strict-transport-security", "Not Set"
416+
),
417+
"x-xss-protection": headers.get("x-xss-protection", "Not Set"),
418+
"x-content-type-options": headers.get(
419+
"x-content-type-options", "Not Set"
420+
),
421+
},
422+
"response_size": len(content),
423+
}
424+
425+
return security_info
426+
427+
except urllib2.HTTPError as e:
428+
# Handle HTTP errors (like 301, 302 etc) when not following redirects
429+
security_info = {
430+
"initial_url": url,
431+
"error": "HTTP Error %d: %s" % (e.code, e.reason),
432+
"status_code": e.code,
433+
"headers": dict(e.headers.items()),
434+
}
435+
return security_info
400436

401437
except Exception as e:
402-
self._scanner_output.setText("Error analyzing URL: {str(e)}")
438+
self._scanner_output.setText("Error analyzing URL: %s" % str(e))
403439
return None
404440

405441
def load_prompt_template(self, is_openapi=False):

0 commit comments

Comments
 (0)