В этой статье я рас­ска­жу, как написать на Python рас­ширение Burp для свя­зи меж­ду Burp и Acunetix. Будем переда­вать тар­геты меж­ду прог­рамма­ми и запус­кать ска­ны в один клик.

В обе­их прог­раммах есть сот­ни ска­неров, при­чем мно­гие уни­каль­ны для одной из них. Acunetix шикар­но выпол­няет мас­совое ска­ниро­вание, тог­да как Burp хорош при работе с одним тар­гетом. На мой взгляд, они иде­аль­но допол­няют друг дру­га.

Я пос­тавил цель — соз­дать инс­тру­мент, который поз­волит быс­тро и удоб­но собирать пол­ную информа­цию о тар­гете и уяз­вимос­тях в про­екте Burp. Цель серь­езная, и код рас­ширения вышел объ­емным. Поэто­му я решил под­готовить два матери­ала.

Нач­нем с соз­дания интерфей­са для управле­ния клю­чами дос­тупа к Acunetix API, нас­тро­им переда­чу тар­гетов из Burp в Acunetix и обратно. Я помогу разоб­рать­ся, как стро­ится интерфейс вклад­ки и как выпол­нять сто­рон­ние зап­росы в Burp. По дороге ты осво­ишь осно­вы Acunetix API.

 

Интерфейс расширения

Нам пот­ребу­ется хра­нить ключ от Acunetix API и пра­виль­ный URL. Давай сде­лаем вклад­ку с неболь­шим интерфей­сом из двух тек­сто­вых полей и кно­пок: Check и Save. Кноп­ка Check про­верит дос­тупность API, Save отпра­вит дан­ные в хра­нили­ще, что­бы не нуж­но было вво­дить кре­ды перед каж­дым исполь­зовани­ем.

www

Ис­ходные коды рас­ширения можешь ска­чать с моего GitHub.

Рас­ширение раз­делим на модули, что­бы сох­ранить чита­емость кода и воз­можность мас­шта­биро­вать без боли. Соз­дай основной файл burp-acunetix.py. При добав­лении в Burp нуж­но будет ука­зывать имен­но этот файл!

# -*- coding: utf-8 -*-
# Обязательно указывай кодировку, если используешь кириллицу в комментариях
# В интерфейсе не используй кириллицу вообще
from burp import IBurpExtender, ITab
# Вынесем интерфейс в отдельный класс, чтобы сохранить читаемость кода
from ui import AppConfigPanel
# Любое расширение должно расширять класс IBurpExtender, ITab нужен, если создаешь собственную вкладку
class BurpExtender(IBurpExtender, ITab):
# Главная функция, в которой определяешь поведение расширения и его возможности
def registerExtenderCallbacks(self, callbacks):
# Сохрани колбэки Burp Extender, чтобы была возможность управлять Burp
self._callbacks = callbacks
# То же с функциями-хелперами
self._helpers = callbacks.getHelpers()
# Установи имя расширения в списке расширений Burp (не название вкладки)
callbacks.setExtensionName("Acunetix Sync")
# Класс интерфейса реализуем чуть позже
self.ui = AppConfigPanel(callbacks)
# Добавление собственной вкладки в интерфейс Burp
callbacks.addSuiteTab(self)
# Функция ITab для установки надписи на вкладке
def getTabCaption(self):
return "Acunetix Sync"
# Функция ITab для привязки интерфейса расширения к твоей вкладке
def getUiComponent(self):
# Создание интерфейса из класса AppConfigPanel
return self.ui.get_component()

info

registerExtenderCallbacks — глав­ная фун­кция, которая выпол­няет ини­циали­зацию любого рас­ширения, написан­ного для Extender API. В рас­ширение переда­ются кол­бэки, через которые мож­но нас­тро­ить само рас­ширение и управлять поведе­нием Burp.

Burp написан на Java, поэто­му интерфей­сы рас­ширения тебе при­дет­ся писать на ком­понен­тах биб­лиоте­ки Swing. От рас­ширений с интерфей­сом Burp ждет стан­дар­тный объ­ект JPanel, к которо­му прик­репле­ны все осталь­ные эле­мен­ты. Получа­ется панель, на которой рас­положе­ны дру­гие панели и лей­ауты (это нуж­но для пра­виль­ного позици­они­рова­ния эле­мен­тов), а на них — конеч­ные эле­мен­ты вро­де тек­сто­вых полей (JTextField) и кно­пок (JButton).

www

