这是对在 Docker 容器中运行的 JavaScript Web 应用程序执行白盒渗透测试的指南。在测试易受原型污染的 Web 应用程序时,我们将演示如何在 Visual Studio Code 中调试 JavaScript,以便在整个代码过程中跟踪我们的有效负载,并了解安全过滤器如何隐藏漏洞。
大纲
-
必要资源
-
安装必要的资源
-
设置
-
文件结构
-
验证我们的设置
-
寻找 JavaScript 漏洞
-
与 JavaScript 相关的常见弱点
-
通过代码分析改进未来的黑盒测试
-
结论
-
参考
必要资源
-
Visual Studio Code (VS Code)(或您喜欢的 IDE)
-
JavaScript 调试器(VS Code 内置)
-
存在漏洞的 Web 应用程序
-
Docker
安装必要的资源
由于Visual Studio Code内置了有效的JavaScript调试器,因此我们只需要安装Visual Studio Code和Docker。
请参阅Docker 的官方文档来安装 Docker。安装过程可能因您的操作系统而异。
我们将使用的易受攻击的 Web 应用程序可以在 YesWeHack 的 Github 存储库中找到:此处的易受攻击的代码片段。
设置
文件结构
我们的项目将使用以下文件结构:
.├──config│└──supervisord.conf├──docker-compose.yml├──Dockerfile└──vsnippet├──package.json├──pp-classic.js└──views└──index.ejs
必须添加或修改某些特别重要的文件。以下文件包含最终文件内容:
pp-classic.js
这是我们易受攻击的 Web 应用程序的主要 JavaScript 文件,我们将在 dockerised 环境中运行它。
/*** YesWeHack - Vulnerable code snippets*/constexpress=require('express');constcrypto=require('crypto');constpath=require('path');constfs=require('fs');constejs=require('ejs');constapp=express()app.locals.SOURCECODE=fs.readFileSync(__filename).toString()// Set the view engine to EJSapp.set('view engine', 'ejs');// Set the views directoryapp.set('views', path.join(__dirname, 'views'));app.use(express.raw({ type: '*/*', limit: '10mb' }));constAPI_KEY=crypto.randomBytes(32).toString('hex');classConfig {constructor(owner, apikey) {this.owner=ownerthis.apikey=apikeythis.public }// Code...}functionmerge(target, source) {for (constattrinsource) {if (typeoftarget[attr] ==="object"&&typeofsource[attr] ==="object") {merge(target[attr], source[attr]); } else {target[attr] =source[attr]; } }returntarget;}app.get('/', (req, res) => {returnres.render('index', { status: 'No config data given' });})// Define a POST route to accept JSON dataapp.post('/', (req, res) => {data=req.body.toString('UTF-8')letconfigDraft=newConfig("guest", undefined)merge(configDraft, JSON.parse(data))constconfig=newConfig("admin", API_KEY)if ( config.public===true ) {returnres.render('index', { status: 'Access granted' }); }// Send a response back to the clientreturnres.render('index', { status: 'You do not have access to the system configurations' });});//Start the server:constPORT=1337app.listen(PORT, '0.0.0.0', () => {console.log(`Server is running on http://0.0.0.0:${PORT}`);});
监控配置文件
我们在supervisord.conf文件中唯一需要修改的是程序“node-app”中的“command”参数。我们将命令设置为“npm run start:debug”,以确保我们的Web应用程序和调试器都开始运行。
conf[supervisord]user=rootnodaemon=truelogfile=/dev/nulllogfile_maxbytes=0pidfile=/run/supervisord.pid[program:node-app]command=npmrunstart:debugdirectory=/appstdout_logfile=/dev/stdoutstdout_logfile_maxbytes=0stderr_logfile=/dev/stderrstderr_logfile_maxbytes=0
启动.json
这将作为配置,告诉 VS Code 如何连接到在 docker 容器中运行的 JavaScript 调试器。
{"version": "0.2.0","configurations": [ {"type": "node","request": "attach","name": "Attach to Docker","port": 9229,"address": "localhost","localRoot": "${workspaceFolder}/vsnippet","remoteRoot": "/app","protocol": "inspector","restart": true } ]}
Dockerfile
除了构建 docker 镜像之外,Dockerfile 还安装了易受攻击的 Web 应用程序所使用的依赖项。
FROMnode:14#InstallandupdatesystemdependenciesRUNaptupdate-y&&aptinstall-ysupervisornpmRUNnpminstallexpressejs#PrepareandsetuptheworkingdirectoryWORKDIR/appCOPYvsnippet .#CopyconfigsCOPYconfig/supervisord.conf/etc/supervisord.confEXPOSE1337EXPOSE9229ENTRYPOINT [ "/usr/bin/supervisord", "-c", "/etc/supervisord.conf" ]
docker-compose.yml
此文件允许我们在 Docker 容器中运行时连接并与 JavaScript 的调试器进行通信。端口 1337 使我们能够通过主机访问 Web 应用程序,而端口 9229 将用于调试通信。
services:node-express:container_name: vsnippet-pp-classicbuild:context: .dockerfile: Dockerfileports:-"127.0.0.1:1337:1337"-"127.0.0.1:9229:9229"
验证我们的设置
为了确保我们的设置按预期工作,我们应该启动我们的 docker 容器,在 VS 代码中设置断点并启动调试器。然后我们可以向 Web 应用程序提交请求,看看调试器是否在我们的断点处停止。
导航到项目文件的根文件夹(参见标题:文件结构)并运行以下命令:
dockercomposeup--build
通常,您会在后台启动此命令(带-d
参数)。但是,如果您对 Docker 还不熟悉,我们建议您使用上面的命令,它会省略-d
参数,以便可以看到日志。
当docker完成构建过程并启动并运行时,我们就可以向运行在端口上的易受攻击的web应用程序发送请求了http://localhost:1337/
:
上面的响应意味着我们的 Docker 成功启动并且 JavaScript 调试器现在正在监听连接。
是时候在 VS Code 中设置一些断点了。您可以通过单击将鼠标悬停在相关行号上时出现的红点来执行此操作。可以在 Web 应用程序的主文件中插入断点:pp-classic.js
。
转到左侧面板上的 VS Code 调试器部分(或按CTRL+SHIFT+D
快捷方式),然后按顶部的绿色箭头图标:
连接调试器后,就可以执行 HTTP 请求来触发 Visual Studio Code 断点了。我们可以使用命令行界面 (CLI) 工具 cURL 向我们的 Web 应用程序发送 GET 请求:
curlhttp://localhost:1337/
除非出现问题,否则您不应该直接收到响应。相反,VS Code 内部会标记一些代码,显示调试器在第一个断点处停止,因此正常运行:
寻找 JavaScript 漏洞
一切正常运行,现在是时候开始探测应用程序中是否存在 JavaScript 漏洞了!
首先,我们将重点关注 Web 应用程序如何处理 JSON 数据。这是一个重要的步骤,因为它使我们能够正确执行攻击。
我们首先在 VS Code 中设置断点:
设置断点后,我们通过按下F5
或CTRL+SHIFT+D
并按下调试窗口中的绿色箭头来启动 VS Code 内的调试器。
我们的调试器现在正在监听传入的连接。我们使用以下 cURL 命令向易受攻击的 Web 应用程序发送 HTTP POST 请求来触发它:
curlhttp://localhost:1337/ -X POST -d '{"public":true}'
我们的调试器拦截了该请求。现在我们可以通过分析代码工作流程来查看我们的易受攻击的 Web 应用程序如何处理帖子正文中提供的 JSON 数据:
在左侧的调试窗口中,我们可以看到与用户config
相关的对象admin
不包含public
我们尝试设置为值的变量:true
。这意味着我们将无法使用我们在 HTTP POST 请求中提供的 JSON 数据访问受限区域。
考虑到这一点,我们现在需要执行新的 JavaScript 调试,仔细分析merge
处理 JSON 数据的函数的工作方式。首先,我们需要设置新的断点来正确分析merge
函数中的代码工作流程:
我们重新启动调试器,CTRL+SHIFT+F5
以便准备下一次攻击。
我们知道 Web 应用程序容易受到原型污染,因此我们使用一个简单的原型污染负载:{"__proto__":{"public":true}}
。因此,我们使用以下命令发送 HTTP POST 请求:
curlhttp://localhost:1337/ -X POST -d '{"__proto__":{"public":true}}'
理论上,我们的有效载荷应该添加到config
具有 user guest
user 的对象中。由于这是原型污染攻击,因此public
具有该值的属性true
应该出现在应用程序使用的所有对象原型中。
让我们分析一下该merge
函数,看看它如何处理我们的新有效载荷。我们继续调试 JavaScript,直到发现第一个 JSON 元素:__proto__:
在代码中,我们可以看到触发的 if 语句正在检查我们提供的值是否是对象属性。代码确定这__proto__
是一个对象,并merge
再次调用其内部的函数,但这次使用__proto__
对象作为参数。
我们继续调试过程,直到看到我们的public
值保持该值true
。
这一次,我们触发了 else 语句,将public
具有值的属性添加true
到原型对象中__proto_
,该原型对象是对象的一部分target
。
由于我们能够public
使用对象添加属性__proto__
,因此我们现在应该已经使用我们的属性及其值污染了应用程序中的其他对象public
。让我们继续调试过程,看看我们是否成功:
正如预期的那样,我们确实污染了下一个定义的config
对象,该对象保存着管理配置。它现在包含public
属性,该属性设置为true
。
我们成功了:我们污染了易受攻击的 Web 应用程序,这使我们获得了访问管理员配置的权限!
附注:如果我们使用 JSON 数据再次运行该过程,我们仍然会成功受到原型污染!
与 JavaScript 相关的常见弱点
以下是与 JavaScript 编程语言相关的三个最常见的弱点。
CWE-1321:对对象原型属性的修改控制不当(“原型污染”)
当用户输入被错误处理并以错误的方式插入为对象属性时,就会发生原型污染。这允许攻击者利用并“污染”对象使用的 JavaScript 原型结构。成功利用该结构允许攻击者修改或覆盖对象的属性,这可能导致严重后果,例如不当访问、文件访问或整个服务器被攻陷。
CWE-843:使用不兼容类型访问资源(“类型混淆”)
当程序假设资源属于特定类型,但实际上将其作为另一种类型处理时,就会发生类型混淆。因此,类型混淆可能会绕过某些限制,导致访问不当。动态类型语言(例如 JavaScript)特别容易受到类型混淆的影响。
CWE-79:网页生成过程中输入的不当中和(“跨站点脚本”)
跨站点脚本 (XSS) 允许攻击者将恶意 JavaScript 代码注入网页。XSS 漏洞主要发生在前端并在受害者的浏览器中执行。这种类型的漏洞可使攻击者劫持用户的会话或窃取其数据。
通过代码分析改进未来的黑盒测试
这种白盒测试过程提供的经验教训也可以增强您的黑盒测试。最值得注意的是,您可以看到测试多个略有不同的有效载荷以尝试发现同一漏洞的价值。尝试一系列有效载荷是发现后端服务器变化并防止误报的有效方法。
本文还表明,正确理解 Web 应用程序如何处理我们的有效负载对于有效部署它们至关重要。下次您在黑盒环境中遇到类似情况时,这些都是有用的经验教训。
JavaScript 调试要点
我们展示了如何通过有效调试应用程序的源代码来更有效地跟踪由客户端(攻击者)触发的执行代码。复制上述详细步骤以优化您的测试流程并发现可以揭示用户输入如何处理或错误处理的行为。
免费网络安全资料PDF大合集
链接:https://pan.quark.cn/s/41b02efa09e6
原文始发于微信公众号(安全视安):【翻译】白盒渗透测试:如何调试 JavaScript 漏洞
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论