Files

1379 lines
53 KiB
Python

# -*- coding: utf-8 -*-
from __future__ import print_function
"""
BurpAI NATIVE REPEATER MODE - Burp Suite Extension
Production-grade Jython extension with FIXED imports, clean UI, no crashes
"""
import sys
import traceback
import threading
import json
import time
# ===== BURP IMPORTS =====
from burp import IBurpExtender, ITab, IHttpListener, IContextMenuFactory, IMessageEditorController
# ===== JAVA/SWING IMPORTS (EXPLICIT - NO java. PREFIX) =====
from javax.swing import JPanel
from javax.swing import JScrollPane
from javax.swing import JSplitPane
from javax.swing import JTabbedPane
from javax.swing import JTable
from javax.swing import JTextArea
from javax.swing import JTextField
from javax.swing import JButton
from javax.swing import JLabel
from javax.swing import JComboBox
from javax.swing import JCheckBox
from javax.swing import JMenuItem
from javax.swing import SwingUtilities
from javax.swing import BorderFactory
from javax.swing import BoxLayout
from javax.swing import Box
from javax.swing import ListSelectionModel
from javax.swing.table import DefaultTableModel
from javax.swing.event import ListSelectionListener
# ===== JAVA AWT IMPORTS (EXPLICIT - NO java. PREFIX) =====
from java.awt import BorderLayout
from java.awt import FlowLayout
from java.awt import Dimension
from java.awt import Color
from java.awt import Font
from java.awt import Insets
# ===== JAVA AWT EVENT IMPORTS =====
from java.awt.event import ActionListener
from java.awt.event import KeyListener
from java.awt.event import KeyEvent
# ===== JAVA LANG IMPORTS =====
from java.lang import Runnable
# ===== URLLIB COMPATIBILITY =====
try:
from urllib2 import Request, urlopen, HTTPError
except ImportError:
from urllib.request import Request, urlopen
from urllib.error import HTTPError
# ===== MESSAGE EDITOR CONTROLLER =====
class MessageEditorController(IMessageEditorController):
def __init__(self, extension):
self.ext = extension
def getHttpService(self):
return None
def getRequest(self):
return None
def setRequest(self, message):
pass
def getResponse(self):
return None
def setResponse(self, message):
pass
def getEditorName(self):
return "BurpAI"
# ===== EVENT LISTENERS =====
class SendButtonListener(ActionListener):
def __init__(self, extension):
self.ext = extension
def actionPerformed(self, event):
try:
self.ext.send_chat_message()
except Exception as e:
print("[!] SendButtonListener error: " + str(e))
traceback.print_exc()
class InputKeyListener(KeyListener):
def __init__(self, extension):
self.ext = extension
def keyPressed(self, e):
try:
if e.getKeyCode() == KeyEvent.VK_ENTER:
self.ext.send_chat_message()
except Exception as e:
print("[!] InputKeyListener error: " + str(e))
traceback.print_exc()
def keyReleased(self, e):
pass
def keyTyped(self, e):
pass
class SaveAPIListener(ActionListener):
def __init__(self, extension):
self.ext = extension
def actionPerformed(self, event):
try:
self.ext.save_api_key()
except Exception as e:
print("[!] SaveAPIListener error: " + str(e))
traceback.print_exc()
class UpdateModelListener(ActionListener):
def __init__(self, extension):
self.ext = extension
def actionPerformed(self, event):
try:
self.ext.update_model()
except Exception as e:
print("[!] UpdateModelListener error: " + str(e))
traceback.print_exc()
class RepeatSendListener(ActionListener):
def __init__(self, extension):
self.ext = extension
def actionPerformed(self, event):
try:
self.ext.send_request()
except Exception as e:
print("[!] RepeatSendListener error: " + str(e))
traceback.print_exc()
class HistorySelectionListener(ListSelectionListener):
def __init__(self, extension):
self.ext = extension
def valueChanged(self, event):
try:
if not event.getValueIsAdjusting():
self.ext.load_from_history()
except Exception as e:
print("[!] HistorySelectionListener error: " + str(e))
traceback.print_exc()
class ContextMenuSendToAIListener(ActionListener):
def __init__(self, extension, messages):
self.ext = extension
self.messages = messages
def actionPerformed(self, event):
try:
self.ext.forward_to_ai_from_menu(self.messages)
except Exception as e:
print("[!] ContextMenuSendToAIListener error: " + str(e))
traceback.print_exc()
class ContextMenuFactory(IContextMenuFactory):
def __init__(self, extension):
self.extension = extension
def createMenuItems(self, invocation):
try:
menu_items = []
selected = invocation.getSelectedMessages()
if selected and len(selected) > 0:
item = JMenuItem("Send to BurpAI")
item.addActionListener(ContextMenuSendToAIListener(self.extension, selected))
menu_items.append(item)
return menu_items if menu_items else None
except Exception as e:
print("[!] ContextMenuFactory error: " + str(e))
traceback.print_exc()
return None
class AnalyzeButtonListener(ActionListener):
def __init__(self, extension):
self.ext = extension
def actionPerformed(self, event):
try:
self.ext.analyze_with_ai()
except Exception as e:
print("[!] AnalyzeButtonListener error: " + str(e))
traceback.print_exc()
class AutoAnalyzeListener(ActionListener):
def __init__(self, extension):
self.ext = extension
def actionPerformed(self, event):
try:
self.ext.auto_analyze = self.ext.auto_analyze_checkbox.isSelected()
print("[*] Auto Analyze: " + str(self.ext.auto_analyze))
except Exception as e:
print("[!] AutoAnalyzeListener error: " + str(e))
traceback.print_exc()
# ===== MAIN EXTENSION CLASS =====
class BurpExtender(IBurpExtender, ITab, IHttpListener):
def registerExtenderCallbacks(self, callbacks):
try:
self.callbacks = callbacks
self.helpers = callbacks.getHelpers()
self.api_key = ""
self.model = "kimi-k2.5"
self.traffic_log = []
self.ai_history = []
self.max_history = 1000 # Limit history to 1000 entries for performance
self.current_request = None
self.current_response = None
# Multi-model engine with fallback (Bug Bounty Hunter Mode)
self.primary_models = [
"alibaba-qwen3-32b",
"deepseek-r1-distill-llama-70b",
"glm-5",
"kimi-k2.5",
"llama3-8b-instruct",
"llama3.3-70b-instruct",
"minimax-m2.5",
"mistral-nemo-instruct-2407",
"nvidia-nemotron-3-super-120b",
"openai-gpt-oss-120b",
"openai-gpt-oss-20b"
]
self.fallback_models = []
self.all_models = self.primary_models + self.fallback_models
self.current_model_index = 0
# UI Components
self.chat_display = None
self.chat_input = None
self.api_input = None
self.status_label = None
self.model_combo = None
self.history_table = None
self.history_model = None
# Native Message Editors
self.request_editor = None
self.response_editor = None
self.editor_controller = MessageEditorController(self)
# Repeater controls
self.auto_analyze = False
self.auto_analyze_checkbox = None
self.callbacks.registerHttpListener(self)
self.callbacks.registerContextMenuFactory(ContextMenuFactory(self))
self.callbacks.addSuiteTab(self)
print("[*] BurpAI loaded successfully - ready to capture requests")
except Exception as e:
print("[!] Error in registerExtenderCallbacks: " + str(e))
traceback.print_exc()
def getTabCaption(self):
try:
return "BurpAI"
except Exception as e:
print("[!] Error in getTabCaption: " + str(e))
traceback.print_exc()
return "BurpAI"
def getUiComponent(self):
try:
return self.build_ui()
except Exception as e:
print("[!] Error in getUiComponent: " + str(e))
traceback.print_exc()
return JPanel()
def build_ui(self):
"""Build main UI with clean alignment"""
try:
main_panel = JPanel(BorderLayout())
main_panel.setBackground(Color(30, 30, 30))
# TOP: Compact toolbar
toolbar = self.build_toolbar()
main_panel.add(toolbar, BorderLayout.NORTH)
# CENTER: Main horizontal split
main_split = JSplitPane(JSplitPane.HORIZONTAL_SPLIT)
main_split.setDividerLocation(400)
main_split.setBackground(Color(30, 30, 30))
main_split.setResizeWeight(0.4)
main_split.setBorder(BorderFactory.createLineBorder(Color(60, 60, 60), 1))
left_panel = self.build_chat_panel()
right_panel = self.build_right_panel()
main_split.setLeftComponent(left_panel)
main_split.setRightComponent(right_panel)
main_panel.add(main_split, BorderLayout.CENTER)
return main_panel
except Exception as e:
print("[!] Error in build_ui: " + str(e))
traceback.print_exc()
return JPanel()
def build_toolbar(self):
"""Create compact Burp-style toolbar with proper alignment"""
try:
toolbar = JPanel(FlowLayout(FlowLayout.LEFT, 8, 5))
toolbar.setBackground(Color(40, 40, 40))
toolbar.setBorder(BorderFactory.createLineBorder(Color(60, 60, 60), 1))
toolbar.setPreferredSize(Dimension(100, 38))
# API Key label
api_label = JLabel("API Key:")
api_label.setForeground(Color(180, 180, 180))
api_label.setFont(Font("Arial", Font.PLAIN, 10))
toolbar.add(api_label)
# API Key input field
self.api_input = JTextField()
self.api_input.setBackground(Color(50, 50, 50))
self.api_input.setForeground(Color(200, 200, 200))
self.api_input.setFont(Font("Monospaced", Font.PLAIN, 10))
self.api_input.setPreferredSize(Dimension(200, 26))
self.api_input.setMaximumSize(Dimension(200, 26))
self.api_input.setMargin(Insets(2, 4, 2, 4))
toolbar.add(self.api_input)
# Save button
save_btn = JButton("Save")
save_btn.setBackground(Color(100, 180, 100))
save_btn.setForeground(Color.WHITE)
save_btn.setFont(Font("Arial", Font.BOLD, 9))
save_btn.setPreferredSize(Dimension(65, 26))
save_btn.setMaximumSize(Dimension(65, 26))
save_btn.setMargin(Insets(2, 8, 2, 8))
save_btn.setFocusPainted(False)
save_btn.addActionListener(SaveAPIListener(self))
toolbar.add(save_btn)
# Separator
toolbar.add(JLabel(" | "))
# Model label
model_label = JLabel("Model:")
model_label.setForeground(Color(180, 180, 180))
model_label.setFont(Font("Arial", Font.PLAIN, 10))
toolbar.add(model_label)
# Model dropdown
self.model_combo = JComboBox(self.all_models)
self.model_combo.setBackground(Color(50, 50, 50))
self.model_combo.setForeground(Color(200, 200, 200))
self.model_combo.setFont(Font("Arial", Font.PLAIN, 10))
self.model_combo.setPreferredSize(Dimension(170, 26))
self.model_combo.setMaximumSize(Dimension(170, 26))
self.model_combo.addActionListener(UpdateModelListener(self))
toolbar.add(self.model_combo)
# Separator
toolbar.add(JLabel(" | "))
# Status label
status_label_text = JLabel("Status:")
status_label_text.setForeground(Color(180, 180, 180))
status_label_text.setFont(Font("Arial", Font.PLAIN, 10))
toolbar.add(status_label_text)
self.status_label = JLabel("Ready")
self.status_label.setForeground(Color(255, 200, 100))
self.status_label.setFont(Font("Arial", Font.BOLD, 10))
toolbar.add(self.status_label)
return toolbar
except Exception as e:
print("[!] Error in build_toolbar: " + str(e))
traceback.print_exc()
return JPanel()
def build_chat_panel(self):
"""Build left chat panel"""
try:
panel = JPanel(BorderLayout())
panel.setBackground(Color(30, 30, 30))
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5))
# Chat display
self.chat_display = JTextArea()
self.chat_display.setEditable(False)
self.chat_display.setBackground(Color(30, 30, 30))
self.chat_display.setForeground(Color(212, 212, 212))
self.chat_display.setFont(Font("Consolas", Font.PLAIN, 11))
self.chat_display.setLineWrap(True)
self.chat_display.setWrapStyleWord(True)
self.chat_display.setMargin(Insets(8, 8, 8, 8))
scroll = JScrollPane(self.chat_display)
scroll.setBackground(Color(30, 30, 30))
scroll.setBorder(BorderFactory.createLineBorder(Color(60, 60, 60), 1))
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED)
scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER)
panel.add(scroll, BorderLayout.CENTER)
# Input area
input_panel = JPanel(BorderLayout())
input_panel.setBackground(Color(30, 30, 30))
input_panel.setBorder(BorderFactory.createEmptyBorder(8, 0, 0, 0))
self.chat_input = JTextField()
self.chat_input.setBackground(Color(45, 45, 48))
self.chat_input.setForeground(Color(212, 212, 212))
self.chat_input.setFont(Font("Monospaced", Font.PLAIN, 11))
self.chat_input.setCaretColor(Color(212, 212, 212))
self.chat_input.setMargin(Insets(4, 6, 4, 6))
self.chat_input.addKeyListener(InputKeyListener(self))
input_panel.add(self.chat_input, BorderLayout.CENTER)
send_btn = JButton("Send")
send_btn.setBackground(Color(51, 122, 183))
send_btn.setForeground(Color.WHITE)
send_btn.setFont(Font("Arial", Font.PLAIN, 10))
send_btn.setFocusPainted(False)
send_btn.setPreferredSize(Dimension(75, 32))
send_btn.setMargin(Insets(2, 10, 2, 10))
send_btn.addActionListener(SendButtonListener(self))
input_panel.add(send_btn, BorderLayout.EAST)
panel.add(input_panel, BorderLayout.SOUTH)
return panel
except Exception as e:
print("[!] Error in build_chat_panel: " + str(e))
traceback.print_exc()
return JPanel()
def build_right_panel(self):
"""Build right panel with history and repeater"""
try:
right_split = JSplitPane(JSplitPane.VERTICAL_SPLIT)
right_split.setDividerLocation(200)
right_split.setBackground(Color(30, 30, 30))
right_split.setResizeWeight(0.35)
right_split.setBorder(BorderFactory.createLineBorder(Color(60, 60, 60), 1))
history_panel = self.build_history_panel()
repeater_panel = self.build_repeater_panel()
right_split.setTopComponent(history_panel)
right_split.setBottomComponent(repeater_panel)
return right_split
except Exception as e:
print("[!] Error in build_right_panel: " + str(e))
traceback.print_exc()
return JPanel()
def build_history_panel(self):
"""Build history table panel with data binding"""
try:
panel = JPanel(BorderLayout())
panel.setBackground(Color(30, 30, 30))
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5))
# Title
title_label = JLabel("Request History")
title_label.setForeground(Color(150, 150, 150))
title_label.setFont(Font("Arial", Font.BOLD, 10))
title_panel = JPanel()
title_panel.setBackground(Color(30, 30, 30))
title_panel.add(title_label)
panel.add(title_panel, BorderLayout.NORTH)
# Create history table model with columns
self.history_model = DefaultTableModel(
["#", "Method", "Host", "Path", "Status"],
0
)
# Bind model to table
self.history_table = JTable(self.history_model)
self.history_table.setBackground(Color(45, 45, 48))
self.history_table.setForeground(Color(212, 212, 212))
self.history_table.setFont(Font("Monospaced", Font.PLAIN, 9))
self.history_table.setGridColor(Color(60, 60, 60))
self.history_table.setRowHeight(22)
self.history_table.setSelectionBackground(Color(66, 110, 165))
# Add selection listener to load requests
self.history_table.getSelectionModel().addListSelectionListener(HistorySelectionListener(self))
# Set column widths
self.history_table.getColumnModel().getColumn(0).setPreferredWidth(30)
self.history_table.getColumnModel().getColumn(1).setPreferredWidth(50)
self.history_table.getColumnModel().getColumn(2).setPreferredWidth(80)
self.history_table.getColumnModel().getColumn(3).setPreferredWidth(100)
self.history_table.getColumnModel().getColumn(4).setPreferredWidth(40)
# Add scroll pane
scroll = JScrollPane(self.history_table)
scroll.setBackground(Color(30, 30, 30))
scroll.setBorder(BorderFactory.createLineBorder(Color(60, 60, 60), 1))
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED)
scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER)
panel.add(scroll, BorderLayout.CENTER)
print("[*] History table initialized: model=" + str(self.history_model) + ", table=" + str(self.history_table))
return panel
except Exception as e:
print("[!] Error in build_history_panel: " + str(e))
traceback.print_exc()
return JPanel()
def build_repeater_panel(self):
"""Build native repeater panel"""
try:
panel = JPanel(BorderLayout())
panel.setBackground(Color(30, 30, 30))
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5))
# Title
title_label = JLabel("Repeater / Response")
title_label.setForeground(Color(150, 150, 150))
title_label.setFont(Font("Arial", Font.BOLD, 10))
title_panel = JPanel()
title_panel.setBackground(Color(30, 30, 30))
title_panel.add(title_label)
panel.add(title_panel, BorderLayout.NORTH)
# Native Burp Message Editors
try:
self.request_editor = self.callbacks.createMessageEditor(self.editor_controller, True)
self.response_editor = self.callbacks.createMessageEditor(self.editor_controller, False)
except Exception as editor_err:
print("[!] Error creating message editors: " + str(editor_err))
traceback.print_exc()
self.request_editor = None
self.response_editor = None
# Tabs for request/response
tabs = JTabbedPane()
tabs.setBackground(Color(40, 40, 40))
tabs.setForeground(Color(180, 180, 180))
if self.request_editor:
request_component = self.request_editor.getComponent()
tabs.addTab("Request", request_component)
if self.response_editor:
response_component = self.response_editor.getComponent()
tabs.addTab("Response", response_component)
panel.add(tabs, BorderLayout.CENTER)
# Control buttons panel
btn_panel = JPanel()
btn_panel.setLayout(FlowLayout(FlowLayout.LEFT, 8, 5))
btn_panel.setBackground(Color(30, 30, 30))
btn_panel.setBorder(BorderFactory.createEmptyBorder(8, 0, 0, 0))
repeat_send = JButton("Send Request")
repeat_send.setBackground(Color(100, 200, 100))
repeat_send.setForeground(Color.WHITE)
repeat_send.setFont(Font("Arial", Font.BOLD, 10))
repeat_send.setPreferredSize(Dimension(120, 30))
repeat_send.setMargin(Insets(4, 15, 4, 15))
repeat_send.setFocusPainted(False)
repeat_send.addActionListener(RepeatSendListener(self))
btn_panel.add(repeat_send)
# Separator
btn_panel.add(JLabel(" | "))
# Analyze button
analyze_btn = JButton("Analyze with AI")
analyze_btn.setBackground(Color(51, 122, 183))
analyze_btn.setForeground(Color.WHITE)
analyze_btn.setFont(Font("Arial", Font.BOLD, 10))
analyze_btn.setPreferredSize(Dimension(130, 30))
analyze_btn.setMargin(Insets(4, 15, 4, 15))
analyze_btn.setFocusPainted(False)
analyze_btn.addActionListener(AnalyzeButtonListener(self))
btn_panel.add(analyze_btn)
# Auto Analyze checkbox
try:
self.auto_analyze_checkbox = JCheckBox()
self.auto_analyze_checkbox.setText("Auto Analyze")
self.auto_analyze_checkbox.setBackground(Color(30, 30, 30))
self.auto_analyze_checkbox.setForeground(Color(212, 212, 212))
self.auto_analyze_checkbox.setFont(Font("Arial", Font.PLAIN, 10))
self.auto_analyze_checkbox.setFocusPainted(False)
self.auto_analyze_checkbox.addActionListener(AutoAnalyzeListener(self))
btn_panel.add(self.auto_analyze_checkbox)
except Exception as checkbox_err:
print("[!] Error creating auto analyze checkbox: " + str(checkbox_err))
panel.add(btn_panel, BorderLayout.SOUTH)
return panel
except Exception as e:
print("[!] Error in build_repeater_panel: " + str(e))
traceback.print_exc()
return JPanel()
# ===== CORE METHODS =====
def save_api_key(self):
try:
key = self.api_input.getText().strip()
if not key:
self.add_chat_message("System", "Error: API key cannot be empty")
return
self.api_key = key
self.callbacks.saveExtensionSetting("burpaai_api_key", key)
self.add_chat_message("System", "API key saved successfully")
self.status_label.setText("Connected")
self.status_label.setForeground(Color(100, 200, 100))
except Exception as e:
print("[!] Error saving API key: " + str(e))
traceback.print_exc()
self.add_chat_message("System", "Error saving API key: " + str(e))
def update_model(self):
try:
self.model = str(self.model_combo.getSelectedItem())
print("[*] Model updated: " + self.model)
except Exception as e:
print("[!] Error updating model: " + str(e))
traceback.print_exc()
def send_chat_message(self):
try:
text = self.chat_input.getText().strip()
if not text:
return
if not self.api_key:
self.add_chat_message("System", "Error: API key not configured")
return
self.add_chat_message("You", text)
self.chat_input.setText("")
thread = threading.Thread(target=lambda: self._send_chat_async(text))
thread.daemon = True
thread.start()
except Exception as e:
print("[!] Error in send_chat_message: " + str(e))
traceback.print_exc()
def _send_chat_async(self, text):
try:
response = self.call_ai(text)
SwingUtilities.invokeLater(lambda: self.add_chat_message("AI", response))
except Exception as e:
print("[!] Error in _send_chat_async: " + str(e))
traceback.print_exc()
SwingUtilities.invokeLater(lambda: self.add_chat_message("System", "Error: " + str(e)))
def add_chat_message(self, sender, text):
def update_ui():
try:
timestamp = time.strftime("%H:%M:%S")
current = self.chat_display.getText()
# Format message based on sender type
if sender == "BugBounty":
prefix = "[" + timestamp + "] [ANALYSIS]: "
elif sender == "AI":
prefix = "[" + timestamp + "] [AI]: "
elif sender == "You":
prefix = "[" + timestamp + "] [YOU]: "
else:
prefix = "[" + timestamp + "] [" + sender + "]: "
formatted_text = prefix + text
if current:
new_text = current + "\n" + formatted_text
else:
new_text = formatted_text
self.chat_display.setText(new_text)
self.chat_display.setCaretPosition(len(new_text))
except Exception as e:
print("[!] Error in add_chat_message: " + str(e))
traceback.print_exc()
SwingUtilities.invokeLater(update_ui)
def send_request(self):
"""Send request via Burp's native HTTP handler"""
try:
# Get request from native editor
request_bytes = self.request_editor.getMessage()
if not request_bytes or len(request_bytes) == 0:
self.add_chat_message("System", "Error: Request editor is empty")
return
# Parse request to extract host, port, protocol
request_str = self.helpers.bytesToString(request_bytes)
# Use Burp's analyzeRequest to get proper structure
analyzed = self.helpers.analyzeRequest(request_bytes)
# Get HTTP service details
host = analyzed.getUrl().getHost()
port = analyzed.getUrl().getPort()
protocol = analyzed.getUrl().getProtocol()
use_https = (protocol.lower() == "https")
if not host:
self.add_chat_message("System", "Error: Could not parse host from request")
return
# Build HTTP service
http_service = self.helpers.buildHttpService(host, port, use_https)
# Send request and get response
response_bytes = self.callbacks.makeHttpRequest(http_service, request_bytes)
if response_bytes:
# Load response into native editor
self.response_editor.setMessage(response_bytes, False)
self.add_chat_message("System", "[RESPONSE] Received from " + host)
# Store in history
entry = {
"method": analyzed.getMethod(),
"host": host,
"path": analyzed.getUrl().getPath(),
"request": request_bytes,
"response": response_bytes,
"timestamp": time.time()
}
self.ai_history.append(entry)
# Update table thread-safe
def update_table():
try:
status_code = self._extract_status_code(response_bytes)
row_num = len(self.ai_history)
self.history_model.addRow([
str(row_num),
analyzed.getMethod(),
host[:30],
analyzed.getUrl().getPath()[:40],
status_code
])
print("[+] Request added to history: " + analyzed.getMethod() + " " + host)
except Exception as e:
print("[!] Error updating table: " + str(e))
SwingUtilities.invokeLater(update_table)
# Auto Analyze if enabled
if self.auto_analyze:
print("[*] Auto Analyze triggered")
thread = threading.Thread(target=self.analyze_with_ai)
thread.daemon = True
thread.start()
else:
self.add_chat_message("System", "Error: No response from server")
except Exception as e:
print("[!] Error in send_request: " + str(e))
traceback.print_exc()
self.add_chat_message("System", "Error: " + str(e))
def load_from_history(self):
"""Load request/response from history table on row selection"""
try:
if not self.history_table:
print("[!] History table not initialized")
return
row = self.history_table.getSelectedRow()
print("[*] History row selected: " + str(row))
if row < 0:
print("[!] No row selected (row < 0)")
return
if row >= len(self.ai_history):
print("[!] Row index out of bounds: " + str(row) + " >= " + str(len(self.ai_history)))
return
entry = self.ai_history[row]
print("[*] Loading from history - row: " + str(row) + ", method: " + entry.get("method", "?"))
# Load request
if "request" in entry and entry["request"]:
if self.request_editor:
self.request_editor.setMessage(entry["request"], True)
print("[+] Request loaded into editor")
else:
print("[!] Request editor not available")
# Load response
if "response" in entry and entry["response"]:
if self.response_editor:
self.response_editor.setMessage(entry["response"], False)
print("[+] Response loaded into editor")
else:
print("[!] Response editor not available")
except Exception as e:
print("[!] Error loading from history: " + str(e))
traceback.print_exc()
def add_row_to_history(self, row_data):
"""Thread-safe method to add row to history table"""
def add_row_ui():
try:
if self.history_model:
self.history_model.addRow(row_data)
print("[+] Row added to history: " + str(row_data[0]))
except Exception as e:
print("[!] Error adding row to history: " + str(e))
traceback.print_exc()
SwingUtilities.invokeLater(add_row_ui)
def _extract_status_code(self, response_bytes):
"""Extract HTTP status code from response"""
try:
response_str = self.helpers.bytesToString(response_bytes)
first_line = response_str.split('\n')[0]
parts = first_line.split(' ')
if len(parts) >= 2:
return parts[1]
except:
pass
return "?"
def _clean_reasoning_content(self, text):
"""Remove thinking/reasoning text from AI response and extract key payload sections"""
try:
# Remove common reasoning patterns
lines = text.split('\n')
cleaned = []
skip_section = False
for line in lines:
line_lower = line.lower().strip()
# Detect and preserve section headers
if any(header in line_lower for header in ["[vulns]", "[payloads]", "[attack", "[exploit", "[test", "[issues]", "[vectors]"]):
cleaned.append(line)
skip_section = False
continue
# Skip extended thinking patterns
if any(pattern in line_lower for pattern in [
"the user is asking",
"the user is requesting",
"i need to",
"let me think",
"first, let me",
"to summarize",
"in conclusion",
"thinking about",
"considering the request",
"<thinking>",
"</thinking>",
"analyze the request"
]):
continue
# Skip lines that are just thinking markers
if line_lower.startswith("<") and line_lower.endswith(">"):
continue
if line.strip():
cleaned.append(line)
result = '\n'.join(cleaned).strip()
# Limit to 800 chars for comprehensive analysis
if len(result) > 800:
result = result[:797] + "..."
return result if result else "Processing complete"
except:
return text
def _parse_vulnerability_response(self, response_text):
"""Parse AI response to extract and structure vulnerability data"""
try:
lines = response_text.split('\n')
parsed = {
"vulns": [],
"attack_points": [],
"payloads": [],
"exploit_idea": [],
"raw": response_text
}
current_section = None
for line in lines:
line_stripped = line.strip()
if not line_stripped:
continue
# Detect section headers
if "[VULNS]" in line_stripped.upper():
current_section = "vulns"
continue
elif "[ATTACK" in line_stripped.upper():
current_section = "attack_points"
continue
elif "[PAYLOADS]" in line_stripped.upper():
current_section = "payloads"
continue
elif "[EXPLOIT" in line_stripped.upper():
current_section = "exploit_idea"
continue
elif "[" in line_stripped and "]" in line_stripped:
current_section = None
continue
# Add content to current section
if current_section and line_stripped:
if line_stripped.startswith("-"):
line_stripped = line_stripped[1:].strip()
parsed[current_section].append(line_stripped)
return parsed
except:
return {"vulns": [], "attack_points": [], "payloads": [], "exploit_idea": [], "raw": response_text}
def _classify_vulnerability_severity(self, vuln_text):
"""Classify vulnerability severity based on keywords"""
vuln_lower = vuln_text.lower()
severity_map = {
"CRITICAL": ["rce", "code execution", "remote command", "database dump", "full system compromise"],
"HIGH": ["idor", "ssrf", "sqli", "auth bypass", "session hijack", "privilege escalation", "admin access"],
"MEDIUM": ["xss", "csrf", "xxe", "header injection", "cookie manipulation", "weak authentication"],
"LOW": ["information disclosure", "missing headers", "weak configuration", "cors"]
}
for severity, keywords in severity_map.items():
if any(kw in vuln_lower for kw in keywords):
return severity
return "MEDIUM"
def _format_vulnerability_output(self, parsed_vulns):
"""Format parsed vulnerability data for display"""
try:
output = ""
if parsed_vulns["vulns"]:
output += "[VULNERABILITIES]\n"
for vuln in parsed_vulns["vulns"]:
severity = self._classify_vulnerability_severity(vuln)
output += " - " + vuln + " (" + severity + ")\n"
output += "\n"
if parsed_vulns["attack_points"]:
output += "[ATTACK VECTORS]\n"
for point in parsed_vulns["attack_points"]:
output += " - " + point + "\n"
output += "\n"
if parsed_vulns["payloads"]:
output += "[TEST PAYLOADS]\n"
for payload in parsed_vulns["payloads"]:
output += " " + payload + "\n"
output += "\n"
if parsed_vulns["exploit_idea"]:
output += "[EXPLOITATION STEPS]\n"
for idea in parsed_vulns["exploit_idea"]:
output += " - " + idea + "\n"
return output if output else parsed_vulns["raw"]
except:
return parsed_vulns["raw"]
def analyze_with_ai(self):
"""Analyze request/response as Elite Bug Bounty Hunter - P1 Focus"""
try:
# Validate API key
if not self.api_key:
self.add_chat_message("System", "Error: API key not configured - cannot analyze")
return
# Get request from editor
if not self.request_editor:
self.add_chat_message("System", "Error: Request editor not available")
return
request_bytes = self.request_editor.getMessage()
if not request_bytes or len(request_bytes) == 0:
self.add_chat_message("System", "Error: Request editor is empty")
return
# Convert request to string
request_str = self.helpers.bytesToString(request_bytes)
# Get response from editor if available
response_str = ""
if self.response_editor:
response_bytes = self.response_editor.getMessage()
if response_bytes and len(response_bytes) > 0:
response_str = self.helpers.bytesToString(response_bytes)
# Bug bounty hunter analysis prompt - P1 focused with structured output
if response_str:
analysis_prompt = """You are an elite bug bounty hunter performing security analysis. Identify CRITICAL (P1/P2) vulnerabilities.
STRUCTURED ANALYSIS REQUIRED:
PRIORITY VULNERABILITIES:
1. RCE - Remote code execution, command injection
2. IDOR - Insecure direct object reference, privilege escalation
3. SSRF - Server-side request forgery, internal access
4. SQLi - SQL injection, data extraction
5. Auth bypass - Session hijacking, weak authentication
6. Critical misconfiguration - Admin panels, debug endpoints
SECONDARY CHECK:
- Missing security headers (CSP, X-Frame-Options, etc.)
- Weak cookies (missing HttpOnly, Secure, SameSite)
- CORS misconfiguration
- XXE, unsafe deserialization
- Header manipulation/injection
RESPONSE FORMAT (MANDATORY):
[VULNS]
- vulnerability name: severity level (CRITICAL/HIGH/MEDIUM/LOW)
[ATTACK POINTS]
- specific parameter/header/endpoint vulnerable
[PAYLOADS]
- raw, executable test code
- payload2
[EXPLOIT IDEA]
- step 1: how to trigger
- step 2: expected result
Analyze this request/response:
Request:
""" + request_str[:2000] + "\n\nResponse:\n" + response_str[:2000]
else:
analysis_prompt = """You are an elite bug bounty hunter. Analyze this request for CRITICAL (P1) vulnerabilities.
FOCUS AREAS:
1. RCE, IDOR, SSRF, SQLi, Auth bypass
2. Critical misconfigurations
3. Any exploitable patterns
RESPONSE FORMAT:
[VULNS]
- vulnerability: severity
[ATTACK POINTS]
- vulnerable vector
[PAYLOADS]
- test payload
[EXPLOIT IDEA]
- exploitation method
Request to analyze:
""" + request_str[:2000]
print("[*] Elite Bug Bounty Hunter Analysis - P1 FOCUS...")
self.add_chat_message("System", "Analyzing for P1 vulnerabilities...")
# Call AI in background
ai_response = self.call_ai(analysis_prompt)
# Parse and format the response
try:
parsed = self._parse_vulnerability_response(ai_response)
formatted = self._format_vulnerability_output(parsed)
self.add_chat_message("BugBounty", formatted)
print("[+] Parsed: " + str(len(parsed["vulns"])) + " vulnerabilities identified")
except:
# Fallback to raw response if parsing fails
self.add_chat_message("BugBounty", ai_response)
print("[+] P1 Analysis complete")
except Exception as e:
print("[!] Error in analyze_with_ai: " + str(e))
traceback.print_exc()
self.add_chat_message("System", "Error analyzing: " + str(e))
# ===== API METHODS =====
def call_ai(self, user_input, model=None):
"""Call DigitalOcean AI API with multi-model fallback engine"""
if not model:
model = self.model
# Ensure model is in our supported list
if model not in self.all_models:
model = self.primary_models[0]
try:
# Find starting index
try:
start_index = self.all_models.index(model)
except ValueError:
start_index = 0
# Try models starting from selected, then fallback chain
for attempt in range(len(self.all_models)):
current_model_idx = (start_index + attempt) % len(self.all_models)
current_model = self.all_models[current_model_idx]
try:
url = "https://inference.do-ai.run/v1/chat/completions"
payload = {
"model": current_model,
"messages": [
{
"role": "user",
"content": user_input
}
],
"max_tokens": 400
}
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer " + self.api_key
}
data_str = json.dumps(payload)
try:
if isinstance(data_str, unicode):
data_str = data_str.encode('utf-8')
except NameError:
pass
req = Request(url, data=data_str, headers=headers)
try:
response = urlopen(req, timeout=15)
resp_data = response.read()
if isinstance(resp_data, bytes):
resp_data = resp_data.decode('utf-8')
print("[*] API Response from " + current_model + ": " + resp_data[:80] + "...")
resp_json = json.loads(resp_data)
if 'choices' in resp_json and len(resp_json['choices']) > 0:
choice = resp_json['choices'][0]
if 'message' in choice:
msg = choice['message']
# Try content first
if 'content' in msg and msg['content'] and msg['content'].strip():
return msg['content'].strip()
# Fallback to reasoning_content if available
if 'reasoning_content' in msg and msg['reasoning_content']:
cleaned = self._clean_reasoning_content(msg['reasoning_content'])
if cleaned and cleaned.strip():
return cleaned
# Response received but empty - try next model
print("[!] Empty response from " + current_model + " - trying next model")
continue
except HTTPError as e:
error_code = e.code
print("[!] HTTPError " + str(error_code) + " from " + current_model + " - trying next model")
if error_code == 401:
return "API authentication failed - check API key"
# For other errors, continue to next model
continue
except Exception as e:
print("[!] Exception from " + current_model + ": " + str(e) + " - trying next model")
continue
except Exception as e:
print("[!] Error preparing request for " + current_model + ": " + str(e))
continue
# All models failed
return "AI service temporarily unavailable - tried all models"
except Exception as e:
print("[!] Exception in call_ai: " + str(e))
traceback.print_exc()
return "AI service error"
def forward_to_ai_from_menu(self, messages):
try:
if not messages or len(messages) == 0:
return
message = messages[0]
request = message.getRequest()
response = message.getResponse()
if not request:
return
# Load into native repeater editor
self.request_editor.setMessage(request, True)
if response:
self.response_editor.setMessage(response, False)
try:
# Get request details using analyzeRequest with message object
analyzed = self.helpers.analyzeRequest(message)
method = analyzed.getMethod()
host = analyzed.getUrl().getHost()
path = analyzed.getUrl().getPath()
# Add to history
entry = {
"method": method,
"host": host,
"path": path,
"request": request,
"response": response,
"timestamp": time.time()
}
self.ai_history.append(entry)
# Update table on UI thread
def update_table():
try:
row_num = len(self.ai_history)
status = self._extract_status_code(response)
self.history_model.addRow([
str(row_num),
method,
host[:25],
path[:35],
status
])
print("[+] Added request to history: " + method + " " + host + path)
except Exception as table_err:
print("[!] Error adding row to history: " + str(table_err))
traceback.print_exc()
SwingUtilities.invokeLater(update_table)
except Exception as analyze_err:
print("[!] Error analyzing request: " + str(analyze_err))
traceback.print_exc()
self.add_chat_message("System", "[FORWARDED] Request from Proxy/Repeater/Target")
except Exception as e:
print("[!] Error in forward_to_ai_from_menu: " + str(e))
traceback.print_exc()
self.add_chat_message("System", "Error forwarding request: " + str(e))
def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
"""HTTP listener callback - captures all traffic"""
try:
if not messageIsRequest:
response = messageInfo.getResponse()
if response:
try:
request = messageInfo.getRequest()
# CRITICAL FIX: Use analyzeRequest with messageInfo object, NOT just request bytes
analyzed = self.helpers.analyzeRequest(messageInfo)
method = analyzed.getMethod()
host = analyzed.getUrl().getHost()
path = analyzed.getUrl().getPath()
# Store in history with size limit
entry = {
"method": method,
"host": host,
"path": path,
"request": request,
"response": response,
"timestamp": time.time()
}
self.ai_history.append(entry)
self.traffic_log.append(messageInfo)
# Limit history to max_history entries to prevent memory bloat
if len(self.ai_history) > self.max_history:
self.ai_history.pop(0)
if len(self.traffic_log) > self.max_history:
self.traffic_log.pop(0)
# Update table on UI thread only
def update_table():
try:
status = self._extract_status_code(response)
row_num = len(self.ai_history)
if self.history_model:
self.history_model.addRow([
str(row_num),
method,
host[:25],
path[:35],
status
])
print("[+] Traffic captured: " + method + " " + host + path + " [" + status + "]")
except Exception as table_err:
print("[!] Error updating history table: " + str(table_err))
SwingUtilities.invokeLater(update_table)
except Exception as e:
print("[!] Error processing HTTP message: " + str(e))
traceback.print_exc()
except Exception as e:
print("[!] Error in processHttpMessage: " + str(e))
traceback.print_exc()