elastic / beats

:tropical_fish: Beats - Lightweight shippers for Elasticsearch & Logstash
https://www.elastic.co/products/beats
Other
12.14k stars 4.91k forks source link

[winlogbeat] Fix ServiceType translation values #40588

Open jeff-bb opened 3 weeks ago

jeff-bb commented 3 weeks ago

service.type, as populated by x-pack/winlogbeat/module/security/ingest/security.yml, is doing a lookup table versus being treated as an access mask.

https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-createservicea https://learn.microsoft.com/en-us/windows/win32/api/winsvc/ns-winsvc-service_status https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-enumservicesstatusexa https://learn.microsoft.com/en-us/windows/application-management/per-user-services-in-windows https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4697 https://docs.rs/windows-sys/latest/windows_sys/Win32/System/Services/index.html https://helgeklein.com/blog/per-user-services-in-windows-info-and-configuration/

I'm not comfortable submitting a PR directly, but have mocked up the bulk of the (untested) code to make this easier to accept.

ServiceTypeDescriptions:
  "0x00000001": SERVICE_KERNEL_DRIVER
  "0x00000002": SERVICE_FILE_SYSTEM_DRIVER
  "0x00000004": SERVICE_ADAPTER
  "0x00000008": SERVICE_RECOGNIZER_DRIVER
  "0x00000010": SERVICE_WIN32_OWN_PROCESS
  "0x00000020": SERVICE_WIN32_SHARE_PROCESS
  "0x00000040": SERVICE_USER_SERVICE
  "0x00000080": SERVICE_USERSERVICE_INSTANCE
  "0x00000100": SERVICE_INTERACTIVE_PROCESS
  "0x00000200": SERVICE_PKG_SERVICE

and

if (ctx?.winlog?.event_data?.ServiceType != null) {
          ArrayList list = new ArrayList();
          long serviceType = 0L;
          for (elem in split(ctx.winlog.event_data.ServiceType)) {
            if (elem.length() == 0) {
              continue;
            }
            list.add(elem);
            def code = elem.replace("%%","").trim();
            serviceType |= Long.decode(code).longValue();
          }
          if (list.length > 0) {
            ctx.winlog.event_data.put("ServiceType", list);
          }

          ArrayList desc = new ArrayList();
          for (long b = 0; b < 32; b++) {
            long flag = 1L << b;
            if ((serviceType & flag) == flag) {
              def fDesc = params.ServiceTypeDescriptions[String.format("0x%08X", w)];
              if (fDesc != null) {
                desc.add(fDesc);
              }
            }
          }
          if (desc.length > 0) {
            ctx.winlog.event_data.put("ServiceTypeDescription", desc);
          }
    }

It feels odd that these are being inserted into service., since the definition of that isn't quit this. The bulk of this feels better placed in file. and process.*. As such, I'm having ServiceTypeDescription stamped back into the winlog.event_data as a new value similar to how other various lookup tables / access masks are handled.

elasticmachine commented 3 weeks ago

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