WEB - 1. JSFBOX
題目中提供一個網頁,只能輸入符號 (Symbol),有提供原始碼, 要讓網頁爆出 Flag。
題目
const express = require('express');const app = express();const fs = require('fs');const fa = fs.readFileSync('/flag', 'utf-8');const port = 1024;
app.use(express.text());
app.use("/", express.static("static"));
app.post("/escape", (req, res) => {    body = req.body;    let validationResult = validateString(body);
    if (validationResult !== "String is valid.") {        return res.send(validationResult);    }
    console.log(body);
    let result;    try {        result = eval(body).toString();    } catch (e) {        return res.send("Something went wrong with your code.");    }
    try {        if (String (eval(result)) === fa) {            return res.send("WOW! How did you know the flag?");        }    } catch (e) {}
    return res.send("Good job! Try harder.");});
app.listen(port, () => {    console.log(`App running on http://localhost:${port}`);});
function validateString(input) {    if (!/^[^\w=]+$/.test(input)) {        return "ERROR: Input must only contain symbols.";    }
    const charCount = {};    for (let char of input) {        charCount[char] = (charCount[char] || 0) + 1;    }
    const sortedSymbols = Object.keys(charCount).sort((a, b) => charCount[b] - charCount[a]);
    if (sortedSymbols.length > 2**4) {        return "ERROR: More than 8 different symbols used.";    }
    for (let i = 0; i < sortedSymbols.length; i++) {        const maxAllowed = 2**7 - i;        if (charCount[sortedSymbols[i]] > maxAllowed) {            return `ERROR: Symbol '${sortedSymbols[i]}' appeared ${charCount[sortedSymbols[i]]} times, which exceeds the limit of ${maxAllowed}.`;        }    }
    return "String is valid.";}解法
使用 eval 函數對比,可以直接帶入 res.send(fa),就能成功把 Flag 搞出來。
題目既然只能用 symbols 作為輸入,那第一步就聯想到 JSFuck, 但原生 JSFuck 產生器會有很多符號,需要自己改良跟運用他比較寬鬆的 regex。
(!![]+[])[+!+[]] + // r(!![]+[])[!+[]+!+[]+!+[]] + // r(![]+[])[+!+[]+!+[]+!+[]] + // s"." + // .(![]+[])[+!+[]+!+[]+!+[]] + // s(!![]+[])[!+[]+!+[]+!+[]] + // e([][[]]+[])[+!+[]] + // n([][[]]+[])[!+[]+!+[]] + // d"(" + // (((![]+[])[+[]]+(![]+[])[+!+[]]) + // fa")" // )MISC - 1. Eazy Jail
題目有分兩個 Stage, 分別是 Python 跟 JS, 第一個 Stage,是在 Python int(input) 的情況下, 要分別用 1, 3, 4, 6, 7, 8, 10, 11 長度的輸入解出 2。
第二個 Stage,是在 JS 的請況下, 要同時滿足 Number(input) 跟 safeEval(input) 分別為 1024 與 532。
題目
import os
def validate_and_execute(user_input, expected_length):    EXPECTED_RESULT = 2    allowed_characters = set('abcdefg123456{}"')
    if len(user_input) != expected_length:        print(f"Invalid input length. Your input must be exactly {expected_length} characters long.")        return False
    if set(user_input).difference(allowed_characters):        print("Invalid input. Only a,b,c,d,e,f,g,1,2,3,4,5,{,} certain characters are allowed.")        return False
    expression = f"int({user_input})"    result = eval(expression, {'__builtins__': None}, {'int': int})    try:        if  result != EXPECTED_RESULT:            print(f"Error.")            return False        else:            return True    except Exception:        print(f"Error.")        return False
levels = [1, 3, 4, 6, 7, 8, 10, 11]
def start_game():    logo="""░█████╗░███████╗░██████╗░██╗░██████╗ Eazy Jail For Beginner██╔══██╗██╔════╝██╔════╝░██║██╔════╝███████║█████╗░░██║░░██╗░██║╚█████╗░██╔══██║██╔══╝░░██║░░╚██╗██║░╚═══██╗██║░░██║███████╗╚██████╔╝██║██████╔╝╚═╝░░╚═╝╚══════╝░╚═════╝░╚═╝╚═════╝░ STAGE 1"""    print(logo)    print("Your task is to enter a string that, when used in a command like 'int(YOUR_INPUT)', results in the number 2.")    print("Each level requires a different input length. If you succeed through all levels, you will reach the next stage!")    for level in levels:        print(f"\nLevel {levels.index(level) + 1} of {len(levels)}: Enter a payload exactly {level} characters long.")        while True:            user_input = input("Enter a payload: ")            if validate_and_execute(user_input, level):                print(f"Congratulations on passing level {levels.index(level) + 1}!")                if level == 11:                    os.system('clear')                    os.system('node stage2.js')                    return                break            else:                print("An error occurred.")                return
if __name__ == "__main__":    start_game()    exit()const fs = require('fs');const fa = fs.readFileSync('./flag', 'utf-8');
const readline = require('readline').createInterface({    input: process.stdin,    output: process.stdout});
const QUESTION = `What's my favorite number?
- 1024 is my birthday- 532 is my last 3 digits of my phone`;
const CORRECT_ANSWER = 1024;const EXPECTED_RESULT = 532;
console.log(QUESTION);
readline.question('Guess the number: ', input => {    const guessedNumber = Number(input);    console.log(guessedNumber);
    let spinnerInterval;    let spinnerIndex = 0;    const spinnerChars = ['|', '/', '-', '\\'];
    const startSpinner = () => {        spinnerInterval = setInterval(() => {            process.stdout.write(`\rChecking your answer... ${spinnerChars[spinnerIndex]}`);            spinnerIndex = (spinnerIndex + 1) % spinnerChars.length;        }, 100);    };
    const stopSpinner = () => {        clearInterval(spinnerInterval);        process.stdout.write('\rChecking your answer... Done!\n');    };
    startSpinner();
    setTimeout(() => {        stopSpinner();        console.log(`\n=====================================\n`);        if (guessedNumber === CORRECT_ANSWER) {            console.log(`Great! You got the number - Awesome!`);            try {                const evaluationResult = safeEval(input);                if (evaluationResult === EXPECTED_RESULT) {                    displaySuccess();                } else {                    displayFailure();                }            } catch (error) {                displayError();            }        } else {            displayFailure();        }        readline.close();    }, 1500);});
function safeEval(input) {    const allowedChars = /^[0-9+\-*/.\s]+$/;
    if (!allowedChars.test(input)) {        throw new Error('Invalid characters detected!');    }
    return new Function(`return (${input})`)();}
function displaySuccess() {    console.log(`Good job! You got it! :)`);    console.log(`Flag: ${fa.trim()}\n`);}
function displayFailure() {    console.log('Oops! Wrong answer! Try again :)\n');}
function displayError() {    console.log(`Error occurred! Please try again!\n`);}解法
第一個 Stage: [ 2, “2”, b”2”, f”{2}”, """2""", f"""2""", f"""{2}""", f”{f”{2}”}” ]
第二個 Stage: 運用新版 JS Number(input) 不會辨識進位的特性,使用 01024 讓他取得 1024, 後面 safeEval(input) 時會辨識進為八進位,1024 即為 532,可滿足兩個條件。
