Cookie Consent by

RAT CTF 2020

RAT CTF 2020


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.

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.

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.

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 as below.

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 ;-)

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.

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##[email protected]/', {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) {
      } else {

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

User.find({}, function(err, dupa) {
        if (err) throw err;
        for (var i = 0;i < dupa.length; i++){

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' }
[email protected]
[email protected]
[email protected]
[email protected]

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
ping -c 1 172.20.0.${i} >> ping_chain.txt 2>&1

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
nc -zv ${i} >> nc2.txt 2>&1
nc -zv ${i} >> nc2.txt 2>&1
nc -zv ${i} >> nc2.txt 2>&1

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


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