diff --git a/pkg/config/schema_windows.go b/pkg/config/schema_windows.go index 7189e3231..3ded274df 100644 --- a/pkg/config/schema_windows.go +++ b/pkg/config/schema_windows.go @@ -197,7 +197,7 @@ var schema = ` "blacklist": { "type": "object", "properties": { - "events": {"type": "array", "items": {"type": "string", "enum": ["CreateThread", "TerminateThread", "OpenProcess", "OpenThread", "SetThreadContext", "LoadImage", "UnloadImage", "CreateFile", "CloseFile", "ReadFile", "WriteFile", "DeleteFile", "RenameFile", "SetFileInformation", "EnumDirectory", "MapViewFile", "UnmapViewFile", "RegCreateKey", "RegOpenKey", "RegSetValue", "RegQueryValue", "RegQueryKey", "RegDeleteKey", "RegDeleteValue", "RegCloseKey", "Accept", "Send", "Recv", "Connect", "Disconnect", "Reconnect", "Retransmit", "CreateHandle", "CloseHandle", "DuplicateHandle", "QueryDns", "ReplyDns", "VirtualAlloc", "VirtualFree"]}}, + "events": {"type": "array", "items": {"type": "string", "enum": ["CreateThread", "TerminateThread", "OpenProcess", "OpenThread", "SetThreadContext", "LoadImage", "UnloadImage", "CreateFile", "CloseFile", "ReadFile", "WriteFile", "DeleteFile", "RenameFile", "SetFileInformation", "EnumDirectory", "MapViewFile", "UnmapViewFile", "RegCreateKey", "RegOpenKey", "RegSetValue", "RegQueryValue", "RegQueryKey", "RegDeleteKey", "RegDeleteValue", "RegCloseKey", "Accept", "Send", "Recv", "Connect", "Disconnect", "Reconnect", "Retransmit", "CreateHandle", "CloseHandle", "DuplicateHandle", "QueryDns", "ReplyDns", "VirtualAlloc", "VirtualFree", "CreateSymbolicLinkObject"]}}, "images": {"type": "array", "items": {"type": "string", "minLength": 1}} }, "additionalProperties": false diff --git a/pkg/filter/rules.go b/pkg/filter/rules.go index bd3eb554f..65231bfbb 100644 --- a/pkg/filter/rules.go +++ b/pkg/filter/rules.go @@ -651,7 +651,8 @@ func (r *Rules) buildCompileResult() *config.RulesCompileResult { if typ == ktypes.MapViewFile || typ == ktypes.UnmapViewFile { rs.HasVAMapEvents = true } - if typ == ktypes.OpenProcess || typ == ktypes.OpenThread || typ == ktypes.SetThreadContext { + if typ == ktypes.OpenProcess || typ == ktypes.OpenThread || typ == ktypes.SetThreadContext || + typ == ktypes.CreateSymbolicLinkObject { rs.HasAuditAPIEvents = true } if typ.Subcategory() == ktypes.DNS { diff --git a/pkg/kevent/flags.go b/pkg/kevent/flags.go index 1298631aa..3df08b573 100644 --- a/pkg/kevent/flags.go +++ b/pkg/kevent/flags.go @@ -256,3 +256,20 @@ var DNSOptsFlags = []ParamFlag{ {"DISABLE_IDN_ENCODING", 0x00200000}, {"APPEND_MULTILABEL", 0x00800000}, } + +// AccessMaskFlags describes the generic and specific access rights +var AccessMaskFlags = []ParamFlag{ + {"DELETE", windows.DELETE}, + {"READ_CONTROL", windows.READ_CONTROL}, + {"WRITE_DAC", windows.WRITE_DAC}, + {"WRITE_OWNER", windows.WRITE_OWNER}, + {"SYNCHRONIZE", windows.SYNCHRONIZE}, + {"STANDARD_RIGHTS_REQUIRED", windows.STANDARD_RIGHTS_REQUIRED}, + {"STANDARD_RIGHTS_ALL", windows.STANDARD_RIGHTS_ALL}, + {"ACCESS_SYSTEM_SECURITY", windows.ACCESS_SYSTEM_SECURITY}, + {"MAXIMUM_ALLOWED", windows.MAXIMUM_ALLOWED}, + {"GENERIC_READ", windows.GENERIC_READ}, + {"GENERIC_WRITE", windows.GENERIC_WRITE}, + {"GENERIC_EXECUTE", windows.GENERIC_EXECUTE}, + {"GENERIC_ALL", windows.GENERIC_ALL}, +} diff --git a/pkg/kevent/kparam_windows.go b/pkg/kevent/kparam_windows.go index a4ff13310..f5a2e56fe 100644 --- a/pkg/kevent/kparam_windows.go +++ b/pkg/kevent/kparam_windows.go @@ -735,6 +735,18 @@ func (e *Kevent) produceParams(evt *etw.EventRecord) { n++ } e.AppendParam(kparams.Callstack, kparams.Slice, callstack) + case ktypes.CreateSymbolicLinkObject: + source, offset := evt.ReadUTF16String(0) + target, offset := evt.ReadUTF16String(offset) + desiredAccess := evt.ReadUint32(offset) + status := evt.ReadUint32(offset + 4) + e.AppendParam(kparams.LinkSource, kparams.UnicodeString, source) + e.AppendParam(kparams.LinkTarget, kparams.UnicodeString, target) + e.AppendParam(kparams.DesiredAccess, kparams.Flags, desiredAccess, WithFlags(AccessMaskFlags)) + e.AppendParam(kparams.NTStatus, kparams.Status, status) + if evt.HasStackTrace() { + e.AppendParam(kparams.Callstack, kparams.Slice, evt.Callstack()) + } } } diff --git a/pkg/kevent/kparams/fields_windows.go b/pkg/kevent/kparams/fields_windows.go index 7b0d71895..7da4327bd 100644 --- a/pkg/kevent/kparams/fields_windows.go +++ b/pkg/kevent/kparams/fields_windows.go @@ -241,4 +241,9 @@ const ( MemProtectMask = "protection_mask" // MemPageType identifies the parameter that represents the allocated region type. MemPageType = "page_type" + + // LinkSource identifies the parameter that represents the source symbolic link object or other kernel object + LinkSource = "source" + // LinkTarget identifies the parameter that represents the target symbolic link object or other kernel object + LinkTarget = "target" ) diff --git a/pkg/kevent/ktypes/category.go b/pkg/kevent/ktypes/category.go index d5a890e1b..6ce413aeb 100644 --- a/pkg/kevent/ktypes/category.go +++ b/pkg/kevent/ktypes/category.go @@ -47,6 +47,8 @@ const ( Driver Category = "driver" // Mem is the category for memory events Mem Category = "mem" + // Object the category for object manager events + Object Category = "object" // Other is the category for uncategorized events Other Category = "other" // Unknown is the category for events that couldn't match any of the previous categories @@ -79,5 +81,6 @@ func Categories() []string { string(Driver), string(Other), string(Unknown), + string(Object), } } diff --git a/pkg/kevent/ktypes/ktypes_windows.go b/pkg/kevent/ktypes/ktypes_windows.go index fe10be09e..be58ca7b7 100644 --- a/pkg/kevent/ktypes/ktypes_windows.go +++ b/pkg/kevent/ktypes/ktypes_windows.go @@ -207,6 +207,9 @@ var ( // StackWalk represents stack walk event with the collection of return addresses StackWalk = pack(windows.GUID{Data1: 0xdef2fe46, Data2: 0x7bd6, Data3: 0x4b80, Data4: [8]byte{0xbd, 0x94, 0xf5, 0x7f, 0xe2, 0x0d, 0x0c, 0xe3}}, 32) + // CreateSymbolicLinkObject represents the event emitted by the object manager when the new symbolic link is created within the object manager directory + CreateSymbolicLinkObject = pack(AuditAPIEventGUID, 3) + // UnknownKtype designates unknown kernel event type UnknownKtype = pack(windows.GUID{}, 0) ) @@ -322,6 +325,8 @@ func (k Ktype) String() string { return "ReplyDns" case StackWalk: return "StackWalk" + case CreateSymbolicLinkObject: + return "CreateSymbolicLinkObject" default: return "" } @@ -355,6 +360,8 @@ func (k Ktype) Category() Category { return Handle case VirtualAlloc, VirtualFree: return Mem + case CreateSymbolicLinkObject: + return Object default: return Unknown } @@ -455,6 +462,8 @@ func (k Ktype) Description() string { return "Sends a DNS query to the name server" case ReplyDNS: return "Receives the response from the DNS server" + case CreateSymbolicLinkObject: + return "Creates the symbolic link within the object manager directory" default: return "" } @@ -540,7 +549,7 @@ func (k *Ktype) HookID() uint16 { // Source designates the provenance of this event type. func (k Ktype) Source() EventSource { switch k { - case OpenProcess, OpenThread, SetThreadContext: + case OpenProcess, OpenThread, SetThreadContext, CreateSymbolicLinkObject: return AuditAPICallsLogger case QueryDNS, ReplyDNS: return DNSLogger @@ -555,7 +564,7 @@ func (k Ktype) Source() EventSource { // events, but it appears first on the consumer callback // before other events published before it. func (k Ktype) CanArriveOutOfOrder() bool { - return k.Category() == Registry || k.Subcategory() == DNS || k == OpenProcess || k == OpenThread || k == SetThreadContext + return k.Category() == Registry || k.Subcategory() == DNS || k == OpenProcess || k == OpenThread || k == SetThreadContext || k == CreateSymbolicLinkObject } // FromParts builds ktype from provider GUID and hook ID. diff --git a/pkg/kevent/ktypes/metainfo_windows.go b/pkg/kevent/ktypes/metainfo_windows.go index 0babe2aca..cbfcd94dc 100644 --- a/pkg/kevent/ktypes/metainfo_windows.go +++ b/pkg/kevent/ktypes/metainfo_windows.go @@ -35,113 +35,115 @@ type KeventInfo struct { } var kevents = map[Ktype]KeventInfo{ - CreateProcess: {"CreateProcess", Process, "Creates a new process and its primary thread"}, - TerminateProcess: {"TerminateProcess", Process, "Terminates the process and all of its threads"}, - OpenProcess: {"OpenProcess", Process, "Opens the process handle"}, - CreateThread: {"CreateThread", Thread, "Creates a thread to execute within the virtual address space of the calling process"}, - TerminateThread: {"TerminateThread", Thread, "Terminates a thread within the process"}, - OpenThread: {"OpenThread", Thread, "Opens the thread handle"}, - SetThreadContext: {"SetThreadContext", Thread, "Sets the thread context"}, - ReadFile: {"ReadFile", File, "Reads data from the file or I/O device"}, - WriteFile: {"WriteFile", File, "Writes data to the file or I/O device"}, - CreateFile: {"CreateFile", File, "Creates or opens a file or I/O device"}, - CloseFile: {"CloseFile", File, "Closes the file handle"}, - DeleteFile: {"DeleteFile", File, "Removes the file from the file system"}, - RenameFile: {"RenameFile", File, "Changes the file name"}, - SetFileInformation: {"SetFileInformation", File, "Sets the file meta information"}, - EnumDirectory: {"EnumDirectory", File, "Enumerates a directory or dispatches a directory change notification to registered listeners"}, - RegCreateKey: {"RegCreateKey", Registry, "Creates a registry key or opens it if the key already exists"}, - RegOpenKey: {"RegOpenKey", Registry, "Opens the registry key"}, - RegCloseKey: {"RegCloseKey", Registry, "Closes the registry key"}, - RegSetValue: {"RegSetValue", Registry, "Sets the data for the value of a registry key"}, - RegQueryValue: {"RegQueryValue", Registry, "Reads the data for the value of a registry key"}, - RegQueryKey: {"RegQueryKey", Registry, "Enumerates subkeys of the parent key"}, - RegDeleteKey: {"RegDeleteKey", Registry, "Removes the registry key"}, - RegDeleteValue: {"RegDeleteValue", Registry, "Removes the registry value"}, - AcceptTCPv4: {"Accept", Net, "Accepts the connection request from the socket queue"}, - AcceptTCPv6: {"Accept", Net, "Accepts the connection request from the socket queue"}, - SendTCPv4: {"Send", Net, "Sends data over the wire"}, - SendTCPv6: {"Send", Net, "Sends data over the wire"}, - SendUDPv4: {"Send", Net, "Sends data over the wire"}, - SendUDPv6: {"Send", Net, "Sends data over the wire"}, - RecvTCPv4: {"Recv", Net, "Receives data from the socket"}, - RecvTCPv6: {"Recv", Net, "Receives data from the socket"}, - RecvUDPv4: {"Recv", Net, "Receives data from the socket"}, - RecvUDPv6: {"Recv", Net, "Receives data from the socket"}, - ConnectTCPv4: {"Connect", Net, "Connects establishes a connection to the socket"}, - ConnectTCPv6: {"Connect", Net, "Connects establishes a connection to the socket"}, - DisconnectTCPv4: {"Disconnect", Net, "Terminates data reception on the socket"}, - DisconnectTCPv6: {"Disconnect", Net, "Terminates data reception on the socket"}, - ReconnectTCPv4: {"Reconnect", Net, "Reconnects to the socket"}, - ReconnectTCPv6: {"Reconnect", Net, "Reconnects to the socket"}, - RetransmitTCPv4: {"Retransmit", Net, "Retransmits unacknowledged TCP segments"}, - RetransmitTCPv6: {"Retransmit", Net, "Retransmits unacknowledged TCP segments"}, - LoadImage: {"LoadImage", Image, "Loads the module into the address space of the calling process"}, - UnloadImage: {"UnloadImage", Image, "Unloads the module from the address space of the calling process"}, - CreateHandle: {"CreateHandle", Handle, "Creates a new handle"}, - CloseHandle: {"CloseHandle", Handle, "Closes the handle"}, - DuplicateHandle: {"DuplicateHandle", Handle, "Duplicates the handle"}, - VirtualAlloc: {"VirtualAlloc", Mem, "Reserves, commits, or changes the state of a region of memory within the process virtual address space"}, - VirtualFree: {"VirtualFree", Mem, "Releases or decommits a region of memory within the process virtual address space"}, - MapViewFile: {"MapViewFile", File, "Maps a view of a file mapping into the address space of a calling process"}, - UnmapViewFile: {"UnmapViewFile", File, "Unmaps a mapped view of a file from the calling process's address space"}, - QueryDNS: {"QueryDns", Net, "Sends a DNS query to the name server"}, - ReplyDNS: {"ReplyDNS", Net, "Receives the response from the DNS server"}, + CreateProcess: {"CreateProcess", Process, "Creates a new process and its primary thread"}, + TerminateProcess: {"TerminateProcess", Process, "Terminates the process and all of its threads"}, + OpenProcess: {"OpenProcess", Process, "Opens the process handle"}, + CreateThread: {"CreateThread", Thread, "Creates a thread to execute within the virtual address space of the calling process"}, + TerminateThread: {"TerminateThread", Thread, "Terminates a thread within the process"}, + OpenThread: {"OpenThread", Thread, "Opens the thread handle"}, + SetThreadContext: {"SetThreadContext", Thread, "Sets the thread context"}, + ReadFile: {"ReadFile", File, "Reads data from the file or I/O device"}, + WriteFile: {"WriteFile", File, "Writes data to the file or I/O device"}, + CreateFile: {"CreateFile", File, "Creates or opens a file or I/O device"}, + CloseFile: {"CloseFile", File, "Closes the file handle"}, + DeleteFile: {"DeleteFile", File, "Removes the file from the file system"}, + RenameFile: {"RenameFile", File, "Changes the file name"}, + SetFileInformation: {"SetFileInformation", File, "Sets the file meta information"}, + EnumDirectory: {"EnumDirectory", File, "Enumerates a directory or dispatches a directory change notification to registered listeners"}, + RegCreateKey: {"RegCreateKey", Registry, "Creates a registry key or opens it if the key already exists"}, + RegOpenKey: {"RegOpenKey", Registry, "Opens the registry key"}, + RegCloseKey: {"RegCloseKey", Registry, "Closes the registry key"}, + RegSetValue: {"RegSetValue", Registry, "Sets the data for the value of a registry key"}, + RegQueryValue: {"RegQueryValue", Registry, "Reads the data for the value of a registry key"}, + RegQueryKey: {"RegQueryKey", Registry, "Enumerates subkeys of the parent key"}, + RegDeleteKey: {"RegDeleteKey", Registry, "Removes the registry key"}, + RegDeleteValue: {"RegDeleteValue", Registry, "Removes the registry value"}, + AcceptTCPv4: {"Accept", Net, "Accepts the connection request from the socket queue"}, + AcceptTCPv6: {"Accept", Net, "Accepts the connection request from the socket queue"}, + SendTCPv4: {"Send", Net, "Sends data over the wire"}, + SendTCPv6: {"Send", Net, "Sends data over the wire"}, + SendUDPv4: {"Send", Net, "Sends data over the wire"}, + SendUDPv6: {"Send", Net, "Sends data over the wire"}, + RecvTCPv4: {"Recv", Net, "Receives data from the socket"}, + RecvTCPv6: {"Recv", Net, "Receives data from the socket"}, + RecvUDPv4: {"Recv", Net, "Receives data from the socket"}, + RecvUDPv6: {"Recv", Net, "Receives data from the socket"}, + ConnectTCPv4: {"Connect", Net, "Connects establishes a connection to the socket"}, + ConnectTCPv6: {"Connect", Net, "Connects establishes a connection to the socket"}, + DisconnectTCPv4: {"Disconnect", Net, "Terminates data reception on the socket"}, + DisconnectTCPv6: {"Disconnect", Net, "Terminates data reception on the socket"}, + ReconnectTCPv4: {"Reconnect", Net, "Reconnects to the socket"}, + ReconnectTCPv6: {"Reconnect", Net, "Reconnects to the socket"}, + RetransmitTCPv4: {"Retransmit", Net, "Retransmits unacknowledged TCP segments"}, + RetransmitTCPv6: {"Retransmit", Net, "Retransmits unacknowledged TCP segments"}, + LoadImage: {"LoadImage", Image, "Loads the module into the address space of the calling process"}, + UnloadImage: {"UnloadImage", Image, "Unloads the module from the address space of the calling process"}, + CreateHandle: {"CreateHandle", Handle, "Creates a new handle"}, + CloseHandle: {"CloseHandle", Handle, "Closes the handle"}, + DuplicateHandle: {"DuplicateHandle", Handle, "Duplicates the handle"}, + VirtualAlloc: {"VirtualAlloc", Mem, "Reserves, commits, or changes the state of a region of memory within the process virtual address space"}, + VirtualFree: {"VirtualFree", Mem, "Releases or decommits a region of memory within the process virtual address space"}, + MapViewFile: {"MapViewFile", File, "Maps a view of a file mapping into the address space of a calling process"}, + UnmapViewFile: {"UnmapViewFile", File, "Unmaps a mapped view of a file from the calling process's address space"}, + QueryDNS: {"QueryDns", Net, "Sends a DNS query to the name server"}, + ReplyDNS: {"ReplyDNS", Net, "Receives the response from the DNS server"}, + CreateSymbolicLinkObject: {"CreateSymbolicLinkObject", Object, "Creates the symbolic link within the object manager directory"}, } var ktypes = map[string]Ktype{ - "CreateProcess": CreateProcess, - "TerminateProcess": TerminateProcess, - "OpenProcess": OpenProcess, - "CreateThread": CreateThread, - "TerminateThread": TerminateThread, - "OpenThread": OpenThread, - "SetThreadContext": SetThreadContext, - "LoadImage": LoadImage, - "UnloadImage": UnloadImage, - "CreateFile": CreateFile, - "CloseFile": CloseFile, - "ReadFile": ReadFile, - "WriteFile": WriteFile, - "SetFileInformation": SetFileInformation, - "DeleteFile": DeleteFile, - "RenameFile": RenameFile, - "EnumDirectory": EnumDirectory, - "RegCreateKey": RegCreateKey, - "RegOpenKey": RegOpenKey, - "RegSetValue": RegSetValue, - "RegQueryValue": RegQueryValue, - "RegQueryKey": RegQueryKey, - "RegDeleteKey": RegDeleteKey, - "RegDeleteValue": RegDeleteValue, - "RegCloseKey": RegCloseKey, - "AcceptTCP4": AcceptTCPv4, - "AcceptTCP6": AcceptTCPv6, - "SendTCP4": SendTCPv4, - "SendTCP6": SendTCPv6, - "SendUDP4": SendUDPv4, - "SendUDP6": SendUDPv6, - "RecvTCP4": RecvTCPv4, - "RecvTCP6": RecvTCPv6, - "RecvUDP4": RecvUDPv4, - "RecvUDP6": RecvUDPv6, - "ConnectTCP4": ConnectTCPv4, - "ConnectTCP6": ConnectTCPv6, - "ReconnectTCP4": ReconnectTCPv4, - "ReconnectTCP6": ReconnectTCPv6, - "DisconnectTCP4": DisconnectTCPv4, - "DisconnectTCP6": DisconnectTCPv6, - "RetransmitTCP4": RetransmitTCPv4, - "RetransmitTCP6": RetransmitTCPv6, - "CreateHandle": CreateHandle, - "CloseHandle": CloseHandle, - "DuplicateHandle": DuplicateHandle, - "VirtualAlloc": VirtualAlloc, - "VirtualFree": VirtualFree, - "MapViewFile": MapViewFile, - "UnmapViewFile": UnmapViewFile, - "QueryDns": QueryDNS, - "ReplyDns": ReplyDNS, + "CreateProcess": CreateProcess, + "TerminateProcess": TerminateProcess, + "OpenProcess": OpenProcess, + "CreateThread": CreateThread, + "TerminateThread": TerminateThread, + "OpenThread": OpenThread, + "SetThreadContext": SetThreadContext, + "LoadImage": LoadImage, + "UnloadImage": UnloadImage, + "CreateFile": CreateFile, + "CloseFile": CloseFile, + "ReadFile": ReadFile, + "WriteFile": WriteFile, + "SetFileInformation": SetFileInformation, + "DeleteFile": DeleteFile, + "RenameFile": RenameFile, + "EnumDirectory": EnumDirectory, + "RegCreateKey": RegCreateKey, + "RegOpenKey": RegOpenKey, + "RegSetValue": RegSetValue, + "RegQueryValue": RegQueryValue, + "RegQueryKey": RegQueryKey, + "RegDeleteKey": RegDeleteKey, + "RegDeleteValue": RegDeleteValue, + "RegCloseKey": RegCloseKey, + "AcceptTCP4": AcceptTCPv4, + "AcceptTCP6": AcceptTCPv6, + "SendTCP4": SendTCPv4, + "SendTCP6": SendTCPv6, + "SendUDP4": SendUDPv4, + "SendUDP6": SendUDPv6, + "RecvTCP4": RecvTCPv4, + "RecvTCP6": RecvTCPv6, + "RecvUDP4": RecvUDPv4, + "RecvUDP6": RecvUDPv6, + "ConnectTCP4": ConnectTCPv4, + "ConnectTCP6": ConnectTCPv6, + "ReconnectTCP4": ReconnectTCPv4, + "ReconnectTCP6": ReconnectTCPv6, + "DisconnectTCP4": DisconnectTCPv4, + "DisconnectTCP6": DisconnectTCPv6, + "RetransmitTCP4": RetransmitTCPv4, + "RetransmitTCP6": RetransmitTCPv6, + "CreateHandle": CreateHandle, + "CloseHandle": CloseHandle, + "DuplicateHandle": DuplicateHandle, + "VirtualAlloc": VirtualAlloc, + "VirtualFree": VirtualFree, + "MapViewFile": MapViewFile, + "UnmapViewFile": UnmapViewFile, + "QueryDns": QueryDNS, + "ReplyDns": ReplyDNS, + "CreateSymbolicLinkObject": CreateSymbolicLinkObject, } // indexedKevents keeps the slice of event infos. When the @@ -200,6 +202,7 @@ var indexedKevents = []KeventInfo{ kevents[UnmapViewFile], kevents[QueryDNS], kevents[ReplyDNS], + kevents[CreateSymbolicLinkObject], } // All returns all event types.