Skip to content

Conversation

@veritasr3x
Copy link

@veritasr3x veritasr3x commented Oct 22, 2025

  • Enhancement

Adds the field 'process.args_count' to the winlogbeat security ingest pipeline.

What: I reviewed the ingest pipeline used for Sysmon and the Script processor that implements the "Windows-like SplitCommandLine" logic. Lines 542 to 546 implement the logic for Sysmon, so I adapted those lines into the correct order of operations defined in the Security ingest pipeline, inserted at line 3718.

Why: To make process.args_count available for both Sysmon and Security telemetry for consistent searching, alerting, and exclusion handling.

Checklist

  • My code follows the style guidelines of this project
    - [ ] I have commented my code, particularly in hard-to-understand areas
    - [ ] I have made corresponding changes to the documentation
    - [ ] I have made corresponding change to the default configuration files
  • I have added tests that prove my fix is effective or that my feature works
  • I have added an entry in ./changelog/fragments using the changelog tool.

Disruptive User Impact

None identified

Author's Checklist

N/A

How to test this PR locally

  1. In an Elastic instance with winlogbeat ingest pipelines installed, modify the security ingest pipeline script processor to include the changes.
  2. Use the winlogbeat repository test data document for Event ID 4688 and either use the synthetic pipeline API method or edit via Kibana UI and run the pipeline. This is the resulting output:
{
  "docs": [
    {
      "doc": {
        "_index": "fake-index",
        "_version": "1",
        "_id": "1dv5h58clFnpCQzq8pr_",
        "_source": {
          "agent": {
            "name": "FAKEAGENT",
            "id": "2c75512f-bd7d-4b01-8aea-58f5f302fb02",
            "type": "winlogbeat",
            "ephemeral_id": "9566a3ed-9991-4014-956d-f4b0892a0999",
            "version": "8.x.x"
          },
          "process": {
            "args": [
              "\"C:\\Windows\\system32\\wevtutil.exe\"",
              "cl",
              "Security"
            ],
            "parent": {
              "name": "powershell.exe",
              "pid": 4652,
              "executable": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"
            },
            "name": "wevtutil.exe",
            "pid": 4556,
            "args_count": 3,     <-----------------------------------------------------  successful output
            "command_line": "\"C:\\Windows\\system32\\wevtutil.exe\" cl Security",
            "executable": "C:\\Windows\\System32\\wevtutil.exe"
          },
          "@timestamp": "2019-11-14T17:10:15.1515514Z",
          "winlog": {
            "computer_name": "vagrant",
            "process": {
              "pid": 4,
              "thread": {
                "id": 5076
              }
            },
            "keywords": [
              "Audit Success"
            ],
            "logon": {
              "id": "0x274a2"
            },
            "channel": "Security",
            "event_data": {
              "MandatoryLabel": "S-1-16-12288",
              "TokenElevationType": "TokenElevationTypeFull (2)",
              "SubjectLogonId": "0x274a2",
              "TargetLogonId": "0x0",
              "CommandLine": "\"C:\\Windows\\system32\\wevtutil.exe\" cl Security",
              "SubjectUserName": "vagrant",
              "SubjectDomainName": "VAGRANT",
              "ProcessId": "0x122c",
              "TargetUserName": "-",
              "TargetDomainName": "-",
              "SubjectUserSid": "S-1-5-21-1610636575-2290000098-1654242922-1000",
              "TargetUserSid": "S-1-0-0"
            },
            "opcode": "Info",
            "version": 2,
            "record_id": "5010",
            "event_id": "4688",
            "task": "Process Creation",
            "provider_guid": "{54849625-5478-4994-A5BA-3E3B0328C30D}",
            "provider_name": "Microsoft-Windows-Security-Auditing"
          },
          "ecs": {
            "version": "1.12.0"
          },
          "related": {
            "user": [
              "vagrant"
            ]
          },
          "log": {
            "level": "information"
          },
          "host": {
            "name": "vagrant"
          },
          "event": {
            "code": "4688",
            "provider": "Microsoft-Windows-Security-Auditing",
            "kind": "event",
            "module": "security",
            "action": "created-process",
            "category": [
              "process"
            ],
            "type": [
              "start"
            ],
            "outcome": "success"
          },
          "message": "A new process has been created.\n\nCreator Subject:\n\tSecurity ID:\t\tS-1-5-21-1610636575-2290000098-1654242922-1000\n\tAccount Name:\t\tvagrant\n\tAccount Domain:\t\tVAGRANT\n\tLogon ID:\t\t0x274a2\n\nTarget Subject:\n\tSecurity ID:\t\tS-1-0-0\n\tAccount Name:\t\t-\n\tAccount Domain:\t\t-\n\tLogon ID:\t\t0x0\n\nProcess Information:\n\tNew Process ID:\t\t0x11cc\n\tNew Process Name:\tC:\\Windows\\System32\\wevtutil.exe\n\tToken Elevation Type:\tTokenElevationTypeFull (2)\n\tMandatory Label:\t\tS-1-16-12288\n\tCreator Process ID:\t0x122c\n\tCreator Process Name:\tC:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\n\tProcess Command Line:\t\"C:\\Windows\\system32\\wevtutil.exe\" cl Security\n\nToken Elevation Type indicates the type of token that was assigned to the new process in accordance with User Account Control policy.\n\nType 1 is a full token with no privileges removed or groups disabled.  A full token is only used if User Account Control is disabled or if the user is the built-in Administrator account or a service account.\n\nType 2 is an elevated token with no privileges removed or groups disabled.  An elevated token is used when User Account Control is enabled and the user chooses to start the program using Run as administrator.  An elevated token is also used when an application is configured to always require administrative privilege or to always require maximum privilege, and the user is a member of the Administrators group.\n\nType 3 is a limited token with administrative privileges removed and administrative groups disabled.  The limited token is used when User Account Control is enabled, the application does not require administrative privilege, and the user does not choose to start the program using Run as administrator.",
          "user": {
            "name": "vagrant",
            "effective": {
              "id": "S-1-0-0"
            },
            "id": "S-1-5-21-1610636575-2290000098-1654242922-1000",
            "domain": "VAGRANT"
          }
        },
        "_ingest": {
          "timestamp": "2025-10-22T10:33:16.347201099Z"
        }
      }
    }
  ]
}

Related issues

Use cases

Explained in the "WHY" above.

Screenshots

I don't think any are needed

Logs

Not applicable

Adds the field 'process.args_count' to the winlogbeat security ingest pipeline
@veritasr3x veritasr3x requested a review from a team as a code owner October 22, 2025 10:39
@botelastic botelastic bot added the needs_team Indicates that the issue/PR needs a Team:* label label Oct 22, 2025
@github-actions
Copy link
Contributor

🤖 GitHub comments

Expand to view the GitHub comments

Just comment with:

  • run docs-build : Re-trigger the docs validation. (use unformatted text in the comment!)

@mergify
Copy link
Contributor

mergify bot commented Oct 22, 2025

This pull request does not have a backport label.
If this is a bug or security fix, could you label this PR @veritasr3x? 🙏.
For such, you'll need to label your PR with:

  • The upcoming major version of the Elastic Stack
  • The upcoming minor version of the Elastic Stack (if you're not pushing a breaking change)

To fixup this pull request, you need to add the backport labels for the needed
branches, such as:

  • backport-8./d is the label to automatically backport to the 8./d branch. /d is the digit
  • backport-active-all is the label that automatically backports to all active branches.
  • backport-active-8 is the label that automatically backports to all active minor branches for the 8 major.
  • backport-active-9 is the label that automatically backports to all active minor branches for the 9 major.

@veritasr3x veritasr3x changed the title Update resolves issue #14767 Update related to elastic integrations issue 14767 Oct 22, 2025
@veritasr3x veritasr3x marked this pull request as draft October 22, 2025 19:38
@veritasr3x veritasr3x marked this pull request as ready for review October 22, 2025 19:54
@botelastic botelastic bot removed the needs_team Indicates that the issue/PR needs a Team:* label label Oct 23, 2025
@elasticmachine
Copy link
Collaborator

Pinging @elastic/sec-windows-platform (Team:Security-Windows Platform)

@marc-gr
Copy link
Contributor

marc-gr commented Oct 23, 2025

/test

@veritasr3x veritasr3x marked this pull request as draft October 28, 2025 00:14
This enhancement adds the 'process.args_count' field to the winlogbeat windows security ingest pipeline, allowing for better tracking of process arguments.
@veritasr3x veritasr3x marked this pull request as ready for review October 28, 2025 00:23
@veritasr3x
Copy link
Author

Figured out how to add the changelog fragment. Should be ready for review, I hope.

Comment on lines +3719 to +3722
def args = ctx?.process.args;
if (args != null && args != "") {
ctx.process.args_count = ctx.process.args.length;
}
Copy link
Member

@andrewkroh andrewkroh Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def args = ctx?.process.args;
if (args != null && args != "") {
ctx.process.args_count = ctx.process.args.length;
}
if (ctx.process?.args instanceof List) { ctx.process.args_count = ctx.process.args.size(); }

This will ensure process.args is a non null List before trying to access the .size().

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that's needed.

If I'm reading correctly, lines 3690 to 3711 above this area handle the null checking since populating process.args is directly derived from line 3690 where there's a validation of whether the CommandLine field is null.

If not null, it sets the CommandLine value into an array list and isolates each component into the array list via the variable args that then populates the process.args (lines 3712 to 3716).

The suggested code change does another null check on the args condition, as derived from the previous null check leveraged against the CommandLine field.

All that being said, I think the non-null checking is already present. I'm very new to diving this deep, so please correct me if I'm mistaken.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andrewkroh What do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My suggestion is safe to use independent of the what happens before.

If you want to depend on the previous block's behavior then move the addition of the process.args_count into that block and directly reference the ArrayList's size().

         ctx.process.put("args", al);
+        ctx.process.put("args_count", al.size());
         ctx.process.put("command_line", ctx.winlog.event_data.CommandLine);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants