Quishing Triage 101: How to Investigate Suspicious QR Codes in Emails

Quishing, derived from combining “QR code” and “phishing,” has manifested as a significant cybersecurity threat, particularly noting a discernible surge in incidents since July 2023. This technique leverages QR codes, square barcodes decipherable by mobile device cameras, to mislead users into interacting with malicious digital content. When a user scans a QR code in a quishing attack, it typically redirects them to a malevolent website, which may deploy malware or solicit confidential information.

The purpose of this blog post is to provide a quick guide for investigating potential quishing emails or any other suspicious email that has an embedded QR code, and also showcase how to leverage a No Code/Low Code platform for accelerating the analysis, which might even benefit other security operations-related use cases.

What is Quishing?

Quishing is a cyber-attack strategy where attackers utilize QR codes to mislead users, typically redirecting them to a malicious website that either downloads malware or solicits their sensitive information. A QR code, or Quick Response code, is a square barcode readable by mobile device cameras. When scanned, it can trigger various actions, such as opening a webpage, initiating a phone call, sending a text message, or facilitating a digital payment.

In a typical quishing scenario, a user might receive an email that appears legitimate, containing a QR code and instructions to scan it for a particular purpose, such as making a payment, accessing a website, or obtaining specific information. Once scanned, the QR code redirects the user to a fraudulent website designed to harvest sensitive data or infiltrate the user’s device with malicious software. Quishing campaigns can be particularly deceptive as they exploit the trust users have developed in scanning QR codes for legitimate purposes, such as menu access in restaurants or facilitating contactless transactions.

Why Are QR Code Phishing Attacks Increasing?

Quishing attacks have the capability to evade conventional security measures, such as secure email gateways, which typically scan for harmful links and attachments. When an email incorporates a QR code, these secure email gateways often deem quishing emails to be safe. Consequently, the emails are delivered directly to the inbox without being flagged as dangerous. Understandably, this presents an opportunity for cyber attackers.

How To Analyze Reported Quishing

If you’re part of a security team or working as a security analyst and receive a report from a user or employee in your company about a suspicious email containing a QR code, it’s imperative to approach the situation with caution. Directly scanning the QR code with your phone is not advisable due to the unknown and potentially harmful link it may contain. Nevertheless, as a security analyst, it’s crucial to delve deeper to comprehend the attack’s nature, aiming to thwart future similar attacks and possibly track successful attacks within the organization. To achieve this, it’s essential to ascertain where the QR code redirects to, ensuring to do so securely.

Here are three steps to meticulously investigate a potential Quishing attack:

  1. Extracting Images from the Reported Email: Ensure to download all images separately from the reported email. This includes those embedded within attached PDF files or forwarded .eml or .msg files, especially if the email has been forwarded to you.
  2. Safely Scan Images for QR Codes and Extract URLs: Scan all images for QR codes by using a 3rd party QR Code scanning service such as qrcoderaptor.com, extracting the corresponding URLs without directly following the link to prevent unintended exposure to malicious content.
  3. Analyze URLs Using Online URL Scanners or Sandboxes: Utilize an online URL scanner or a sandbox to scrutinize all extracted URLs, enabling you to analyze the full origin and intent of the attack without jeopardizing security.

The only problem with the above steps is that it can take too much time and effort. Now let’s try to automate it!

Using Low Code Platform To Automate Quishing Triage

For this purpose I will use Pipedream and some Python coding to create a proof-of-concept quishing triage automation, however feel free to use any preferred workflow builder. Pipedream is a really great tool that helps to easily create automated workflows, and it has a very generous free tier. I recommend to check them out!

What I want to create is a simple workflow that works as following:

  1. Have a dedicated mailbox that will receive any reported Quishing
  2. Extracts all images from the received emails
  3. Checks for QR code in the images and extracts all URLs
  4. Replies back to the original sender with the extracted URLs

That will allow a security analyst to simply forward any suspicious email to another email address, and immediately get a response with the URL to scan in any online URL scanning solution. A definite next-step would be to automatically scan the URL already in the automated workflow and send back results, but I already promised just a proof of concept You can use Intezer’s API for that purpose or any other API of your tool of choice.

Receive emails

I created a new workflow with an “Email” type Trigger, which creates a dedicated email box for us:

Now, I would recommend to send an example email with a QR code, just for the sake of testing and ease of development.

Extracting images from the email

The following code iterates over all attachments of the received email, and extracts images that are embedded within attached PDF, EML and MSG files, as well as just from the original email. I’ve created a Python step in Pipedream, right after the trigger step, where I used this code in:

