Merge pull request #772 from amnezia-vpn/feature/check-openvpn-config

added checking for dangerous strings in openvpn configuration files
This commit is contained in:
pokamest 2024-04-30 10:26:12 -07:00 committed by GitHub
commit eb48e4b668
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 90 additions and 3 deletions

View file

@ -3,8 +3,8 @@
#include <QFile>
#include <QFileInfo>
#include <QQuickItem>
#include <QStandardPaths>
#include <QRandomGenerator>
#include <QStandardPaths>
#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("<br><i>%1</i>").arg(string));
}
}
}
}
}

View file

@ -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<int, QByteArray> m_qrCodeChunks;

View file

@ -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
}
}

View file

@ -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()
}
}