Tags: jsfuck brainfuck rev web 

Rating:

The challenge has a web app running. On the cliend source code there is a comment:
```

```
This seems a hint to check robots.txt:
```
User-agent: * Disallow: /source
```
When checking the /source we get a very long file that starts with the following:
```
exec('%c'%((()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()==())+(()
```
This is just a piece of it, this is python, when changing the exec to print and we run it, we get the following code:
```
_A='backend.js'
from flask import Flask,send_file,request,redirect
import os,json,subprocess
app=Flask(__name__)
@app.route('/')
def index():return send_file('index.html')
@app.route('/logo.svg')
def logo():return send_file('logo.svg')
@app.route('/robots.txt')
def robots():return'User-agent: *\nDisallow: /source'
@app.route('/source')
def source():
with open('app.py')as A:return A.read()
@app.route('/source/js')
def js_source():
with open(_A)as A:return A.read()
@app.route('/3ng1n33r1ng-s4mpl3',methods=['POST'])
def flag():
A={A[0]:A[1]for A in request.headers.items()};B=request.args.to_dict()
print(subprocess.check_output(['node',_A,str(A),str(B),str(request.json)]).decode().strip())
if subprocess.check_output(['node',_A,str(A),str(B),str(request.json)]).decode().strip()=='Valid':return os.environ.get('FLAG')
return redirect('/')
if __name__=='__main__':app.run()
```
It seems there is a /source/js, and it starts like this:
```
[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]
```
This is again just part of it, it is jsfuck, I've pasted it into a file, it ended with () so it was a function, I've surrounded it with console.log([...].toString()) to get the function code and I got the following:
```
d=JSON.parse(`{"header_key": "[-]>[-]<++++++++[>++++++++++<-]>++++++++.<++++[>----------<-]>---.<++[>++++++++++<-]>++++.<++[>++++++++++<-]>++++++++.<+[>++++++++++<-]>+++++++.<[>----------<-]>------.<+[>++++++++++<-]>+++.<+++++++[>----------<-]>------.<++[>++++++++++<-]>.<+++[>++++++++++<-]>++++.<[>----------<-]>.<[>++++++++++<-]>++.<+[>++++++++++<-]>++++.<[>----------<-]>.<", "header_value": "[-]>[-]<++++++++++[>++++++++++<-]>+++++++.<[>----------<-]>--.<+[>++++++++++<-]>+.<+[>----------<-]>-------.<+[>++++++++++<-]>+++++++.<+[>----------<-]>----.<+++++[>----------<-]>-------.<+++++[>++++++++++<-]>++++.<[>++++++++++<-]>++.<+[>++++++++++<-]>+++.<[>++++++++++<-]>++.<+[>----------<-]>-.<[>----------<-]>---.<[>++++++++++<-]>+++.<[>----------<-]>----.<[>----------<-]>-.<+++++[>----------<-]>-----.<+++++++[>++++++++++<-]>+.<+[>----------<-]>-----.<+[>++++++++++<-]>++++.<[>++++++++++<-]>+.<+[>----------<-]>-----.<+[>++++++++++<-]>+++.<", "query_key": "[-]>[-]<++++++++++[>++++++++++<-]>+++++++.<[>----------<-]>------.<++[>++++++++++<-]>.<", "query_value": "[-]>[-]<+++++[>++++++++++<-]>+++.<[>----------<-]>-.<[>++++++++++<-]>++.<[>++++++++++<-]>++.<[>----------<-]>--.<[>++++++++++<-]>+++.<[>----------<-]>--.<[>----------<-]>----.<[>----------<-]>-.<[>----------<-]>--.<[>++++++++++<-]>++++++.<[>++++++++++<-]>+++.<[>----------<-]>--.<[>----------<-]>----.<[>----------<-]>-.<[>----------<-]>--.<[>++++++++++<-]>++++++.<[>----------<-]>-----.<[>++++++++++<-]>+.<[>----------<-]>--.<[>++++++++++<-]>+++++++.<[>----------<-]>-.<[>----------<-]>.<[>----------<-]>-----.<[>++++++++++<-]>+++++.<++++[>++++++++++<-]>+++++.<++++[>----------<-]>-----.<[>++++++++++<-]>+++.<[>----------<-]>---.<[>----------<-]>--.<[>----------<-]>--.<[>----------<-]>--.<[>++++++++++<-]>++++++.<++++[>++++++++++<-]>++++.<++++[>----------<-]>----.<[>----------<-]>-.<[>++++++++++<-]>++.<[>++++++++++<-]>++.<", "body_key": "[-]>[-]<+++++++++++[>++++++++++<-]>++++.<+[>----------<-]>---.<+[>++++++++++<-]>++++.<[>----------<-]>----.<[>++++++++++<-]>++++++.<[>----------<-]>---.<+[>----------<-]>-----.<[>++++++++++<-]>++.<", "body_value": "[-]>[-]<++++++++++[>++++++++++<-]>++.<[>++++++++++<-]>++++++.<+[>----------<-]>-.<[>++++++++++<-]>++++++.<", "cookie_key": "[-]>[-]<+++++++++++[>++++++++++<-]>.<+[>----------<-]>.<[>----------<-]>---.<", "cookie_value": "[-]>[-]<+++++++++++[>++++++++++<-]>++++++.<[>----------<-]>--.<[>++++++++++<-]>+++.<+[>----------<-]>------.<"}`);
function interpret(e){
let r="",a=new Array(420).fill(0),s=0,t=0,o="",i=!1;var c=[];
braces={},e=e.replace(/[^<>+-.,\[\]]/,"");
for(let r=0;r<e.length;r++)"["===e[r]&&c.push(r),"]"===e[r]&&(start=c.pop(),braces[start]=r,braces[r]=start);
for(;!i;){switch(e[s]){case">":t++;break;case"<":t--;break;case"-":a[t]--;break;case"+":a[t]++;break;case".":o+=String.fromCharCode(a[t]);break;case",":a[t]=r.charCodeAt(0),r=r.substring(1);break;case"[":0===a[t]&&(s=braces[s]);break;case"]":0!==a[t]&&(s=braces[s]);break;case void 0:i=!0}s++}return o}

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");;
```
I've run this server code of both files on my local machine and printed what was being compared and checked. The final request that got me the flag was the following:
```
POST /3ng1n33r1ng-s4mpl3?resource=flag&key=5468697320697320612076616c6964206b6579 HTTP/2
Host: wtf-0.chals.kitctf.de
X-Early-Access: kitctf-certified-tester
Cookie: nda=true
Content-Type: application/json
[...]

{"resource":"flag"}
```
And the server answered with the following:
```
HTTP/2 200 OK
Content-Type: text/html; charset=utf-8
Date: Sat, 10 Jun 2023 21:30:45 GMT
Server: Werkzeug/2.3.5 Python/3.10.12
Content-Length: 28

GPNCTF{qSf1PSqRtUspio040GHg}
```