From f3cd3d4f060fe138d72700e374f6fa9801b5781f Mon Sep 17 00:00:00 2001 From: "vladimir.kuznetsov" Date: Sun, 21 Apr 2024 17:58:57 +0500 Subject: [PATCH] added checking for dangerous strings in openvpn configuration files --- client/ui/controllers/importController.cpp | 60 ++++++++++++++++++- client/ui/controllers/importController.h | 4 ++ client/ui/qml/Controls2/WarningType.qml | 13 ++++ .../qml/Pages2/PageSetupWizardViewConfig.qml | 16 +++++ 4 files changed, 90 insertions(+), 3 deletions(-) diff --git a/client/ui/controllers/importController.cpp b/client/ui/controllers/importController.cpp index f531ebb6..8d1ff53e 100644 --- a/client/ui/controllers/importController.cpp +++ b/client/ui/controllers/importController.cpp @@ -3,8 +3,8 @@ #include #include #include -#include #include +#include #include "core/errorstrings.h" #ifdef Q_OS_ANDROID @@ -103,7 +103,11 @@ bool ImportController::extractConfigFromData(QString data) switch (m_configType) { case ConfigTypes::OpenVpn: { 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::WireGuard: { @@ -116,7 +120,11 @@ bool ImportController::extractConfigFromData(QString data) } case ConfigTypes::Amnezia: { 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: { if (!m_serversModel->getServersCount()) { @@ -161,6 +169,11 @@ QString ImportController::getConfigFileName() return m_configFileName; } +QString ImportController::getMaliciousWarningText() +{ + return m_maliciousWarningText; +} + bool ImportController::isNativeWireGuardConfig() { return m_configType == ConfigTypes::WireGuard; @@ -223,6 +236,7 @@ void ImportController::importConfig() m_config = {}; m_configFileName.clear(); + m_maliciousWarningText.clear(); } 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); } #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("
%1").arg(string)); + } + } + } + } +} diff --git a/client/ui/controllers/importController.h b/client/ui/controllers/importController.h index bebbeca3..509c4631 100644 --- a/client/ui/controllers/importController.h +++ b/client/ui/controllers/importController.h @@ -34,6 +34,7 @@ public slots: bool extractConfigFromQr(const QByteArray &data); QString getConfig(); QString getConfigFileName(); + QString getMaliciousWarningText(); #if defined Q_OS_ANDROID || defined Q_OS_IOS void startDecodingQr(); @@ -63,6 +64,8 @@ private: QJsonObject extractWireGuardConfig(const QString &data); QJsonObject extractXrayConfig(const QString &data); + void checkForMaliciousStrings(const QJsonObject &protocolConfig); + #if defined Q_OS_ANDROID || defined Q_OS_IOS void stopDecodingQr(); #endif @@ -74,6 +77,7 @@ private: QJsonObject m_config; QString m_configFileName; ConfigTypes m_configType; + QString m_maliciousWarningText; #if defined Q_OS_ANDROID || defined Q_OS_IOS QMap m_qrCodeChunks; diff --git a/client/ui/qml/Controls2/WarningType.qml b/client/ui/qml/Controls2/WarningType.qml index 08890944..f996403e 100644 --- a/client/ui/qml/Controls2/WarningType.qml +++ b/client/ui/qml/Controls2/WarningType.qml @@ -1,13 +1,18 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts +import Qt5Compat.GraphicalEffects import "TextTypes" Rectangle { + id: root + property string textColor: "#D7D8DB" property string backGroundColor: "#1C1D21" + property string imageColor: "#D7D8DB" property string textString + property int textFormat: Text.PlainText property string iconPath property real iconWidth: 16 @@ -36,6 +41,13 @@ Rectangle { height: iconHeight source: iconPath + + layer { + enabled: true + effect: ColorOverlay { + color: imageColor + } + } } CaptionTextType { @@ -45,6 +57,7 @@ Rectangle { Layout.leftMargin: 8 text: textString + textFormat: root.textFormat color: textColor } } diff --git a/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml b/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml index 88368734..024f3488 100644 --- a/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml +++ b/client/ui/qml/Pages2/PageSetupWizardViewConfig.qml @@ -125,6 +125,20 @@ PageType { 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 { Layout.topMargin: 16 Layout.fillWidth: true @@ -151,6 +165,8 @@ PageType { anchors.fill: parent anchors.margins: 16 + wrapMode: Text.Wrap + text: ImportController.getConfig() } }