This commit is contained in:
Tim Blume 2021-03-20 22:56:03 +01:00
parent 8b7b40d3ab
commit 600d7146d3
21 changed files with 175 additions and 39 deletions

2
.gitignore vendored
View file

@ -77,3 +77,5 @@ Thumbs.db
# Clion
.idea/
.tox
*.egg-info

View file

@ -19,7 +19,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(PLUGIN_DIR ${CMAKE_BINARY_DIR}/plugins)
find_package(Qt5 COMPONENTS Widgets REQUIRED)
find_package(cppzmq REQUIRED)
find_package(nlohmann_json REQUIRED)
find_package(SQLite3 REQUIRED)
find_package(Catch2 REQUIRED)
@ -27,7 +26,6 @@ find_package(Catch2 REQUIRED)
add_executable(bigsnitch
main.cpp
mainwindow.cpp
networkthread.cpp
session.cpp
httpflow.cpp
pluginhandler.cpp
@ -38,7 +36,6 @@ add_executable(bigsnitch
mainwindow.h
httpflow.h
networkthread.h
session.h
includes.h
proxyhandler.h
@ -55,18 +52,18 @@ add_executable(bigsnitch
mainwindow.ui
editandresend.ui
settings.ui
pluginlist.ui
)
target_include_directories(bigsnitch PRIVATE /usr/local/include)
target_link_libraries(bigsnitch PRIVATE Qt5::Widgets cppzmq sqlite3)
target_link_libraries(bigsnitch PRIVATE Qt5::Widgets sqlite3)
add_executable(bigsnitch_tests
tests/generic_tests.cpp
networkthread.cpp
)
target_include_directories(bigsnitch_tests PRIVATE /usr/local/include)
target_link_libraries(bigsnitch_tests PRIVATE Qt5::Widgets cppzmq sqlite3 Catch2::Catch2)
target_link_libraries(bigsnitch_tests PRIVATE Qt5::Widgets sqlite3 Catch2::Catch2)
add_subdirectory(plugins/mitmproxy/)

View file

@ -6,11 +6,13 @@ namespace Ui {
class EditAndResend;
}
//! EditAndResend Dialog
class EditAndResend : public QDialog
{
Q_OBJECT
public:
//! EditAndResend constructor
explicit EditAndResend(std::tuple<QString, QString, QString, QString> initial, QWidget *parent = nullptr);
~EditAndResend();

View file

@ -6,6 +6,7 @@
#include <mutex>
#include <sstream>
//! The HistoryModel implements the AbstractTableModel for interacting with the view.
class HistoryModel : public QAbstractTableModel
{
Q_OBJECT
@ -15,19 +16,28 @@ private:
std::string getRequestHeader(const HistoryItem& item) const;
std::string getResponseHeader(const HistoryItem& item) const;
public:
//! HistoryModel constructor
HistoryModel(QObject *parent = nullptr);
//! rowCount
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
//! columnCount
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
//! data
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
//! headerData
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
//! update
void update(std::vector<HistoryItem>* items);
};
//! HistoryProxyModel implements a SortFilterProxyModel for interacting with the view
class HistoryProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
private:
public:
//! lessThan
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
//! filterAcceptsRow
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
};

View file

@ -3,14 +3,6 @@
//major minor patch
#define LITTLESNITCH_VERSION 100
#include <QtCore/QtGlobal>
#if defined(IS_PROXY_LIBRARY)
# define MYSHAREDLIB_EXPORT Q_DECL_EXPORT
#else
# define MYSHAREDLIB_EXPORT Q_DECL_IMPORT
#endif
#include <iostream>
#include <map>
#include <vector>

View file

@ -21,8 +21,11 @@ namespace http {
*/
class ProxyInterface {
public:
// the path the proxy listens on
std::string path;
virtual ~ProxyInterface() = default;
//! returns name of the plugin
virtual QString getName() = 0;
//! returns, whether the proxy is currently connected
virtual bool connected() = 0;
//! disconnects the handle

View file

@ -2,7 +2,6 @@
#include <historymodel.h>
#include "./ui_mainwindow.h"
#include <QtGui>
#include "networkthread.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent),
@ -10,20 +9,17 @@ MainWindow::MainWindow(QWidget *parent)
{
qRegisterMetaType<http::Flow>("httpflow");
current_session = new Session();
// TODO: make configurable
current_session->load("/tmp/littlesnitch.session");
// TODO: use relative paths
plugin_handler.loadPlugins(QDir("/home/end/projects/bigsnitch/build/plugins/"));
/*
thread = new QThread;
NetworkThread* worker = new NetworkThread();
worker->moveToThread(thread);
connect(thread, SIGNAL (started()), worker, SLOT (process()));
//connect(worker, SIGNAL (error(QString)), this, SLOT (errorString(QString)));
connect(worker, SIGNAL (httpMessage(http::Flow)), current_session, SLOT (saveFlow(http::Flow)), Qt::QueuedConnection);
connect(worker, SIGNAL (httpMessage(http::Flow)), this, SLOT (updateHistory()), Qt::QueuedConnection);
thread->start();
*/
// TODO: fix error string
//QObject::connect(plugin_handler, SIGNAL (proxy_error(QString)), this, SLOT ( errorString(QString)), Qt::QueuedConnection);
QObject::connect(&plugin_handler, SIGNAL (proxy_message(http::Flow)), this, SLOT (updateHistory()), Qt::QueuedConnection);
QObject::connect(&plugin_handler, SIGNAL (proxy_message(http::Flow)), current_session, SLOT (saveFlow(http::Flow)), Qt::QueuedConnection);
history_model.update(current_session->getHistoryItems());
history_proxy.setSourceModel(&history_model);

View file

@ -13,6 +13,7 @@ QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
//! MainWindow
class MainWindow : public QMainWindow
{
Q_OBJECT
@ -34,15 +35,23 @@ private:
// hack for supplying the initial data to edit&resend
std::tuple<QString, QString, QString, QString> current_selection;
public:
//! MainWindow constructor
MainWindow(QWidget *parent = nullptr);
~MainWindow();
//! opens the EditAndResend window
void openEditAndResend();
public slots:
//! triggers a history update
void updateHistory();
//! right click menu
void editMenuRequested(QPoint pos);
//! right click menu
void edit2MenuRequested(QPoint pos);
//! right click menu
void edit3MenuRequested(QPoint pos);
//! right click menu
void edit4MenuRequested(QPoint pos);
//! right click menu
void historyMenuRequested(QPoint pos);
private slots:
void on_selectionChange(const QItemSelection& selection);

View file

@ -0,0 +1,3 @@
mitmproxy
mitmdump
pyzmq

6
mitmaddon/setup.py Normal file
View file

@ -0,0 +1,6 @@
#!/usr/bin/env python
from setuptools import setup, find_packages
setup(name='bigsnitch-mitmaddon',
version='1.0',
packages=find_packages())

15
mitmaddon/tox.ini Normal file
View file

@ -0,0 +1,15 @@
[tox]
skipsdist = true
envlist = py3
# Add environment to use the default python3 installation
[testenv:py3]
basepython = python3
[testenv]
usedevelop = true
deps = -r{toxinidir}/requirements.txt
setenv =
PYTHONDONTWRITEBYTECODE=1
commands =
{envpython} sh ../test.sh

View file

@ -15,6 +15,10 @@ bool PluginHandler::load(QString path)
qDebug() << "loading plugin " << plugin;
proxyhandler.loadPlugin(plugin);
loaded_plugins += path;
QObject::connect(plugin, SIGNAL (error(QString)), this, SIGNAL (proxy_error(QString)), Qt::QueuedConnection);
QObject::connect(plugin, SIGNAL (message(http::Flow)), this, SIGNAL (proxy_message(http::Flow)), Qt::QueuedConnection);
return true;
} else {
qDebug() << "fo " << loader.errorString();

View file

@ -7,12 +7,25 @@
#include <QPluginLoader>
#include <proxyhandler.h>
class PluginHandler
//! PluginHandler controls all plugins.
//! Every different plugin interface, that got signals has to reference them here
//! Other parts of bigsnitch connect to them here.
class PluginHandler : public QObject
{
Q_OBJECT
private:
QStringList loaded_plugins;
http::ProxyHandler proxyhandler;
public:
//! Loads a single plugin.
bool load(QString path);
//! loads all plugins in a directory.
void loadPlugins(QDir path);
signals:
//! error signal from ProxyInterface
void proxy_error(QString err);
//! message signal from ProxyInterface
void proxy_message(http::Flow flow);
};

70
pluginlist.ui Normal file
View file

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>701</width>
<height>626</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTreeView" name="treeView">
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QFrame" name="frame">
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<widget class="QLineEdit" name="lineEdit">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>281</width>
<height>21</height>
</rect>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -1,4 +1,7 @@
SET(CMAKE_AUTOMOC ON)
find_package(cppzmq REQUIRED)
add_compile_definitions(IS_HTTP_PROXY_INTERFACE)
add_library(mitmproxy_plugin SHARED mitmproxy_network.cpp mitmproxy_network.h mitmproxy.json)
target_include_directories(mitmproxy_plugin PRIVATE ../../include/)

View file

@ -22,6 +22,11 @@ void mitmproxyPlugin::reconnect()
this->connect();
}
QString mitmproxyPlugin::getName()
{
return QString("mitmproxy bridge");
}
void mitmproxyPlugin::process()
{
connect();
@ -46,7 +51,7 @@ void mitmproxyPlugin::process()
qDebug() << "received " << msg_type.c_str();
} else if(msg_type == "response") {
qDebug() << "received " << msg_type.c_str();
message(j);
emit message(j);
} else if(msg_type == "requestheaders") {
qDebug() << "received " << msg_type.c_str();
} else if(msg_type == "request") {
@ -55,8 +60,8 @@ void mitmproxyPlugin::process()
qDebug() << "received " << msg_type.c_str();
} else if(msg_type == "error") {
qDebug() << "received " << msg_type.c_str();
// websocket events
emit error("error received");
} else if(msg_type == "websocket_handshake") {
qDebug() << "received " << msg_type.c_str();
} else if(msg_type == "websocket_start") {

View file

@ -28,6 +28,8 @@ private:
void reconnect();
public:
//! name of the plugin
QString getName() override;
//! returns, whether the proxy is currently connected
bool connected() override;
//! disconnects the handle

View file

@ -15,13 +15,13 @@ bool http::ProxyHandler::loadPlugin(QObject *proxy)
// TODO: get path from config or something
inst->path = "tcp://127.0.0.1:12345";
QObject::connect(thread, SIGNAL (started()), proxy, SLOT (process()));
//QObject::connect(proxy, SIGNAL (error(QString)), this, SLOT (errorString(QString)));
//QObject::connect(proxy, SIGNAL (message(http::Flow)), current_session, SLOT (saveFlow(http::Flow)), Qt::QueuedConnection);
//QObject::connect(proxy, SIGNAL (message(http::Flow)), this, SLOT (updateHistory()), Qt::QueuedConnection);
QObject::connect(proxy, SIGNAL (error(QString)), this, SIGNAL (error(QString)), Qt::QueuedConnection);
QObject::connect(proxy, SIGNAL (message(http::Flow)), this, SIGNAL (message(http::Flow)), Qt::QueuedConnection);
thread->start();
//proxies.insert({"foo", inst, thread});
auto name = inst->getName();
proxies.insert({name, {inst, thread}});
return true;
}

View file

@ -6,13 +6,19 @@
namespace http {
class ProxyHandler
class ProxyHandler : public QObject
{
Q_OBJECT
private:
std::map<std::string, ProxyInterface*, QThread*> proxies;
std::map<QString, std::pair<ProxyInterface*, QThread*>> proxies;
public:
bool loadPlugin(QObject *proxy);
QStringList getProxies();
signals:
void error(QString err);
void message(http::Flow flow);
};
}

View file

@ -1,8 +1,8 @@
#!/bin/sh
mitmdump -k -p 1878 -s mitmaddon/littlesnitch.py &
mitmdump -k -p 1878 -s ./mitmaddon/bigsnitch.py &
export mitmpid=$!
./build/littlesnitch &
./build/bin/bigsnitch &
sleep 5
curl -s -x http://localhost:1878 -k https://yolo.jetzt > /dev/null

View file

@ -1,8 +1,6 @@
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>
#include "networkthread.h"
TEST_CASE( "1 eq 1", "[test]" ) {
REQUIRE( 1 == 1 );
}