summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Borner2023-06-10 16:59:34 +0200
committerMarvin Borner2023-06-10 16:59:34 +0200
commit01c8af3bf6574622a4f650bc7c8e9e1e26c15d60 (patch)
tree7dc6460f0495f60155acc8fb8dd1d02873cd456b
Initial commit hehe
-rw-r--r--insanity.md13
-rw-r--r--ref4ctory.md24
-rw-r--r--sanity.md5
-rw-r--r--what-the-flag.md84
4 files changed, 126 insertions, 0 deletions
diff --git a/insanity.md b/insanity.md
new file mode 100644
index 0000000..3e653e2
--- /dev/null
+++ b/insanity.md
@@ -0,0 +1,13 @@
+# Insanity Check
+
+Starting with the confidence from the "Sanity Check" challenge, we
+initially didn't take this challenge to seriously.
+
+After trying to find some hidden messages in the "rules" section of the
+Discord server for multiple hours, we gave up.
+
+Who would've thought that the flag would only appear to the people who
+looked at the "rules" section on the website? Insanity.
+
+Anyway, we found the flag on a moving image of a train behind the rule
+text. Insane.
diff --git a/ref4ctory.md b/ref4ctory.md
new file mode 100644
index 0000000..179ecee
--- /dev/null
+++ b/ref4ctory.md
@@ -0,0 +1,24 @@
+# Ref4ctory
+
+This challenge involved finding the factors of multiple composite
+numbers.
+
+``` python
+def check_factors(a,b,ab):
+ if abs(a)<=1 or abs(b)<=1:
+ print("too easy")
+ return False
+ if type(a*b) == float:
+ print("no floats please")
+ return False
+ return a*b == ab
+```
+
+The `check_factors` function disallows floats and factors $-1\le a\le 1$
+and $-1\le b\le 1$.
+
+Our quick-and-dirty strategy was therefore to use the factor $a=2$ and
+$b=ab/2$ if $a\pmod2=0$. If $a\pmod2\ne0$, we would use wolframalpha's
+prime factorization (because primes are awesome). While we had some
+problems with typing fast enough (`ncat` timeouted), we got the flag
+using this approach in the end.
diff --git a/sanity.md b/sanity.md
new file mode 100644
index 0000000..3c64b31
--- /dev/null
+++ b/sanity.md
@@ -0,0 +1,5 @@
+# Sanity Check
+
+The challenge instructions were "read the rules".
+
+The rules contained a string "GPNCTF{...}". Yep, that's all.
diff --git a/what-the-flag.md b/what-the-flag.md
new file mode 100644
index 0000000..167534c
--- /dev/null
+++ b/what-the-flag.md
@@ -0,0 +1,84 @@
+# What-the-flag
+
+The provided webpage tells us that the "KITCTF FlagGenerator" is
+currently not available to the public. There are no buttons or links,
+leading us to investigate the source-code.
+
+We found the comment
+`<!-- TODO prevent google from leaking our source code -->` in the
+source code. Well, how can you prevent Google (or web crawlers in
+general) from crwaling your webpage? Using the `/robots.txt`!
+
+The `robots.txt` file contains the string
+`User-agent: * Disallow: /source`. Soo the next step was obviously to
+investigate the `/source` file. This was the moment we understood the
+name of the challenge "wtf" -- the code mainly consists of "(", ")", "="
+and "+", all wrapped in an `exec` call. The existence of the `exec`
+function made us believe that the source is written in Python (lucky
+guess, to be honest). As the string inside the `exec` function would
+represent some kind of source-code, we could potentially retrieve it by
+replacing it with a `print` function -- which gave us a (weirdly
+formatted) Flask backend!
+
+Two routes were especially interesting:
+
+``` python
+@app.route('/3ng1n33r1ng-s4mpl3',methods=['POST'])
+def flag():
+ A={A[0]:A[1]for A in request.headers.items()};B=request.args.to_dict()
+ if subprocess.check_output(['node',_A,str(A),str(B),str(request.json)]).decode().strip()=='Valid':return os.environ.get('FLAG')
+ return redirect('/')
+```
+
+and
+
+``` python
+@app.route('/source/js')
+def js_source():
+ with open(_A)as A:return A.read()
+```
+
+After some investigation it seems like POSTing some data to
+`/3ng1n33r1ng-s4mpl3` would return the flag *if* the provided JS code
+(applied with the given request data) would return "valid".
+
+The `/source/js` code, however, looks even weirder than the previous
+Python code.
+
+``` javascript
+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]](([][[]]+[])[!+[]+!+[]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])...
+```
+
+Luckily we immediatly realized that this encoding must be "jsfuck". By
+executing and reformatting the code, we arrived at a NodeJS application
+that uses its arguments to decide whether they match the interpretation
+of some brainfuck codes (wtf?):
+
+``` javascript
+const headers = JSON.parse(process.argv[2].split("'").join('"')),
+ args = JSON.parse(process.argv[3].split("'").join('"')),
+ body = JSON.parse(process.argv[4].split("'").join('"'));
+headers[interpret(d.header_key)] === interpret(d.header_value) &&
+args[interpret(d.query_key)] === interpret(d.query_value) &&
+body[interpret(d.body_key)] === interpret(d.body_value) &&
+headers.Cookie.split("=")[0] === interpret(d.cookie_key) &&
+headers.Cookie.split("=")[1] === interpret(d.cookie_value)
+ ? console.log("Valid")
+ : console.log("Fake");
+```
+
+By calling the `interpret` function directly on the values in the `d`
+object and logging the results, we achieved the data that we would have
+to put in the request parameters:
+
+- path "/3ng1n33r1ng-s4mpl3"
+- cookie with "nda=true"
+- json body with {"resource": "flag"}
+- header with "X-Early-Access: kitctf-certified-tester"
+- query with "key=5468697320697320612076616c6964206b6579"
+
+Plugging all this into a `curl` request finally gave us the flag:
+
+``` bash
+curl --cookie "nda=true" --data '{"resource":"flag"}' -H "X-Early-Access: kitctf-certified-tester" -H "Content-Type: application/json" -X POST "https://wtf-0.chals.kitctf.de/3ng1n33r1ng-s4mpl3?key=5468697320697320612076616c6964206b6579"
+```