反向shell黑客脚本破解渗透
1.1K subscribers
93 photos
3 links
Download Telegram
我在virtio-gpu外设中发现了类似的问题,如下所示,input指针是Guest物理内存在Host进程中的内存映射,在处理VIRTIO_GPU_CMD_UPDATE_CURSOR请求时,从Guest的input中读取了两个变量input->pos.scanout_id和input->resource_id,在第8行对scanout_id进行检查数组索引是否越界。
我们可以通过第8行到第16行的代码执行间隙新起一个线程,将scanout_id修改为任意数据,即可以实现在数组越界写任意值。
如果这时scanout_id被修改为非法值,有可能造成非法访存,这是当时的崩溃日志。
目前我们已经有了相对偏移的任意数据写,接下来讲述通过篡改a1的结构体(gpu_buffer)数据,构造信息泄露以及任意地址读写。
memfd_create() 函数是在我们研究已废弃的 kdbus IPC 时开发的,您可以在 David Herrmann 的原始文章 memfd_create() 中了解更多信息。
memfd_create() 函数会创建一个匿名文件,并返回一个指向该文件的文件描述符。该文件的行为与普通文件类似,因此可以进行修改、截断、内存映射等操作。然而,与普通文件不同的是,它驻留在 RAM 中,并拥有易失性后备存储。一旦所有指向该文件的引用都被释放,它就会自动释放。匿名内存用于存储文件的所有后备页面。因此,memfd_create() 创建的文件与其他匿名内存分配(例如使用带有 MAP_ANONYMOUS 标志的 mmap(2) 分配的文件)具有相同的语义。
攻击者和恶意软件正在滥用此特性,将二进制有效载荷写入该内存驻留文件,然后像处理文件系统中的任何其他二进制文件一样执行其中的程序。
例如,让我们来看一下 Pat H. 在 Sysmon for Linux 帖子中发布的使用 memfd_create() 的内存加载器示例。加载器代码在这里 github 仓库。
加载器会创建一个匿名文件,将基本二进制文件或其他任何传入的二进制文件复制到该文件中,然后执行引用的文件。这通常与恶意软件用于执行无文件二进制文件的技术相同:获取代码执行权限,从互联网接收有效载荷并在其中执行,所有操作均无需触及文件系统。
localspl.dll!IsModuleFilePathAllowed 会验证规范路径是否直接位于 C:\Windows\System32\ 目录下,或者位于打印机驱动程序目录中。例如,`C:\Windows\System32\payload.dll` 是允许的,而 C:\Windows\System32\Tasks\payload.dll 则不允许。打印机驱动程序目录中的任何路径都是允许的,例如 C:\Windows\System32\spool\drivers\x64\my\path\to\payload.dll 是允许的。如果我们能够在 C:\Windows\System32\ 目录下或打印机驱动程序目录中的任何位置创建 DLL,就可以将该 DLL 加载到打印后台处理程序服务中。
现在我们知道,可以使用 SpoolDirectory 创建一个任意目录,并赋予所有用户写入权限,而且可以将位于 C:\Windows\System32\ 或打印机驱动程序目录中的任何 DLL 加载到 Spooler 服务中。但是,这里存在一个问题。如前所述,Spool 目录是在 Spooler 初始化期间创建的。当 localspl.dll!SplCreateSpooler 调用 localspl.dll!BuildPrinterInfo 时,Spool 目录就会被创建。在 localspl.dll!BuildPrinterInfo 授予 Everybody 用户 FILE_ADD_FILE 权限之前,还会进行最终检查,以确保目录路径不在打印机驱动程序目录中。
localspl.dll!IsValidSpoolDirectory 函数会调用 localspl.dll!AdjustFileName 函数将该路径转换为规范路径。例如,`C:\spooldir\` 的规范路径为 \\?\C:\spooldir\`,如果 `C:\spooldir\ 是指向 C:\Windows\System32\ 的符号链接,则规范路径为 \\?\C:\Windows\System32\`。然后,`localspl.dll!IsValidSpoolDirectory 函数会检查当前用户是否拥有以 GENERIC_WRITE 权限打开或创建该目录的权限。如果目录已成功创建或打开,该函数还会进行最终检查,确认指向该目录的链接数量是否大于 1(由 GetFileInformationByHandle 函数返回)。
因此,要设置 SpoolDirectory,用户必须能够创建或以可写权限打开该目录。如果验证成功,打印提供程序将更新打印机的 SpoolDirectory 注册表项。但是,打印后台处理程序只有在重新初始化后才会创建后台处理目录。这意味着我们需要找到重启后台处理程序服务的方法(稍后会讨论这一点),但也意味着用户只需在设置 SpoolDirectory 注册表项的验证期间能够创建目录,而无需在实际创建目录时也具备这种能力。
调用 SetPrinterDataEx 时,会向本地打印后台处理程序 spoolsv.exe 发送 RPC 请求,spoolsv.exe 会将请求路由到本地打印提供程序 localspl.dll 中的 SplSetPrinterDataEx 实现。控制流程包含以下事件:
1. spoolsv.exe!SetPrinterDataEx 路由到本地打印提供程序 localspl.dll 中的 SplSetPrinterDataEx
2. localspl.dll!SplSetPrinterDataEx 在恢复 SYSTEM 上下文并通过 localspl.dll!SplRegSetValue 修改注册表之前,验证权限
如果要设置 SpoolDirectory 值,localspl.dll!SplSetPrinterDataEx 会在更新注册表项之前验证所提供的目录是否有效。此检查在 CVE-2020-1030 之前不存在。
路由器 spoolss.dll 根据每次函数调用时提供的打印机名称或句柄来确定要调用哪个打印提供程序,并将函数调用传递给正确的提供程序。
打印提供程序
支持指定打印设备的打印提供程序。
本地打印提供程序
本地打印提供程序为所有通过其端口监视器访问的打印机提供作业控制和打印机管理功能。
下图展示了应用程序创建打印作业时,本地打印提供程序各组件之间的控制流。
我直接调用 execve("pkexec", a_argv, a_envp);,在a_envp中指定GCONV_PATH不就完事了吗?
linux 的动态连接器ld-linux-x86-64.so.2 会在特权程序执行的时候清除敏感环境变量,除了GCONV_PATH以外,也有其他环境变量可以直接引入外部so,如LD_PRELOAD ,所以这种方法是没用的
可以看到,GCONV_PATH就在其中,这些环境变量都能有动态加载路径的能力,因此需要防止低权限用户通过这些环境变量利用suid程序造成提权
高级攻击者可能会尝试攻击存在漏洞的自定义组件和第三方组件。
浏览该网站时,我们可以看到浏览器加载了几个不同的 JavaScript 文件,这些文件的 URL 很奇怪,以 /l/ 开头,后面跟着一个编码后的 JSON 对象。
在这些 JavaScript 文件中,我们可以找到最常用端点的定义,包括自定义端点和/或第三方应用程序的端点。这些定义以 JSON 格式编码:
通过扫描响应中类似格式的 JSON 字符串,可以了解自定义方法以及如何调用它们。
Salesforce Experiences 运行在 Salesforce 的 Lightning 框架之上。Lightning 是一个用于移动和桌面网站的快速开发框架。
Salesforce Lightning 是一个面向组件的框架。这些组件被称为 Aura 组件,它们是独立的对象,开发人员可以将它们组装起来以创建自定义网页。
Aura 组件可用于对 Salesforce 对象执行操作,例如查看或更新记录。组件包含控制器,这些控制器导出不同的方法来执行特定任务。
使用代理服务(例如 Burp Suite)浏览 Experience 站点,可以直观地了解 Lightning 的运行方式。Experience 的前端 Web UI 使用 HTTP 端点 /s/sfsites/aura。
当用户与 Experience 站点交互时,浏览器使用 Aura 端点来检索站点信息并执行服务器端操作。当然,这些操作都受用户的权限限制。
现在我们可以执行 alt=media 的技巧。Google 云端硬盘返回的 JSON 数据是我们控制的响应,因此我们可以控制 URL。首先获取的文件会被解析为 PPT 格式,从而阻止完全读取权限,但我怀疑即使解析失败,下载文件也已经存储在 CDN 上了。总之,为了获得响应,我们只需重定向到一个返回 404 的页面,从而在 Java 层抛出一个异常,该异常最终会在 Web 应用中被抛出。
注意——标头“SSRF”,我的服务器会读取此标头以重定向到内部主机。
我本来想尝试一些与 pptx 相关的攻击,但团队反应迅速,一直在监控我的漏洞利用,在我第二天醒来之前就已经在生产环境中修复了。团队的反应真是太棒了 ;)
While you were playing with our systems our alerting went batshit, so we were able to react pretty quickly. We deployed quick fix for the issue. Would you be so kind and validate if our quick attempt was successful?
在深入探讨漏洞之前,让我们先来看看 Google 云端硬盘通常是如何集成到应用程序中的。
一般有三种方法;
客户端嵌入。
客户端获取 CDN URL,服务器端下载。
通过 Google Drive API 从服务器端获取文件。
前两个测试起来相对简单,但最后一个测试才更有乐趣。
为了理解这一点,不妨考虑一个简单的应用程序,它可以从 Google 云端硬盘中检索并渲染选定的图像文件。我知道这并非必要,但我试图展示其底层工作原理,以便读者理解。
以下是负责列出和渲染您的 Google 云端硬盘图像文件的两个路由,前提是您提供了访问令牌。
寻找__destruct方法,因为有一些类都存在 __wakeup方法,所以剩下的也不多。剩下的类 __destruct方法调用也很乱,所以尝试搜索 __call 方法,看看有什么可以利用的。在vendor/symfony/cache/Traits/RedisProxy.php 定义的RedisProxy类存在__call方法:

