wazuh / wazuh-agent

Wazuh agent, the Wazuh agent for endpoints.
GNU Affero General Public License v3.0
32 stars 18 forks source link

Implement Windows Logcollector Module #206

Open cborla opened 1 month ago

cborla commented 1 month ago

Description

This issue is a section of #201, focuses on implementing the Windows Logcollector module in the Wazuh Agent 5.0.0. The Windows collector will utilize the Event Channel (eventchannel) API to gather system logs, ensuring seamless integration and log management on Windows platforms.

Functional Requirements

Non-functional Requirements

Deliverables

  1. Wazuh Agent Executable with Windows Collector
    • [ ] An updated Wazuh Agent build that includes the implemented Windows collector within the Logcollector module.
  2. Design Documentation for Windows Collector
    • [ ] Comprehensive documentation detailing the architecture, components, and workflow of the Windows collector.

Acceptance Criteria

LucioDonda commented 1 month ago

Update 7/10/2024 and 8/10/2024

Analysis and comparisson of libraries:

1) *Windows Event Log API** (EvtQuery, EvtNext, etc.) :

2) Event Tracing for Windows (ETW):

3) krabsetw:

4) Integrating PowerShell:

First Approach

Some basic design and tentative approach on how can this be achieved, this should be double checked based on the different libraries limitations and needs:

Class Diagram:

classDiagram
    class EventChannelQuerySystem {
        - Session session
        - Provider provider
        - Consumer consumer
        -BookmarkManager bookmarkMgr
        -QueryBuilder queryBuilder
        +initialize()
        +startQuery(channelName, queryString)
        +stopQuery()
        +getResults()
        +setReconnectTime(time)
        +rotateLog()
    }
    class Session {
        -sessionName
        -sessionProperties
        +open()
        +close()
        +enableProvider(provider)
    }
    class Provider {
    }
    class Consumer {
        -eventCallback
        +processEvent(event)
        +setEventCallback(callback)
    }
    class BookmarkManager {
        -bookmarks
        +createBookmark(event)
        +getBookmark(id)
        +saveBookmarks()
        +loadBookmarks()
    }
    class QueryBuilder {
        +buildQuery(channelName, conditions)
        +addWildcardMatch(field, pattern)
    }

    EventChannelQuerySystem -- Session
    EventChannelQuerySystem -- Provider
    EventChannelQuerySystem -- Consumer
    EventChannelQuerySystem -- BookmarkManager
    EventChannelQuerySystem -- QueryBuilder
  1. EventChannelQuerySystem: The main class that orchestrates the entire querying process.
  2. Session: Manages the ETW session, including opening, closing, and enabling providers.
  3. Provider: Represents an ETW provider, which can be enabled or disabled.
  4. Consumer: Processes the events received from the ETW session.
  5. BookmarkManager: Handles the creation, saving, and loading of bookmarks.
  6. QueryBuilder: Constructs queries, including support for wildcard matches.

Flow chart:

  1. The system starts by initializing the ETWQuerySystem.
  2. It opens an ETW session and enables the required provider.
  3. The ETW consumer is set up to handle incoming events.
  4. Bookmarks are loaded from persistent storage.
  5. A query is built using the QueryBuilder, incorporating channel name and specific query conditions.
  6. The query is started, and the system enters an event processing loop.
  7. For each received event:
    • The event is processed.
    • Bookmarks are updated.
    • Log rotation is performed if needed.
  8. The system checks if reconnection is needed and performs it if necessary.
  9. When the query is stopped, bookmarks are saved, and the session is closed.
graph TD
    A[init] --> B[Initialize - ETWQuerySystem]
    B --> C[Open - ETWSession]
    C --> D[Enable - ETWProvider]
    D --> E[Set up - ETWConsumer]
    E --> F[Load Bookmarks -> store]
    E --> W[(Store)]
    F --> G[Build N Queries]
    G --> H[run]
    H --> I{While Event Received?}
    I -->|Yes| J[Process Event]
    J --> K[Update Bookmark]
    K --> I
    I -->|No| N{Query Stopped or shutdown signal ?}
    N -->|Yes| O[Save Bookmarks]
    O --> P[Close Session]
    P --> Q[End]
    N -->|No| R{Reconnect Needed?}
    R -->|Yes| S[Reconnect]
    S --> I
    R -->|No| I
