Abusing Dynamic QR Codes because Static is Boring

Good day, readers! It's been a while since my last post. A lot of this is due to me working diligently on my vulnerability API, called KEVin. You can learn more about that project at https://kevin.gtfkd.com. In this post, we're going to take a look at a fun abuse case with QR codes.

Backstory

Over the last few months, many company/research blogs have uncovered the use of QR codes for phishing/social engineering attacks. A non-exhaustive list:

...just to show a few.

One of the more interesting use cases was abusing Bing URL contstructors to craft a url, turn it into a QR code, then send the QR code with a pretext pretending to be a multi-factor authentication setup process. The images from Bleepingcomputer show this.

9dDgD.png

As can be seen below, the attackers added a base64-encoded URL followed by a parameter to be used within the DOM to autofill elements:

9WpAT.png

One of the questions I had was "what can I do with QR codes?" This leads us into the title of this post. While creating URLs from Bing is cool and creating a static image works, what if we could generate the QR code dynamically?

Theory

Looking back at the QR code used to perform social engineering, attackers likely generated the image and embedded it within the html in Base64. If you're unfamiliar with this, you can learn more about it here: https://www.w3docs.com/snippets/html/how-to-display-base64-images-in-html.html. Ultimately, detecting this is going to be difficult, as doing so would require scoring off the use of base64 encoded data within email bodies. I'm not saying this is impossible.

While generating a QR code and embedding it isn't necessarily anything advanced, I was curious if I could take it a step further. What if we wanted to remove Bing from the equation and dynamically generate QR codes based off of each target? This could be done simply in a few lines of Python.

The attack scenario would be something like:

  1. Attacker generates link for campaign
  2. Attacker simply adds html code pointing to our server
  3. Our QR code is dynamically created at the time of opening the email/loading resources

qrTrap

In comes qrTrap. This simple python script uses Flask and qrcode libraries to allow for embedding <img> tags with specified URLs (in Base64) and displaying the QR Code. This removes the need for a middleman service as well as not using search engines, which log activity. Instead, we can stand up an easy server that will accept a sent parameter and send back a binary payload which, in this case, will be a png file.

Here's an example html snippet that's used to display this capability:

<!DOCTYPE html>
<html>
<head>
    <title>External Website</title>
</head>
<body>
    <h1>QR Code on External Website</h1>
    <img src="http://127.0.0.1:5000/generate_qr?pg=aHR0cHM6Ly9ndGZrZC5jb20=" alt="QR Code">
</body>
</html>

This will result in a QR code being shown:

9dufH.png

In this case, we've simply Base64-encoded https://gtfkd.com. If we were using a tool such as Gophish or other framework that allows for templates, we could--in theory--use our service to easily generate QR codes on the fly. Since we also control the server, we'd also be able to see if links are being clicked/opened.

Before you ask, yes, this is super detectable as it would require external connections. That said, people will still allow external resources to load and click things. Else, phishing wouldn't be a thing ;)

There is a lot more that could be done with this, however, going much deeper would result in me making a whole attack framework with this and having to then support it. :)

If you'd like to roll your own instance or copy the code into your own tools/make it useful, you can find it here: https://github.com/synfinner/qrTrap

It's also worth noting that on the server side, we could also restrict requests to only those with User-Agent strings containing Microsoft Outlook. I'll leave you all to your imagination.