From 34f7b75f12390454ed831037ff34531b90307c55 Mon Sep 17 00:00:00 2001 From: Chocobo1 Date: Sat, 7 Oct 2023 12:28:07 +0800 Subject: [PATCH] Add support for Mark-of-the-Web https://redcanary.com/threat-detection-report/techniques/mark-of-the-web-bypass/ https://mikehadlow.blogspot.com/2011/07/detecting-and-changing-files-internet.html https://textslashplain.com/2016/04/04/downloads-and-the-mark-of-the-web/ Closes #19648. PR #19675. --- src/base/bittorrent/torrentimpl.cpp | 19 +++++++++++++++++-- src/base/net/downloadhandlerimpl.cpp | 17 +++++++++++++++++ src/base/utils/misc.cpp | 21 +++++++++++++++++++++ src/base/utils/misc.h | 1 + 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp index 61987b92f..cb548a3ad 100644 --- a/src/base/bittorrent/torrentimpl.cpp +++ b/src/base/bittorrent/torrentimpl.cpp @@ -43,6 +43,7 @@ #include #endif +#include #include #include #include @@ -67,6 +68,10 @@ #include "peerinfo.h" #include "sessionimpl.h" +#ifdef Q_OS_WIN +#include "base/utils/misc.h" +#endif + using namespace BitTorrent; namespace @@ -2193,10 +2198,20 @@ void TorrentImpl::handleFileCompletedAlert(const lt::file_completed_alert *p) m_completedFiles.setBit(fileIndex); + const Path actualPath = actualFilePath(fileIndex); + +#ifdef Q_OS_WIN + // only apply Mark-of-the-Web to new download files + if (isDownloading()) + { + const Path fullpath = actualStorageLocation() / actualPath; + Utils::Misc::applyMarkOfTheWeb(fullpath); + } +#endif + if (m_session->isAppendExtensionEnabled()) { const Path path = filePath(fileIndex); - const Path actualPath = actualFilePath(fileIndex); if (actualPath != path) { qDebug("Renaming %s to %s", qUtf8Printable(actualPath.toString()), qUtf8Printable(path.toString())); @@ -2331,7 +2346,7 @@ void TorrentImpl::adjustStorageLocation() moveStorage(targetPath, MoveStorageContext::AdjustCurrentLocation); } -void TorrentImpl::doRenameFile(int index, const Path &path) +void TorrentImpl::doRenameFile(const int index, const Path &path) { const QVector nativeIndexes = m_torrentInfo.nativeIndexes(); diff --git a/src/base/net/downloadhandlerimpl.cpp b/src/base/net/downloadhandlerimpl.cpp index fa9275e3f..9a9fda377 100644 --- a/src/base/net/downloadhandlerimpl.cpp +++ b/src/base/net/downloadhandlerimpl.cpp @@ -29,6 +29,7 @@ #include "downloadhandlerimpl.h" +#include #include #include @@ -146,17 +147,33 @@ void Net::DownloadHandlerImpl::processFinishedDownload() { const nonstd::expected result = saveToTempFile(m_result.data); if (result) + { m_result.filePath = result.value(); + +#ifdef Q_OS_WIN + Utils::Misc::applyMarkOfTheWeb(m_result.filePath, m_result.url); +#endif + } else + { setError(tr("I/O Error: %1").arg(result.error())); + } } else { const nonstd::expected result = Utils::IO::saveToFile(destinationPath, m_result.data); if (result) + { m_result.filePath = destinationPath; + +#ifdef Q_OS_WIN + Utils::Misc::applyMarkOfTheWeb(m_result.filePath, m_result.url); +#endif + } else + { setError(tr("I/O Error: %1").arg(result.error())); + } } } diff --git a/src/base/utils/misc.cpp b/src/base/utils/misc.cpp index e0836efbf..d75c963a3 100644 --- a/src/base/utils/misc.cpp +++ b/src/base/utils/misc.cpp @@ -602,6 +602,27 @@ QString Utils::Misc::zlibVersionString() } #ifdef Q_OS_WIN +bool Utils::Misc::applyMarkOfTheWeb(const Path &file, const QString &url) +{ + const QString zoneIDStream = file.toString() + u":Zone.Identifier"; + HANDLE handle = ::CreateFileW(zoneIDStream.toStdWString().c_str(), GENERIC_WRITE + , (FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE) + , nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + if (handle == INVALID_HANDLE_VALUE) + return false; + + // 5.6.1 Zone.Identifier Stream Name + // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/6e3f7352-d11c-4d76-8c39-2516a9df36e8 + const QByteArray zoneID = QByteArrayLiteral("[ZoneTransfer]\r\nZoneId=3\r\n") + + (!url.isEmpty() ? u"HostUrl=%1\r\n"_s.arg(url).toUtf8() : QByteArray()); + + DWORD written = 0; + const BOOL writeResult = ::WriteFile(handle, zoneID.constData(), zoneID.size(), &written, nullptr); + ::CloseHandle(handle); + + return writeResult && (written == zoneID.size()); +} + Path Utils::Misc::windowsSystemPath() { static const Path path = []() -> Path diff --git a/src/base/utils/misc.h b/src/base/utils/misc.h index 3418faeb9..1d6a43989 100644 --- a/src/base/utils/misc.h +++ b/src/base/utils/misc.h @@ -94,6 +94,7 @@ namespace Utils::Misc QString languageToLocalizedString(const QString &localeStr); #ifdef Q_OS_WIN + bool applyMarkOfTheWeb(const Path &file, const QString &url = {}); Path windowsSystemPath(); template