class BurpExtender(IBurpExtender, IScannerListener, IContextMenuFactory, ActionListener, ITab, IHttpService, IScanIssue, IBurpExtenderCallbacks): def __init__(self): self.msgrel = False self.project = False self.projectId = None print("[+] Carregando GAT CORE Extension...") def registerExtenderCallbacks(self, callbacks): """ registrar classes """ self._callbacks = callbacks self._helpers = self._callbacks.getHelpers() self._callbacks.setExtensionName("GAT CORE Integration") self.gui_elements = self.build_gui() callbacks.customizeUiComponent(self.gui_elements) callbacks.addSuiteTab(self) self._callbacks.registerContextMenuFactory(self) self._callbacks.registerScannerListener(self) save_setting = self._callbacks.saveExtensionSetting save_setting('project_id', None) self.reload_config() print("[+] GAT CORE Extension carregado!") def newScanIssue(self, issue): print("[+] Issue encontrada (%s)" % issue.getIssueName()) return def actionTarget(self, event): print("*" * 80) self.fileId = [] requestResponses = self.invocation.getSelectedMessages() chosts, ihosts = self.countHostIssues(requestResponses) if self.project <= 1: panelinput = JPanel() panelinput.add(JLabel("Projeto ID: ")) projectq = JTextField(20) panelinput.add(projectq) result = JOptionPane.showOptionDialog( None, panelinput, "Qual projeto enviar Issues?", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, None, ["OK", "Sem projeto"], "OK") if result == -1: print("[-] Cancelado envio!") return if result == JOptionPane.OK_OPTION: self.project_id.setText(projectq.getText()) self.projectId = str(projectq.getText()) if not re.match('([0-9a-f]{24})', self.projectId): self.projectId = None mess = "Projeto Id formato inválido".decode("utf8") JOptionPane.showMessageDialog(None, mess, "Error", JOptionPane.ERROR_MESSAGE) return mess = "Sessão atual".decode("utf8") ever = JOptionPane.showOptionDialog( None, "Solicitar Id de Projeto novamente?", mess, JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, None, ["Nunca", "Sim"], "Sim") # let user select parameters for new session if ever == JOptionPane.OK_OPTION: self.project = 2 else: self.project = 1 for reqResp in requestResponses: url = reqResp.getHttpService() requestIssues = self._callbacks.getScanIssues(str(url)) listIssues = [] if requestIssues: if len(requestIssues) > 0: for i in requestIssues: scanissue = i if scanissue.getIssueName() not in ['']: sep = "<br><hr><br>" issue = {} issue['Tool_Type'] = "BURP" IssueType = scanissue.getIssueType() IssueName = scanissue.getIssueName() IssueCrit = scanissue.getSeverity() IssueConf = scanissue.getConfidence() protocol = scanissue.getHttpService().getProtocol() host = scanissue.getHttpService().getHost() IssuePath = i.getUrl().getPath() IssueDesc = scanissue.getIssueDetail() IssueDescBk = scanissue.getIssueBackground() IssueRecom = scanissue.getRemediationDetail() IssueRecomBk = scanissue.getRemediationBackground() if IssueType: issue['IssueType'] = scanissue.getIssueType() else: issue['IssueType'] = 0000 if IssueName: issue['DetailsFinding_Title'] = IssueName issue['Recomenation_Title'] = IssueName else: issue['DetailsFinding_Title'] = "No Issue name" issue['Recomenation_Title'] = "No Issue name" if "False positive" in IssueCrit: sTag = "False positive" IssueCrit = "" elif "Information" in IssueCrit: IssueCrit = "Informative" sTag = "" else: sTag = "" if IssueCrit: issue['Severity'] = IssueCrit else: issue['Severity'] = "Informative" issue['Web_Application_URI'] = "{}://{}".format( protocol, host) if IssuePath: issue['Web_Application_Path'] = IssuePath else: issue['Web_Application_Path'] = "/" if IssueConf: issue['fTag'] = IssueConf else: issue['fTag'] = " " issue['sTag'] = sTag if IssueDescBk is not None: issue['Description'] = IssueDescBk.replace( "\n", "") else: issue['Description'] = "" if IssueDesc is not None: issue['Description'] += "{}{}".format( sep, IssueDesc.replace("\n", "")) if IssueRecomBk is not None: issue['Recommendation'] = IssueRecomBk.replace( "\n", "") else: issue['Recommendation'] = IssueName if IssueRecom is not None: issue['Recommendation'] += "{}{}".format( sep, IssueRecom.replace("\n", "")) listIssues.append(issue) self.generateReportGat(listIssues) # iniciar threads print("[+] Thread(s) Iniciada(s)...") if self.project: print("[+] Enviando Issues para o Project Id: {}".format( self.projectId)) print("[+] Enviando {} host(s), total de {} Issue(s),\n".format( chosts, ihosts)) self.launchThread(self.sendIssues) def actionScanner(self): pass def createMenuItems(self, invocation): self.invocation = invocation context = invocation.getInvocationContext() if context in [invocation.CONTEXT_TARGET_SITE_MAP_TREE]: sendToGAT = JMenuItem("Enviar Issues para GAT CORE") # sendToGAT.setForeground(Color.ORANGE) FONT = sendToGAT.getFont() sendToGAT.setFont( Font(FONT.getFontName(), Font.BOLD, FONT.getSize())) sendToGAT.addActionListener(self.actionTarget) menuItems = ArrayList() menuItems.add(sendToGAT) return menuItems else: # TODO: add support for other tools pass def build_gui(self): """Construct GUI elements.""" Mpanel = JPanel() # Mpanel.setLayout(GridLayout(0, 3)) Mpanel.setLayout(BoxLayout(Mpanel, BoxLayout.X_AXIS)) panel = JPanel() panel.setLayout(None) Mpanel.add(Box.createVerticalGlue()) Mpanel.add(panel) Mpanel.add(Box.createVerticalGlue()) img = os.path.abspath("gat_logo_sticky.png") logo = JLabel(ImageIcon(img)) logo.setBounds(150, 40, 165, 49) save_btn = JButton('Salvar', actionPerformed=self.save_config) save_btn.setBounds(100, 240, 75, 30) save_btn.setPreferredSize(Dimension(75, 30)) limpar_btn = JButton('Limpar ID Projeto', actionPerformed=self.clsProjectId) limpar_btn.setBounds(250, 240, 150, 30) limpar_btn.setPreferredSize(Dimension(150, 30)) label_h = JLabel('API Url:') label_h.setHorizontalAlignment(SwingConstants.RIGHT) label_h.setBounds(0, 120, 95, 30) label_h.setPreferredSize(Dimension(100, 30)) self.host_api = JTextField(50) self.host_api.setBounds(100, 120, 300, 30) self.host_api.setPreferredSize(Dimension(250, 30)) label_a = JLabel('API Token:') label_a.setHorizontalAlignment(SwingConstants.RIGHT) label_a.setBounds(0, 160, 95, 30) label_a.setPreferredSize(Dimension(100, 30)) self.api_token = JTextField(50) self.api_token.setBounds(100, 160, 300, 30) self.api_token.setPreferredSize(Dimension(250, 30)) label_p = JLabel('Project ID:') label_p.setHorizontalAlignment(SwingConstants.RIGHT) label_p.setBounds(0, 200, 95, 30) label_p.setPreferredSize(Dimension(100, 30)) self.project_id = JTextField(50) self.project_id.setForeground(Color.orange) self.project_id.setBackground(Color.gray) self.project_id.setBounds(100, 200, 300, 30) self.project_id.setPreferredSize(Dimension(250, 30)) self.project_id.editable = False panel.add(logo) panel.add(label_h) panel.add(self.host_api) panel.add(label_a) panel.add(self.api_token) panel.add(label_p) panel.add(self.project_id) panel.add(limpar_btn) panel.add(save_btn) return Mpanel def save_config(self, _): """Save settings.""" url = self.host_api.getText() token = self.api_token.getText() if re.match('https?://', url): url = re.sub('https?://', '', url) if url[-1:] == "/": url = url[:-1] if re.match('^(?i)Bearer ', token): token = re.sub('^(?i)Bearer ', '', token) if not re.match( '([a-f\d]{8})-([a-f\d]{4})-([a-f\d]{4})-([a-f\d]{4})-([a-f\d]{12})', token): JOptionPane.showMessageDialog(None, "Formato de TOKEN invalido!", "Error", JOptionPane.ERROR_MESSAGE) return save_setting = self._callbacks.saveExtensionSetting save_setting('host_api', url) save_setting('api_token', token) self.msgrel = True self.reload_config() return def reload_config(self): """Reload settings.""" load_setting = self._callbacks.loadExtensionSetting host_api_url = load_setting('host_api') or '' host_api_token = load_setting('api_token') or '' # project_id = '' self.host_api.setText(host_api_url) self.api_token.setText(host_api_token) # self.project_id.setText(project_id) if self.msgrel: if self.host_api and self.api_token: JOptionPane.showMessageDialog( None, "API token, API url dados salvo\n ", "Informativo", JOptionPane.INFORMATION_MESSAGE) print("[+] API token, API url dados salvo") print("[+] Recarregue: GAT CORE Extension") return try: vapi = self.checkAuth() if vapi.status_code == 200: data = json.loads(vapi.text) print("[ ] Conectado: {}, {}".format(data['name'], data['email'])) # if self.msgrel: JOptionPane.showMessageDialog( None, "Conectado: {}, {}".format(data['name'], data['email']), "Informativo", JOptionPane.INFORMATION_MESSAGE) else: raise Exception("Status_Code({})".format(vapi.status_code)) except Exception as e: print("[-] GAT CORE Settings, erro ao conectar na API.") print("[-] Exception: {}".format(e)) return def getTabCaption(self): """Return the text to be displayed on the tab""" return "GAT CORE Settings" def getUiComponent(self): """Passes the UI to burp""" return self.gui_elements def generateReportGat(self, rows): quote = '"' Id = uuid.uuid4().hex self.fileId.append(Id) path = os.getcwd() folder = "\\exports\\" file_name = "{}{}{}.csv".format(path, folder, Id) with open(file_name, mode='w') as csv_file: fields = [ 'Tool_Type', 'IssueType', 'DetailsFinding_Title', 'Severity', 'Web_Application_URI', 'Web_Application_Path', 'fTag', 'sTag', 'Description', 'Recomenation_Title', 'Recommendation' ] writer = csv.DictWriter(csv_file, fieldnames=fields, quotechar=quote, quoting=csv.QUOTE_NONNUMERIC, lineterminator='\n') writer.writeheader() writer.writerows(rows) csv_file.close() return Id def sendIssues(self): for Id in self.fileId: print("[+] Processando ID: {}".format(Id)) path = os.getcwd() folder = "\\exports\\" file_name = "{}{}{}.csv".format(path, folder, Id) self.launchThread(self.requestAPI, arguments=file_name) def launchThread(self, targetFunction, arguments=None, retur=False): """Launches a thread against a specified target function""" if arguments: t = Thread(name='args', target=targetFunction, args=(arguments, )) else: t = Thread(name='no-args', target=targetFunction) t.setDaemon(True) t.start() if retur: r = t.join() return r def countHostIssues(self, requestResponses): count = 0 icount = 0 for reqResp in requestResponses: url = reqResp.getHttpService() requestIssues = self._callbacks.getScanIssues(str(url)) if requestIssues: if len(requestIssues) > 0: count += 1 for issue in requestIssues: icount += 1 return count, icount def requestAPI(self, filename): load_setting = self._callbacks.loadExtensionSetting api_uri = load_setting('host_api') or '' api_token = load_setting('api_token') or '' projectid = self.projectId name_csv = os.path.basename(filename) if projectid: resource = "/app/vulnerability/upload/api/Burp/{}".format( projectid) else: resource = "/app/vulnerability/upload/api/Burp" # print(resource) protocol = "http" if api_uri == "localhost" else "https" gatPoint = "{}://{}{}".format(protocol, api_uri, resource) try: dataList = [] api_url = URL(gatPoint) boundary = name_csv.replace(".csv", "") headers = ArrayList() headers.add('POST %s HTTP/1.1' % resource) headers.add('Host: %s' % api_uri) headers.add('Authorization: Bearer %s' % api_token) headers.add('Accept: application/json') headers.add( 'Content-type: multipart/form-data; boundary={}'.format( boundary)) dataList.append('--' + boundary) dataList.append( 'Content-Disposition: form-data; name=file; filename={}'. format(name_csv)) dataList.append('Content-Type: text/csv') dataList.append('') with open(filename) as f: dataList.append(f.read()) dataList.append('--' + boundary + '--') dataList.append('') body = '\r\n'.join(dataList) newBody = self._helpers.bytesToString(body) newRequest = self._helpers.buildHttpMessage(headers, newBody) requestInfo = self._helpers.analyzeRequest(newRequest) headers = requestInfo.getHeaders() response = self._callbacks.makeHttpRequest(api_url.getHost(), 443, True, newRequest) response_info = self._helpers.analyzeResponse(response) response_value = self._helpers.bytesToString( response)[response_info.getBodyOffset():].encode("utf-8") except Exception as e: print("[-] Falha arquivo/envio de Issues ID:{} - Error: {}".format( name_csv, e)) if response_info.getStatusCode() == 200: self.removeCSV(filename) print("[+] Success ID: {}".format(name_csv.replace(".csv", ""))) else: print("[-] Falhou o envio do ID: {} - code :{}".format( name_csv.replace(".csv", ""), response_info.getStatusCode())) if response_value: print("Error: {}".format(response_value)) JOptionPane.showMessageDialog(None, "Falhou o envio das Issues", "Error", JOptionPane.ERROR_MESSAGE) self.removeCSV(filename) def checkAuth(self): """ Validar api + token GAT """ load_setting = self._callbacks.loadExtensionSetting api_uri = load_setting('host_api') or '' api_token = load_setting('api_token') or '' resource = "/api/v1/me" protocol = "http" if api_uri == "localhost" else "https" gatPoint = "{}://{}{}".format(protocol, api_uri, resource) api_url = URL(gatPoint) headers = ArrayList() headers.add('GET %s HTTP/1.1' % resource) headers.add('Host: %s' % api_uri) headers.add('Authorization: Bearer %s' % api_token) headers.add('Content-Type: application/json') newRequest = self._helpers.buildHttpMessage(headers, None) requestInfo = self._helpers.analyzeRequest(newRequest) headers = requestInfo.getHeaders() response = self._callbacks.makeHttpRequest(api_url.getHost(), 443, True, newRequest) response_info = self._helpers.analyzeResponse(response) response_value = self._helpers.bytesToString( response)[response_info.getBodyOffset():].encode("utf-8") response = {} response['status_code'] = response_info.getStatusCode() response['text'] = response_value r = DotDict(response) return r def removeCSV(self, path): """ param <path> could either be relative or absolute. """ if os.path.isfile(path) or os.path.islink(path): os.remove(path) else: raise ValueError("file {} is not a file".format(path)) def clsProjectId(self, _): self.project_id.setText(None) self.project = False self.projectId = None JOptionPane.showMessageDialog( None, "Redefinido envio de Issues sem Projeto.", "Informativo", JOptionPane.INFORMATION_MESSAGE)
class BurpExtender(IBurpExtender, IContextMenuFactory, IHttpListener, ISessionHandlingAction, ITab): def registerExtenderCallbacks(self, callbacks): self._callbacks = callbacks self._helpers = callbacks.getHelpers() callbacks.setExtensionName("JC-AntiToken") callbacks.registerContextMenuFactory(self) # callbacks.registerHttpListener(self) callbacks.registerSessionHandlingAction(self) self.drawUI() def printcn(self, msg): print(msg.decode('utf-8').encode(sys_encoding)) def drawUI(self): # 最外层:垂直盒子,内放一个水平盒子+一个胶水 out_vBox_main = Box.createVerticalBox() # 次外层:水平盒子,使用说明 usage = u''' JC-AntiToken(简单防重放绕过) 适用场景:防重放的方式为,提前向一个页面发送请求取得token,替换到下一个页面中。 适用说明: 1. 请求头中Headers和Data的值必须是JSON字符串,如:{"var":"value"} 2. 左边tokenRegex的格式为: a. .*开头,.*结尾,用()括住要取出的token b. 如:.*,"token":"(.*?)".* 3. 右边tokenRegex的格式为: a. 需要三个(),第二个()括住要替换的token b. 如:(.*,"token":")(.*?)(".*) 详见:https://github.com/chroblert/JC-AntiToken ''' hBox_usage = Box.createHorizontalBox() jpanel_test = JPanel() jTextarea_usage = JTextArea() jTextarea_usage.setText(usage) jTextarea_usage.setRows(13) jTextarea_usage.setEditable(False) # jpanel_test.add(jTextarea_usage) hBox_usage.add(JScrollPane(jTextarea_usage)) # 次外层:水平盒子,内放两个垂直盒子 hBox_main = Box.createHorizontalBox() # 左垂直盒子 vBox_left = Box.createVerticalBox() # 右垂直盒子 vBox_right = Box.createVerticalBox() # 左垂直盒子内部:发送请求包拿token # URL标签 jlabel_url = JLabel(" URL: ") self.jtext_url = JTextField(generWidth) self.jtext_url.setMaximumSize(self.jtext_url.getPreferredSize()) hbox_url = Box.createHorizontalBox() hbox_url.add(jlabel_url) hbox_url.add(self.jtext_url) hglue_url = Box.createHorizontalGlue() hbox_url.add(hglue_url) # 请求方法标签 jlabel_reqMeth = JLabel("ReqMeth: ") self.jcombobox_reqMeth = JComboBox() self.jcombobox_reqMeth.addItem("GET") self.jcombobox_reqMeth.addItem("POST") hbox_reqMeth = Box.createHorizontalBox() hbox_reqMeth.add(jlabel_reqMeth) hbox_reqMeth.add(self.jcombobox_reqMeth) self.jcombobox_reqMeth.setMaximumSize( self.jcombobox_reqMeth.getPreferredSize()) hglue_reqMeth = Box.createHorizontalGlue() hbox_reqMeth.add(hglue_reqMeth) # ContentType标签 jlabel_contentType = JLabel("ConType: ") self.jcombobox_contentType = JComboBox() self.jcombobox_contentType.addItem("application/json") self.jcombobox_contentType.addItem("application/x-www-form-urlencoded") hbox_contentType = Box.createHorizontalBox() hbox_contentType.add(jlabel_contentType) hbox_contentType.add(self.jcombobox_contentType) self.jcombobox_contentType.setMaximumSize( self.jcombobox_contentType.getPreferredSize()) hglue_contentType = Box.createHorizontalGlue() hbox_contentType.add(hglue_contentType) # Charset标签 jlabel_charset = JLabel("CharSet: ") self.jcombobox_charset = JComboBox() self.jcombobox_charset.addItem("UTF-8") self.jcombobox_charset.addItem("GBK") hbox_charset = Box.createHorizontalBox() hbox_charset.add(jlabel_charset) hbox_charset.add(self.jcombobox_charset) self.jcombobox_charset.setMaximumSize( self.jcombobox_charset.getPreferredSize()) hglue_charset = Box.createHorizontalGlue() hbox_charset.add(hglue_charset) # 请求头标签 jlabel_headers = JLabel("Headers: ") self.jtext_headers = JTextField(generWidth) self.jtext_headers.setMaximumSize( self.jtext_headers.getPreferredSize()) hbox_headers = Box.createHorizontalBox() hbox_headers.add(jlabel_headers) hbox_headers.add(self.jtext_headers) hglue_headers = Box.createHorizontalGlue() hbox_headers.add(hglue_headers) # 请求参数标签 jlabel_data = JLabel(" Data: ") self.jtext_data = JTextField(generWidth) self.jtext_data.setPreferredSize(Dimension(20, 40)) self.jtext_data.setMaximumSize(self.jtext_data.getPreferredSize()) hbox_data = Box.createHorizontalBox() hbox_data.add(jlabel_data) hbox_data.add(self.jtext_data) hglue_data = Box.createHorizontalGlue() hbox_data.add(hglue_data) # token标志位置标签 hbox_radiobtn = Box.createHorizontalBox() jlabel_tokenPosition = JLabel("Token Position: ") self.radioBtn01 = JRadioButton("Header") self.radioBtn02 = JRadioButton("Body") btnGroup = ButtonGroup() btnGroup.add(self.radioBtn01) btnGroup.add(self.radioBtn02) self.radioBtn01.setSelected(True) hbox_radiobtn.add(jlabel_tokenPosition) hbox_radiobtn.add(self.radioBtn01) hbox_radiobtn.add(self.radioBtn02) # token正则表达式标签 hbox_token = Box.createHorizontalBox() hbox_token_header = Box.createHorizontalBox() hbox_token_body = Box.createHorizontalBox() # token正则表达式标签:header中 jlabel_tokenName = JLabel("tokenName: ") self.jtext_tokenName = JTextField(tokenWidth) self.jtext_tokenName.setMaximumSize( self.jtext_tokenName.getPreferredSize()) hbox_token_header.add(jlabel_tokenName) hbox_token_header.add(self.jtext_tokenName) hglue_token_header = Box.createHorizontalGlue() hbox_token_header.add(hglue_token_header) # token正则表达式标签:body中 jlabel_tokenRegex = JLabel("tokenRegex: ") self.jtext_tokenRegex = JTextField(tokenWidth) self.jtext_tokenRegex.setMaximumSize( self.jtext_tokenRegex.getPreferredSize()) hbox_token_body.add(jlabel_tokenRegex) hbox_token_body.add(self.jtext_tokenRegex) hglue_token_body = Box.createHorizontalGlue() hbox_token_body.add(hglue_token_body) # token正则表达式标签 hbox_token.add(hbox_token_header) hbox_token.add(hbox_token_body) # test测试按钮 hbox_test = Box.createHorizontalBox() jbtn_test = JButton("TEST", actionPerformed=self.btnTest) self.jlabel_test = JLabel("Result: ") hbox_test.add(jbtn_test) hbox_test.add(self.jlabel_test) # 水平胶水填充 hGlue_test = Box.createHorizontalGlue() hbox_test.add(hGlue_test) hbox_test.setBorder(BorderFactory.createLineBorder(Color.green, 2)) # 响应数据输出 hbox_resp = Box.createHorizontalBox() self.jtextarea_resp = JTextArea() jsp = JScrollPane(self.jtextarea_resp) hbox_resp.add(self.jtextarea_resp) # 左垂直盒子:添加各种水平盒子 vBox_left.add(hbox_url) vBox_left.add(hbox_reqMeth) vBox_left.add(hbox_contentType) vBox_left.add(hbox_charset) vBox_left.add(hbox_headers) vBox_left.add(hbox_data) vBox_left.add(hbox_radiobtn) vBox_left.add(hbox_token) vBox_left.add(hbox_test) vBox_left.add(hbox_resp) # 左垂直盒子:垂直胶水填充 vGlue_test = Box.createGlue() vBox_left.add(vGlue_test) # 右垂直盒子内部:指定token在请求包中的位置 # token标志位置单选按钮 hbox_radiobtn_r = Box.createHorizontalBox() jlabel_tokenPosition_r = JLabel("Token Position: ") self.radioBtn01_r = JRadioButton("Header") self.radioBtn02_r = JRadioButton("Body") btnGroup_r = ButtonGroup() btnGroup_r.add(self.radioBtn01_r) btnGroup_r.add(self.radioBtn02_r) self.radioBtn01_r.setSelected(True) hbox_radiobtn_r.add(jlabel_tokenPosition_r) hbox_radiobtn_r.add(self.radioBtn01_r) hbox_radiobtn_r.add(self.radioBtn02_r) # token正则表达式 hbox_token_r = Box.createHorizontalBox() hbox_token_header_r = Box.createHorizontalBox() hbox_token_body_r = Box.createHorizontalBox() # token正则表达式:在header中 jlabel_tokenName_r = JLabel("tokenName: ") self.jtext_tokenName_r = JTextField(tokenWidth) self.jtext_tokenName_r.setMaximumSize( self.jtext_tokenName_r.getPreferredSize()) hbox_token_header_r.add(jlabel_tokenName_r) hbox_token_header_r.add(self.jtext_tokenName_r) hglue_token_header_r = Box.createHorizontalGlue() hbox_token_header_r.add(hglue_token_header_r) # token正则表达式:在Body中 jlabel_tokenRegex_r = JLabel("tokenRegex: ") self.jtext_tokenRegex_r = JTextField(tokenWidth) self.jtext_tokenRegex_r.setMaximumSize( self.jtext_tokenRegex_r.getPreferredSize()) hbox_token_body_r.add(jlabel_tokenRegex_r) hbox_token_body_r.add(self.jtext_tokenRegex_r) hglue_token_body_r = Box.createHorizontalGlue() hbox_token_body_r.add(hglue_token_body_r) # token正则表达式 hbox_token_r.add(hbox_token_header_r) hbox_token_r.add(hbox_token_body_r) # 测试按钮 hbox_test_r = Box.createHorizontalBox() jbtn_test_r = JButton("SET", actionPerformed=self.btnTest_r) self.jlabel_test_r = JLabel("Result: ") hbox_test_r.add(jbtn_test_r) hbox_test_r.add(self.jlabel_test_r) # 水平胶水填充 hGlue02 = Box.createHorizontalGlue() hbox_test_r.add(hGlue02) hbox_test_r.setBorder(BorderFactory.createLineBorder(Color.green, 2)) # 右垂直盒子:添加各种水平盒子 vBox_right.add(hbox_radiobtn_r) vBox_right.add(hbox_token_r) vBox_right.add(hbox_test_r) vGlue = Box.createVerticalGlue() vBox_right.add(vGlue) vBox_left.setBorder(BorderFactory.createLineBorder(Color.black, 3)) vBox_right.setBorder(BorderFactory.createLineBorder(Color.black, 3)) # 次外层水平盒子:添加左右两个垂直盒子 hBox_main.add(vBox_left) hBox_main.add(vBox_right) # 最外层垂直盒子:添加次外层水平盒子,垂直胶水 out_vBox_main.add(hBox_usage) out_vBox_main.add(hBox_main) self.mainPanel = out_vBox_main self._callbacks.customizeUiComponent(self.mainPanel) self._callbacks.addSuiteTab(self) def getTabCaption(self): return "JC-AntiToken" def getUiComponent(self): return self.mainPanel def testBtn_onClick(self, event): print("click button") def createMenuItems(self, invocation): menu = [] if invocation.getToolFlag() == IBurpExtenderCallbacks.TOOL_REPEATER: menu.append( JMenuItem("Test menu", None, actionPerformed=self.testmenu)) return menu def testmenu(self, event): print(event) print("JCTest test menu") def processHttpMessage(self, toolflag, messageIsRequest, messageInfo): service = messageInfo.getHttpService() if messageIsRequest: pass print("Host: " + str(service.getHost())) print("Port: " + str(service.getPort())) print("Protocol: " + str(service.getProtocol())) print("-----------------------------------") def getActionName(self): return "JC-AntiToken" def performAction(self, currentRequest, macroItems): # url url = self._helpers.analyzeRequest(currentRequest).getUrl() print(url) reqInfo = self._helpers.analyzeRequest(currentRequest) # request headers headers = reqInfo.getHeaders() print("ReqHeaders: " + headers) # get cookie from request header cookie = self.getCookieFromReq(headers) print(cookie) print(type(cookie)) # offset to req body reqBodyOffset = reqInfo.getBodyOffset() reqBody = str(bytearray(currentRequest.getRequest()[reqBodyOffset:])) print("ReqBody: " + reqBody) # modify Request Body newToken = self.getNewToken(cookie) if newToken != None: # tokenInReqHeader res = False if self.tokenInHeader_r: # pass # 普通header中 for header in headers: if ":" in header: if header.split(":")[0] == self.tokenName_r: headers = [ self.tokenName_r + ": " + newToken if i.split(":")[0] == self.tokenName_r else i for i in headers ] res = True break # cookie中 if not res and cookie != None and self.tokenName_r + "=" in cookie: # pass for i in range(len(headers)): if headers[i].startwith("Cookie:"): cookies2 = headers[i] cookies3 = cookies2.split(":")[1] if ";" not in cookies3: headers[ i] = "Cookie: " + self.tokenName_r + "=" + newToken res = True break else: cookies4 = cookies3.split(";") for cookie_idx in range(len(cookies4)): if self.tokenName_r + "+" in cookies4[ cookie_idx]: cookies4[ cookie_idx] = self.tokenName_r + "=" + newToken res = True break headers[i] = "Cookie: " + ";".join(cookies4) break # query string中 if not res: meth = headers[0].split(" ")[0] url = headers[0].split(" ")[1] ver = headers[0].split(" ")[2] if self.tokenName_r + "=" not in url: pass else: if "&" not in url: url = url.split("?")[ 0] + "?" + self.tokenName_r + "=" + newToken headers[0] = meth + " " + url + " " + ver else: params = url.split("?")[1].split("&") for i in range(len(params)): if self.tokenName_r + "=" in params[i]: params[ i] = self.tokenName_r + "=" + newToken break url = url.split("?")[0] + "?" + "&".join(params) headers[0] = meth + " " + url + " " + ver # tokenInReqBody else: if re.match(self.tokenRegex_r, reqBody): try: reqBody = re.sub(self.tokenRegex_r, r'\g<1>' + newToken + r'\g<3>', reqBody, 0, re.M | re.I) except Exception as e: print(e) # print(reqBody) # reqBody = re.sub(self.tokenRegex_r,r'\g<1>'+newToken+r'\g<3>',reqBody,0,re.M|re.I) # if re.match(r'(.*?"_tokenName":")([a-zA-Z0-9]{6,})(")',reqBody): # reqBody = re.sub(r'(.*?"_tokenName":")([a-zA-Z0-9]{6,})(")',r'\1'+newToken+r'\3',reqBody,0,re.M|re.I) # rebuild request reqMessage = self._helpers.buildHttpMessage(headers, bytes(reqBody)) # forward currentRequest.setRequest(reqMessage) print("++++++++++++++++++++++++") def getCookieFromReq(self, headers): for header in headers: if re.match(r'^Cookie:', header, re.I): return re.match(r'^Cookie: (.*)', header, re.I).group(1) # get new token def getNewToken(self, cookie): print(cookie) print("getNewToken") # url = "http://myip.ipip.net" headers_cookie = { 'Cookie': cookie, } if cookie != '': self.headers.update(**headers_cookie) if self.reqMeth == "GET": resp = self.sendGetHttp(self.url, self.headers, self.data, self.contentType) else: resp = self.sendPostHttp(self.url, self.headers, self.data, self.contentType) respBody = resp.read() respInfo = resp.info() if self.tokenInHeader: if respInfo.getheader(self.tokenName) != None: newToken = respInfo.getheader(self.tokenName) print(newToken) return newToken else: regexPattern = '.*' + self.tokenName + '=(.*?);' if respInfo.getheader("set-cookie") != None: cookies = respInfo.getheader("set-cookie") if re.match(regexPattern, cookies, re.M | re.I): newToken = re.match(regexPattern, cookies, re.M | re.I).group(1) print("newToken: ", newToken) return newToken else: return None else: return None else: regexPattern = self.tokenRegex if re.match(regexPattern, respBody, re.M | re.I): newToken = re.match(regexPattern, respBody, re.M | re.I).group(1) print("newToken: ", newToken) return newToken else: return None def sendGetHttp(self, url, headers, data, contentType): context = ssl._create_unverified_context() headers_contentType = {'Content-Type': contentType} if not headers.has_key("Content-Type"): headers.update(**headers_contentType) headers_userAgent = { 'User-Agent': 'Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25' } if not headers.has_key("User-Agent"): headers.update(**headers_userAgent) try: if data != None: # if "urlencode" in contentType: data = urllib.urlencode(data) url = url + "?" + data req = urllib2.Request(url, headers=headers) else: req = urllib2.Request(url, headers=headers) resp = urllib2.urlopen(req, context=context) return resp except urllib2.HTTPError as error: print("ERROR: ", error) return None def sendPostHttp(self, url, headers, data, contentType): context = ssl._create_unverified_context() headers_contentType = {'Content-Type': contentType} if not headers.has_key("Content-Type"): headers.update(**headers_contentType) headers_userAgent = { 'User-Agent': 'Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25' } if not headers.has_key("User-Agent"): headers.update(**headers_userAgent) print(headers) resp = "" print("data: ", data) if data != None: if "urlencode" in contentType: data = urllib.urlencode(data) req = urllib2.Request(url, headers=headers, data=data) else: data = json.dumps(data) req = urllib2.Request(url, headers=headers, data=data) else: if "urlencode" in contentType: req = urllib2.Request(url, headers=headers) else: data = json.dumps(data) req = urllib2.Request(url, headers=headers) try: resp = urllib2.urlopen(req, context=context) return resp except urllib2.HTTPError as error: print("ERROR: ", error) return None def btnTest(self, e): self.printcn("中文测试") self.url = self.jtext_url.getText() if self.url == "": self.jlabel_test.setText("please input url") return self.reqMeth = self.jcombobox_reqMeth.getSelectedItem() # 用户设置content-type self.contentType = self.jcombobox_contentType.getSelectedItem( ) + ";charset=" + self.jcombobox_charset.getSelectedItem() # 用户有没有自定义请求头 if self.jtext_headers.getText() != "": self.headers = json.loads(self.jtext_headers.getText()) else: self.headers = {} # 用户有没有自定义请求体 if self.jtext_data.getText() != "": self.data = json.loads(self.jtext_data.getText()) else: self.data = None self.tokenName = self.jtext_tokenName.getText() self.tokenRegex = self.jtext_tokenRegex.getText() resp = '' if self.reqMeth == "GET": resp = self.sendGetHttp(self.url, self.headers, self.data, self.contentType) else: resp = self.sendPostHttp(self.url, self.headers, self.data, self.contentType) if resp == None: self.jlabel_test.setText("error,detail in extender output") return respHeader = resp.info().headers print("resp-headers: ", respHeader) # print(resp.info().getheader("content-type")) self.printcn(resp.info().getheader("set-cookie")) # print(resp.info().getheader("xxx")) respBody = resp.read() print("respBody: ", respBody) self.jtextarea_resp.setText("".join(respHeader) + "\n" + "".join(respBody)) if (self.radioBtn01.isSelected()): self.tokenInHeader = True if self.tokenName == "": self.jlabel_test.setText("please input tokenName") return else: self.tokenInHeader = False if self.tokenRegex == "": self.jlabel_test.setText("please input tokenRegex") return print(self.reqMeth) newToken = self.getNewToken("") if newToken != None: self.jlabel_test.setText("Result: " + str(newToken)) self.jlabel_test.setBackground(Color.cyan) else: self.jlabel_test.setText("Result: None") def btnTest_r(self, e): self.tokenName_r = self.jtext_tokenName_r.getText() self.tokenRegex_r = self.jtext_tokenRegex_r.getText() if (self.radioBtn01_r.isSelected()): self.tokenInHeader_r = True if self.tokenName_r == "": self.jlabel_test_r.setText("please input tokenName") return else: self.tokenInHeader_r = False if self.tokenRegex_r == "": self.jlabel_test_r.setText("please input tokenRegex") return self.jlabel_test_r.setText("SUCCESS")
class JBrukerSubmit: colHeads = ('block/sample #', 'Holder', 'Name', 'Experiment', 'Solvent', 'Group', 'Member', 'Sample Name') if platform.node() == 'DM-CHEM-200': basedir = r"W:\downloads\Eric\jython" elif platform.node() == 'ERIC-PC': basedir = r"C:\Users\ERIC\Dropbox\projects\programming\2020\python\autoNMRinput" else: # running from Bruker spectrometers basedir = "/data/downloads/Eric" def listSubmit(self, event): """Submit highlighted to csv file to automation folder of spectrometer """ # Ask for starting carousel position and submit experimets to topspin # obtain file name of CSV file selected = self.list.selectedIndex csvName = self.data[selected] # if no selected file and table is empty just return if self.label.text == "Selected File": return # Create check dialog before submitting data to automation self.dataTableModel.dataVector # submitString = "submit " + csvName + " starting at carousel position " + self.carouselStartingPosition.text submitString = "submit " + csvName + " starting at carousel position " + str( (self.dataTableModel.dataVector)[0][1]) result = JOptionPane.showConfirmDialog(self.frame, submitString) # if submission confirmed if result == 0: # submit csv file to automation ret = readcsv243A.submitNMRexpts([ self.dataTableModel.dataVector, csvName, self.carouselStartingPosition.text ]) # if successful or not update status string if ret == 0: self.statusLabel.text = "File " + csvName + " Submitted to TOPSPIN Starting at Carousel Position " + str( (self.dataTableModel.dataVector)[0][1]) self.panelStatusLabel.setBackground(Color.GREEN) elif ret == 1: self.statusLabel.text = "Carousel Position not a number" self.panelStatusLabel.setBackground(Color.RED) elif ret == 2: self.statusLabel.text = "Incompatible experiment chosen for spectrometer" self.panelStatusLabel.setBackground(Color.RED) elif ret == 3: self.statusLabel.text = "A holder starting position is not between 1 and 60 inclusive" self.panelStatusLabel.setBackground(Color.RED) elif ret == 4: self.statusLabel.text = "Too many samples for starting position chosen" self.panelStatusLabel.setBackground(Color.RED) # if an error occured display error message also in a warning dialog too. if ret in [1, 2, 3, 4]: JOptionPane.showMessageDialog(self.frame, self.statusLabel.text) def listSelect(self, event): """When a new csv file is selected from the list read in the file and display its contents in the table. Unordered csv files will be ordered based on the block/sample number. A holder column will be added to the CSV data based on the carousel starting position. """ # Process the events from the list box and update the label # get the index from the list and then the filename selected = self.list.selectedIndex if selected >= 0: # update file label and set background colour to normal csvName = self.data[selected] self.label.text = csvName self.panelLabel.setBackground(self.standardBackgroundColor) # reset status label self.statusLabel.text = "Status" self.panelStatusLabel.setBackground(self.standardBackgroundColor) # # update table by reading in csv file # read in csv file and store as a list of dictionaries # one dictionary for each line fn = csvName self.expt_list = [] f = open(os.path.join(JBrukerSubmit.basedir, fn), 'r') reader = csv.DictReader(f) for row in reader: self.expt_list.append(row) f.close() # get carousel starting position, if the value cannot be converted # to an integer reset it to 1 and reset the GUI to 1 try: self.cnumber = int(self.carouselStartingPosition.text) except: self.cnumber = 1 self.self.carouselStartingPosition.text = "1" # get the csv data into a list of lists form ready for displaying self.tableData = returnJTableData(self.expt_list, self.cnumber) # display csv table in table view colNames = JBrukerSubmit.colHeads # transfer the data over to the table model self.dataTableModel.setDataVector(self.tableData, colNames) # display the table in the GUI self.scrollPaneTable.getViewport().setView((self.table)) # check to see if experiments will run on the spectometer ok, pulseSequence = checkExperimentsWillRun(self.expt_list) if not ok: # display warning dialog warningText = pulseSequence + " cannot be run on this spectrometer" JOptionPane.showMessageDialog(self.frame, warningText) def returnCSVlist(self, hiddenFiles): """ read in csv files ommitting any that are created after auto submission and return as list of strings. Miss out any that have been hidden""" csvlist = [ f for f in os.listdir(JBrukerSubmit.basedir) if (f.endswith(".csv")) and (f[-6] not in ['A', 'B', 'N']) ] csvlist = [f for f in csvlist if f not in self.hiddenFiles] return csvlist def listUpdate(self, event): """ when update button clicked renew csv list """ self.data = self.returnCSVlist(self.hiddenFiles) self.list.setListData(self.data) def checkCarouselNumber(self, event): """ check that carousel field is an integer change background to white if okay, red if not.""" self.cnumber = self.carouselStartingPosition.text try: self.cnumber = int(self.cnumber) self.carouselStartingPosition.background = Color.WHITE self.listSelect(event) except: self.carouselStartingPosition.background = Color.RED def tableMouseClicked(self, event): """Prior to editing the user will click the holder number cell more often than not. This function saves the cell row and column and the value in the cell prior to editing.""" tble = event.getSource() self.rw = tble.getSelectedRow() self.cl = tble.getSelectedColumn() self.oldHolderValue = tble.getValueAt(self.rw, self.cl) # print "table mouse clicked", self.rw, self.cl def tableChangedCB(self, event): """Function is called when a cell is being edited. After the user presses return the data is updated. Should only work if Holder column is being edited""" print "Table Changed" tble = event.getSource() if (event.keyChar == "\n") and (self.cl != 1): tble.setValueAt(self.oldHolderValue, self.rw, self.cl) elif (event.keyChar == "\n") and (self.cl == 1): print "RETURN" vlue = tble.getValueAt(self.rw, self.cl) print "row", self.rw, "col", self.cl, "value", vlue # # check to see if new holder number is used by another sample # get block number of sample changed blckNumber = tble.getValueAt(self.rw, 0) # # get values in table holderAlreadyOccupied = False tableValues = self.dataTableModel.dataVector for i, rw in enumerate(tableValues): print i if (int(rw[1]) == int(vlue)) and (int(blckNumber) != int(rw[0])): tble.setValueAt(int(self.oldHolderValue), self.rw, 1) holderAlreadyOccupied = True warningText = "Holder " + str( vlue) + " already used for sample " + str(rw[0]) JOptionPane.showMessageDialog(self.frame, warningText) break # # check to see if any other rows with same sample number need to be updated if not holderAlreadyOccupied: for i, rw in enumerate(tableValues): if int(blckNumber) == int(rw[0]): tble.setValueAt(int(vlue), i, 1) # def tableKeyPressedCB(self, event): # print "tableKeyPressedCB" # tble = event.getSource() # if event.keyChar == "\n": # print "RETURN" # vlue = tble.getValueAt(self.rw, self.cl) # print "row", self.rw, "col", self.cl, "value", vlue # elif (event.keyChar).isdigit(): # print "event.keyChar", event.keyChar # self.rw = tble.getSelectedRow() # self.cl = tble.getSelectedColumn() def listShowAllFiles(self, event): fp = open("hiddenFiles.txt", 'w') fp.write('zzz\n') fp.close() self.hiddenFiles = ['zzz'] self.listUpdate(event) def listHideFile(self, event): # find highlighted csv file name selected = self.list.selectedIndex csvName = self.data[selected] # add csv file name to hidden csv files list self.hiddenFiles.append(csvName) # update label above table view self.label.text = "Selected File" self.panelLabel.setBackground(self.standardBackgroundColor) # display csv table in table view # set table to blanks self.tableData = [] for i in range(18): self.tableData.append([ "", ] * len(JBrukerSubmit.colHeads)) self.dataTableModel.setDataVector(self.tableData, JBrukerSubmit.colHeads) self.listUpdate(event) # save hiddenFiles file fp = open("hiddenFiles.txt", 'w') for f in self.hiddenFiles: fp.write(f + '\n') fp.close() def __init__(self): self.rw = 0 # table row self.cl = 0 # table column # load hidden files list self.hiddenFiles = ["zzz"] if os.path.exists("hiddenFiles.txt"): fp = open("hiddenFiles.txt", "r") self.hiddenFiles = fp.readlines() fp.close() self.hiddenFiles = [f.strip() for f in self.hiddenFiles] print self.hiddenFiles # These lines setup the basic frame, size and layout # the setDefaultCloseOperation so that only the window closes and not TOPSPIN self.frame = JFrame("Submit NMR Experimets") self.frame.setSize(1200, 440) self.frame.setLayout(BorderLayout()) self.frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE) # set up the list and the contents of the list # the python tuple get converted to a Java vector self.data = self.returnCSVlist(self.hiddenFiles) self.list = JList(self.data, valueChanged=self.listSelect) self.spane = JScrollPane() self.spane.setPreferredSize(Dimension(145, 150)) self.spane.getViewport().setView((self.list)) panel = JPanel() panel.add(self.spane) # define buttons bpanel = JPanel() btnS = JButton('Submit File', actionPerformed=self.listSubmit) btnU = JButton('Update List', actionPerformed=self.listUpdate) btnHideFile = JButton('Hide File', actionPerformed=self.listHideFile) btnShowAllFiles = JButton('Show All Files', actionPerformed=self.listShowAllFiles) # label displaying CSV file selected self.label = JLabel('Selected File', JLabel.CENTER) # label to display warnings and confirm expriments submitted self.statusLabel = JLabel('Status', JLabel.CENTER) # Create table to display csv file self.tableData = [] for r in range(18): self.tableData.append([ "", ] * len(JBrukerSubmit.colHeads)) colNames = JBrukerSubmit.colHeads self.dataTableModel = DefaultTableModel(self.tableData, colNames) self.table = JTable(self.dataTableModel, keyTyped=self.tableChangedCB, mouseClicked=self.tableMouseClicked) # set all columns to uneditable except Holder column # print dir(self.table) # self.table.getColumn(0).setEditable(False) # self.table.getColumn(2).setEditable(False) # self.table.getColumn(3).setEditable(False) # self.table.getColumn(4).setEditable(False) # self.table.getColumn(5).setEditable(False) # self.table.getColumn(6).setEditable(False) # self.table = JTable(self.dataTableModel, # keyPressed=self.tableKeyPressedCB) self.scrollPaneTable = JScrollPane() self.scrollPaneTable.setPreferredSize(Dimension(900, 300)) self.scrollPaneTable.getViewport().setView((self.table)) panelTable = JPanel() panelTable.add(self.scrollPaneTable) # create text field to get carousel starting position self.carouselLabel = JLabel("Carousel Position", JLabel.CENTER) self.carouselStartingPosition = JTextField( '1', 13, keyPressed=self.checkCarouselNumber) # add widgets to do with manupulating csv list in FlowLayout Mode panelList = JPanel() panelList.setLayout(FlowLayout()) panelList.setPreferredSize(Dimension(170, 200)) # set preferred size of buttons btnU.setPreferredSize(Dimension(140, 20)) btnS.setPreferredSize(Dimension(140, 20)) btnHideFile.setPreferredSize(Dimension(140, 20)) btnShowAllFiles.setPreferredSize(Dimension(140, 20)) self.carouselLabel.setPreferredSize(Dimension(140, 20)) self.carouselStartingPosition.setPreferredSize(Dimension(170, 20)) panelList.add(btnU) panelList.add(panel) panelList.add(btnHideFile) panelList.add(btnShowAllFiles) panelList.add(JSeparator(JSeparator.HORIZONTAL), BorderLayout.LINE_START) panelList.add(self.carouselLabel) panelList.add(self.carouselStartingPosition) panelList.add(btnS) self.panelLabel = JPanel() self.panelLabel.add(self.label) self.standardBackgroundColor = self.panelLabel.getBackground() # put status label in a panel so that background color can be changed self.panelStatusLabel = JPanel() self.panelStatusLabel.add(self.statusLabel) # add widgets to frame self.frame.add(self.panelLabel, BorderLayout.NORTH) self.frame.add(panelList, BorderLayout.WEST) self.frame.add(panelTable, BorderLayout.CENTER) self.frame.add(self.panelStatusLabel, BorderLayout.SOUTH) self.frame.setVisible(True)