В статье интерфейс опи­сан кодом. Если хочешь переде­лать интерфейс для себя, исполь­зуй Apache NetBeans. IDE пол­ностью бес­плат­ная и кросс‑плат­формен­ная. С ее помощью ты смо­жешь мыш­кой накидать интерфейс любой слож­ности. Пос­ле возь­ми исходный код интерфей­са и по ана­логии с кодом рас­ширения перене­си его на Jython для исполь­зования в рас­ширени­ях Burp.

Код интерфей­са помес­ти в файл ui.py.

# -*- coding: utf-8 -*-
# Заранее импортирую все элементы, которые потребуются для конечного расширения, а не только нужные сейчас
from javax.swing import (
JPanel, JLabel, JTextField, JButton, BoxLayout, BorderFactory, Box, JScrollPane,
JTable, ListSelectionModel, SwingUtilities, JComboBox, JOptionPane
)
from javax.swing.table import DefaultTableModel
from java.awt import GridBagLayout, GridBagConstraints, Insets, Dimension, BorderLayout, Color
from java.net import URL
class AppConfigPanel(object):
# При инициализации сохрани ссылки на важные части расширения для доступа к ним. Client и store определим позже, пока укажи, что они могут быть None
def __init__(self, callbacks, client = None, store = None):
# Колбэки API Burp
self._callbacks = callbacks
# Через client будем передавать объект API Acunetix для прямых вызовов
self.client = client
# Объект с данными, которые необходимо хранить между запусками
self.store = store
self.current_target = None
self._build_ui()
def _build_ui(self):
self.panel = JPanel(BorderLayout())
main_container = JPanel()
main_container.setLayout(BoxLayout(main_container, BoxLayout.Y_AXIS))
main_container.add(Box.createVerticalStrut(15))
api_panel = JPanel(GridBagLayout())
api_panel.setBorder(BorderFactory.createTitledBorder("API Settings"))
gbc = GridBagConstraints()
gbc.insets = Insets(6, 6, 6, 6)
gbc.anchor = GridBagConstraints.WEST
gbc.gridx = 0
gbc.gridy = 0
gbc.weightx = 0
gbc.fill = GridBagConstraints.NONE
api_panel.add(JLabel("API Key:"), gbc)
gbc.gridx = 1
gbc.weightx = 1.0
gbc.fill = GridBagConstraints.HORIZONTAL
# Сохраняем ссылку на текстовое поле в переменной объекта, чтобы был прямой доступ
self.key_field = JTextField()
self.key_field.setPreferredSize(Dimension(280, 26))
api_panel.add(self.key_field, gbc)
gbc.gridx = 0
gbc.gridy = 1
gbc.weightx = 0; gbc.fill = GridBagConstraints.NONE
api_panel.add(JLabel("API URL:"), gbc)
gbc.gridx = 1; gbc.weightx = 1.0; gbc.fill = GridBagConstraints.HORIZONTAL
# Сохраняем ссылку на текстовое поле в переменной объекта, чтобы был прямой доступ
self.url_field = JTextField()
api_panel.add(self.url_field, gbc)
btn_panel = JPanel()
btn_panel.setLayout(BoxLayout(btn_panel, BoxLayout.X_AXIS))
self.check_btn = JButton("Check", actionPerformed=self.on_check_connection)
self.check_btn.setPreferredSize(Dimension(100, 28))
btn_panel.add(self.check_btn)
btn_panel.add(Box.createHorizontalStrut(8))
# Создаем кнопку, указав функцию, обрабатывающую событие клика. actionPerformed основное событие для элемента. Для кнопки это клик
self.save_btn = JButton("Save", actionPerformed=self.on_save)
self.save_btn.setPreferredSize(Dimension(100, 28))
btn_panel.add(self.save_btn)
gbc.gridx = 1
gbc.gridy = 2
gbc.weightx = 0
gbc.fill = GridBagConstraints.NONE
gbc.anchor = GridBagConstraints.EAST
api_panel.add(btn_panel, gbc)
main_container.add(api_panel)
main_container.add(Box.createVerticalStrut(15))
wrapper = JPanel(BorderLayout())
wrapper.add(main_container, BorderLayout.NORTH)
self.panel.add(JScrollPane(wrapper), BorderLayout.CENTER)
def get_component(self):
return self.panel
# Функция проверки доступности Acunetix API при нажатии на Check
def on_check_connection(self, event):
pass
# Функция сохранения кредов при нажатии на Save
def on_save(self, event):
pass
 

Первый запуск расширения

В Burp открой вклад­ку Extensions → Extensions Settings. Най­ди Python environment, убе­дись, что ука­зан путь к Jython. Если Jython не уста­нов­лен, ска­чай Jython Standalone пос­ледней вер­сии и ука­жи путь к это­му фай­лу.

Продолжение доступно только участникам

Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».

Присоединяйся к сообществу «Xakep.ru»!

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии