Cyber Deception (Anti-Phishing) - A Low Cost Mitigation

This article is part of the blog series Cyber Deception.

English Version available here.

Table of Contents

What is cyber deception?

Cyber Deception is a preventative and proactive IT strategy that aims to trap a potential attacker before they can do any damage. The focus in this article is on the implementation of a “low tech” and cost-effective cyber deception measure.

The measure presented will

  1. have a measurable effect,
  2. not require an operations team, and
  3. not require a special security tool.

On the third point, however, it should be noted that an information channel must be available, e.g. e-mail, Grafana or SIEM, if someone is to be informed about the security-relevant event.

But now the question is, what is this measure anyway and what do we want to detect? We want to be able to detect website cloning and react to it in some way. Be it to warn employees or simply to block the attacker domain.

Website cloning is often used in phishing or phishing campaigns disguised as a red team. This measure can be used to react to this and close a popular attack surface.

Two scenarios are naively conceivable, either you recognize the attack before it is launched or you receive information that an attack is underway. Ideally, you also recognize which asset is affected.

What is low-tech?

I maintain that cyber deception can be a low-tech measure that can be easily implemented by IT operations. Before I pull a complex solution with various tools out of my hat like a magician and praise it as “low-tech”, I will briefly explain what is actually meant by this.

By “low-tech” I mean that no programming knowledge or highly specialized know-how is required to configure the system. The configuration is pure: parameters in, functionality out. Ready-made and tried-and-tested components are also used, which do not require user management due to their nature.

The use of external CDN providers from Akamai, Microsoft, AWS etc. is also avoided for this demonstration. Although it is possible in principle to integrate one of these external providers, it is not absolutely necessary.

Case study: Phishing

First of all, there are various forms of phishing. To name just a few: Smishing (via SMS), via customer service by phone, CEO fraud by email, emails with dubious links and attachments, sometimes extortionate, sometimes nice. Sometimes with the aim of stealing access data from employees, sometimes to gain access to systems via malware.

At this point, I will focus on phishing emails that supposedly contain internal links and thus use website cloning from company websites. The cloned website then usually looks like the original, uses similar CSS. Punycode 1 or similar looking company names are used for the domain to make the link and the website look more real. For example, google.com becomes goolge.com or gooogle.com.

Setup

The setup for testing looks like this:

We assume that there is an attacker site that has cloned our legitimate site. Our legitimate website uses a “CDN” server, which can also simply be a normal web server. When the website is cloned, the CSS URLs used are typically not adapted, so both our legitimate website and the attacker's website use the same website styling.

We take advantage of this feature to implement the cyber deception measure. We set up logging on our CDN server to obtain the source of the request by reading the “Referer” header.

Implementation

Only three components need to be considered for implementation:

  • Configuration of the web server to create targeted logs for us,
  • Extension or adaptation of the CSS of our website,
  • setting up and configuring a log forwarding tool so that the logs can be processed by a solution.

I use caddy as a web server, as the configuration is sufficiently well documented without having to search Stackoverflow. For log forwarding, I chose vector by Datadog. The agent is lightweight, fast, the installation is simple and the documentation is excellent.

Both tools are open source.

Caddy configuration

First, we configure Caddy so that a log file is written if the Referer header does not correspond to our domain. The referer header is set by the browser every time an image of the website is requested via CSS.

cdn.WEBSITE.de {
    root * /usr/share/caddy
    file_server

    @bad_referer {
    	header Referer "https://WEBSITE.de/"
    }

    log {
        output file /var/log/caddy/referer.log
    }
    # `log_skip` with newer versions
    skip_log @bad_referer
}

There is an edge case in the configuration. The Referer header is set, but without content. In this scenario, a log entry is also written. This special case can be handled via the observability agent.

Caddy writes log files in JSON format by default. This format has no particular advantage over others. Most observability or SIEM agents support different formats.

{
    "level": "error",
    "ts": 1739190378.4174354,
    "logger": "http.log.access.log0",
    "msg": "handled request",
    "request": {
        "remote_ip": "<IP>",
        "remote_port": "43776",
        "proto": "HTTP/2.0",
        "method": "GET",
        "host": "cdn.WEBSITE.de",
        "uri": "/background.png",
        "headers": {
            "Referer": ["https://attacker.ru/"],
            "Sec-Fetch-Mode": ["no-cors"],
            "Priority": ["u=4, i"],
            "User-Agent": ["Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0"],
            "Accept": ["image/avif,image/webp,image/png,image/svg+xml,image/*;q=0.8,*/*;q=0.5"],
            "Accept-Encoding": ["gzip, deflate, br, zstd"],
            "Te": ["trailers"],
            "Accept-Language": ["de,en;q=0.5"],
            "Dnt": ["1"],
            "Sec-Fetch-Dest": ["image"],
            "Sec-Fetch-Site": ["same-site"]
        },
        "tls": {
            "resumed": false,
            "version": 772,
            "cipher_suite": 4865,
            "proto": "h2",
            "server_name": "cdn.WEBSITE.de"
        }
    },
    "user_id": "",
    "duration": 0.000100842,
    "size": 0,
    "status": 404,
    "resp_headers": {
        "Server": ["Caddy"],
        "Alt-Svc": ["h3=\":443\"; ma=2592000"]
    }
}

CSS configuration

To ensure that a potential attacker also falls into our little trap, the CSS of the website must be adapted. The configuration of the body element ensures that it is always triggered. However, other HTML elements can also be used.

body {
    background: url('https://cdn.WEBSITE.de/background.png') !important;
}

When a website is cloned, the URL of the CSS styling is usually also copied. The common social engineering toolkits do not adapt URLs in the CSS. This ensures that the CDN server is requested each time the cloned website is called up. When the fake site sends a request, the Referer header is typically set by the browser, which in turn writes our log entry.

This configuration ensures that we generate logs that can then be processed by an observability pipeline in the next step. For simplicity's sake, I send my logs to a Loki instance with Grafana; other communication channels are also possible.

Vector configuration

Finally, let's take a look at the vector configuration. After installing the tool, the configuration file is located under /etc/vector/vector.toml.

Brief outline of common terminology for observability agents. An observability agent has sources, transformations, and sinks. In other words, it processes data according to the EVA principle (input-processing-output).

Our source is the log file that Caddy writes. To do this, we configure the source caddy_referer_log in vector, which reads in this file. As below:

[sources.caddy_referer_log]
type = "file"
exclude = []
file_key = "file"
ignore_not_found = true
include = ["/var/log/caddy/*.log"]
line_delimiter = """

"""

Our transformer skip_empty_referer has our source caddy_referer_log as input. The transformer processes the content of the .message field. First, the JSON of our log entry is parsed and if the Referer header is not set, processing is aborted. This implements the correct handling of the edge case mentioned above.

[transforms.skip_empty_referer]
type = "remap"
inputs = ["caddy_referer_log"]
source = '''
. = parse_json!(.message)
if !exists(.request.headers.Referer) {
        abort
}
'''

Finally, the sink grafana_loki is defined. The input of the sink of the transformer skip_empty_referer is also configured here. We also define the label service=“phishing-detection”. The codec for the transmission to Loki will be JSON.

[sinks.grafana_loki]
type = "loki"
inputs = ["skip_empty_referer"]
endpoint = "https://loki.WEBSITE.de"
labels = {service="phishing-detection"}

[sinks.grafana_loki.encoding]
codec = "json"

[sinks.grafana_loki.auth]
password = "PASS"
user = "USER"
strategy = "basic"

The complete configuration:

data_dir = "/var/lib/vector/"

[sources.caddy_referer_log]
type = "file"
exclude = []
ignore_not_found = true
include = ["/var/log/caddy/*.log"]
line_delimiter = """

"""

[transforms.skip_empty_referer]
type = "remap"
inputs = ["caddy_referer_log"]
source = '''
. = parse_json!(.message)
if !exists(.request.headers.Referer) {
        abort
}
'''

[sinks.grafana_loki]
type = "loki"
inputs = ["skip_empty_referer"]
endpoint = "https://loki.WEBSITE.de"
labels = {service="phishing-detection"}

[sinks.grafana_loki.encoding]
codec = "json"

[sinks.grafana_loki.auth]
password = "PASS"
user = "USER"
strategy = "basic"

What comes next?

TBA


Ben Stuart (M.Sc.) is a certified pentester (OSCP, OSEP, OSWE), developer and IT security consultant. He has several years of cross-industry experience in IT security. With the aim of solving the challenges of IT security hands-on and pragmatically.

Did you like the article and need professional consulting Please don't hesitate to contact without further commitment! Also take a look at the services.


References