渗透测试GraphQL时学到的经验教训
Sean Verity //
GraphQL是我几年前就听说过但直到最近才在实际渗透测试中遇到的技术。在阅读了一两篇博客后,我记得当时想的是“JSON、数据库查询,明白了”,然后就继续前进了。直到大约一个月前,我才在实际渗透测试中遇到GraphQL。
在提升GraphQL渗透测试技能的过程中,我遇到了一些痛点。希望当你在渗透测试、漏洞赏金狩猎或CTF中第一次遇到GraphQL时,我能帮你避免这些同样的痛点。
市面上有几种工具。我开始时是手动操作,这对于学习GraphQL很有好处,但当你开始处理超出非常基础的GraphQL查询的内容时,很快就会变得非常困难。因此,我建议使用一个可以自动化或至少能从语法角度创建良好查询的工具。
这篇博客还假设GraphQL introspection已启用。有工具可以在introspection禁用时枚举GraphQL模式,但这超出了本博客的范围。但如果你需要一个,这里有一个:
https://github.com/nikitastupin/clairvoyance
如何找到GraphQL
找到GraphQL的最简单方法是查看你的Burp History日志。在HTTP History标签中,通过搜索词“graphql”进行过滤,看看是否有任何结果弹出。你也可以在“Site map”标签中搜索你的目标以查找“graphql”。如果应用在前端使用GraphQL,你会在URL中的某个地方看到一个包含“graphql”的端点。
但如果GraphQL本意不是要暴露呢?
嗯,有一个GraphQL SecList可以解决这个问题!将GraphQL SecList输入Gobuster或你喜欢的强制浏览工具以取得效果。(顺便说一句——你看到我们最近关于Gobuster的博客了吗?https://www.blackhillsinfosec.com/for-web-content-discovery-who-you-gonna-call-gobuster/)
说GraphQL的语言
找到GraphQL后,你可能想做的第一件事之一是将请求发送到Burp Suite的Repeater标签进行进一步分析。让我印象深刻的一点是GraphQL非常透明。看看以下错误消息:
这个查询实际上有几个问题,但从阅读错误消息来看,我们可以从哪里开始修复是显而易见的。
GraphQL还有一个叫做“introspection”的奇妙特性。GraphQL的introspection特性是GraphQL与其他开发者或GraphQL实例消费者分享自身细节的便捷方式。当introspection启用时,整个GraphQL模式可以通过一个查询检索。这为渗透测试人员、漏洞赏金猎人或任何寻找漏洞的人提供了显著优势。
GraphQL可视化工具graphql-voyager可以导入GraphQL模式并将其转换为带有节点和边的地图。这是一种很好的方式来概览模式的类型、查询和大小。以下是一个示例GraphQL模式的片段,描述了一个设定在遥远星系的流行电影系列:
顺便说一下,我第一次在渗透测试中看到GraphQL时,我将一个模式导入graphql-voyager,并开始在Repeater中从头编写GraphQL查询。从学习的角度来看,这很有趣,对于简单的查询来说也没什么大不了的。但当我进一步深入模式,那里有更复杂的查询时,我很快意识到这种方法不可持续。很容易包含一个放错位置的花括号。
然后我了解了这个叫做InQL(Introspection Query Language)的棒极了的项目。InQL可以通过GraphQL的introspection特性从远程服务器检索GraphQL模式,并将其解析为请求模板。如果你有模式保存在磁盘上,InQL也可以导入文件。InQL可以作为CLI工具或Burp Suite扩展运行。作为Burp扩展运行InQL的好处是有一个工作区,你可以将请求模板复制粘贴到其他工具中,如Repeater或Intruder,进行进一步测试。
安装InQL Burp Suite扩展
安装InQL Burp Suite扩展就像在BApp商店中搜索它并点击安装按钮一样简单。
你可能想知道为什么我在BApp商店中搜索“graphql”而不是“inql”。在测试期间,我经常在BApp商店中搜索特定技术或事物(例如JavaScript、secrets、Node等),而不是搜索工具。我发现这在我遇到特定扩展问题并需要替代方案时很有帮助。
安装InQL后,获取模式就像将GraphQL端点复制到地址栏并点击“Load”按钮一样简单。模式加载可能需要几秒钟。完成后,界面应该类似于以下内容。
上面截图中的模式是从Damn Vulnerable GraphQL Application获取的。如上图所示,InQL将模式解析为查询、变更和订阅。InQL还会在请求模板中记录相关的字段和参数。
当你在渗透测试中遇到GraphQL时,你可能会找到订阅,但你几乎肯定会遇到查询和变更。查询,如你所料,将从GraphQL数据存储中获取数据。我喜欢将变更视为函数,因为它们的目的修改GraphQL数据存储中的数据。查询和变更都可以接受参数,这些参数很适合进行模糊测试。
将模式加载到InQL后,你可以检查对象并将请求模板从InQL复制到Repeater进行进一步测试。
当你将请求模板从InQL复制到Repeater时,注意你从哪个标签复制。从GraphQL标签复制请求模板到Repeater是行不通的。
然而,你可以从“Raw”标签复制请求到Repeater中的POST请求体。
好的,实际上,当安装InQL时,Repeater中会包含一个额外的标签来粘贴或调整你的GraphQL查询。但要记住的重要事情是,你需要将正确的查询格式放入正确的Repeater标签中。在下面的示例中,一个来自InQL的GraphQL查询被复制到Repeater中的GraphQL标签。
当查询systemHealth类型时,我们看到了一个合理的响应。作为比较的基础,以下是当你意外地将“raw”查询放入GraphQL查询标签时发生的情况。
现在看看那个美丽的错误消息。是不是很nice?即使查询格式不正确,GraphQL也足够慷慨地回应了一个有用的错误消息,你可以用它来排除故障。
从这一点出发,你可以继续用Repeater手动测试,或将其发送到Intruder进行模糊测试。将GraphQL API视为与应用程序后端交互的一种迂回方式。这里有一些黑客想法:
- 在模糊测试“正常”请求时失败?尝试模糊测试GraphQL查询/变更及其参数。
- 应用在防止暴力破解方面做得好吗?找到一个接受密码作为参数的查询或变更,看看那里是否有暴力破解预防。更多关于这个主题的内容在这里:https://owasp.org/www-project-web-security-testing-guide/v42/4-Web_Application_Security_Testing/04-Authentication_Testing/10-Testing_for_Weaker_Authentication_in_Alternative_Channel
- 查看所有看起来有趣的查询和变更并尝试它们。你可能会幸运地遇到一个揭示应用程序秘密的查询。
其他GraphQL测试技巧
- 找到一个需要参数的查询?在Burp History中搜索参数。搜索模式中内容的子字符串或变体。例如,模式可能枚举了一个名为“fooBar”的参数。尝试在Burp History中搜索“foo”,以防前端使用不同的命名约定,如“foo_bar”。看看Burp的Target Analyzer是否也为你发现了GraphQL参数。在Sitemap标签中,右键点击目标的基础节点,然后选择“Engagement Tools > Analyze Target”。
- 注意GraphQL响应中的错误消息。GraphQL会清楚地告诉你查询有什么问题。你可能忘记了一个参数,或者在期望字符串时传递了一个整数,等等。
参加Modern WebApp Pentesting w/ BB King。涵盖了其他对测试GraphQL有用的测试技术(如NoSQL注入)。
故障排除
在测试GraphQL时,我遇到的最令人沮丧的事情之一是查询今天工作,但第二天就不工作了。
问题通常很简单,容易忽略。如果你处于这种情况,这里有几件事要检查:
- 确保你发送的是POST请求。GET请求可能会触发错误消息,提示你GraphQL存在。但是,你必须使用POST请求进行有效查询。
- 确保存在以下请求头:Content-Type: application/json
- 阅读响应中的错误消息并相应修改你的请求。
- 双重检查你将查询粘贴到哪个上下文中。GraphQL查询只能粘贴到Repeater中的GraphQL上下文中。原始请求粘贴到Repeater中的GraphQL上下文中是行不通的。
- 如果你在Repeater中看不到“InQL”下拉选项:从InQL复制一个查询到“raw”格式,粘贴到Repeater中的POST请求中,然后点击Send。这通常会引导Repeater中的InQL上下文。