added checking for dangerous strings in openvpn configuration files

This commit is contained in:
vladimir.kuznetsov 2024-04-21 17:58:57 +05:00
parent d90685600e
commit f3cd3d4f06
4 changed files with 90 additions and 3 deletions

View file

@ -3,8 +3,8 @@
#include <QFile> #include <QFile>
#include <QFileInfo> #include <QFileInfo>
#include <QQuickItem> #include <QQuickItem>
#include <QStandardPaths>
#include <QRandomGenerator> #include <QRandomGenerator>
#include <QStandardPaths>
#include "core/errorstrings.h" #include "core/errorstrings.h"
#ifdef Q_OS_ANDROID #ifdef Q_OS_ANDROID
@ -103,7 +103,11 @@ bool ImportController::extractConfigFromData(QString data)
switch (m_configType) { switch (m_configType) {
case ConfigTypes::OpenVpn: { case ConfigTypes::OpenVpn: {
m_config = extractOpenVpnConfig(config); m_config = extractOpenVpnConfig(config);
return m_config.empty() ? false : true; if (!m_config.empty()) {
checkForMaliciousStrings(m_config);
return true;
}
return false;
} }
case ConfigTypes::Awg: case ConfigTypes::Awg:
case ConfigTypes::WireGuard: { case ConfigTypes::WireGuard: {
@ -116,7 +120,11 @@ bool ImportController::extractConfigFromData(QString data)
} }
case ConfigTypes::Amnezia: { case ConfigTypes::Amnezia: {
m_config = QJsonDocument::fromJson(config.toUtf8()).object(); m_config = QJsonDocument::fromJson(config.toUtf8()).object();
return m_config.empty() ? false : true; if (!m_config.empty()) {
checkForMaliciousStrings(m_config);
return true;
}
return false;
} }
case ConfigTypes::Backup: { case ConfigTypes::Backup: {
if (!m_serversModel->getServersCount()) { if (!m_serversModel->getServersCount()) {
@ -161,6 +169,11 @@ QString ImportController::getConfigFileName()
return m_configFileName; return m_configFileName;
} }
QString ImportController::getMaliciousWarningText()
{
return m_maliciousWarningText;
}
bool ImportController::isNativeWireGuardConfig() bool ImportController::isNativeWireGuardConfig()
{ {
return m_configType == ConfigTypes::WireGuard; return m_configType == ConfigTypes::WireGuard;
@ -223,6 +236,7 @@ void ImportController::importConfig()
m_config = {}; m_config = {};
m_configFileName.clear(); m_configFileName.clear();
m_maliciousWarningText.clear();
} }
QJsonObject ImportController::extractOpenVpnConfig(const QString &data) QJsonObject ImportController::extractOpenVpnConfig(const QString &data)
@ -526,3 +540,43 @@ QString ImportController::getQrCodeScanProgressString()
return tr("Scanned %1 of %2.").arg(m_receivedQrCodeChunksCount).arg(m_totalQrCodeChunksCount); return tr("Scanned %1 of %2.").arg(m_receivedQrCodeChunksCount).arg(m_totalQrCodeChunksCount);
} }
#endif #endif
void ImportController::checkForMaliciousStrings(const QJsonObject &serverConfig)
{
const QJsonArray &containers = serverConfig[config_key::containers].toArray();
for (const QJsonValue &container : containers) {
auto containerConfig = container.toObject();
auto containerName = containerConfig[config_key::container].toString();
if ((containerName == ContainerProps::containerToString(DockerContainer::OpenVpn))
|| (containerName == ContainerProps::containerToString(DockerContainer::Cloak))
|| (containerName == ContainerProps::containerToString(DockerContainer::ShadowSocks))) {
QString protocolConfig =
containerConfig[ProtocolProps::protoToString(Proto::OpenVpn)].toObject()[config_key::last_config].toString();
QString protocolConfigJson = QJsonDocument::fromJson(protocolConfig.toUtf8()).object()[config_key::config].toString();
const QRegularExpression regExp { "(\\w+-\\w+|\\w+)" };
const size_t dangerousTagsMaxCount = 3;
// https://github.com/OpenVPN/openvpn/blob/master/doc/man-sections/script-options.rst
QStringList dangerousTags {
"up", "tls-verify", "ipchange", "client-connect", "route-up", "route-pre-down", "client-disconnect", "down", "learn-address", "auth-user-pass-verify"
};
QStringList maliciousStrings;
QStringList lines = protocolConfigJson.replace("\r", "").split("\n");
for (const QString &l : lines) {
QRegularExpressionMatch match = regExp.match(l);
if (dangerousTags.contains(match.captured(0))) {
maliciousStrings << l;
}
}
if (maliciousStrings.size() >= dangerousTagsMaxCount) {
m_maliciousWarningText = tr("In the imported configuration, potentially dangerous lines were found:");
for (const auto &string : maliciousStrings) {
m_maliciousWarningText.push_back(QString("<br><i>%1</i>").arg(string));
}
}
}
}
}

View file

@ -34,6 +34,7 @@ public slots:
bool extractConfigFromQr(const QByteArray &data); bool extractConfigFromQr(const QByteArray &data);
QString getConfig(); QString getConfig();
QString getConfigFileName(); QString getConfigFileName();
QString getMaliciousWarningText();
#if defined Q_OS_ANDROID || defined Q_OS_IOS #if defined Q_OS_ANDROID || defined Q_OS_IOS
void startDecodingQr(); void startDecodingQr();
@ -63,6 +64,8 @@ private:
QJsonObject extractWireGuardConfig(const QString &data); QJsonObject extractWireGuardConfig(const QString &data);
QJsonObject extractXrayConfig(const QString &data); QJsonObject extractXrayConfig(const QString &data);
void checkForMaliciousStrings(const QJsonObject &protocolConfig);
#if defined Q_OS_ANDROID || defined Q_OS_IOS #if defined Q_OS_ANDROID || defined Q_OS_IOS
void stopDecodingQr(); void stopDecodingQr();
#endif #endif
@ -74,6 +77,7 @@ private:
QJsonObject m_config; QJsonObject m_config;
QString m_configFileName; QString m_configFileName;
ConfigTypes m_configType; ConfigTypes m_configType;
QString m_maliciousWarningText;
#if defined Q_OS_ANDROID || defined Q_OS_IOS #if defined Q_OS_ANDROID || defined Q_OS_IOS
QMap<int, QByteArray> m_qrCodeChunks; QMap<int, QByteArray> m_qrCodeChunks;

View file

@ -1,13 +1,18 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import "TextTypes" import "TextTypes"
Rectangle { Rectangle {
id: root
property string textColor: "#D7D8DB" property string textColor: "#D7D8DB"
property string backGroundColor: "#1C1D21" property string backGroundColor: "#1C1D21"
property string imageColor: "#D7D8DB"
property string textString property string textString
property int textFormat: Text.PlainText
property string iconPath property string iconPath
property real iconWidth: 16 property real iconWidth: 16
@ -36,6 +41,13 @@ Rectangle {
height: iconHeight height: iconHeight
source: iconPath source: iconPath
layer {
enabled: true
effect: ColorOverlay {
color: imageColor
}
}
} }
CaptionTextType { CaptionTextType {
@ -45,6 +57,7 @@ Rectangle {
Layout.leftMargin: 8 Layout.leftMargin: 8
text: textString text: textString
textFormat: root.textFormat
color: textColor color: textColor
} }
} }

View file

@ -125,6 +125,20 @@ PageType {
text: qsTr("Enable WireGuard obfuscation. It may be useful if WireGuard is blocked on your provider.") text: qsTr("Enable WireGuard obfuscation. It may be useful if WireGuard is blocked on your provider.")
} }
WarningType {
Layout.topMargin: 16
Layout.fillWidth: true
textString: ImportController.getMaliciousWarningText()
textFormat: Qt.RichText
visible: textString !== ""
iconPath: "qrc:/images/controls/alert-circle.svg"
textColor: "#EB5757"
imageColor: "#EB5757"
}
WarningType { WarningType {
Layout.topMargin: 16 Layout.topMargin: 16
Layout.fillWidth: true Layout.fillWidth: true
@ -151,6 +165,8 @@ PageType {
anchors.fill: parent anchors.fill: parent
anchors.margins: 16 anchors.margins: 16
wrapMode: Text.Wrap
text: ImportController.getConfig() text: ImportController.getConfig()
} }
} }