def handler(pd: "pipedream"):
    EXTRACTED_URLS = []
    IMAGES = []

    for att in pd.steps["trigger"]["event"]["attachments"]:
        # collect images that are directly attached to the received email
        if 'image/' in att["contentType"]:
            IMAGES.append(download_file_to_bytes(att["contentUrl"]))

        # collect images in attached EML file
        elif att["filename"].lower().endswith('.eml'):
            file_path = download_file_to_tmp(att['filename'])
            with open(file_path, "r", encoding="utf-8") as f:
                msg = email.message_from_file(f)
                for part in msg.walk():
                    if part.get_content_maintype() == 'image':
                        image_data = part.get_payload(decode=True)
                        IMAGES.append(image_data)

        # collect images in attached MSG file
        elif att["filename"].lower().endswith('.msg'):
            file_path = download_file_to_tmp(att['filename'])
            msg = extract_msg.Message(file_path)
            for attachment in msg.attachments:
                if 'image' in attachment.type:
                    image_data = attachment.data
                    IMAGES.append(image_data)

        # collect images in attached PDF file
        elif att["filename"].lower().endswith('.pdf'):
            file_path = download_file_to_tmp(att['filename'])
            with open(file_path, "rb") as f:
                reader = PdfReader(file_path)
                for page_number, page in enumerate(reader.pages):
                    for image_file_object in page.images:
                        IMAGES.append(image_file_object.data)

I’ve used two simple utility functions to download attachments to disk and to memory:

def download_file_to_bytes(url):
    response = requests.get(url)
    response.raise_for_status()

    return io.BytesIO(response.content)

def download_file_to_tmp(url, filename):
    file_path = f"/tmp/" + filename
    response = requests.get(att["contentUrl"])
    with open(file_path, "wb") as f:
        f.write(response.content)

    return file_path

It’s surely not the best code I’ve ever written, but have I already mentioned it’s just a proof-of-concept?

Extracting URLs from QR code images

After we have all the images stored in the IMAGES variable, let’s use an external service API (goqr.me) to scan those images for QR codes and extract the URL from them:

(continued handler function)
    for img in IMAGES:
        url_from_qrcode = get_qr_code_data(img)
        if url_from_qrcode:
            EXTRACTED_URLS.append(url_from_qrcode)

    return EXTRACTED_URLS

def get_qr_code_data(image_bytes):
    api_endpoint = "http://api.qrserver.com/v1/read-qr-code/"
    files = {'file': ('qrcode.png', image_bytes)}
    response = requests.post(api_endpoint, files=files)
    
    if response.status_code == 200:
        data = response.json()
        qr_data = data[0]['symbol'][0]['data']
        return qr_data
    else:
        return None

Send extracted URLs back to the sender

First, let’s make sure we don’t send any raw malicious links. Let’s de-link the URLs with the following Python step I created in Pipedream:

def handler(pd: "pipedream"):
    res = ""
    if len(pd.steps["python"]["$return_value"]) > 0:
        for url in pd.steps["python"]["$return_value"]:
            delinked_url = url.replace("http://", "http[:]//").replace("https://", "https[:]//").replace(".", "[.]")
            res += delinked_url + '\n'
        return res
    else:
        return None

Now, let’s use a simple Gmail step to send the de-linked URLs back to the sender:

Testing it

Right after forwarding an email with attached QR code to the generated Pipedream email address, I got a reply to my inbox with the URL!

Try It Yourself!

Feel free to give it a go and send emails that contain QR codes to this address: [email protected]

I’m taking a leap of faith here, hoping that the above address won’t be abused by script kiddies and can serve as a nice tool for security analysts who are looking for an intermediate solution.

What’s Next?

While the demonstration of utilizing a low-code platform to automate certain labor-intensive tasks is valuable, it doesn’t fully address the Quishing issue at a scalable level. At Intezer, we’re taking a step further. In the upcoming weeks, we will be unveiling an enhanced Anti-Quishing logic integrated into our automated reported phishing pipeline, which would be another stride in our journey to develop the world’s premier Autonomous SOC.

This enhancement will empower new Intezer users to effortlessly link their user-reported phishing workflows to Intezer, enabling automated triage. This includes unraveling any embedded QR codes, conducting an in-depth scan of the corresponding URL, and examining any other email artifacts. Consequently, your focus will be directed only towards emails that necessitate your attention, eliminating the need to sift through unnecessary reported emails. For our existing customers who are already utilizing the automated phishing pipeline, the new QR code scanning logic will be seamlessly integrated, functioning out-of-the-box. Essentially, this addition not only extracts but also meticulously analyzes the URL, along with other vital email artifacts, providing a thorough investigation of the potential threat and enhancing the efficacy of the code presented above.

If you’re having scaling or resources shortage issues with combating against Quishing, Phishing, endpoint or SIEM alerts — just book some time with us and we would be happy to help!

Try Intezer for free or book a demo to learn more.

The post Quishing Triage 101: How to Investigate Suspicious QR Codes in Emails appeared first on Intezer.

Article Link: Quishing Triage: How to Investigate Suspicious QR Codes in Emails