声明:该公众号分享的安全工具和项目均来源于网络,仅供安全研究与学习之用,如用于其他用途,由使用者承担全部法律及连带责任,与工具作者和本公众号无关。
本文为翻译文章,需要阅读原文请访问:https://sharpsec.run/rce-vulnerability-in-qbittorrent/
引言
在qBittorrent中,自2010年4月6日以来的14年零6个月里,DownloadManager类忽略了所有平台上出现的SSL证书验证错误。直到2024年10月12日,默认行为才更改为进行验证,相关的提交为3d9e971。第一个修复版本是5.0.1,于两天前发布。
DownloadManager在程序中的使用非常广泛,影响搜索、.torrent下载、RSS订阅、favicon下载等功能。以下所有代码路径都接受任何证书,无论是过期的、自签名的还是两者兼有,按严重程度递减:
1. 恶意可执行文件加载器(隐秘功能)
如果您在Windows上运行且没有安装足够新版本的Python,qBittorrent在启动时会提示您从硬编码的URL安装或更新Python,以便使用需要它的搜索插件,源代码如下:
#ifdef Q_OS_WIN
const QMessageBox::StandardButton buttonPressed = QMessageBox::question(this, tr("缺少Python运行时"),
tr("使用搜索引擎需要Python,但似乎未安装。\n您想现在安装它吗?"),
(QMessageBox::Yes | QMessageBox::No), QMessageBox::Yes);
if (buttonPressed == QMessageBox::Yes)
installPython();
...
#endif // Q_OS_WIN
一旦您点击或按下自动选择的“是”选项,qBittorrent将会下载、执行然后删除该.exe文件,源代码如下:
void MainWindow::pythonDownloadFinished(const Net::DownloadResult &result)
{
if (result.status != Net::DownloadStatus::Success)
{
...
}
setCursor(QCursor(Qt::ArrowCursor));
QProcess installer;
qDebug("以被动模式启动Python安装程序...");
const Path exePath = result.filePath + u".exe";
Utils::Fs::renameFile(result.filePath, exePath);
installer.start(exePath.toString(), {u"/passive"_s});
...
}
从2015年6月到现在,qBittorrent一直存在这种行为,影响v3.2.1到v5.0.0(含)。该行为似乎未在其他操作系统变种中复制,如果找不到或版本不够新,搜索小部件会被禁用。
下载完成的可执行文件将存储在例如:
C:\Users\_user_\AppData\Local\Temp\is-G61QK.tmp
由于QProcess
实例的行为,将会有两个线程的exe在运行,其中只有一个在执行后被杀死,另一个则处于睡眠状态。
不可避免的屏幕截图显示calc.exe被注入,使用mitmproxy实现:
2. 浏览器劫持 + 可执行文件下载(软件升级上下文)
如果您在Windows或Linux上运行已安装的qBittorrent版本,而不是appImage
文件,则在启动时默认会进行更新检查,这涉及从硬编码的URL下载一个XML文档的RSS feed,以解析程序版本信息:
void ProgramUpdater::checkForUpdates() const
{
const auto RSS_URL = u"https://www.fosshub.com/feed/5b8793a7f9ee5a5c3e97a3b2.xml"_s;
Net::DownloadManager::instance()->download(
Net::DownloadRequest(RSS_URL).userAgent(QStringLiteral("qBittorrent/" QBT_VERSION_2 " ProgramUpdater (www.qbittorrent.org)")),
Preferences::instance()->useProxyForGeneralPurposes(), this, &ProgramUpdater::rssDownloadFinished);
}
然后它将解析XML,提取更新链接,如果版本高于当前版本,则提示用户访问该URL,而不进行任何过滤或验证:
if (type.compare(variant, Qt::CaseInsensitive) == 0)
{
...
if (isVersionMoreRecent(version))
{
m_newVersion = version;
m_updateURL = updateLink;
}
break;
}
如果用户接受此提示,他们将在默认浏览器中打开此URL。用户的预期是下载一个可执行文件,并且该上下文是基于信任的,因为该链接/下载来自于他们运行的软件:
bool ProgramUpdater::updateProgram() const
{
return QDesktopServices::openUrl(m_updateURL);
}
因此,如果用户被引导到任何文件共享网站,如mediafire等,他们可能会下载一个攻击者控制的可执行文件,而这个文件期望像升级一样正常工作。由于该项目是开源的,最新版本可以轻松重新编译并添加后门功能。开发者提供了一个密钥来检查二进制文件的签名,但必须进行检查,且在验证失败时必须尊重以保护用户。
3. RSS订阅(任意URL注入)
所有由应用程序解析的RSS feed都通过DownloadManager,因此它们可以被劫持。受害者访问的URL可以被观察和记录,且由于其静态性和长期存在性,link
元素中的每个条目都被直接解析,并在双击时下载。即使没有MITM篡改,您也只需双击即可访问您关注的任何RSS feed中插入的任意URL,无论是作者还是攻击者所投毒的。
else if (name == u"link")
{
const QString link = (xml.attributes().isEmpty()
? xml.readElementText().trimmed()
: xml.attributes().value(u"href"_s).toString());
...
}
更具破坏性的是CVE-2019-13640,它允许通过种子名称或当前跟踪器参数中的shell元字符进行远程命令执行。这种结合意味着真实的RSS作者不需要发送恶意数据,因为MITM攻击者也可以做到这一点。
4. 解压缩库攻击面(0点击)
默认情况下,程序在启动时将自动从硬编码的URL下载一个.gz扩展名的MaxMind GeopIP数据库二进制文件,然后提取。如果zlib解压缩中存在任何漏洞,例如2022年的CVE-2022-37434(CVSS 9.8严重缓冲区溢出),虽然此处并不适用,因为未调用inflateGetHeader()
函数,攻击者可以利用此攻击面,任意文件大小最大可达64MB,并在出现任何错误时记录并返回:
bool ok = false;
const QByteArray data = Utils::Gzip::decompress(result.data, &ok);
if (!ok)
{
LogMsg(tr("无法解压IP地理位置数据库文件。"), Log::WARNING);
return;
}
2024年后,解析MaxMind数据库二进制文件的代码得到了良好的保护,但以前可能看起来不同,可能提供更多的攻击面。还有一个有趣的提交,某个贡献者对gzip::decompress()
函数进行了调整,暗示可能的栈溢出,因为目标缓冲区从静态分配的栈更改为动态分配的堆,虽然由于写入前的检查而无法被利用:
-105 char tmpBuf[BUFSIZE] = {0};
+107 std::vector<char> tmpBuf(BUFSIZE);
利用可能性
由于所有Python安装程序的exe URL和更新RSS feed的URL都是硬编码的,因此它们可以轻松枚举,并且在MITM上下文中,恶意脚本可以攻击每个易受攻击的版本。此外,RSS feed的URL提供了软件的指纹,因为没有其他理由去访问这些URL,除非qBittorrent正在运行。这意味着诸如PRISM等大规模监视程序可以轻松通过被动流量监控检测到qBittorrent用户。而且,由于没有证书验证,因此无需进行复杂昂贵的部署,如QUANTUM以执行侧面攻击——您可以简单地伪造目标服务器。
硬编码URL的另一个方面是,攻击者可以选择性地拦截来自qBittorrent的请求,而无需验证连接,从而不会在用户浏览器或其他应用程序未能安全连接互联网时发出警报。
由于该软件是开源的,因此可以轻松地在其上添加后门并重新编译,从而为受害者提供功能齐全的软件,避免引起受害者的怀疑。
脚本可能性
结合使用mitmproxy和-s
提供Python脚本,可以实现以下功能:
自动将所有Python exe替换为任意exe:通过单击实现RCE
自动替换RSS feed中的所有qBittorrent更新URL:浏览器劫持/RCE,用户中等交互
自动替换qBittorrent RSS查看器中的所有/特定链接:RCE直到2019年,下载劫持