LucioDonda commented 1 month ago

Update 9/10/2024

LucioDonda commented 1 month ago

Update 10/10/2024

LucioDonda commented 1 month ago

Update 14/10/2024

Seccond Approach

Because we're using krabsetw and it needs to create a thread for each provider, this is the rework of the design:

Class Diagram:

```mermaid classDiagram class EventChannelQuerySystem { - Provider provider - Consumer consumer -BookmarkManager bookmarkMgr -QueryBuilder queryBuilder +initialize() +setEventCallback(callback) +start() +qttyOfResults() +setReconnectTime(time) +rotateLog() } class Provider { -channel -providerName } class Consumer { -eventCallback -queryString +processEvent(event) } class BookmarkManager { -bookmarks +createBookmark(event) +getBookmark(id) +saveBookmarks() +loadBookmarks() } class QueryBuilder { +buildQuery(channelName, conditions) +addWildcardMatch(field, pattern) } EventChannelQuerySystem -- Session EventChannelQuerySystem -- Provider EventChannelQuerySystem -- Consumer EventChannelQuerySystem -- BookmarkManager EventChannelQuerySystem -- QueryBuilder ```

Flow chart Changes:

  1. For loop for every channel neeeded
  2. In each case a thread is created for that purpose.
  3. Process events should fire an async task to the logcollector module.
Details

```mermaid flowchart TD A["init"] --> C["Initialize Channel / Provider"] C --> E["Initialice Trace Session"] E --> F["Load Bookmarks"] & W[("Store")] F --> G["Build / Check Queries"] G --> H["Start Provider Thread"] H --> I{"Receiveing events"} & B["Next Provider"] I -- Yes --> J["Process Event"] J --> K["Update Bookmark"] K --> I I -- No --> N{"Stopped ?"} N -- Yes --> O["Save Bookmarks"] O --> P["Close Session"] P --> Q["End"] N -- No --> R{"Reconnection?"} R -- Yes --> S["Reconnect"] S --> I R -- No --> I B --> A I --> n1["Untitled Node"] ```

Example of reading Application events -> ⚠️ User should be SYSTEM:

void EventLogApplication::start()
{
    // While Adminstrator is sufficent to view the Security EventLog,
    // SYSTEM is required for the Microsoft-Windows-Security-Auditing provider.
    char user_name[128] = { 0 };
    DWORD user_name_length = 128;
    if (!GetUserNameA(user_name, &user_name_length) || !strcmp(user_name, "SYSTEM") == 0)
    {
        std::wcout << L"Microsoft-Windows-Security-Auditing can only be traced by SYSTEM" << std::endl;
        return;
    }

    krabs::user_trace trace(L"EventLog-Application");
    krabs::provider<> provider(L"Microsoft-Windows-Security-SPP");
    provider.any((ULONGLONG)-1);
    provider.add_on_event_callback([](const EVENT_RECORD &record, const krabs::trace_context &trace_context) {
        krabs::schema schema(record, trace_context.schema_locator);
        std::wcout << L"Event " << schema.event_id();
        std::wcout << L"(" << schema.event_name() << L") received." << std::endl;

        if (schema.event_id() == 4703) {
            krabs::parser parser(schema);
            std::wstring enabled_privilege_list = parser.parse<std::wstring>(L"EnabledPrivilegeList");
            std::wstring disabled_privilege_list = parser.parse<std::wstring>(L"DisabledPrivilegeList");
            std::wcout << L"\tEnabledPrivilegeList=" << enabled_privilege_list << std::endl;
            std::wcout << L"\tDisabledPrivilegeList=" << disabled_privilege_list << std::endl;
        }
    });

    trace.enable(provider);
    trace.start();
}
LucioDonda commented 1 month ago

Update 15/10/2024

LucioDonda commented 1 month ago

Update 16/10/2024

LucioDonda commented 1 month ago

Update 17/10/2024

LucioDonda commented 1 month ago

Update 18/10/2024

cborla commented 1 month ago

Moved to on hold until the release testing stage is completed.