0x00 起因

前几日在hackerone上挖掘某高赏金厂商,走了一遍业务点后,偶然发现http history里面有个graphql的接口

于是一场坐牢之旅开始了

0x01 前置知识与内省查询

不了解graphql的兄弟可以看看如下的图

通俗易懂地说:Graphql类似于restful的API 开源查询语言,其巧妙的新方法来改善应用程序中客户端和服务器之间的交互,为项目构建和后期维护提供了新思路

image-20230316102800443

image-20230316102729116

在实践经验中,发现国内用graphql技术的厂商并不是很多,大部分还是基于restful的,国外比较流行

在graphql中,是支持“内省查询”这种比较特殊的技术的

简单来说就是,GraphQL内置了类似于“swagger的”接口文档,你可以通过内省的方法获得这些信息,如graphql中对象定义、接口参数等信息。

当使用者不知道某个GraphQL接口中的类型哪些是可用的,可以通过__schema字段来向GraphQL查询哪些类型是可用的。

例如,您可以通过__schema通过此自省功能了解有关接口类型的更多信息。(下方图源于酒仙桥部队的一篇文章)

img

而内省查询通常是不应该对外能直接使用的

0x02 挖掘过程

有了一定的前置知识,我们来看这个graphql的点

笔者在抓到该厂商某个graphql的接口后,尝试使用_schema内省查询来获取接口的额外信息

POST /web-stories-api/graphql HTTP/1.1
Host: xxxxxxxxxx
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en-US;q=0.9,en;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.78 Safari/537.36
Connection: close
Cache-Control: max-age=0
Content-Type: application/json
Content-Length: 1531
    
{"query":"query Query {\n    __schema {\n      queryType { name }\n      mutationType { name }\n      subscriptionType { name }\n      types {\n        ...FullType\n      }\n      directives {\n        name\n        description\n        locations\n        args {\n          ...InputValue\n        }\n      }\n    }\n  }\n\n  fragment FullType on __Type {\n    kind\n    name\n    description\n    fields(includeDeprecated: true) {\n      name\n      description\n      args {\n        ...InputValue\n      }\n      type {\n        ...TypeRef\n      }\n      isDeprecated\n      deprecationReason\n    }\n    inputFields {\n      ...InputValue\n    }\n    interfaces {\n      ...TypeRef\n    }\n    enumValues(includeDeprecated: true) {\n      name\n      description\n      isDeprecated\n      deprecationReason\n    }\n    possibleTypes {\n      ...TypeRef\n    }\n  }\n\n  fragment InputValue on __InputValue {\n    name\n    description\n    type { ...TypeRef }\n    defaultValue\n  }\n\n  fragment TypeRef on __Type {\n    kind\n    name\n    ofType {\n      kind\n      name\n      ofType {\n        kind\n        name\n        ofType {\n          kind\n          name\n          ofType {\n            kind\n            name\n            ofType {\n              kind\n              name\n              ofType {\n                kind\n                name\n                ofType {\n                  kind\n                  name\n                }\n              }\n            }\n          }\n        }\n      }\n    }\n  }"}

结果非常nice,内省查询后目标返回了接口的详细信息

image-20230401094521366

但是以上的数据看起来比较杂乱无章,决定使用内省查询的图形化的解析功能

https://apis.guru/graphql-voyager/ 这个site为内省查询的JSON response提供了不错的图形化解析

image-20230401094819603

解析后结果如图(有些字段涉及厂商名称,打码了)

image-20230401095109158

该graphql接口是基于某个获取“社交分享”的业务点的,最终我在图形化的解析结果中发现:某个查询对象中有一个并没有用到实际业务中的敏感参数“address”

image-20230401095411362

看到这里,颅内高潮便起来了

直接把address参数加入query查询里,最终成功回显出来了众多“社交分享”中的address

image-20230401100029460

但是很遗憾,大部分address都是null,或者最高精确度到“镇级行政区”的数据,没有详细到能出发表社交信息人的具体位置

但是还是决定试一试,向xx厂商安全团队报告了这个问题

image-20230401100539493

厂商先后回复的意思大概是说,address等字段虽然在明面的业务请求上没展示,但是并不属于特别敏感的信息,对用户数据安全不会产生影响

尽管关闭这个graphql接口的内省查询会更安全,但是我们认为保留graphql内省查询这个feature会让菜鸡的安全研究人员(比如你)更容易找到api中的漏洞问题

所以我们暂时不会修改这个功能点,虽然我们很赞赏你花时间来提交我们赏金项目的问题

0x03 后言

看到这里,虽然有些失落,但是也无所谓,在每次漏洞挖掘与经验的学习的过程中中,有所习得(无论是知识还是经验)才是关键所在,而漏洞的最终效果和产出往往是天注定,我们强求不来

谁又知道下个”内省查询”不会产出boom级别的信息和漏洞呢

Hack to learn and learn to hack缺一不可