我们可以调用任意类的 __invoke 方法,并且参数可控。寻找可利用的 __invoke,在vendor/doctrine/doctrine-bundle/Dbal/SchemaAssetsFilterManager.php定义的SchemaAssetsFilterManager类:

可以发现明显的动态函数调用,并且函数名和参数都可控。与之类似的vendor/symfony/console/Helper/Dumper.php 定义的Dumper类,这个更直接一些:
所以现在我们只需在 __destruct 中找到任意一个可控变量对任意函数的调用即可,类似$xxxx->xxxx(),这应该不难寻找,在vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/CacheAdapter.php中定义的CacheAdapter类:
variables.c的initialize_shell_variables函数用于将环境变量注册成SHELL的变量,其中包含的一段代码引起了我的注意:
这里for遍历了所有环境变量,并用=分割,name就是环境变量名,string是值。
当满足下面这些条件的情况下,temp_string将被传入parse_and_execute执行:
privmode == 0,即不能传入-p参数
read_but_dont_execute == 0,即不能传入-n参数
STREQN (BASHFUNC_PREFIX, name, BASHFUNC_PREFLEN),环境变量名前10个字符等于BASH_FUNC_
STREQ (BASHFUNC_SUFFIX, name + char_index - BASHFUNC_SUFFLEN),环境变量名后两个字符等于%%
STREQN ("() {", string, 4),环境变量的值前4个字符等于() {
前两个条件肯定是满足的,后三个条件是用户可控的,所以这个if语句是肯定可以进入的。进入if语句后,去除前缀BASH_FUNC_和后缀%%的部分将是一个变量名,而由() {开头的字符串将会被执行。