├── README.md
└── plugin.py
/README.md:
--------------------------------------------------------------------------------
1 | # burp-xss-sql-plugin
2 |
3 | Publishing plugin which I used for years which helped me to find several bugbounty-worthy XSSes, OpenRedirects and SQLi.
4 |
5 | __HTML Inj__: Special symbols are checked one-by-one if they appear in output. WAF/base64encoding/location/content-type/etc detections.
6 |
7 | __SQL Inj__: All parameters are transfered through SQLMap API to host, which in used for asynchronous scanning.
8 |
9 | __Tip__: Change Burp's Active Scan scope so it will automatically append new HTTP requests into queue, e.g.:
10 |
11 | ```
12 | Host: bugbounty.com
13 | File: (? $task) {
24 | $task_data = json_decode(file_get_contents("http://0.0.0.0:8775/scan/".$id."/data"), true);
25 | if(count($task_data['data']) > 0)
26 | echo "[".$id."]
SQL Inj!
";
27 | //else echo "[".$id."] None...
";
28 | }
29 | }
30 |
31 | ?>
32 | ```
33 |
--------------------------------------------------------------------------------
/plugin.py:
--------------------------------------------------------------------------------
1 | from burp import IBurpExtender, IScanIssue, IScannerCheck, IHttpListener, IProxyListener, IScannerListener, IExtensionStateListener
2 | from java.io import PrintWriter
3 | from java.lang import RuntimeException
4 | from uuid import uuid4
5 | import urllib2
6 | import array
7 | import re
8 | import json
9 | import hashlib
10 | import os.path
11 | import string
12 | import random
13 |
14 | class BurpExtender(IBurpExtender, IScannerCheck, IHttpListener, IProxyListener, IScannerListener, IExtensionStateListener):
15 |
16 | def registerExtenderCallbacks(self, callbacks):
17 |
18 | global burp_callbacks
19 | burp_callbacks = callbacks
20 | global burp_helpers
21 | burp_helpers = burp_callbacks.getHelpers()
22 | burp_callbacks.setExtensionName("BugBountyPlugin")
23 |
24 | self.stdout = PrintWriter(burp_callbacks.getStdout(), True)
25 |
26 | self.println("SQL/XSS custom plugin (c) @httpsonly")
27 |
28 | burp_callbacks.registerScannerCheck(self)
29 | burp_callbacks.registerProxyListener(self)
30 | return
31 |
32 | def doActiveScan(self, baseRequestResponse, insertionPoint):
33 | textIssue = ""
34 | tags = ""
35 | doSqlmap = 1
36 | name = insertionPoint.getInsertionPointName()
37 | value = insertionPoint.getBaseValue()
38 | if re.search(r'^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$', value) is not None:
39 | doSqlmap = 0
40 | #textIssue = "Input parameter '"+name+"' is Base64-encoded
"
41 | if re.search(r'(?i)(.*?)http[s]*:\/\/(.*?)', value) is not None:
42 | doSqlmap = 0
43 | textIssue = "Input parameter '"+name+"' has http(s)://
"
44 | if re.search(r'(?i)(.*?)<\?xml(.*?)', value) is not None:
45 | doSqlmap = 0
46 | textIssue = textIssue + "Input parameter '"+name+"' has <?xml
"
47 | if doSqlmap == 1:
48 | #sqlmap_host = '10.0.70.51'
49 | sqlmap_host = 'mydomain.com'
50 | reqHeaders = burp_helpers.bytesToString(baseRequestResponse.getRequest())
51 | referer = None
52 | cookie = None
53 | postdata = None
54 | reqInfo = burp_helpers.analyzeRequest(baseRequestResponse)
55 | url = str(reqInfo.getUrl())
56 | if re.search(r'(?i)Cookie: (.*?)[\r|\n]', reqHeaders) is not None:
57 | cookie = re.search(r'(?i)Cookie: (.*?)[\r|\n]', reqHeaders).group(1)
58 | if re.search(r'[\r|\n]{2}(.*?)$', reqHeaders) is not None:
59 | postdata = re.search(r'[\r|\n]{2}(.*?)$', reqHeaders).group(1)
60 | #SQLMap API
61 | try:
62 | req = urllib2.Request('http://'+sqlmap_host+':8775/task/new')
63 | resp = json.load(urllib2.urlopen(req))
64 | if resp['success'] == True and resp['taskid']:
65 | sqlitask = resp['taskid']
66 | sqliopts = {'delay': 0, 'risk': 1, 'timeout': 30, 'level': 1, 'answers': 'crack=N,dict=N', 'cookie': cookie, 'threads': 1, 'url': url, 'referer': referer, 'retries': 3, 'timeSec': 5, 'getBanner': True, 'data': postdata, 'timeSec': 5}
67 | try:
68 | req = urllib2.Request('http://'+sqlmap_host+':8775/option/' + sqlitask + '/set')
69 | req.add_header('Content-Type', 'application/json')
70 | resp = json.load(urllib2.urlopen(req, json.dumps(sqliopts)))
71 | if resp['success'] == True:
72 | sqliopts = {'url': url}
73 | try:
74 | checkreq = urllib2.Request('http://'+sqlmap_host+':8775/option/' + sqlitask + '/list')
75 | checkresp = json.load(urllib2.urlopen(checkreq))
76 | except:
77 | print 'Failed to get list of options from SQLMap API\n'
78 | try:
79 | req = urllib2.Request('http://'+sqlmap_host+':8775/scan/' + sqlitask + '/start')
80 | req.add_header('Content-Type', 'application/json')
81 | resp = json.load(urllib2.urlopen(req, json.dumps(sqliopts)))
82 | if resp['success'] == True:
83 | print 'Started SQLMap Scan on Task ' + sqlitask +'\n'
84 | else:
85 | print 'Failed to start SQLMap Scan for Task: ' + sqlitask + '\n'
86 | except:
87 | print 'Failed to start SQLMap Scan for Task: ' + sqlitask + '\n'
88 | else:
89 | print 'Failed to set options on SQLMap Task: ' + sqlitask + '\n'
90 | except:
91 | print 'Failed to set options on SQLMap Task: ' + sqlitask + '\n'
92 | else:
93 | print 'SQLMap task creation failed\n'
94 | except:
95 | print 'SQLMap task creation failed\n'
96 | score = 0
97 | flag1 = 0
98 | attack1 = burp_callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), insertionPoint.buildRequest(burp_helpers.stringToBytes("yyyyyyyyy")))
99 | response1 = attack1.getResponse()
100 | response_str1 = burp_helpers.bytesToString(response1)
101 | # if re.search(r'[\r|\n](?i)(Content-type:[\s]*application\/(?!xml)(.*?))[\r|\n]', response_str1) is not None:
102 | # return None
103 | # break
104 | #m = re.search(r'<([a-zA-Z0-9]+)[^>]*([^<]*?)yyyyyyyyy', response_str1)
105 | # if m.group(1) is not None:
106 | # textIssue = textIssue + "Input parameter gets into tag '"+m.group(1)+"'
"
107 | # flag1 = 1
108 | # if m.group(1) == 'script': score = 4
109 | if re.search(r'(?is)(