├── BurpParamFlagger.py
├── README.md
├── issue.png
├── paramname.png
└── value.png
/BurpParamFlagger.py:
--------------------------------------------------------------------------------
1 | from burp import IBurpExtender
2 | from burp import IScannerCheck
3 | from burp import IScanIssue
4 | from array import array
5 | import sys
6 |
7 |
8 | ssrfParamChecks = ["icon_url","url","uri","authorization_url","redirect_uri","redirect_url","redirect","referrer","origin","location","return_url","link","starturl","return","preview","previewurl","preview_url","loc","path","template","forward","goto","fetch","domain","check","dest","continue","next","site","html","callback","returnto","return_to","feed","host","to","out","view","show","open","viewurl","go","fromurl","from","from_url","fromuri","from_uri","redir","website","profileurl","profile_url","icon","avatar","targeturl","target_url","start","baseurl","oembed"]
9 | lfiParamChecks = ["samplefile","file","html_file","src","source","upload","download","content","template","attachment","image","path","page","location","loc","include","dir","document","folder","root","pg","p","style","pdf","php_path","doc","icon","directory"]
10 | fileExtensions = [".js", ".svg", ".jpeg", ".jpg", ".csv", ".xml", ".html", ".php", ".asp", ".aspx", ".png", ".ico", ".json", ".pdf", ".css", ".jsp", ".zip", ".gz", ".swf", ".woff"]
11 | webRef = ["https", "http", "www"]
12 |
13 | class BurpExtender(IBurpExtender, IScannerCheck):
14 |
15 | def registerExtenderCallbacks(self, callbacks):
16 | self._callbacks = callbacks
17 | self._helpers = callbacks.getHelpers()
18 |
19 | callbacks.setExtensionName("BurpParamFlagger")
20 |
21 | sys.stdout = callbacks.getStdout()
22 | sys.stderr = callbacks.getStderr()
23 |
24 | callbacks.registerScannerCheck(self)
25 |
26 | def _check_params(self, reqInfo):
27 | findings = {}
28 | params = reqInfo.getParameters()
29 | url = reqInfo.getUrl()
30 | for param in params:
31 | name = param.getName()
32 | value = param.getValue()
33 |
34 | if name.lower() in ssrfParamChecks or "_" + name.lower() in ssrfParamChecks or value.lower().startswith(tuple(webRef)):
35 | if "SSRF" not in findings.keys():
36 | findings["SSRF"] = []
37 | findings["SSRF"].append(name)
38 |
39 | if name.lower() in lfiParamChecks or "_" + name.lower() in lfiParamChecks or value.lower().endswith(tuple(fileExtensions)):
40 | if "LFI" not in findings.keys():
41 | findings["LFI"] = []
42 | findings["LFI"].append(name)
43 |
44 | return findings
45 |
46 | def doPassiveScan(self, baseRequestResponse):
47 | if self._callbacks.isInScope(self._helpers.analyzeRequest(baseRequestResponse).getUrl()):
48 | issues = []
49 |
50 | print(baseRequestResponse.getUrl())
51 | analyzed = self._helpers.analyzeRequest(baseRequestResponse.getHttpService(), baseRequestResponse.getRequest())
52 | matches = self._check_params(analyzed)
53 |
54 | if len(matches) == 0:
55 | return None
56 |
57 | print(matches)
58 | print(type(matches))
59 | print(matches.keys())
60 | req = baseRequestResponse.getRequest()
61 |
62 | for category, params in matches.items():
63 | for param in params:
64 | start = self._helpers.indexOf(req,
65 | param + "=", True, 0, len(req))
66 | offset = array('i', [0, 0])
67 | offset[0] = start
68 | offset[1] = start + len(param + "=")
69 |
70 | issues.append(ScanIssue(
71 | baseRequestResponse.getHttpService(),
72 | self._helpers.analyzeRequest(baseRequestResponse).getUrl(),
73 | [self._callbacks.applyMarkers(baseRequestResponse, [offset], None)],
74 | "Potential Target Parameter for {}".format(category),
75 | "The request has the parameter: {}
The name and/or value of this parameter indicates it may be a good place to test for {}.".format(param, category),
76 | "Information"))
77 | return issues
78 | else:
79 | print("Out of Scope")
80 | print(self._helpers.analyzeRequest(baseRequestResponse).getUrl())
81 |
82 |
83 | def consolidateDuplicateIssues(self, existingIssue, newIssue):
84 | if (existingIssue.getIssueName() == newIssue.getIssueName()) and (existingIssue.getIssueDetail() == newIssue.getIssueDetail()) and (existingIssue.getUrl() == newIssue.getUrl()):
85 | print("Duplicate")
86 | print(existingIssue.getIssueDetail())
87 | return -1
88 | return 0
89 |
90 | class ScanIssue (IScanIssue):
91 | def __init__(self, httpService, url, httpMessages, name, detail, severity):
92 | self._url = url
93 | self._name = name
94 | self._detail = detail
95 | self._severity = severity
96 | self._httpMessages = httpMessages
97 | self._httpService = httpService
98 |
99 | def getUrl(self):
100 | return self._url
101 |
102 | def getIssueName(self):
103 | return self._name
104 |
105 | def getIssueDetail(self):
106 | return self._detail
107 |
108 | def getSeverity(self):
109 | return self._severity
110 |
111 | def getConfidence(self):
112 | return "Certain"
113 |
114 | def getIssueBackground(self):
115 | return None
116 |
117 | def getRemediationBackground(self):
118 | return None
119 |
120 | def getRemediationDetail(self):
121 | return None
122 |
123 | def getIssueType(self):
124 | return 0
125 |
126 | def getHttpMessages(self):
127 | return self._httpMessages
128 |
129 | def getHttpService(self):
130 | return self._httpService
131 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BurpParamFlagger
2 |
3 | A Burp extension adding a passive scan check to flag parameters whose name or value may indicate a possible insertion point for SSRF or LFI.
4 |
5 | *Note:* I believe that Burp Pro is required to use this extension, since it adds onto the scanner functionality, which isn't included in the Community version.
6 |
7 | 
8 |
9 | The extension will look at both the **name** of a parameter and the **value** of that parameter and look for any common words or patterns indicating that it could be an insertion point for SSRF or LFI.
10 |
11 | For example, SSRF checks include looking for parameter names like 'redirect', 'url', or 'domain', as well as looking for values that look like a URL.
12 |
13 | LFI checks look for names like 'include', 'attach', or 'file', and look for values that have a file extension.
14 |
15 | A few basic examples:
16 |
17 | 
18 | 
19 |
20 |
21 | ## Installation
22 |
23 | Just clone the repo and load the extension into Burp: Go to the Extender tab, click 'Add', change the extension type to 'Python', provide the cloned BurpParamFlagger.py file, and follow the next prompts.
24 |
25 |
26 | ## Usage
27 |
28 | Once the extension is loaded, nothing more is needed. You should start seeing any flagged requests with your other scanner issues on the Dashboard.
29 |
--------------------------------------------------------------------------------
/issue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/allyomalley/BurpParamFlagger/e4aa3f0e906a9a961fac599ab43b20b09a61d0bc/issue.png
--------------------------------------------------------------------------------
/paramname.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/allyomalley/BurpParamFlagger/e4aa3f0e906a9a961fac599ab43b20b09a61d0bc/paramname.png
--------------------------------------------------------------------------------
/value.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/allyomalley/BurpParamFlagger/e4aa3f0e906a9a961fac599ab43b20b09a61d0bc/value.png
--------------------------------------------------------------------------------