Web App Pen Testing in an Angular Context
Joff Thyer //
如果您是Web应用渗透测试的爱好者,那么多年来您一定享受了许多轻松的目标。我们都喜欢拦截代理,我知道我们中许多人都非常欣赏PortSwigger多年来在Burp Suite上所做的出色工作。话虽如此,在现代Web应用时代,测试那些专注于文档对象模型(DOM)的框架应用与测试传统的基于HTML的应用有些不同。
在本文的剩余部分,请假设我指的是Angular 2及更高版本,这些版本是面向对象的,基于ECMAScript第6版(ES6或ECMAScript 2015)。Angular 1.x以前称为AngularJS,现已弃用,虽然尚未完全消失,但不太可能遇到!
话虽如此,不要惊慌,也不要放弃您正常的Web应用渗透测试技术。您需要理解的是,在Angular 2+的世界中,该框架从设计之初就考虑了安全性,如果开发者使用默认设置和常见最佳实践,您通常注入JavaScript到DOM的机会将大大受限。我们应该庆祝现代框架正朝着正确的方向前进,开发者不必不断重复造轮子!
这里有一些很好的背景参考资料供您参考。
https://blog.nvisium.com/angular-for-pentesters-part-1
https://blog.nvisium.com/angular-for-pentesters-part-2
https://angular.io/guide/security
开发者可能犯一些错误,使Angular应用从DOM角度变得脆弱。这些错误主要归结为开发者故意绕过框架设置的安全措施。示例如下:
- 如果开发者将用户输入与模板创建结合,那么该用户输入可能直接影响DOM渲染,导致模板注入漏洞。Angular默认认为模板是可信的。
- 如果开发者决定将用户输入标记为可信,并禁用极其有效的Angular清理和输出编码方法,那么您就回到了潜在跨站脚本(XSS)引入的糟糕旧日子。作为规则,任何Angular插值内容总是被转义。
- 不鼓励直接使用DOM API!您可能需要做的每件事可能都有一个Angular方法。如果没有,如果您真的必须在不应插手的地方捣乱,有一个Angular“DomSanitize()”函数。
从攻击者的角度来看,如果开发者遵循最佳实践,攻击面的大部分已被移除。然而,仍有发现机会。一些想法如下:
- 应用的后端很可能是基于JSON/RESTful的API调用。服务器端数据验证可能出错。
- 不安全的直接对象引用(IDOR)可在API中发现,您应始终请求多个认证账户进行测试,以检查跨用户角色入侵。
- 会话管理仍需正确实现。在基于Angular的应用中,使用JSON Web令牌(JWT)进行会话管理并不罕见。
会话令牌可能在注销时未正确失效,可能是长期有效的,或者令牌失效完全由客户端DOM控制。
- JWT可能能够使用“None”值作为签名算法重新签名,创建不安全令牌,或者签名密钥本身可能被破解。
- 签署自己的应用JWT可能导致其他认证用户受损。
有关JWT的快速参考,请访问这些URL:
https://jwt.io/
https://en.wikipedia.org/wiki/JSON_Web_Token
未文档化或调试API功能可能通过更改浏览器DOM中的值被发现。
- 如果开发者决定实现服务器端渲染(SSR)而不是正常的DOM密集型客户端渲染(CSR),可能会重新引入JavaScript注入机会。Angular项目正试图通过引入Angular Universal来领先于此。这里有一些参考资料供您参考。
https://angular.io/guide/universal
https://developers.google.com/web/updates/2019/02/rendering-on-the-web
在渗透测试Angular应用时,技术转变的结果之一是您可能会花更多时间在浏览器开发者控制台和拦截代理中。Angular 2+有一个特殊功能,称为“enableProdMode()”,在框架在DOM中引导后立即调用。这假设开发者确实以“生产模式”部署了应用。
“enableProdMode()”函数使Angular跳过在浏览器中构建调试元素树。这个调试元素树对您作为渗透测试员很有用,因为您可以在选择页面上的元素后使用Angular“ng.probe()”函数检查页面元素。在生产模式下,页面组件的“ng.probe()”将返回空值,这没有用。
您早期想做的一件事是在拦截代理中“飞行中”修改此函数,使其“失败”以启用生产模式。
这有一个小转折。如果应用也使用https://webpack.js.org部署,那么函数名称可能被混淆。幸运的是,函数内有一个字符串“Cannot enable prod mode after platform setup”,您可以用它来找到混淆的函数名称。
如果您使用Burp Suite,这里有一种方法可以配置代理以重写飞行中的函数。此示例假设未使用webpack混淆函数名称。步骤如下:
- 在Burp Suite中选择Proxy选项卡
- 选择Proxy -> Options子选项卡
- 向下滚动到“Match/Replace”部分并删除任何现有规则
- 单击“Add”添加新规则
- 选择“Response Body”作为类型
- 匹配字符串“function enableProdMode(){”
- 添加一个替换字符串,添加“_devMode=1;”并从函数返回。完成此操作时,重要的是小心保持脚本语法完整性,以免完全破坏功能。
Burp Suite匹配/替换规则
重写“enableProdMode()”函数的规则
重新加载页面后的调试器控制台输出
您可能遇到的另一个障碍将迫使您添加另一个匹配/替换规则。我当然是通过艰难的方式学到这一点的(像许多事情一样)。
自2016年以来,一些包含源标签的HTML有一个“完整性”选项,这实际上是一个很好的功能。简而言之,完整性标签允许开发者指定哈希算法和base64编码的哈希。浏览器将尝试验证哈希,如果哈希不匹配,将不执行JavaScript。
一个相关的深度防御技术是利用内容安全策略(CSP)。CSP是一种白名单技术,允许Web服务器管理员指定应被视为可执行脚本有效源的域。对于支持CSP的浏览器,此技术进一步有助于缓解跨站脚本和数据注入攻击。CSP通过添加到服务器响应的HTTP头实现。不支持CSP的浏览器将回退到正常的同源策略模型。有关更多信息,请参阅https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP。
正如您可能想象的那样,飞行中重写JavaScript函数肯定会违反完整性标签检查(如果存在)。第二个类似于下图的匹配/替换规则将为您修复此障碍以继续测试。
移除“完整性”标签的示例响应体规则
在实施此操作并重新加载Angular应用内容后,您可以选择任何页面元素,并使用开发者工具控制台中的“ng.probe()”探测其状态,然后甚至创建JavaScript对象的实例以开始探索。从这里,您可以操纵该对象的属性以查看其影响。您尝试做的事情仅受您的创造力和时间限制。使用此探测技术的示例如下所示。
示例调试器控制台输出
这就是我现在为您准备的全部内容。祝Web应用测试之路愉快,继续黑客之旅。