diff --git a/.github/coverage/badge.svg b/.github/coverage/badge.svg index 548b0db..eea6c1f 100644 --- a/.github/coverage/badge.svg +++ b/.github/coverage/badge.svg @@ -1 +1 @@ -coverage: 58.4%coverage58.4% \ No newline at end of file +coverage: 60.5%coverage60.5% \ No newline at end of file diff --git a/.github/coverage/coverage.txt b/.github/coverage/coverage.txt index d00ae52..1772acc 100644 --- a/.github/coverage/coverage.txt +++ b/.github/coverage/coverage.txt @@ -1,13 +1,13 @@ -ok github.com/0xrawsec/whids/agent 53.872s coverage: 52.0% of statements -ok github.com/0xrawsec/whids/agent/config 4.223s coverage: 46.1% of statements -ok github.com/0xrawsec/whids/agent/sysinfo 0.966s coverage: 95.2% of statements -ok github.com/0xrawsec/whids/api/server 220.042s coverage: 66.6% of statements -ok github.com/0xrawsec/whids/event 92.751s coverage: 75.3% of statements -ok github.com/0xrawsec/whids/ioc 44.868s coverage: 73.3% of statements -ok github.com/0xrawsec/whids/logger 70.295s coverage: 76.7% of statements -ok github.com/0xrawsec/whids/sysmon 9.328s coverage: 83.1% of statements -ok github.com/0xrawsec/whids/utils 22.681s coverage: 17.1% of statements -ok github.com/0xrawsec/whids/utils/command 1.058s coverage: 100.0% of statements +ok github.com/0xrawsec/whids/agent 57.877s coverage: 60.8% of statements +ok github.com/0xrawsec/whids/agent/config 3.042s coverage: 44.6% of statements +ok github.com/0xrawsec/whids/agent/sysinfo 0.929s coverage: 90.5% of statements +ok github.com/0xrawsec/whids/api/server 193.186s coverage: 65.9% of statements +ok github.com/0xrawsec/whids/event 60.038s coverage: 75.3% of statements +ok github.com/0xrawsec/whids/ioc 48.623s coverage: 73.3% of statements +ok github.com/0xrawsec/whids/logger 50.776s coverage: 76.7% of statements +ok github.com/0xrawsec/whids/sysmon 7.109s coverage: 83.1% of statements +ok github.com/0xrawsec/whids/utils 12.258s coverage: 13.7% of statements +ok github.com/0xrawsec/whids/utils/command 0.867s coverage: 100.0% of statements github.com/0xrawsec/whids/agent/actions.go:72: NewActionHandler 100.0% github.com/0xrawsec/whids/agent/actions.go:81: dumpname 100.0% github.com/0xrawsec/whids/agent/actions.go:86: prepare 100.0% @@ -24,34 +24,37 @@ github.com/0xrawsec/whids/agent/actions.go:271: regdump 26.7% github.com/0xrawsec/whids/agent/actions.go:302: suspend_process 0.0% github.com/0xrawsec/whids/agent/actions.go:312: kill_process 0.0% github.com/0xrawsec/whids/agent/actions.go:325: Queue 100.0% -github.com/0xrawsec/whids/agent/actions.go:335: HandleActions 67.7% +github.com/0xrawsec/whids/agent/actions.go:335: HandleActions 58.1% github.com/0xrawsec/whids/agent/actions.go:408: queueCompression 100.0% -github.com/0xrawsec/whids/agent/actions.go:414: compressionLoop 90.0% -github.com/0xrawsec/whids/agent/actions.go:433: handleActionsLoop 100.0% +github.com/0xrawsec/whids/agent/actions.go:414: compressionLoop 81.8% +github.com/0xrawsec/whids/agent/actions.go:434: handleActionsLoop 100.0% github.com/0xrawsec/whids/agent/agent.go:104: newActionnableEngine 100.0% -github.com/0xrawsec/whids/agent/agent.go:123: NewAgent 81.0% -github.com/0xrawsec/whids/agent/agent.go:196: initEnvVariables 100.0% -github.com/0xrawsec/whids/agent/agent.go:200: initDB 66.7% -github.com/0xrawsec/whids/agent/agent.go:209: initEventProvider 71.4% -github.com/0xrawsec/whids/agent/agent.go:229: initHooks 100.0% -github.com/0xrawsec/whids/agent/agent.go:256: update 37.5% -github.com/0xrawsec/whids/agent/agent.go:350: needsRulesUpdate 0.0% -github.com/0xrawsec/whids/agent/agent.go:376: needsIoCsUpdate 0.0% -github.com/0xrawsec/whids/agent/agent.go:399: fetchRulesFromManager 0.0% -github.com/0xrawsec/whids/agent/agent.go:427: containerPaths 0.0% -github.com/0xrawsec/whids/agent/agent.go:433: fetchIoCsFromManager 0.0% -github.com/0xrawsec/whids/agent/agent.go:486: loadContainers 14.3% -github.com/0xrawsec/whids/agent/agent.go:518: updateSystemInfo 0.0% -github.com/0xrawsec/whids/agent/agent.go:546: updateSysmon 0.0% -github.com/0xrawsec/whids/agent/agent.go:592: updateSysmonConfig 0.0% -github.com/0xrawsec/whids/agent/agent.go:652: cleanup 33.3% -github.com/0xrawsec/whids/agent/agent.go:668: IsHIDSEvent 93.8% -github.com/0xrawsec/whids/agent/agent.go:702: Report 0.0% -github.com/0xrawsec/whids/agent/agent.go:729: Run 58.0% -github.com/0xrawsec/whids/agent/agent.go:846: LogStats 0.0% -github.com/0xrawsec/whids/agent/agent.go:855: Stop 68.8% -github.com/0xrawsec/whids/agent/agent.go:891: Wait 0.0% -github.com/0xrawsec/whids/agent/agent.go:896: WaitWithTimeout 0.0% +github.com/0xrawsec/whids/agent/agent.go:123: NewAgent 100.0% +github.com/0xrawsec/whids/agent/agent.go:133: Initialize 100.0% +github.com/0xrawsec/whids/agent/agent.go:155: Prepare 81.0% +github.com/0xrawsec/whids/agent/agent.go:210: initEnvVariables 100.0% +github.com/0xrawsec/whids/agent/agent.go:214: initDB 66.7% +github.com/0xrawsec/whids/agent/agent.go:223: initEventProvider 71.4% +github.com/0xrawsec/whids/agent/agent.go:243: initHooks 100.0% +github.com/0xrawsec/whids/agent/agent.go:270: update 52.1% +github.com/0xrawsec/whids/agent/agent.go:364: needsRulesUpdate 75.0% +github.com/0xrawsec/whids/agent/agent.go:390: needsIoCsUpdate 90.0% +github.com/0xrawsec/whids/agent/agent.go:413: fetchRulesFromManager 69.2% +github.com/0xrawsec/whids/agent/agent.go:441: containerPaths 100.0% +github.com/0xrawsec/whids/agent/agent.go:447: fetchIoCsFromManager 69.2% +github.com/0xrawsec/whids/agent/agent.go:500: loadContainers 66.7% +github.com/0xrawsec/whids/agent/agent.go:532: updateSystemInfo 88.9% +github.com/0xrawsec/whids/agent/agent.go:560: updateSysmonBin 30.0% +github.com/0xrawsec/whids/agent/agent.go:606: updateSysmonConfig 66.7% +github.com/0xrawsec/whids/agent/agent.go:666: updateAgentConfig 36.0% +github.com/0xrawsec/whids/agent/agent.go:716: cleanup 33.3% +github.com/0xrawsec/whids/agent/agent.go:732: IsHIDSEvent 93.8% +github.com/0xrawsec/whids/agent/agent.go:766: Report 0.0% +github.com/0xrawsec/whids/agent/agent.go:793: Run 58.0% +github.com/0xrawsec/whids/agent/agent.go:910: LogStats 0.0% +github.com/0xrawsec/whids/agent/agent.go:919: Stop 68.8% +github.com/0xrawsec/whids/agent/agent.go:955: Wait 0.0% +github.com/0xrawsec/whids/agent/agent.go:960: WaitWithTimeout 0.0% github.com/0xrawsec/whids/agent/commands.go:33: Path 100.0% github.com/0xrawsec/whids/agent/commands.go:37: Hash 90.9% github.com/0xrawsec/whids/agent/commands.go:71: FromFSFileInfo 100.0% @@ -76,10 +79,13 @@ github.com/0xrawsec/whids/agent/config/canary_windows.go:247: Clean 80.0% github.com/0xrawsec/whids/agent/config/config.go:59: RulesPaths 0.0% github.com/0xrawsec/whids/agent/config/config.go:73: Configure 0.0% github.com/0xrawsec/whids/agent/config/config.go:99: Restore 0.0% -github.com/0xrawsec/whids/agent/config/config.go:133: LoadsHIDSConfig 0.0% -github.com/0xrawsec/whids/agent/config/config.go:145: IsForwardingEnabled 0.0% -github.com/0xrawsec/whids/agent/config/config.go:150: Prepare 0.0% -github.com/0xrawsec/whids/agent/config/config.go:169: Verify 0.0% +github.com/0xrawsec/whids/agent/config/config.go:135: LoadAgentConfig 0.0% +github.com/0xrawsec/whids/agent/config/config.go:147: Sha256 0.0% +github.com/0xrawsec/whids/agent/config/config.go:152: IsForwardingEnabled 0.0% +github.com/0xrawsec/whids/agent/config/config.go:157: Prepare 0.0% +github.com/0xrawsec/whids/agent/config/config.go:180: Verify 0.0% +github.com/0xrawsec/whids/agent/config/config.go:190: Path 0.0% +github.com/0xrawsec/whids/agent/config/config.go:195: Save 0.0% github.com/0xrawsec/whids/agent/config/etw_windows.go:36: ConfigureAutologger 62.5% github.com/0xrawsec/whids/agent/config/etw_windows.go:55: UnifiedProviders 75.0% github.com/0xrawsec/whids/agent/config/etw_windows.go:69: UnifiedTraces 0.0% @@ -89,15 +95,15 @@ github.com/0xrawsec/whids/agent/config/reports.go:94: PrepareCommands 0.0% github.com/0xrawsec/whids/agent/cron.go:26: containCmd 0.0% github.com/0xrawsec/whids/agent/cron.go:40: uncontainCmd 0.0% github.com/0xrawsec/whids/agent/cron.go:49: handleManagerCommand 0.0% -github.com/0xrawsec/whids/agent/cron.go:308: taskCommandRunner 0.0% +github.com/0xrawsec/whids/agent/cron.go:308: taskCommandRunner 55.0% github.com/0xrawsec/whids/agent/cron.go:343: scheduleCleanArchivedTask 42.1% github.com/0xrawsec/whids/agent/cron.go:383: taskUploadDumps 0.0% -github.com/0xrawsec/whids/agent/cron.go:437: updateTools 0.0% -github.com/0xrawsec/whids/agent/cron.go:507: scheduleTasks 29.3% +github.com/0xrawsec/whids/agent/cron.go:437: updateTools 22.6% +github.com/0xrawsec/whids/agent/cron.go:507: scheduleTasks 82.6% github.com/0xrawsec/whids/agent/defaults.go:12: BuildDefaultConfig 100.0% github.com/0xrawsec/whids/agent/filters.go:73: NewFilter 100.0% github.com/0xrawsec/whids/agent/filters.go:81: Match 100.0% -github.com/0xrawsec/whids/agent/hookdefs.go:39: hookSetImageSize 82.4% +github.com/0xrawsec/whids/agent/hookdefs.go:39: hookSetImageSize 94.1% github.com/0xrawsec/whids/agent/hookdefs.go:71: hookImageLoad 95.0% github.com/0xrawsec/whids/agent/hookdefs.go:108: trackSysmonProcessCreate 76.1% github.com/0xrawsec/whids/agent/hookdefs.go:229: hookTrack 50.0% @@ -154,7 +160,7 @@ github.com/0xrawsec/whids/agent/ptrack.go:406: freeRtn 100.0% github.com/0xrawsec/whids/agent/ptrack.go:444: CheckDumpCountOrInc 100.0% github.com/0xrawsec/whids/agent/ptrack.go:458: Add 100.0% github.com/0xrawsec/whids/agent/ptrack.go:469: PS 0.0% -github.com/0xrawsec/whids/agent/ptrack.go:480: Blacklist 100.0% +github.com/0xrawsec/whids/agent/ptrack.go:480: Blacklist 0.0% github.com/0xrawsec/whids/agent/ptrack.go:484: IsBlacklisted 100.0% github.com/0xrawsec/whids/agent/ptrack.go:488: SourceTrackFromEvent 80.0% github.com/0xrawsec/whids/agent/ptrack.go:500: TargetTrackFromEvent 80.0% @@ -185,7 +191,7 @@ github.com/0xrawsec/whids/agent/stats.go:85: DynEPS 75.0% github.com/0xrawsec/whids/agent/stats.go:93: HasPerfIssue 38.5% github.com/0xrawsec/whids/agent/stats.go:113: HasCriticalPerfIssue 0.0% github.com/0xrawsec/whids/agent/sysinfo/sysinfo.go:15: RegisterEdrInfo 0.0% -github.com/0xrawsec/whids/agent/sysinfo/windows_sysinfo.go:31: NewSystemInfo 100.0% +github.com/0xrawsec/whids/agent/sysinfo/windows_sysinfo.go:31: NewSystemInfo 95.0% github.com/0xrawsec/whids/api/server/command.go:18: ToCommand 77.8% github.com/0xrawsec/whids/api/server/log_streamer.go:18: Queue 75.0% github.com/0xrawsec/whids/api/server/log_streamer.go:26: Stream 100.0% @@ -216,12 +222,13 @@ github.com/0xrawsec/whids/api/server/manager.go:424: Endpoints 85.7% github.com/0xrawsec/whids/api/server/manager.go:440: ImportRules 0.0% github.com/0xrawsec/whids/api/server/manager.go:465: CreateNewAdminAPIUser 50.0% github.com/0xrawsec/whids/api/server/manager.go:478: AddEndpoint 100.0% -github.com/0xrawsec/whids/api/server/manager.go:483: UpdateReducer 100.0% -github.com/0xrawsec/whids/api/server/manager.go:498: logAPIErrorf 100.0% -github.com/0xrawsec/whids/api/server/manager.go:511: Wait 100.0% -github.com/0xrawsec/whids/api/server/manager.go:516: IsDone 0.0% -github.com/0xrawsec/whids/api/server/manager.go:521: Shutdown 82.4% -github.com/0xrawsec/whids/api/server/manager.go:550: Run 100.0% +github.com/0xrawsec/whids/api/server/manager.go:482: AddIoCs 81.8% +github.com/0xrawsec/whids/api/server/manager.go:513: UpdateReducer 100.0% +github.com/0xrawsec/whids/api/server/manager.go:528: logAPIErrorf 100.0% +github.com/0xrawsec/whids/api/server/manager.go:541: Wait 100.0% +github.com/0xrawsec/whids/api/server/manager.go:546: IsDone 0.0% +github.com/0xrawsec/whids/api/server/manager.go:551: Shutdown 82.4% +github.com/0xrawsec/whids/api/server/manager.go:580: Run 100.0% github.com/0xrawsec/whids/api/server/manager_admin_api.go:43: admApiParseDuration 71.4% github.com/0xrawsec/whids/api/server/manager_admin_api.go:56: admApiParseTime 66.7% github.com/0xrawsec/whids/api/server/manager_admin_api.go:80: NewAdminAPIResponse 100.0% @@ -239,47 +246,48 @@ github.com/0xrawsec/whids/api/server/manager_admin_api.go:170: admAPIUsers 54 github.com/0xrawsec/whids/api/server/manager_admin_api.go:238: admAPIUser 59.4% github.com/0xrawsec/whids/api/server/manager_admin_api.go:299: admAPIEndpoints 82.1% github.com/0xrawsec/whids/api/server/manager_admin_api.go:352: admAPIEndpoint 77.8% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:429: admAPIEndpointConfig 78.8% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:496: admAPIEndpointCommand 74.1% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:552: admAPIEndpointCommandField 52.9% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:589: admAPIEndpointLogs 70.7% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:729: admAPIEndpointReport 78.9% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:769: admAPIEndpointReportArchive 67.4% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:844: admAPIEndpointsReports 83.3% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:871: listEndpointDumps 80.6% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:938: admAPIArtifacts 61.1% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:969: admAPIEndpointArtifacts 61.1% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:1000: admAPIEndpointArtifact 62.9% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:1066: admAPIEndpointSysmonConfig 65.7% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:1139: admAPIEndpointToolMgmt 66.7% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:1226: admAPIEndpointSysmonBinary 100.0% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:1230: admAPIEndpointOSQueryiBinary 100.0% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:1239: admAPIStats 75.0% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:1251: admAPIIocs 62.1% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:1373: admAPIRules 58.8% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:1479: wsHandleControlMessage 100.0% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:1489: admAPIStreamEvents 71.4% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:1512: admAPIStreamDetections 0.0% -github.com/0xrawsec/whids/api/server/manager_admin_api.go:1537: runAdminAPI 87.8% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:429: admAPIEndpointConfig 78.1% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:495: admAPIEndpointCommand 74.1% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:551: admAPIEndpointCommandField 52.9% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:588: admAPIEndpointLogs 70.7% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:728: admAPIEndpointReport 78.9% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:768: admAPIEndpointReportArchive 67.4% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:843: admAPIEndpointsReports 83.3% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:870: listEndpointDumps 80.6% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:937: admAPIArtifacts 61.1% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:968: admAPIEndpointArtifacts 61.1% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:999: admAPIEndpointArtifact 62.9% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:1065: admAPIEndpointSysmonConfig 65.7% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:1138: admAPIEndpointToolMgmt 66.7% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:1225: admAPIEndpointSysmonBinary 100.0% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:1229: admAPIEndpointOSQueryiBinary 100.0% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:1238: admAPIStats 75.0% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:1250: admAPIIocs 58.0% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:1353: admAPIRules 58.8% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:1459: wsHandleControlMessage 100.0% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:1469: admAPIStreamEvents 71.4% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:1492: admAPIStreamDetections 0.0% +github.com/0xrawsec/whids/api/server/manager_admin_api.go:1517: runAdminAPI 87.8% github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:34: eptAPIMutEndpointFromRequest 75.0% github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:44: endpointAuthorizationMiddleware 65.2% github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:87: isVerboseURL 100.0% github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:96: endptLogHTTPMiddleware 0.0% github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:104: endptQuietLogHTTPMiddleware 100.0% -github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:114: runEndpointAPI 81.2% -github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:184: eptAPIServerKey 100.0% -github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:189: eptAPIRules 100.0% -github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:196: eptAPIConfig 0.0% -github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:249: eptAPIRulesSha256 100.0% -github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:255: eptAPIIoCs 50.0% -github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:264: eptAPIIoCsSha256 100.0% -github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:269: eptAPIUploadDump 44.4% -github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:302: eptAPICollect 86.0% -github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:385: eptAPICommand 79.3% -github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:441: eptAPISystemInfo 70.0% -github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:460: eptAPISysmonConfig 87.5% -github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:477: eptAPISysmonConfigSha256 100.0% -github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:490: eptAPITools 0.0% +github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:114: runEndpointAPI 81.8% +github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:185: eptAPIServerKey 100.0% +github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:190: eptAPIRules 100.0% +github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:197: eptAPIConfigSha256 0.0% +github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:221: eptAPIConfig 0.0% +github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:275: eptAPIRulesSha256 100.0% +github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:281: eptAPIIoCs 50.0% +github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:290: eptAPIIoCsSha256 100.0% +github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:295: eptAPIUploadDump 44.4% +github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:328: eptAPICollect 86.0% +github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:411: eptAPICommand 79.3% +github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:467: eptAPISystemInfo 70.0% +github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:486: eptAPISysmonConfig 87.5% +github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:503: eptAPISysmonConfigSha256 100.0% +github.com/0xrawsec/whids/api/server/manager_endpoint_api.go:516: eptAPITools 0.0% github.com/0xrawsec/whids/api/server/utils.go:14: muxGetVar 75.0% github.com/0xrawsec/whids/api/server/utils.go:22: format 100.0% github.com/0xrawsec/whids/api/server/utils.go:27: readPostAsJSON 80.0% @@ -415,6 +423,11 @@ github.com/0xrawsec/whids/utils/audit.go:190: RemoveEDRAuditACL 77.8% github.com/0xrawsec/whids/utils/command/command.go:15: Command 100.0% github.com/0xrawsec/whids/utils/command/command.go:22: CommandTimeout 100.0% github.com/0xrawsec/whids/utils/command/command.go:29: Terminate 100.0% +github.com/0xrawsec/whids/utils/crypto.go:22: publicKey 0.0% +github.com/0xrawsec/whids/utils/crypto.go:33: pemBlockForKey 0.0% +github.com/0xrawsec/whids/utils/crypto.go:49: GenerateCert 0.0% +github.com/0xrawsec/whids/utils/crypto.go:122: CertFileSha256 0.0% +github.com/0xrawsec/whids/utils/crypto.go:133: CertSha256 0.0% github.com/0xrawsec/whids/utils/files.go:25: CountFiles 0.0% github.com/0xrawsec/whids/utils/files.go:33: GzipFileBestSpeed 0.0% github.com/0xrawsec/whids/utils/files.go:73: HidsMkdirAll 0.0% @@ -443,22 +456,24 @@ github.com/0xrawsec/whids/utils/utils.go:69: Toml 0.0% github.com/0xrawsec/whids/utils/utils.go:80: TomlString 0.0% github.com/0xrawsec/whids/utils/utils.go:89: ExpandEnvs 0.0% github.com/0xrawsec/whids/utils/utils.go:98: Sha256StringArray 0.0% -github.com/0xrawsec/whids/utils/utils.go:108: HashEventBytes 0.0% -github.com/0xrawsec/whids/utils/utils.go:113: HashInterface 0.0% -github.com/0xrawsec/whids/utils/utils.go:123: GetCurFuncName 0.0% -github.com/0xrawsec/whids/utils/utils.go:151: NewWindowsLogger 0.0% -github.com/0xrawsec/whids/utils/utils.go:164: Log 0.0% -github.com/0xrawsec/whids/utils/utils.go:175: Close 0.0% -github.com/0xrawsec/whids/utils/utils.go:184: Round 0.0% -github.com/0xrawsec/whids/utils/utils.go:190: RegQuery 0.0% -github.com/0xrawsec/whids/utils/utils.go:202: Utf16ToUtf8 0.0% -github.com/0xrawsec/whids/utils/utils.go:234: Len 0.0% -github.com/0xrawsec/whids/utils/utils.go:238: Swap 0.0% -github.com/0xrawsec/whids/utils/utils.go:244: Less 0.0% +github.com/0xrawsec/whids/utils/utils.go:106: toBytes 0.0% +github.com/0xrawsec/whids/utils/utils.go:117: Sha1EventBytes 0.0% +github.com/0xrawsec/whids/utils/utils.go:122: Sha1Interface 0.0% +github.com/0xrawsec/whids/utils/utils.go:132: Sha256Interface 0.0% +github.com/0xrawsec/whids/utils/utils.go:142: GetCurFuncName 0.0% +github.com/0xrawsec/whids/utils/utils.go:170: NewWindowsLogger 0.0% +github.com/0xrawsec/whids/utils/utils.go:183: Log 0.0% +github.com/0xrawsec/whids/utils/utils.go:194: Close 0.0% +github.com/0xrawsec/whids/utils/utils.go:203: Round 0.0% +github.com/0xrawsec/whids/utils/utils.go:209: RegQuery 0.0% +github.com/0xrawsec/whids/utils/utils.go:221: Utf16ToUtf8 0.0% +github.com/0xrawsec/whids/utils/utils.go:253: Len 0.0% +github.com/0xrawsec/whids/utils/utils.go:257: Swap 0.0% +github.com/0xrawsec/whids/utils/utils.go:263: Less 0.0% github.com/0xrawsec/whids/utils/windows.go:22: ArgvFromCommandLine 0.0% github.com/0xrawsec/whids/utils/windows.go:41: HideFile 0.0% github.com/0xrawsec/whids/utils/windows.go:53: ResolveCDrive 0.0% github.com/0xrawsec/whids/utils/windows.go:76: RegValue 0.0% github.com/0xrawsec/whids/utils/windows.go:91: RegJoin 0.0% github.com/0xrawsec/whids/utils/windows.go:98: RegValueToString 0.0% -total: (statements) 58.4% +total: (statements) 60.5% diff --git a/agent/actions.go b/agent/actions.go index c4922ea..8f9a3eb 100644 --- a/agent/actions.go +++ b/agent/actions.go @@ -62,7 +62,7 @@ var ( type ActionHandler struct { ctx context.Context - hids *Agent + edr *Agent queue *datastructs.Fifo compressionQueue *datastructs.Fifo compressionLoopRunning bool @@ -72,7 +72,7 @@ type ActionHandler struct { func NewActionHandler(h *Agent) *ActionHandler { return &ActionHandler{ ctx: h.ctx, - hids: h, + edr: h, queue: &datastructs.Fifo{}, compressionQueue: &datastructs.Fifo{}, semJobs: semaphore.New(2)} @@ -86,19 +86,19 @@ func (m *ActionHandler) dumpname(src string) string { func (m *ActionHandler) prepare(e *event.EdrEvent, filename string) string { id := e.Hash() guid := sourceGUIDFromEvent(e) - dumpDir := filepath.Join(m.hids.config.Dump.Dir, guid, id) + dumpDir := filepath.Join(m.edr.config.Dump.Dir, guid, id) utils.HidsMkdirAll(dumpDir) return filepath.Join(dumpDir, filename) } func (m *ActionHandler) shouldDump(e *event.EdrEvent) bool { guid := sourceGUIDFromEvent(e) - return m.hids.tracker.CheckDumpCountOrInc(guid, m.hids.config.Dump.MaxDumps, m.hids.config.Dump.DumpUntracked) + return m.edr.tracker.CheckDumpCountOrInc(guid, m.edr.config.Dump.MaxDumps, m.edr.config.Dump.DumpUntracked) } func (m *ActionHandler) writeReader(dst string, reader io.Reader) error { - compress := m.hids.config.Dump.Compression - return utils.HidsWriteReader(dst, reader, compress) + // compression is managed by compression routine + return utils.HidsWriteReader(dst, reader, false) } func (m *ActionHandler) dumpAsJson(path string, i interface{}) (err error) { @@ -136,7 +136,7 @@ func (m *ActionHandler) dumpFile(src, dst string) (err error) { // dump sha256 of file anyway utils.HidsWriteData(fmt.Sprintf("%s.sha256", dst), []byte(sha256)) // we dump file - if !m.hids.filedumped.Contains(sha256) { + if !m.edr.filedumped.Contains(sha256) { var f *os.File log.Debugf("Dumping file: %s->%s", src, dst) if f, err = os.Open(src); err != nil { @@ -146,7 +146,7 @@ func (m *ActionHandler) dumpFile(src, dst string) (err error) { return } // we mark file dumped - m.hids.filedumped.Add(sha256) + m.edr.filedumped.Add(sha256) // queueing compression m.queueCompression(dst) } @@ -179,7 +179,7 @@ func listFilesFromCommandLine(cmdLine string, cwd string) []string { func (m *ActionHandler) filedumpSet(e *event.EdrEvent) *datastructs.Set { s := datastructs.NewSet() - if pt := m.hids.tracker.SourceTrackFromEvent(e); !pt.IsZero() { + if pt := m.edr.tracker.SourceTrackFromEvent(e); !pt.IsZero() { s.Add(pt.Image) s.Add(pt.ParentImage) // parse command line @@ -212,7 +212,7 @@ func (m *ActionHandler) filedumpSet(e *event.EdrEvent) *datastructs.Set { if hashes, ok := e.GetString(pathSysmonHashes); ok { if target, ok := e.GetString(pathSysmonTargetFilename); ok { fname := fmt.Sprintf("%s%s", sysmonArcFileRe.ReplaceAllString(hashes, ""), filepath.Ext(target)) - path := filepath.Join(m.hids.config.Sysmon.ArchiveDirectory, fname) + path := filepath.Join(m.edr.config.Sysmon.ArchiveDirectory, fname) s.Add(path) } } @@ -241,14 +241,14 @@ func (m *ActionHandler) filedump(e *event.EdrEvent) { func (m *ActionHandler) memdump(e *event.EdrEvent) (err error) { hash := e.Hash() - if pt := m.hids.tracker.SourceTrackFromEvent(e); !pt.IsZero() { + if pt := m.edr.tracker.SourceTrackFromEvent(e); !pt.IsZero() { guid := sourceGUIDFromEvent(e) pid := int(pt.PID) - if kernel32.IsPIDRunning(pid) && pid != os.Getpid() && !m.hids.memdumped.Contains(guid) && !m.hids.dumping.Contains(guid) { + if kernel32.IsPIDRunning(pid) && pid != os.Getpid() && !m.edr.memdumped.Contains(guid) && !m.edr.dumping.Contains(guid) { // To avoid dumping the same process twice, possible if two alerts // comes from the same GUID in a short period of time - m.hids.dumping.Add(guid) - defer m.hids.dumping.Del(guid) + m.edr.dumping.Add(guid) + defer m.edr.dumping.Del(guid) dumpFilename := fmt.Sprintf("%s_%d_%d.dmp", filepath.Base(pt.Image), pid, time.Now().UnixNano()) dumpPath := m.prepare(e, dumpFilename) @@ -256,7 +256,7 @@ func (m *ActionHandler) memdump(e *event.EdrEvent) (err error) { return fmt.Errorf("failed to dump process event=%s pid=%d image=%s: %s", hash, pid, pt.Image, err) } else { // dump was successfull - m.hids.memdumped.Add(guid) + m.edr.memdumped.Add(guid) m.queueCompression(dumpPath) } } else { @@ -300,7 +300,7 @@ func (m *ActionHandler) regdump(e *event.EdrEvent) { } func (m *ActionHandler) suspend_process(e *event.EdrEvent) { - if pt := m.hids.tracker.SourceTrackFromEvent(e); !pt.IsZero() { + if pt := m.edr.tracker.SourceTrackFromEvent(e); !pt.IsZero() { // additional check not to suspend agent if pt.PID != int64(os.Getpid()) { // before we kill we suspend the process @@ -310,7 +310,7 @@ func (m *ActionHandler) suspend_process(e *event.EdrEvent) { } func (m *ActionHandler) kill_process(e *event.EdrEvent) error { - if pt := m.hids.tracker.SourceTrackFromEvent(e); !pt.IsZero() { + if pt := m.edr.tracker.SourceTrackFromEvent(e); !pt.IsZero() { // additional check not to suspend agent if pt.PID != int64(os.Getpid()) { if err := pt.TerminateProcess(); err != nil { @@ -323,7 +323,7 @@ func (m *ActionHandler) kill_process(e *event.EdrEvent) error { } func (m *ActionHandler) Queue(e *event.EdrEvent) { - if !m.hids.IsHIDSEvent(e) && m.hids.config.Endpoint { + if !m.edr.IsHIDSEvent(e) && m.edr.config.Endpoint { if det := e.GetDetection(); det != nil { if det.Actions.Len() > 0 { m.queue.Push(e) @@ -336,7 +336,7 @@ func (m *ActionHandler) HandleActions(e *event.EdrEvent) { det := e.GetDetection() - if m.shouldDump(e) && !m.hids.IsHIDSEvent(e) && det != nil { + if m.shouldDump(e) && !m.edr.IsHIDSEvent(e) && det != nil { hash := e.Hash() // Test variables @@ -346,10 +346,10 @@ func (m *ActionHandler) HandleActions(e *event.EdrEvent) { // handling blacklisting action if det.Actions.Contains(ActionBlacklist) { - if pt := m.hids.tracker.SourceTrackFromEvent(e); !pt.IsZero() { + if pt := m.edr.tracker.SourceTrackFromEvent(e); !pt.IsZero() { // additional check not to blacklist agent if int(pt.PID) != os.Getpid() { - m.hids.tracker.Blacklist(pt.CommandLine) + m.edr.tracker.Blacklist(pt.CommandLine) } } } @@ -375,9 +375,9 @@ func (m *ActionHandler) HandleActions(e *event.EdrEvent) { } // handling report dumping - if (report || brief) && m.hids.config.Report.EnableReporting { + if (report || brief) && m.edr.config.Report.EnableReporting { reportPath := m.prepare(e, reportFilename) - if err := m.dumpAsJson(reportPath, m.hids.Report(brief)); err != nil { + if err := m.dumpAsJson(reportPath, m.edr.Report(brief)); err != nil { log.Errorf("Failed to dump report for event %s: %s", hash, err) } else { m.queueCompression(reportPath) @@ -406,13 +406,14 @@ func (m *ActionHandler) HandleActions(e *event.EdrEvent) { } func (m *ActionHandler) queueCompression(path string) { - if m.hids.config.Dump.Compression && m.compressionLoopRunning { + if m.edr.config.Dump.Compression && m.compressionLoopRunning { m.compressionQueue.Push(path) } } func (m *ActionHandler) compressionLoop() { - if !m.hids.config.Dump.Compression { + log.Info("Compression loop starting") + if !m.edr.config.Dump.Compression { return } diff --git a/agent/agent.go b/agent/agent.go index cb577ba..0520904 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -120,33 +120,47 @@ func newActionnableEngine(c *config.Agent) (e *engine.Engine) { } // NewAgent creates a new Agent object from configuration -func NewAgent(c *config.Agent) (h *Agent, err error) { +func NewAgent(c *config.Agent) (a *Agent, err error) { + a = &Agent{} + a.Initialize() + + err = a.Prepare(c) + + return +} + +func (a *Agent) Initialize() { + // context inititialization ctx, cancel := context.WithCancel(context.Background()) - h = &Agent{ - ctx: ctx, - cancel: cancel, - scheduler: crony.NewWithContext(ctx), - eventProvider: etw.NewRealTimeConsumer(ctx), - stats: NewEventStats(MaxEPS, MaxEPSDuration), - preHooks: NewHookMan(), - postHooks: NewHookMan(), - channels: datastructs.NewSyncedSet(), - channelsSignals: make(chan bool), - config: c, - waitGroup: sync.WaitGroup{}, - tracker: NewActivityTracker(), - memdumped: datastructs.NewSyncedSet(), - dumping: datastructs.NewSyncedSet(), - filedumped: datastructs.NewSyncedSet(), - // has to be empty to post structure the first time - systemInfo: &sysinfo.SystemInfo{}, - db: sod.Open(c.DatabasePath), - } + a.ctx = ctx + a.cancel = cancel + a.scheduler = crony.NewWithContext(ctx) + a.eventProvider = etw.NewRealTimeConsumer(ctx) + a.stats = NewEventStats(MaxEPS, MaxEPSDuration) + a.preHooks = NewHookMan() + a.postHooks = NewHookMan() + a.channels = datastructs.NewSyncedSet() + a.channelsSignals = make(chan bool) + a.waitGroup = sync.WaitGroup{} + a.tracker = NewActivityTracker() + a.memdumped = datastructs.NewSyncedSet() + a.dumping = datastructs.NewSyncedSet() + a.filedumped = datastructs.NewSyncedSet() + // has to be empty to post structure the first time + a.systemInfo = &sysinfo.SystemInfo{} +} + +func (a *Agent) Prepare(c *config.Agent) (err error) { + // assigning configuration to agent + a.config = c + + // opening database + a.db = sod.Open(c.DatabasePath) // initializing action manager - h.actionHandler = NewActionHandler(h) + a.actionHandler = NewActionHandler(a) // Creates missing directories c.Prepare() @@ -157,7 +171,7 @@ func NewAgent(c *config.Agent) (h *Agent, err error) { } // initialize database - if err = h.initDB(); err != nil { + if err = a.initDB(); err != nil { return } @@ -167,24 +181,24 @@ func NewAgent(c *config.Agent) (h *Agent, err error) { } // loading forwarder config - if h.forwarder, err = client.NewForwarder(h.ctx, &h.config.FwdConfig); err != nil { + if a.forwarder, err = client.NewForwarder(a.ctx, &a.config.FwdConfig); err != nil { return } // cleaning up previous runs - h.cleanup() + a.cleanup() // initialization - h.initEnvVariables() - h.initEventProvider() - h.initHooks(c.EnableHooks) + a.initEnvVariables() + a.initEventProvider() + a.initHooks(c.EnableHooks) // schedule tasks - h.scheduleTasks() + a.scheduleTasks() // fixing local audit policies if necessary - h.config.AuditConfig.Configure() + a.config.AuditConfig.Configure() // update and load engine - if err = h.update(true); err != nil { + if err = a.update(true); err != nil { return } @@ -193,79 +207,79 @@ func NewAgent(c *config.Agent) (h *Agent, err error) { /** Private Methods **/ -func (h *Agent) initEnvVariables() { +func (a *Agent) initEnvVariables() { os.Setenv(los.PathEnvVar, los.BuildPathEnv(los.GetPathEnv(), toolsDir)) } -func (h *Agent) initDB() (err error) { +func (a *Agent) initDB() (err error) { - if err = h.db.Create(&tools.Tool{}, sod.DefaultSchema); err != nil { + if err = a.db.Create(&tools.Tool{}, sod.DefaultSchema); err != nil { return } return } -func (h *Agent) initEventProvider() { +func (a *Agent) initEventProvider() { // parses the providers and init filters - for _, sprov := range h.config.EtwConfig.UnifiedProviders() { + for _, sprov := range a.config.EtwConfig.UnifiedProviders() { if prov, err := etw.ParseProvider(sprov); err != nil { log.Errorf("Error while parsing provider %s: %s", sprov, err) } else { - h.eventProvider.Filter.Update(&prov) + a.eventProvider.Filter.Update(&prov) } } // open traces - for _, trace := range h.config.EtwConfig.UnifiedTraces() { - if err := h.eventProvider.OpenTrace(trace); err != nil { + for _, trace := range a.config.EtwConfig.UnifiedTraces() { + if err := a.eventProvider.OpenTrace(trace); err != nil { log.Errorf("Failed to open trace %s: %s", trace, err) } } } -func (h *Agent) initHooks(advanced bool) { +func (a *Agent) initHooks(advanced bool) { // We enable those hooks anyway since it is needed to skip // events generated by WHIDS process. These ar very light hooks - h.preHooks.Hook(hookSelfGUID, fltProcessCreate) - h.preHooks.Hook(hookProcTerm, fltProcTermination) - h.preHooks.Hook(hookStats, fltStats) - h.preHooks.Hook(hookTrack, fltTrack) + a.preHooks.Hook(hookSelfGUID, fltProcessCreate) + a.preHooks.Hook(hookProcTerm, fltProcTermination) + a.preHooks.Hook(hookStats, fltStats) + a.preHooks.Hook(hookTrack, fltTrack) if advanced { // Process terminator hook, terminating blacklisted (by action) processes - h.preHooks.Hook(hookTerminator, fltProcessCreate) - h.preHooks.Hook(hookImageLoad, fltImageLoad) - h.preHooks.Hook(hookSetImageSize, fltImageSize) - h.preHooks.Hook(hookProcessIntegrityProcTamp, fltImageTampering) - h.preHooks.Hook(hookEnrichServices, fltAnySysmon) - h.preHooks.Hook(hookClipboardEvents, fltClipboard) - h.preHooks.Hook(hookFileSystemAudit, fltFSObjectAccess) + a.preHooks.Hook(hookTerminator, fltProcessCreate) + a.preHooks.Hook(hookImageLoad, fltImageLoad) + a.preHooks.Hook(hookSetImageSize, fltImageSize) + a.preHooks.Hook(hookProcessIntegrityProcTamp, fltImageTampering) + a.preHooks.Hook(hookEnrichServices, fltAnySysmon) + a.preHooks.Hook(hookClipboardEvents, fltClipboard) + a.preHooks.Hook(hookFileSystemAudit, fltFSObjectAccess) // Must be run the last as it depends on other filters - h.preHooks.Hook(hookEnrichAnySysmon, fltAnySysmon) - h.preHooks.Hook(hookKernelFiles, fltKernelFile) + a.preHooks.Hook(hookEnrichAnySysmon, fltAnySysmon) + a.preHooks.Hook(hookKernelFiles, fltKernelFile) // This hook must run before action handling as we want // the gene score to be set before an eventual reporting - h.postHooks.Hook(hookUpdateGeneScore, fltAnyEvent) + a.postHooks.Hook(hookUpdateGeneScore, fltAnyEvent) } } -func (h *Agent) update(force bool) (last error) { +func (a *Agent) update(force bool) (last error) { var reloadRules, reloadContainers bool // check that we are connected to any manager - if h.config.IsForwardingEnabled() { - reloadRules = h.needsRulesUpdate() - reloadContainers = h.needsIoCsUpdate() + if a.config.IsForwardingEnabled() { + reloadRules = a.needsRulesUpdate() + reloadContainers = a.needsIoCsUpdate() } // check if we need rule update if reloadRules { log.Info("Updating WHIDS rules") - if err := h.fetchRulesFromManager(); err != nil { + if err := a.fetchRulesFromManager(); err != nil { log.Errorf("Failed to fetch rules from manager: %s", err) reloadRules = false } @@ -273,7 +287,7 @@ func (h *Agent) update(force bool) (last error) { if reloadContainers { log.Info("Updating WHIDS containers") - if err := h.fetchIoCsFromManager(); err != nil { + if err := a.fetchIoCsFromManager(); err != nil { log.Errorf("Failed to fetch containers from manager: %s", err) reloadContainers = false } @@ -282,11 +296,11 @@ func (h *Agent) update(force bool) (last error) { log.Debugf("reloading rules:%t containers:%t forced:%t", reloadRules, reloadContainers, force) if reloadRules || reloadContainers || force { // We need to create a new engine if we received a rule/containers update - newEngine := newActionnableEngine(h.config) + newEngine := newActionnableEngine(a.config) // containers must be loaded before the rules anyway - log.Infof("Loading HIDS containers (used in rules) from: %s", h.config.RulesConfig.ContainersDB) - if err := h.loadContainers(newEngine); err != nil { + log.Infof("Loading HIDS containers (used in rules) from: %s", a.config.RulesConfig.ContainersDB) + if err := a.loadContainers(newEngine); err != nil { err = fmt.Errorf("failed at loading containers: %s", err) last = err } @@ -300,24 +314,24 @@ func (h *Agent) update(force bool) (last error) { } // Loading canary rules - if h.config.CanariesConfig.Enable { + if a.config.CanariesConfig.Enable { log.Infof("Loading canary rules") // Sysmon rule - sr := h.config.CanariesConfig.GenRuleSysmon() + sr := a.config.CanariesConfig.GenRuleSysmon() if err := newEngine.LoadRule(&sr); err != nil { log.Errorf("Failed to load canary rule: %s", err) last = err } // File System Audit Rule - fsr := h.config.CanariesConfig.GenRuleFSAudit() + fsr := a.config.CanariesConfig.GenRuleFSAudit() if err := newEngine.LoadRule(&fsr); err != nil { log.Errorf("Failed to load canary rule: %s", err) last = err } // File System Audit Rule - kfr := h.config.CanariesConfig.GenRuleKernelFile() + kfr := a.config.CanariesConfig.GenRuleKernelFile() if err := newEngine.LoadRule(&kfr); err != nil { log.Errorf("Failed to load canary rule: %s", err) last = err @@ -325,8 +339,8 @@ func (h *Agent) update(force bool) (last error) { } // Loading rules - log.Infof("Loading HIDS rules from: %s", h.config.RulesConfig.RulesDB) - if err := newEngine.LoadDirectory(h.config.RulesConfig.RulesDB); err != nil { + log.Infof("Loading HIDS rules from: %s", a.config.RulesConfig.RulesDB) + if err := newEngine.LoadDirectory(a.config.RulesConfig.RulesDB); err != nil { last = fmt.Errorf("failed to load rules: %s", err) } log.Infof("Number of rules loaded in engine: %d", newEngine.Count()) @@ -335,7 +349,7 @@ func (h *Agent) update(force bool) (last error) { if last == nil { // we update engine only if there was no error // no need to lock HIDS as newEngine is ready to use at this point - h.Engine = newEngine + a.Engine = newEngine } else { log.Error("EDR engine not updated:", last) } @@ -347,17 +361,17 @@ func (h *Agent) update(force bool) (last error) { } // rules needs to be updated with the new ones available in manager -func (h *Agent) needsRulesUpdate() bool { +func (a *Agent) needsRulesUpdate() bool { var err error var oldSha256, sha256 string - _, rulesSha256Path := h.config.RulesConfig.RulesPaths() + _, rulesSha256Path := a.config.RulesConfig.RulesPaths() // Don't need update if not connected to a manager - if !h.config.IsForwardingEnabled() { + if !a.config.IsForwardingEnabled() { return false } - if sha256, err = h.forwarder.Client.GetRulesSha256(); err != nil { + if sha256, err = a.forwarder.Client.GetRulesSha256(); err != nil { log.Errorf("Failed to fetch rules sha256: %s", err) return false } @@ -373,19 +387,19 @@ func (h *Agent) needsRulesUpdate() bool { } // returns true if a container needs to be updated -func (h *Agent) needsIoCsUpdate() bool { +func (a *Agent) needsIoCsUpdate() bool { var localSha256, remoteSha256 string // Don't need update if not connected to a manager - if !h.config.IsForwardingEnabled() { + if !a.config.IsForwardingEnabled() { return false } container := server.IoCContainerName - _, locContSha256Path := h.containerPaths(container) + _, locContSha256Path := a.containerPaths(container) // means that remoteCont is also a local container - remoteSha256, _ = h.forwarder.Client.GetIoCsSha256() + remoteSha256, _ = a.forwarder.Client.GetIoCsSha256() localSha256, _ = utils.ReadFileString(locContSha256Path) // log message only if we need to update @@ -396,22 +410,22 @@ func (h *Agent) needsIoCsUpdate() bool { return localSha256 != remoteSha256 } -func (h *Agent) fetchRulesFromManager() (err error) { +func (a *Agent) fetchRulesFromManager() (err error) { var rules, sha256 string - rulePath, sha256Path := h.config.RulesConfig.RulesPaths() + rulePath, sha256Path := a.config.RulesConfig.RulesPaths() // if we are not connected to a manager we return - if h.config.FwdConfig.Local { + if a.config.FwdConfig.Local { return } log.Infof("Fetching new rules available in manager") - if sha256, err = h.forwarder.Client.GetRulesSha256(); err != nil { + if sha256, err = a.forwarder.Client.GetRulesSha256(); err != nil { return err } - if rules, err = h.forwarder.Client.GetRules(); err != nil { + if rules, err = a.forwarder.Client.GetRules(); err != nil { return err } @@ -424,18 +438,18 @@ func (h *Agent) fetchRulesFromManager() (err error) { } // containerPaths returns the path to the container and the path to its sha256 file -func (h *Agent) containerPaths(container string) (path, sha256Path string) { - path = filepath.Join(h.config.RulesConfig.ContainersDB, fmt.Sprintf("%s%s", container, containerExt)) +func (a *Agent) containerPaths(container string) (path, sha256Path string) { + path = filepath.Join(a.config.RulesConfig.ContainersDB, fmt.Sprintf("%s%s", container, containerExt)) sha256Path = fmt.Sprintf("%s.sha256", path) return } -func (h *Agent) fetchIoCsFromManager() (err error) { +func (a *Agent) fetchIoCsFromManager() (err error) { var iocs []string - cl := h.forwarder.Client + cl := a.forwarder.Client // if we are not connected to a manager we return - if h.config.FwdConfig.Local { + if a.config.FwdConfig.Local { return } @@ -453,7 +467,7 @@ func (h *Agent) fetchIoCsFromManager() (err error) { } // we dump the container - contPath, contSha256Path := h.containerPaths(server.IoCContainerName) + contPath, contSha256Path := a.containerPaths(server.IoCContainerName) fd, err := utils.HidsCreateFile(contPath) if err != nil { return err @@ -483,8 +497,8 @@ func (h *Agent) fetchIoCsFromManager() (err error) { } // loads containers found in container database directory -func (h *Agent) loadContainers(engine *engine.Engine) (lastErr error) { - for wi := range fswalker.Walk(h.config.RulesConfig.ContainersDB) { +func (a *Agent) loadContainers(engine *engine.Engine) (lastErr error) { + for wi := range fswalker.Walk(a.config.RulesConfig.ContainersDB) { for _, fi := range wi.Files { path := filepath.Join(wi.Dirpath, fi.Name()) // we take only files with good extension @@ -515,11 +529,11 @@ func (h *Agent) loadContainers(engine *engine.Engine) (lastErr error) { return } -func (h *Agent) updateSystemInfo() (err error) { +func (a *Agent) updateSystemInfo() (err error) { var hnew, hold string new := sysinfo.NewSystemInfo() - if hnew, err = utils.HashInterface(new); err != nil { + if hnew, err = utils.Sha1Interface(new); err != nil { // we return cause we don't want to overwrite with // a faulty structure return @@ -527,11 +541,11 @@ func (h *Agent) updateSystemInfo() (err error) { // if it returns an error we don't really care because // it will be replaced by new - hold, _ = utils.HashInterface(h.systemInfo) + hold, _ = utils.Sha1Interface(a.systemInfo) if hnew != hold { - h.systemInfo = new - return h.forwarder.Client.PostSystemInfo(h.systemInfo) + a.systemInfo = new + return a.forwarder.Client.PostSystemInfo(a.systemInfo) } return @@ -543,7 +557,7 @@ need to update because Sysmon.exe (32 bit version) contains both the 32 and 64 bit version of the tool. When Sysmon gets installed only one of the two versions is installed. */ -func (h *Agent) updateSysmon() (err error) { +func (a *Agent) updateSysmonBin() (err error) { var version string var si *sysmon.Info @@ -576,25 +590,25 @@ func (h *Agent) updateSysmon() (err error) { // updating system information before config update as config update // may return on error - if err = h.updateSystemInfo(); err != nil { + if err = a.updateSystemInfo(); err != nil { return fmt.Errorf("failed to update system info: %w", err) } log.Info("Updating sysmon config") // we update configuration - if err = h.updateSysmonConfig(); err != nil { + if err = a.updateSysmonConfig(); err != nil { return fmt.Errorf("failed to update sysmon config: %w", err) } return } -func (h *Agent) updateSysmonConfig() (err error) { +func (a *Agent) updateSysmonConfig() (err error) { var remoteSha256 string var xml []byte var cfg *sysmon.Config - c := h.forwarder.Client + c := a.forwarder.Client systemInfo := sysinfo.NewSystemInfo() schemaVersion := systemInfo.Sysmon.Config.Version.Schema sha256 := systemInfo.Sysmon.Config.Hash @@ -642,19 +656,69 @@ func (h *Agent) updateSysmonConfig() (err error) { return fmt.Errorf("failed to configure sysmon: %w", err) } - if err = h.updateSystemInfo(); err != nil { + if err = a.updateSystemInfo(); err != nil { err = fmt.Errorf("failed to update system info: %w", err) } return } -func (h *Agent) cleanup() { +func (a *Agent) updateAgentConfig() (err error) { + var newConf *config.Agent + var localSha256, remoteSha256 string + + c := a.forwarder.Client + + if localSha256, err = a.config.Sha256(); err != nil { + return fmt.Errorf("failed to compute local config sha256: %w", err) + } + + remoteSha256, err = c.GetAgentConfigSha256() + + switch err { + case nil: + if localSha256 == remoteSha256 { + // nothing to do + return + } + + case client.ErrNoAgentConfig: + return c.PostAgentConfig(a.config) + + default: + return + } + + // we need to get configuration from manager + if newConf, err = c.GetAgentConfig(); err != nil { + return fmt.Errorf("failed to get agent config: %w", err) + } + + log.Infof("received endpoint configuration update old=%s new=%s, saving it at %s", localSha256, remoteSha256, a.config.Path()) + // overwrite current configuration + newConf.Save(a.config.Path()) + + log.Infof("stopping agent after update") + a.Stop() + a.Wait() + + a.Initialize() + if err = a.Prepare(newConf); err != nil { + err = fmt.Errorf("failed to prepare agent with new configuration: %w", err) + return + } + log.Infof("restarting agent after update") + a.Run() + + return +} + +func (a *Agent) cleanup() { // Cleaning up empty dump directories if needed - fis, _ := ioutil.ReadDir(h.config.Dump.Dir) + fis, _ := ioutil.ReadDir(a.config.Dump.Dir) for _, fi := range fis { if fi.IsDir() { - fp := filepath.Join(h.config.Dump.Dir, fi.Name()) + fp := filepath.Join(a.config.Dump.Dir, fi.Name()) if utils.CountFiles(fp) == 0 { os.RemoveAll(fp) } @@ -665,31 +729,31 @@ func (h *Agent) cleanup() { /** Public Methods **/ // IsHIDSEvent returns true if the event is generated by IDS activity -func (h *Agent) IsHIDSEvent(e *event.EdrEvent) bool { +func (a *Agent) IsHIDSEvent(e *event.EdrEvent) bool { if pguid, ok := e.GetString(pathSysmonParentProcessGUID); ok { - if pguid == h.guid { + if pguid == a.guid { return true } } if guid, ok := e.GetString(pathSysmonProcessGUID); ok { - if guid == h.guid { + if guid == a.guid { return true } // search for parent in processTracker - if pt := h.tracker.GetByGuid(guid); !pt.IsZero() { - if pt.ParentProcessGUID == h.guid { + if pt := a.tracker.GetByGuid(guid); !pt.IsZero() { + if pt.ParentProcessGUID == a.guid { return true } } } if sguid, ok := e.GetString(pathSysmonSourceProcessGUID); ok { - if sguid == h.guid { + if sguid == a.guid { return true } // search for parent in processTracker - if pt := h.tracker.GetByGuid(sguid); !pt.IsZero() { - if pt.ParentProcessGUID == h.guid { + if pt := a.tracker.GetByGuid(sguid); !pt.IsZero() { + if pt.ParentProcessGUID == a.guid { return true } } @@ -699,23 +763,23 @@ func (h *Agent) IsHIDSEvent(e *event.EdrEvent) bool { // Report generate a forensic ready report (meant to be dumped) // this method is blocking as it runs commands and wait after those -func (h *Agent) Report(light bool) (r Report) { +func (a *Agent) Report(light bool) (r Report) { r.StartTime = time.Now() // generate a report for running processes or those terminated still having one child or more // do this step first not to polute report with commands to run - r.Processes = h.tracker.PS() + r.Processes = a.tracker.PS() // Modules ever loaded - r.Modules = h.tracker.Modules() + r.Modules = a.tracker.Modules() // Drivers loaded - r.Drivers = h.tracker.Drivers + r.Drivers = a.tracker.Drivers // if this is a light report, we don't run the commands if !light { // run all the commands configured to include in the report - r.Commands = h.config.Report.PrepareCommands() + r.Commands = a.config.Report.PrepareCommands() for i := range r.Commands { r.Commands[i].Run() } @@ -726,67 +790,67 @@ func (h *Agent) Report(light bool) (r Report) { } // Run starts the WHIDS engine and waits channel listening is stopped -func (h *Agent) Run() { +func (a *Agent) Run() { // start task scheduler - h.scheduler.Start() + a.scheduler.Start() - for _, t := range h.scheduler.Tasks() { + for _, t := range a.scheduler.Tasks() { log.Infof("Scheduler running: %s", t.Name) } // Dry run don't do anything - if h.DryRun { - for _, trace := range h.config.EtwConfig.UnifiedTraces() { + if a.DryRun { + for _, trace := range a.config.EtwConfig.UnifiedTraces() { log.Infof("Dry run: would open trace %s", trace) } return } // Starting event provider - h.eventProvider.Start() + a.eventProvider.Start() // start stats monitoring - h.stats.Start() + a.stats.Start() - h.waitGroup.Add(1) + a.waitGroup.Add(1) go func() { - defer h.waitGroup.Done() + defer a.waitGroup.Done() // Trying to raise thread priority if err := kernel32.SetCurrentThreadPriority(win32.THREAD_PRIORITY_ABOVE_NORMAL); err != nil { log.Errorf("Failed to raise IDS thread priority: %s", err) } - for e := range h.eventProvider.Events { + for e := range a.eventProvider.Events { event := event.NewEdrEvent(e) - if yes, eps := h.stats.HasPerfIssue(); yes { - log.Warnf("Average event rate above limit of %.2f e/s in the last %s: %.2f e/s", h.stats.Threshold(), h.stats.Duration(), eps) + if yes, eps := a.stats.HasPerfIssue(); yes { + log.Warnf("Average event rate above limit of %.2f e/s in the last %s: %.2f e/s", a.stats.Threshold(), a.stats.Duration(), eps) - if h.stats.HasCriticalPerfIssue() { + if a.stats.HasCriticalPerfIssue() { log.Critical("Event throughput too high for too long, consider filtering out events") - } else if crit := h.stats.CriticalEPS(); eps > crit { - log.Criticalf("Event throughput above %.0fx the limit, if repeated consider filtering out events", eps/h.stats.Threshold()) + } else if crit := a.stats.CriticalEPS(); eps > crit { + log.Criticalf("Event throughput above %.0fx the limit, if repeated consider filtering out events", eps/a.stats.Threshold()) } } // Warning message in certain circumstances - if h.config.EnableHooks && !h.flagProcTermEn && h.stats.Events() > 0 && int64(h.stats.Events())%1000 == 0 { + if a.config.EnableHooks && !a.flagProcTermEn && a.stats.Events() > 0 && int64(a.stats.Events())%1000 == 0 { log.Warn("Sysmon process termination events seem to be missing. WHIDS won't work as expected.") } - h.RLock() + a.RLock() // Runs pre detection hooks // putting this before next condition makes the processTracker registering // HIDS events and allows detecting ProcessAccess events from HIDS childs - h.preHooks.RunHooksOn(h, event) + a.preHooks.RunHooksOn(a, event) // We skip if it is one of IDS event // we keep process termination event because it is used to control if process termination is enabled - if h.IsHIDSEvent(event) && !isSysmonProcessTerminate(event) { - if h.PrintAll { + if a.IsHIDSEvent(event) && !isSysmonProcessTerminate(event) { + if a.PrintAll { fmt.Println(utils.JsonStringOrPanic(event)) } goto CONTINUE @@ -794,45 +858,45 @@ func (h *Agent) Run() { // if event is skipped we don't log it even with PrintAll if event.IsSkipped() { - h.stats.Update(event) + a.stats.Update(event) goto CONTINUE } // if the event has matched at least one signature or is filtered - if n, crit, filtered := h.Engine.MatchOrFilter(event); len(n) > 0 || filtered { + if n, crit, filtered := a.Engine.MatchOrFilter(event); len(n) > 0 || filtered { switch { - case crit >= h.config.CritTresh: - if !h.PrintAll && !h.config.LogAll { - h.forwarder.PipeEvent(event) + case crit >= a.config.CritTresh: + if !a.PrintAll && !a.config.LogAll { + a.forwarder.PipeEvent(event) } // Pipe the event to be sent to the forwarder // Run hooks post detection - h.postHooks.RunHooksOn(h, event) - h.stats.Update(event) - case filtered && h.config.EnableFiltering && !h.PrintAll && !h.config.LogAll: + a.postHooks.RunHooksOn(a, event) + a.stats.Update(event) + case filtered && a.config.EnableFiltering && !a.PrintAll && !a.config.LogAll: //event.Del(&engine.GeneInfoPath) // we pipe filtered event - h.forwarder.PipeEvent(event) + a.forwarder.PipeEvent(event) } } // we queue event in action handler - h.actionHandler.Queue(event) + a.actionHandler.Queue(event) // Print everything - if h.PrintAll { + if a.PrintAll { fmt.Println(utils.JsonStringOrPanic(event)) } // We log all events - if h.config.LogAll { - h.forwarder.PipeEvent(event) + if a.config.LogAll { + a.forwarder.PipeEvent(event) } - h.stats.Update(event) + a.stats.Update(event) CONTINUE: - h.RUnlock() + a.RUnlock() } log.Infof("HIDS main loop terminated") }() @@ -843,35 +907,35 @@ func (h *Agent) Run() { } // LogStats logs whids statistics -func (h *Agent) LogStats() { - log.Infof("Time Running: %s", h.stats.SinceStart()) - log.Infof("Count Event Scanned: %.0f", h.stats.Events()) - log.Infof("Average Event Rate: %.2f EPS", h.stats.EPS()) - log.Infof("Alerts Reported: %.0f", h.stats.Detections()) - log.Infof("Count Rules Used (loaded + generated): %d", h.Engine.Count()) +func (a *Agent) LogStats() { + log.Infof("Time Running: %s", a.stats.SinceStart()) + log.Infof("Count Event Scanned: %.0f", a.stats.Events()) + log.Infof("Average Event Rate: %.2f EPS", a.stats.EPS()) + log.Infof("Alerts Reported: %.0f", a.stats.Detections()) + log.Infof("Count Rules Used (loaded + generated): %d", a.Engine.Count()) } // Stop stops the IDS -func (h *Agent) Stop() { +func (a *Agent) Stop() { log.Infof("Stopping HIDS") // cancelling parent context - h.cancel() + a.cancel() // gently close forwarder needs to be done before // stop listening othewise we corrupt local logfiles // because of race condition log.Infof("Closing forwarder") - h.forwarder.Close() + a.forwarder.Close() // closing event provider log.Infof("Closing event provider") - if err := h.eventProvider.Stop(); err != nil { + if err := a.eventProvider.Stop(); err != nil { log.Errorf("Error while closing event provider: %s", err) } // cleaning canary files - if h.config.CanariesConfig.Enable { + if a.config.CanariesConfig.Enable { log.Infof("Cleaning canaries") - h.config.CanariesConfig.Clean() + a.config.CanariesConfig.Clean() } // updating autologger configuration @@ -880,7 +944,7 @@ func (h *Agent) Stop() { log.Errorf("Failed to delete autologger: %s", err) } - if err := h.config.EtwConfig.ConfigureAutologger(); err != nil { + if err := a.config.EtwConfig.ConfigureAutologger(); err != nil { log.Errorf("Failed to update autologger configuration: %s", err) } @@ -888,15 +952,15 @@ func (h *Agent) Stop() { } // Wait waits the IDS to finish -func (h *Agent) Wait() { - h.waitGroup.Wait() +func (a *Agent) Wait() { + a.waitGroup.Wait() } // WaitWithTimeout waits the IDS to finish -func (h *Agent) WaitWithTimeout(timeout time.Duration) { +func (a *Agent) WaitWithTimeout(timeout time.Duration) { t := time.NewTimer(timeout) go func() { - h.waitGroup.Wait() + a.waitGroup.Wait() t.Stop() }() <-t.C diff --git a/agent/hook_test.go b/agent/agent_test.go similarity index 60% rename from agent/hook_test.go rename to agent/agent_test.go index 70a44fd..aa98edd 100644 --- a/agent/hook_test.go +++ b/agent/agent_test.go @@ -6,7 +6,9 @@ import ( "errors" "fmt" "log" + "math/rand" "os" + "path/filepath" "testing" "time" @@ -14,7 +16,11 @@ import ( "github.com/0xrawsec/golang-utils/datastructs" "github.com/0xrawsec/toast" "github.com/0xrawsec/whids/agent/config" + "github.com/0xrawsec/whids/api" + cconfig "github.com/0xrawsec/whids/api/client/config" + "github.com/0xrawsec/whids/api/server" "github.com/0xrawsec/whids/event" + "github.com/0xrawsec/whids/ioc" "github.com/0xrawsec/whids/sysmon" "github.com/0xrawsec/whids/utils" ) @@ -71,8 +77,118 @@ var ( ` + + testAdminUser = &server.AdminAPIUser{ + Identifier: "test", + Key: utils.UnsafeKeyGen(api.DefaultKeySize), + } + + mroot = filepath.Join(os.TempDir(), utils.UnsafeUUIDGen().String(), "data") + mconf = server.ManagerConfig{ + AdminAPI: server.AdminAPIConfig{ + Host: "localhost", + Port: randport(), + }, + EndpointAPI: server.EndpointAPIConfig{ + Host: "localhost", + Port: randport(), + }, + Logging: server.ManagerLogConfig{ + Root: filepath.Join(mroot, "logs"), + LogBasename: "alerts", + }, + Database: filepath.Join(mroot, "database"), + DumpDir: filepath.Join(mroot, "uploads"), + TLS: server.TLSConfig{ + Cert: filepath.Join(mroot, "cert.pem"), + Key: filepath.Join(mroot, "key.pem"), + }, + } ) +func generateCert(c server.ManagerConfig) { + hosts := []string{c.AdminAPI.Host, c.EndpointAPI.Host} + key, cert, err := utils.GenerateCert("Test", hosts, time.Hour*24*365) + if err != nil { + panic(err) + } + if err = os.MkdirAll(mroot, 0777); err != nil { + panic(err) + } + if err = utils.HidsWriteData(c.TLS.Cert, cert); err != nil { + panic(err) + } + if err = utils.HidsWriteData(c.TLS.Key, key); err != nil { + panic(err) + } +} + +func randport() (port int) { + for ; port <= 10000; port = rand.Intn(65535) { + } + return +} + +func randomIoCs(n int) (iocs []*ioc.IOC) { + for ; n > 0; n-- { + iocs = append(iocs, &ioc.IOC{ + Uuid: utils.UnsafeUUIDGen().String(), + GroupUuid: utils.UnsafeUUIDGen().String(), + Source: "Xyz", + Value: fmt.Sprintf("%d.some.random.domain", rand.Intn(10000)), + Type: "domain", + }) + } + return +} + +func makeClientConfig(mc *server.ManagerConfig) (c cconfig.Client) { + var err error + + c = cconfig.Client{ + Proto: "https", + Host: "localhost", + Port: mc.EndpointAPI.Port, + UUID: utils.UnsafeUUIDGen().String(), + Key: utils.UnsafeUUIDGen().String(), + Unsafe: true, + } + + if c.ServerFingerprint, err = utils.CertFileSha256(mc.TLS.Cert); err != nil { + panic(err) + } + + return +} + +func prepareManager() (m *server.Manager, cconf cconfig.Client) { + var err error + + mconf := mconf + generateCert(mconf) + cconf = makeClientConfig(&mconf) + + if m, err = server.NewManager(&mconf); err != nil { + panic(err) + } + + // we don't handle error as we don't care if user + // already exists + m.CreateNewAdminAPIUser(testAdminUser) + + m.AddEndpoint(cconf.UUID, cconf.Key) + if err := m.AddIoCs(randomIoCs(1000)); err != nil { + panic(err) + } + m.Run() + + return +} + +func cleanup() { + os.RemoveAll(mroot) +} + func installSysmon() { var i *sysmon.Info var c *sysmon.Config @@ -126,7 +242,9 @@ func testHook(h *Agent, e *event.EdrEvent) { fmt.Println(utils.PrettyJsonOrPanic(e)) } -func TestHooks(t *testing.T) { +func TestAgent(t *testing.T) { + defer cleanup() + _, clConf := prepareManager() installSysmon() @@ -138,6 +256,8 @@ func TestHooks(t *testing.T) { defer os.RemoveAll(tmp) c := BuildDefaultConfig(tmp) + c.FwdConfig.Local = false + c.FwdConfig.Client = clConf c.Actions = config.Actions{ AvailableActions: AvailableActions, Low: []string{}, @@ -146,12 +266,19 @@ func TestHooks(t *testing.T) { Critical: []string{}, } - h, err := NewAgent(c) + log.SetOutput(os.Stdout) + a, err := NewAgent(c) // show EDR logs in console log.SetOutput(os.Stdout) + // reduce scheduled task ticker + for _, t := range a.scheduler.Tasks() { + if t.Tick() > 0 { + t.Ticker(time.Second * 5) + } + } // add a final hook to catch all events after enrichment - h.preHooks.Hook(func(h *Agent, e *event.EdrEvent) { + a.preHooks.Hook(func(h *Agent, e *event.EdrEvent) { if e.Channel() == sysmonChannel { gotSysmonEvent = true } @@ -159,22 +286,22 @@ func TestHooks(t *testing.T) { d := engine.NewDetection(true, true) // enable all actions //d.Actions = datastructs.NewInitSet(datastructs.ToInterfaceSlice(AvailableActions)...) - d.Actions = datastructs.NewInitSet(ActionFiledump, ActionRegdump, ActionBlacklist, ActionBrief, ActionReport) + d.Actions = datastructs.NewInitSet(ActionFiledump, ActionRegdump, ActionBrief, ActionReport) d.Criticality = 6 e.SetDetection(d) }, fltAnyEvent) tt.TimeIt( "configuring autologgers", - func() { tt.CheckErr(h.config.EtwConfig.ConfigureAutologger()) }, + func() { tt.CheckErr(a.config.EtwConfig.ConfigureAutologger()) }, ) tt.CheckErr(err) - h.Run() + a.Run() time.Sleep(20 * time.Second) - h.Stop() + a.Stop() tt.Assert(gotSysmonEvent, "failed to monitor Sysmon events") - t.Log(utils.PrettyJsonOrPanic(h.tracker.Modules())) + t.Log(utils.PrettyJsonOrPanic(a.tracker.Modules())) } diff --git a/agent/config/config.go b/agent/config/config.go index 8fe5dad..d3ef3ae 100644 --- a/agent/config/config.go +++ b/agent/config/config.go @@ -111,6 +111,8 @@ func (c *Audit) Restore() { // Agent structure type Agent struct { + path string + DatabasePath string `json:"db-path" toml:"db-path" comment:"Path to local database root directory"` CritTresh int `json:"criticality-treshold" toml:"criticality-treshold" comment:"Dumps/forward only events above criticality threshold\n or filtered events (i.e. Gene filtering rules)" ` EnableHooks bool `json:"en-hooks" toml:"en-hooks" comment:"Enable enrichment hooks and dump hooks"` @@ -129,8 +131,8 @@ type Agent struct { CanariesConfig Canaries `json:"canaries" toml:"canaries" comment:"Canary files configuration"` } -// LoadsHIDSConfig loads a HIDS configuration from a file -func LoadsHIDSConfig(path string) (c Agent, err error) { +// LoadAgentConfig loads a HIDS configuration from a file +func LoadAgentConfig(path string) (c Agent, err error) { fd, err := os.Open(path) if err != nil { return @@ -138,9 +140,14 @@ func LoadsHIDSConfig(path string) (c Agent, err error) { defer fd.Close() dec := toml.NewDecoder(fd) err = dec.Decode(&c) + c.path = path return } +func (c *Agent) Sha256() (string, error) { + return utils.Sha256Interface(c) +} + // IsForwardingEnabled returns true if a forwarder is actually configured to forward logs func (c *Agent) IsForwardingEnabled() bool { return c.FwdConfig != emptyForwarderConfig && !c.FwdConfig.Local @@ -151,15 +158,19 @@ func (c *Agent) Prepare() { if !fsutil.Exists(c.RulesConfig.RulesDB) { os.MkdirAll(c.RulesConfig.RulesDB, 0600) } + if !fsutil.Exists(c.RulesConfig.ContainersDB) { os.MkdirAll(c.RulesConfig.ContainersDB, 0600) } + if !fsutil.Exists(c.Dump.Dir) { os.MkdirAll(c.Dump.Dir, 0600) } + if !fsutil.Exists(filepath.Dir(c.FwdConfig.Logging.Dir)) { os.MkdirAll(filepath.Dir(c.FwdConfig.Logging.Dir), 0600) } + if !fsutil.Exists(filepath.Dir(c.Logfile)) { os.MkdirAll(filepath.Dir(c.Logfile), 0600) } @@ -175,3 +186,18 @@ func (c *Agent) Verify() error { } return nil } + +func (c *Agent) Path() string { + return c.path +} + +// Save saves configuration to path +func (c *Agent) Save(path string) (err error) { + var b []byte + + if b, err = utils.Json(c); err != nil { + return + } + + return utils.HidsWriteData(path, b) +} diff --git a/agent/cron.go b/agent/cron.go index efedd42..8130cf5 100644 --- a/agent/cron.go +++ b/agent/cron.go @@ -23,8 +23,8 @@ import ( "github.com/0xrawsec/whids/utils" ) -func (h *Agent) containCmd() *exec.Cmd { - ip := h.forwarder.Client.ManagerIP +func (a *Agent) containCmd() *exec.Cmd { + ip := a.forwarder.Client.ManagerIP // only allow connection to the manager configured return exec.Command("netsh.exe", "advfirewall", @@ -37,7 +37,7 @@ func (h *Agent) containCmd() *exec.Cmd { "action=block") } -func (h *Agent) uncontainCmd() *exec.Cmd { +func (a *Agent) uncontainCmd() *exec.Cmd { return exec.Command("netsh.exe", "advfirewall", "firewall", "delete", @@ -46,7 +46,7 @@ func (h *Agent) uncontainCmd() *exec.Cmd { ) } -func (h *Agent) handleManagerCommand(cmd *api.EndpointCommand) { +func (a *Agent) handleManagerCommand(cmd *api.EndpointCommand) { // command documentation template: /* @@ -71,7 +71,7 @@ func (h *Agent) handleManagerCommand(cmd *api.EndpointCommand) { } */ case "contain": - cmd.FromExecCmd(h.containCmd()) + cmd.FromExecCmd(a.containCmd()) /* @command: { @@ -81,7 +81,7 @@ func (h *Agent) handleManagerCommand(cmd *api.EndpointCommand) { } */ case "uncontain": - cmd.FromExecCmd(h.uncontainCmd()) + cmd.FromExecCmd(a.uncontainCmd()) /* @command: { @@ -250,7 +250,7 @@ func (h *Agent) handleManagerCommand(cmd *api.EndpointCommand) { case "report": cmd.Unrunnable() cmd.ExpectJSON = true - cmd.Json = h.Report(false) + cmd.Json = a.Report(false) /* @command: { @@ -260,11 +260,11 @@ func (h *Agent) handleManagerCommand(cmd *api.EndpointCommand) { } */ case "processes": - h.tracker.RLock() + a.tracker.RLock() cmd.Unrunnable() cmd.ExpectJSON = true - cmd.Json = h.tracker.PS() - h.tracker.RUnlock() + cmd.Json = a.tracker.PS() + a.tracker.RUnlock() /* @command: { @@ -274,11 +274,11 @@ func (h *Agent) handleManagerCommand(cmd *api.EndpointCommand) { } */ case "modules": - h.tracker.RLock() + a.tracker.RLock() cmd.Unrunnable() cmd.ExpectJSON = true - cmd.Json = h.tracker.Modules() - h.tracker.RUnlock() + cmd.Json = a.tracker.Modules() + a.tracker.RUnlock() /* @command: { @@ -288,11 +288,11 @@ func (h *Agent) handleManagerCommand(cmd *api.EndpointCommand) { } */ case "drivers": - h.tracker.RLock() + a.tracker.RLock() cmd.Unrunnable() cmd.ExpectJSON = true - cmd.Json = h.tracker.Drivers - h.tracker.RUnlock() + cmd.Json = a.tracker.Drivers + a.tracker.RUnlock() } // we finally run the command @@ -305,7 +305,7 @@ func (h *Agent) handleManagerCommand(cmd *api.EndpointCommand) { // routine which manages command to be executed on the endpoint // it is made in such a way that we can send burst of commands -func (h *Agent) taskCommandRunner() { +func (a *Agent) taskCommandRunner() { defaultSleep := time.Second * 5 sleep := defaultSleep @@ -314,15 +314,15 @@ func (h *Agent) taskCommandRunner() { burstSleep := time.Millisecond * 500 for { - if cmd, err := h.forwarder.Client.FetchCommand(); err != nil && err != client.ErrNothingToDo { + if cmd, err := a.forwarder.Client.FetchCommand(); err != nil && err != client.ErrNothingToDo { log.Error(err) } else if err == nil { // reduce sleeping time if a command was received sleep = burstSleep burstDur = 0 log.Infof("[command runner] handling manager command: %s", cmd.String()) - h.handleManagerCommand(cmd) - if err := h.forwarder.Client.PostCommand(cmd); err != nil { + a.handleManagerCommand(cmd) + if err := a.forwarder.Client.PostCommand(cmd); err != nil { log.Error("[command runner]", err) } } @@ -340,9 +340,9 @@ func (h *Agent) taskCommandRunner() { } } -func (h *Agent) scheduleCleanArchivedTask() error { - if h.config.Sysmon.CleanArchived { - archivePath := h.config.Sysmon.ArchiveDirectory +func (a *Agent) scheduleCleanArchivedTask() error { + if a.config.Sysmon.CleanArchived { + archivePath := a.config.Sysmon.ArchiveDirectory if archivePath == "" { return errors.New("sysmon archive directory not configured") @@ -356,7 +356,7 @@ func (h *Agent) scheduleCleanArchivedTask() error { reported := datastructs.NewSyncedSet() log.Infof("Scheduling archive cleanup loop for directory: %s", archivePath) - h.scheduler.Schedule(crony.NewTask("Sysmon archived files cleaner").Func(func() { + a.scheduler.Schedule(crony.NewTask("Sysmon archived files cleaner").Func(func() { // used to mark files for which we already reported errors // expiration fixed to five minutes expired := time.Now().Add(time.Minute * -5) @@ -380,9 +380,9 @@ func (h *Agent) scheduleCleanArchivedTask() error { return nil } -func (h *Agent) taskUploadDumps() { +func (a *Agent) taskUploadDumps() { // Sending dump files over to the manager - for wi := range fswalker.Walk(h.config.Dump.Dir) { + for wi := range fswalker.Walk(a.config.Dump.Dir) { for _, fi := range wi.Files { sp := strings.Split(wi.Dirpath, string(os.PathSeparator)) // upload only file with some extensions @@ -401,14 +401,14 @@ func (h *Agent) taskUploadDumps() { continue } - if shrink.Size() > h.config.FwdConfig.Client.MaxUploadSize { + if shrink.Size() > a.config.FwdConfig.Client.MaxUploadSize { log.Warnf("[dump uploader] dump file is above allowed upload limit, %s will be deleted without being sent", fullpath) goto CleanShrinker } // we shrink a file into several chunks to reduce memory impact for fu := shrink.Next(); fu != nil; fu = shrink.Next() { - if err = h.forwarder.Client.PostDump(fu); err != nil { + if err = a.forwarder.Client.PostDump(fu); err != nil { log.Error(err) break } @@ -434,12 +434,12 @@ func (h *Agent) taskUploadDumps() { } } -func (h *Agent) updateTools() (err error) { +func (a *Agent) updateTools() (err error) { var mtools map[string]*tools.Tool var locToolNames []string // getting the list of tools from the manager, only metatada are returned - if mtools, err = h.forwarder.Client.ListTools(); err != nil { + if mtools, err = a.forwarder.Client.ListTools(); err != nil { return } @@ -448,17 +448,17 @@ func (h *Agent) updateTools() (err error) { var old *tools.Tool // if the tool is already there we continue - if h.db.Search(&tools.Tool{}, "Metadata.Sha512", "=", t.Metadata.Sha512).Len() == 1 { + if a.db.Search(&tools.Tool{}, "Metadata.Sha512", "=", t.Metadata.Sha512).Len() == 1 { continue } // we get the tool from manager - if t, err = h.forwarder.Client.GetTool(t.Metadata.Sha256); err != nil { + if t, err = a.forwarder.Client.GetTool(t.Metadata.Sha256); err != nil { return } // search for a tool with the same name - if err = h.db.Search(&tools.Tool{}, "Name", "=", t.Name).And("OS", "=", los.OS).AssignUnique(&old); err != nil && !sod.IsNoObjectFound(err) { + if err = a.db.Search(&tools.Tool{}, "Name", "=", t.Name).And("OS", "=", los.OS).AssignUnique(&old); err != nil && !sod.IsNoObjectFound(err) { return } else if err == nil { // we use same UUID not to duplicate entry @@ -466,7 +466,7 @@ func (h *Agent) updateTools() (err error) { } // we update local database - if err = h.db.InsertOrUpdate(t); err != nil { + if err = a.db.InsertOrUpdate(t); err != nil { return } @@ -477,7 +477,7 @@ func (h *Agent) updateTools() (err error) { } // We retrieve the names of the local files - if err = h.db.AssignIndex(&tools.Tool{}, "Name", &locToolNames); err != nil { + if err = a.db.AssignIndex(&tools.Tool{}, "Name", &locToolNames); err != nil { return } @@ -486,7 +486,7 @@ func (h *Agent) updateTools() (err error) { // if we have a tool locally that has been deleted from remote if _, ok := mtools[locName]; !ok { var t *tools.Tool - s := h.db.Search(&tools.Tool{}, "Name", "=", locName) + s := a.db.Search(&tools.Tool{}, "Name", "=", locName) if err = s.AssignUnique(&t); err != nil { return } @@ -504,108 +504,128 @@ func (h *Agent) updateTools() (err error) { return } -func (h *Agent) scheduleTasks() { +func (a *Agent) scheduleTasks() { inLittleWhile := time.Now().Add(time.Second * 5) // routines scheduled only if connected to a manager - if h.config.IsForwardingEnabled() { - // command runner routine, we run it only once as it creates a go routine to handle commands - h.scheduler.Schedule( - crony.NewAsyncTask("Command handler goroutine"). - Func(h.taskCommandRunner). - Schedule(time.Now()), + if a.config.IsForwardingEnabled() { + // High prio tasks + + // agent configuration update + a.scheduler.Schedule( + crony.NewTask("Configuration update"). + Func(func() { + task := "[configuration update]" + log.Info(task, "update starting") + if err := a.updateAgentConfig(); err != nil { + log.Error(task, err) + } + }).Ticker(time.Minute*15).Schedule(time.Now()), + crony.PrioHigh, + ) + + // updating tools + a.scheduler.Schedule(crony.NewTask("Utilities update"). + Func(func() { + task := "[utilities update]" + log.Info(task, "update starting") + if err := a.updateTools(); err != nil { + log.Error(task, err) + } + }).Ticker(time.Minute*15).Schedule(inLittleWhile), crony.PrioHigh) // updating engine - h.scheduler.Schedule(crony.NewTask("Rule/IOC Update"). + a.scheduler.Schedule(crony.NewTask("Rule/IOC Update"). Func(func() { task := "[rule/ioc update]" log.Info(task, "update starting") - if err := h.update(false); err != nil { + if err := a.update(false); err != nil { log.Error(task, err) } - }).Ticker(h.config.RulesConfig.UpdateInterval).Schedule(inLittleWhile), + }).Ticker(a.config.RulesConfig.UpdateInterval).Schedule(inLittleWhile), crony.PrioHigh) + // command runner routine, we run it only once as it creates a go routine to handle commands + a.scheduler.Schedule( + crony.NewAsyncTask("Command handler goroutine"). + Func(a.taskCommandRunner). + Schedule(time.Now()), + crony.PrioHigh) + + // Medium Prio Tasks + // uploading dumps - h.scheduler.Schedule(crony.NewTask("Upload Dump"). - Func(h.taskUploadDumps).Ticker(time.Minute), + a.scheduler.Schedule(crony.NewTask("Upload Dump"). + Func(a.taskUploadDumps).Ticker(time.Minute), crony.PrioMedium) - // updating system information - h.scheduler.Schedule(crony.NewTask("System Info Update"). - Func(func() { - task := "[system info update]" - log.Info(task, "update starting") - if err := h.updateSystemInfo(); err != nil { - log.Error(task, err) - } - }).Ticker(h.config.RulesConfig.UpdateInterval). - Schedule(inLittleWhile), - crony.PrioLow) - // updating sysmon - h.scheduler.Schedule(crony.NewTask("Sysmon update"). + a.scheduler.Schedule(crony.NewTask("Sysmon update"). Func(func() { task := "[sysmon update]" log.Info(task, "update starting") - if err := h.updateSysmon(); err != nil { + if err := a.updateSysmonBin(); err != nil { log.Error(task, err) } }).Ticker(time.Hour).Schedule(inLittleWhile), crony.PrioMedium) // updating sysmon configuration - h.scheduler.Schedule(crony.NewTask("Sysmon configuration update"). + a.scheduler.Schedule(crony.NewTask("Sysmon configuration update"). Func(func() { task := "[sysmon config update]" log.Info(task, "update starting") - if err := h.updateSysmonConfig(); err != nil { + if err := a.updateSysmonConfig(); err != nil { log.Error(task, err) } }).Ticker(time.Minute*15).Schedule(inLittleWhile), crony.PrioMedium) - // updating tools - h.scheduler.Schedule(crony.NewTask("Utilities update"). + // Low Prio Tasks + + // updating system information + a.scheduler.Schedule(crony.NewTask("System Info Update"). Func(func() { - task := "[utilities update]" + task := "[system info update]" log.Info(task, "update starting") - if err := h.updateTools(); err != nil { + if err := a.updateSystemInfo(); err != nil { log.Error(task, err) } - }).Ticker(time.Minute*15).Schedule(inLittleWhile), - crony.PrioHigh) + }).Ticker(a.config.RulesConfig.UpdateInterval). + Schedule(inLittleWhile), + crony.PrioLow) + } // routines scheduled in any case // Forwarder scheduling - h.scheduler.Schedule(crony.NewTask("Log forwarder").Func(func() { + a.scheduler.Schedule(crony.NewTask("Log forwarder").Func(func() { // this call starts a new go routine so we don't need to create // a new AsyncTask as it is not a blocking call - h.forwarder.Run() + a.forwarder.Run() }).Schedule(time.Now()), crony.PrioHigh) // routine managing Sysmon archived files cleanup - if err := h.scheduleCleanArchivedTask(); err != nil { + if err := a.scheduleCleanArchivedTask(); err != nil { log.Error("failed to schedule sysmon archived file cleaning: ", err) } // routine creating canary files - h.scheduler.Schedule(crony.NewAsyncTask("Canary configuration").Func(func() { + a.scheduler.Schedule(crony.NewAsyncTask("Canary configuration").Func(func() { task := "[canary configuration]" - if err := h.config.CanariesConfig.Configure(); err != nil { + if err := a.config.CanariesConfig.Configure(); err != nil { log.Error(task, err) } }).Schedule(time.Now()), crony.PrioHigh) // Action handler scheduling - h.scheduler.Schedule(crony.NewAsyncTask("Action Handler").Func(func() { - h.actionHandler.handleActionsLoop() + a.scheduler.Schedule(crony.NewAsyncTask("Action Handler").Func(func() { + a.actionHandler.handleActionsLoop() }).Schedule(time.Now()), crony.PrioHigh) - h.scheduler.Schedule(crony.NewAsyncTask("Action Handler File Compression").Func(func() { - h.actionHandler.compressionLoop() + a.scheduler.Schedule(crony.NewAsyncTask("Action Handler File Compression").Func(func() { + a.actionHandler.compressionLoop() }).Schedule(time.Now()), crony.PrioHigh) } diff --git a/agent/sysinfo/sysinfo_test.go b/agent/sysinfo/sysinfo_test.go index a8e1a5f..61bf54a 100644 --- a/agent/sysinfo/sysinfo_test.go +++ b/agent/sysinfo/sysinfo_test.go @@ -11,13 +11,13 @@ func TestSystemInfo(t *testing.T) { var h string var err error info := NewSystemInfo() - if h, err = utils.HashInterface(info); err != nil { + if h, err = utils.Sha1Interface(info); err != nil { t.Error(err) } t.Log(utils.PrettyJsonOrPanic(info)) t.Logf("Structure hash: %s", h) for i := 0; i < 1000; i++ { - if n, err := utils.HashInterface(info); err != nil { + if n, err := utils.Sha1Interface(info); err != nil { t.Error(err) t.FailNow() } else if n != h { diff --git a/api/client/api_client.go b/api/client/api_client.go index bff4322..530043e 100644 --- a/api/client/api_client.go +++ b/api/client/api_client.go @@ -556,6 +556,35 @@ func (m *ManagerClient) GetSysmonConfig(schemaVersion string) (c *sysmon.Config, return } +func (m *ManagerClient) GetAgentConfigSha256() (sha256 string, err error) { + var req *http.Request + var resp *http.Response + + if auth, _ := m.IsServerAuthenticated(); !auth { + return "", ErrServerUnauthenticated + } + + if req, err = m.Prepare("GET", api.EptAPIConfigSha256Path, nil); err != nil { + return + } + + if resp, err = m.HTTPClient.Do(req); err != nil { + return + } + + defer resp.Body.Close() + + if err = ValidateRespStatus(resp, http.StatusOK, http.StatusNoContent); err == nil { + if resp.StatusCode == http.StatusNoContent { + err = ErrNoAgentConfig + return + } + sha256 = respBodyToString(resp) + } + + return +} + func (m *ManagerClient) GetAgentConfig() (config *aconfig.Agent, err error) { var req *http.Request var resp *http.Response @@ -587,6 +616,37 @@ func (m *ManagerClient) GetAgentConfig() (config *aconfig.Agent, err error) { return } +func (m *ManagerClient) PostAgentConfig(c *aconfig.Agent) (err error) { + + var b []byte + var req *http.Request + var resp *http.Response + + if auth, _ := m.IsServerAuthenticated(); !auth { + return ErrServerUnauthenticated + } + + if b, err = utils.Json(c); err != nil { + return + } + + if req, err = m.PrepareGzip("POST", api.EptAPIConfigPath, bytes.NewBuffer(b)); err != nil { + return + } + + if resp, err = m.HTTPClient.Do(req); err != nil { + return + } + + defer resp.Body.Close() + + if err = ValidateRespStatus(resp, http.StatusOK); err != nil { + return + } + + return +} + func (m *ManagerClient) ListTools() (t map[string]*tools.Tool, err error) { var req *http.Request var resp *http.Response diff --git a/api/routes.go b/api/routes.go index b7915fe..d599d03 100644 --- a/api/routes.go +++ b/api/routes.go @@ -7,7 +7,8 @@ const ( // EptAPIServerKeyPath API route used to get server key EptAPIServerKeyPath = "/key" // EptAPIConfigPath API route used to get/post endpoint configuration - EptAPIConfigPath = "/config" + EptAPIConfigPath = "/config" + EptAPIConfigSha256Path = "/config/sha256" // EptAPIRulesPath API route used to get Gene rules available in server EptAPIRulesPath = "/rules" // EptAPIRulesSha256Path API route used to retrieve sha256 of latest batch of Gene rules diff --git a/api/server/manager.go b/api/server/manager.go index 7d7f433..d1fc943 100644 --- a/api/server/manager.go +++ b/api/server/manager.go @@ -479,6 +479,36 @@ func (m *Manager) AddEndpoint(uuid, key string) { m.db.InsertOrUpdate(api.NewEndpoint(uuid, key)) } +func (m *Manager) AddIoCs(iocs []*ioc.IOC) (err error) { + + // we preprocess to update existing IOCs + insert := make([]*ioc.IOC, 0, len(iocs)) + for _, i := range iocs { + // we need to apply transformation before searching otherwise we + // might not find some values which have been transformed + i.Transform() + search := m.db.Search(&ioc.IOC{}, + "Uuid", "=", i.Uuid) + if o, err := search.One(); err == nil { + // in order to update existing IOCs + i.Initialize(o.UUID()) + } + + insert = append(insert, i) + } + + // Do bulk insertion + if _, err = m.db.InsertOrUpdateMany(sod.ToObjectSlice(insert)...); err != nil { + //wt.Write(admErr(err)) + return + } + + // Add IoCs to sync with endpoints + m.iocs.Add(insert...) + + return +} + // UpdateReducer updates the reducer member of the Manager func (m *Manager) UpdateReducer(identifier string, e *event.EdrEvent) { if e.Event.Detection != nil { diff --git a/api/server/manager_admin_api.go b/api/server/manager_admin_api.go index 5848204..f1483cb 100644 --- a/api/server/manager_admin_api.go +++ b/api/server/manager_admin_api.go @@ -443,7 +443,6 @@ func (m *Manager) admAPIEndpointConfig(wt http.ResponseWriter, rq *http.Request) log.Info("format=", qpfmt) switch qpfmt { case "toml": - log.Info("reading toml") err = readPostAsTOML(rq, &c) default: err = readPostAsJSON(rq, &c) @@ -1286,31 +1285,12 @@ func (m *Manager) admAPIIocs(wt http.ResponseWriter, rq *http.Request) { wt.Write(admErr(err)) } else { - // we preprocess to update existing IOCs - insert := make([]*ioc.IOC, 0, len(iocs)) - for _, i := range iocs { - // we need to apply transformation before searching otherwise we - // might not find some values which have been transformed - i.Transform() - search := m.db.Search(&ioc.IOC{}, - "Uuid", "=", i.Uuid) - if o, err := search.One(); err == nil { - // in order to update existing IOCs - i.Initialize(o.UUID()) - } - - insert = append(insert, i) - } - - // Do bulk insertion - if _, err := m.db.InsertOrUpdateMany(sod.ToObjectSlice(insert)...); err != nil { + if err := m.AddIoCs(iocs); err != nil { wt.Write(admErr(err)) return } - // Add IoCs to sync with endpoints - m.iocs.Add(insert...) - wt.Write(admJSONResp(insert)) + wt.Write(admJSONResp(iocs)) } case "DELETE": diff --git a/api/server/manager_endpoint_api.go b/api/server/manager_endpoint_api.go index 40ddb1b..1621beb 100644 --- a/api/server/manager_endpoint_api.go +++ b/api/server/manager_endpoint_api.go @@ -151,6 +151,7 @@ func (m *Manager) runEndpointAPI() { rt.HandleFunc(api.EptAPISysmonConfigPath, m.eptAPISysmonConfig).Methods("GET") rt.HandleFunc(api.EptAPISysmonConfigSha256Path, m.eptAPISysmonConfigSha256).Methods("GET") rt.HandleFunc(api.EptAPITools, m.eptAPITools).Methods("GET") + rt.HandleFunc(api.EptAPIConfigSha256Path, m.eptAPIConfigSha256).Methods("GET") // GET and POST rt.HandleFunc(api.EptAPICommandPath, m.eptAPICommand).Methods("GET", "POST") @@ -192,6 +193,30 @@ func (m *Manager) eptAPIRules(wt http.ResponseWriter, rq *http.Request) { wt.Write([]byte(m.gene.rules)) } +// eptAPIConfigSha256 HTTP handler +func (m *Manager) eptAPIConfigSha256(wt http.ResponseWriter, rq *http.Request) { + var endpt *api.Endpoint + + if endpt = m.eptAPIMutEndpointFromRequest(rq); endpt == nil { + m.logAPIErrorf("unknown endpoint") + return + } + + // if configuration is nil we return StatusNoContent + if endpt.Config == nil { + http.Error(wt, "", http.StatusNoContent) + return + } + + sha256, err := endpt.Config.Sha256() + if err != nil { + http.Error(wt, "failed to compute config hash", http.StatusInternalServerError) + return + } + + wt.Write([]byte(sha256)) +} + // eptAPIConfigHTTP handler func (m *Manager) eptAPIConfig(wt http.ResponseWriter, rq *http.Request) { var endpt *api.Endpoint @@ -213,6 +238,7 @@ func (m *Manager) eptAPIConfig(wt http.ResponseWriter, rq *http.Request) { out, err := json.Marshal(endpt.Config) if err != nil { m.logAPIErrorf("failed at serializing config to JSON: %s", err) + http.Error(wt, "failed to serialize config", http.StatusInternalServerError) return } @@ -321,7 +347,7 @@ func (m *Manager) eptAPICollect(wt http.ResponseWriter, rq *http.Request) { // building up EdrData edrData := event.EdrData{} - edrData.Event.Hash = utils.HashEventBytes(tok) + edrData.Event.Hash = utils.Sha1EventBytes(tok) edrData.Event.ReceiptTime = time.Now().UTC() edrData.Endpoint.UUID = uuid diff --git a/api/server/openapi_def.go b/api/server/openapi_def.go index a320388..bffcc35 100644 --- a/api/server/openapi_def.go +++ b/api/server/openapi_def.go @@ -74,10 +74,10 @@ var OpenAPIDefinition = ` "group": "", "hostname": "OpenHappy", "ip": "127.0.0.1", - "key": "n2hcbth96fTPLgDIHIMK3BKSi09UUbX65lB7xbg5T0vTWX6W9VHIGEGFBpORLlvd", - "last-connection": "2022-07-27T16:20:49.458879336Z", - "last-detection": "2022-07-27T18:20:48.389870049+02:00", - "last-event": "2022-07-27T18:20:48.389870049+02:00", + "key": "gCx59uTlWsW9a4MX2yJOEN4NSCln3TOu58aTXJcbii5fSRvR34kmyBhN6JfbiJyw", + "last-connection": "2022-08-24T10:48:29.474420629Z", + "last-detection": "2022-08-24T12:48:28.433692184+02:00", + "last-event": "2022-08-24T12:48:28.433692184+02:00", "score": 0, "status": "", "system-info": { @@ -154,13 +154,13 @@ var OpenAPIDefinition = ` "group": "", "hostname": "", "ip": "", - "key": "VvHJGJORk6qUXHxzNaS85EPNkRVbKn4mT5XqWdMkjn98yHsfeaDvtqPNFGPYRy0P", + "key": "8vDtCLSXvKqycbzcNj5j1lYvn0l2FmBz2YIg1WpYB6FwUSR50KDsgJxfQK6KQth3", "last-connection": "0001-01-01T00:00:00Z", "last-detection": "0001-01-01T00:00:00Z", "last-event": "0001-01-01T00:00:00Z", "score": 0, "status": "", - "uuid": "a52a6152-2b74-9166-9ddf-8e8dc1186376" + "uuid": "1b98404b-b614-c91a-f351-4f8b4216838d" }, "error": "", "message": "OK" @@ -200,21 +200,21 @@ var OpenAPIDefinition = ` "5a92baeb-9384-47d3-92b4-a0db6f9b8c6d": [ { "base-url": "/endpoints/5a92baeb-9384-47d3-92b4-a0db6f9b8c6d/artifacts/5a92baeb-9384-47d3-92b4-a0db6f9b8c6d/3d8441643c204ba9b9dcb5c414b25a3129f66f6c/", - "creation": "2022-07-27T16:20:54.923059418Z", + "creation": "2022-08-24T10:48:34.904939052Z", "event-hash": "3d8441643c204ba9b9dcb5c414b25a3129f66f6c", "files": [ { "name": "bar.txt", "size": 4, - "timestamp": "2022-07-27T16:20:54.923059418Z" + "timestamp": "2022-08-24T10:48:34.904939052Z" }, { "name": "foo.txt", "size": 4, - "timestamp": "2022-07-27T16:20:54.923059418Z" + "timestamp": "2022-08-24T10:48:34.904939052Z" } ], - "modification": "2022-07-27T16:20:54.923059418Z", + "modification": "2022-08-24T10:48:34.904939052Z", "process-guid": "5a92baeb-9384-47d3-92b4-a0db6f9b8c6d" } ] @@ -248,30 +248,30 @@ var OpenAPIDefinition = ` "avg-signature-criticality": 0, "bounded-score": 0, "count-by-signature": { - "DefenderConfigChanged": 5, - "NewAutorun": 18, - "SuspiciousService": 11, - "UnknownServices": 7, - "UntrustedDriverLoaded": 9 + "DefenderConfigChanged": 4, + "NewAutorun": 19, + "SuspiciousService": 5, + "UnknownServices": 9, + "UntrustedDriverLoaded": 13 }, "count-uniq-signatures": 5, "identifier": "5a92baeb-9384-47d3-92b4-a0db6f9b8c6d", - "median-time": "2022-07-27T18:20:52.73721162+02:00", + "median-time": "2022-08-24T12:48:32.709584161+02:00", "score": 0, "signature-count": 50, "signature-criticality-metric": 0, "signature-diversity": 100, "signatures": [ "UntrustedDriverLoaded", - "UnknownServices", "NewAutorun", - "SuspiciousService", - "DefenderConfigChanged" + "UnknownServices", + "DefenderConfigChanged", + "SuspiciousService" ], - "start-time": "2022-07-27T18:20:52.735957283+02:00", + "start-time": "2022-08-24T12:48:32.708425432+02:00", "std-dev-alert-criticality": 0, "std-dev-signature-criticality": -92233720368547760, - "stop-time": "2022-07-27T18:20:52.738465958+02:00", + "stop-time": "2022-08-24T12:48:32.71074289+02:00", "sum-alert-criticality": 0, "sum-rule-criticality": 0, "tactics": null, @@ -332,7 +332,7 @@ var OpenAPIDefinition = ` }, "name": "osqueryi", "os": "windows", - "uuid": "bd8b09e0-42b6-9a00-0a8b-9054cc7d1a65" + "uuid": "2010ab6c-4bba-a535-8720-2d66feef4e90" }, "error": "", "message": "OK" @@ -399,7 +399,7 @@ var OpenAPIDefinition = ` }, "name": "osqueryi", "os": "windows", - "uuid": "bd8b09e0-42b6-9a00-0a8b-9054cc7d1a65" + "uuid": "2010ab6c-4bba-a535-8720-2d66feef4e90" }, "error": "", "message": "OK" @@ -453,7 +453,7 @@ var OpenAPIDefinition = ` }, "name": "osqueryi", "os": "windows", - "uuid": "bd8b09e0-42b6-9a00-0a8b-9054cc7d1a65" + "uuid": "2010ab6c-4bba-a535-8720-2d66feef4e90" }, "error": "", "message": "OK" @@ -509,7 +509,7 @@ var OpenAPIDefinition = ` }, "name": "sysmon", "os": "windows", - "uuid": "c53008dc-28f8-2da6-e7e6-81fd622ddf3f" + "uuid": "c4c0a5ef-ada8-8f80-ff6c-928e70c925c2" }, "error": "", "message": "OK" @@ -576,7 +576,7 @@ var OpenAPIDefinition = ` }, "name": "sysmon", "os": "windows", - "uuid": "c53008dc-28f8-2da6-e7e6-81fd622ddf3f" + "uuid": "c4c0a5ef-ada8-8f80-ff6c-928e70c925c2" }, "error": "", "message": "OK" @@ -630,7 +630,7 @@ var OpenAPIDefinition = ` }, "name": "sysmon", "os": "windows", - "uuid": "c53008dc-28f8-2da6-e7e6-81fd622ddf3f" + "uuid": "c4c0a5ef-ada8-8f80-ff6c-928e70c925c2" }, "error": "", "message": "OK" @@ -1897,9 +1897,9 @@ var OpenAPIDefinition = ` "group": "", "hostname": "OpenHappy", "ip": "127.0.0.1", - "last-connection": "2022-07-27T16:20:49.458879336Z", - "last-detection": "2022-07-27T18:20:48.389870049+02:00", - "last-event": "2022-07-27T18:20:48.389870049+02:00", + "last-connection": "2022-08-24T10:48:29.474420629Z", + "last-detection": "2022-08-24T12:48:28.433692184+02:00", + "last-event": "2022-08-24T12:48:28.433692184+02:00", "score": 0, "status": "", "system-info": { @@ -2611,9 +2611,9 @@ var OpenAPIDefinition = ` "group": "New Group", "hostname": "OpenHappy", "ip": "127.0.0.1", - "last-connection": "2022-07-27T16:20:49.458879336Z", - "last-detection": "2022-07-27T18:20:48.389870049+02:00", - "last-event": "2022-07-27T18:20:48.389870049+02:00", + "last-connection": "2022-08-24T10:48:29.474420629Z", + "last-detection": "2022-08-24T12:48:28.433692184+02:00", + "last-event": "2022-08-24T12:48:28.433692184+02:00", "score": 0, "status": "New Status", "system-info": { @@ -2701,9 +2701,9 @@ var OpenAPIDefinition = ` "group": "New Group", "hostname": "OpenHappy", "ip": "127.0.0.1", - "last-connection": "2022-07-27T16:20:49.458879336Z", - "last-detection": "2022-07-27T18:20:48.389870049+02:00", - "last-event": "2022-07-27T18:20:48.389870049+02:00", + "last-connection": "2022-08-24T10:48:29.474420629Z", + "last-detection": "2022-08-24T12:48:28.433692184+02:00", + "last-event": "2022-08-24T12:48:28.433692184+02:00", "score": 0, "status": "New Status", "system-info": { @@ -2802,21 +2802,21 @@ var OpenAPIDefinition = ` "data": [ { "base-url": "/endpoints/5a92baeb-9384-47d3-92b4-a0db6f9b8c6d/artifacts/5a92baeb-9384-47d3-92b4-a0db6f9b8c6d/3d8441643c204ba9b9dcb5c414b25a3129f66f6c/", - "creation": "2022-07-27T16:20:54.923059418Z", + "creation": "2022-08-24T10:48:34.904939052Z", "event-hash": "3d8441643c204ba9b9dcb5c414b25a3129f66f6c", "files": [ { "name": "bar.txt", "size": 4, - "timestamp": "2022-07-27T16:20:54.923059418Z" + "timestamp": "2022-08-24T10:48:34.904939052Z" }, { "name": "foo.txt", "size": 4, - "timestamp": "2022-07-27T16:20:54.923059418Z" + "timestamp": "2022-08-24T10:48:34.904939052Z" } ], - "modification": "2022-07-27T16:20:54.923059418Z", + "modification": "2022-08-24T10:48:34.904939052Z", "process-guid": "5a92baeb-9384-47d3-92b4-a0db6f9b8c6d" } ], @@ -2961,11 +2961,11 @@ var OpenAPIDefinition = ` "json": null, "name": "/usr/bin/printf", "sent": true, - "sent-time": "2022-07-27T18:20:52.672816414+02:00", + "sent-time": "2022-08-24T12:48:32.653944225+02:00", "stderr": null, "stdout": "SGVsbG8gV29ybGQ=", "timeout": 0, - "uuid": "c4c07b0b-3b7d-f754-1d86-e6042438f498" + "uuid": "d8f859cb-a5a6-f547-9e80-ae30ddfc3ef7" }, "error": "", "message": "OK" @@ -3053,16 +3053,16 @@ var OpenAPIDefinition = ` "stderr": null, "stdout": null, "timeout": 0, - "uuid": "c4c07b0b-3b7d-f754-1d86-e6042438f498" + "uuid": "d8f859cb-a5a6-f547-9e80-ae30ddfc3ef7" }, "criticality": 0, "group": "", "hostname": "OpenHappy", "ip": "127.0.0.1", - "key": "t5hCITGliyw2iWpRbhLWCBWsORg6hBDysSjkO8LomPThkhXRrtUV7gFaLI8eyUoM", - "last-connection": "2022-07-27T16:20:51.669573134Z", - "last-detection": "2022-07-27T18:20:50.615009758+02:00", - "last-event": "2022-07-27T18:20:50.615009758+02:00", + "key": "CR7kBoCE8iNvFnbp7emRyNYMF2Ih9POtzNHkOC6iUsNURhR64NfUS22mESgBlFYr", + "last-connection": "2022-08-24T10:48:31.650949593Z", + "last-detection": "2022-08-24T12:48:30.602528676+02:00", + "last-event": "2022-08-24T12:48:30.602528676+02:00", "score": 0, "status": "", "system-info": { @@ -3946,9 +3946,9 @@ var OpenAPIDefinition = ` "Event": { "Detection": { "Actions": [], - "Criticality": 8, + "Criticality": 4, "Signature": [ - "NewAutorun" + "SuspiciousService" ] }, "EdrData": { @@ -3960,29 +3960,39 @@ var OpenAPIDefinition = ` }, "Event": { "Detection": true, - "Hash": "6edf48b18b3eefb73facc7376e8b9606de63933f", - "ReceiptTime": "2022-07-27T08:25:52.162327775Z" + "Hash": "039f9f93b6f830ecb8be3a6be503c0a679d7f765", + "ReceiptTime": "2022-08-24T10:48:28.371120128Z" } }, "EventData": { + "Ancestors": "System|C:\\Windows\\System32\\smss.exe|C:\\Windows\\System32\\smss.exe|C:\\Windows\\System32\\wininit.exe|C:\\Windows\\System32\\services.exe", "CommandLine": "\"C:\\ProgramData\\Microsoft\\Windows Defender\\Platform\\4.18.2106.6-0\\MsMpEng.exe\"", + "Company": "Microsoft Corporation", "CurrentDirectory": "C:\\Windows\\system32\\", - "Details": "\"%%ProgramFiles%%\\Windows Defender\\MSASCuiL.exe\"", - "EventType": "SetValue", + "Description": "Antimalware Service Executable", + "FileVersion": "4.18.2106.6 (WinBuild.160101.0800)", + "Hashes": "SHA1=FBF03B5D6DC1A7EDAB0BA8D4DD27291C739E5813,MD5=B1C15F9DB942B373B2FC468B7048E63F,SHA256=1DC05B6DD6281840CEB822604B0E403E499180D636D02EC08AD77B4EB56F1B9C,IMPHASH=8AA2B8727E6858A3557A4C09970B9A5D", "Image": "C:\\ProgramData\\Microsoft\\Windows Defender\\Platform\\4.18.2106.6-0\\MsMpEng.exe", - "ImageHashes": "SHA1=FBF03B5D6DC1A7EDAB0BA8D4DD27291C739E5813,MD5=B1C15F9DB942B373B2FC468B7048E63F,SHA256=1DC05B6DD6281840CEB822604B0E403E499180D636D02EC08AD77B4EB56F1B9C,IMPHASH=8AA2B8727E6858A3557A4C09970B9A5D", - "ImageSignature": "?", - "ImageSignatureStatus": "?", - "ImageSigned": "false", + "ImageSize": "136640", "IntegrityLevel": "System", + "LogonGuid": "{515cd0d1-7667-6123-e703-000000000000}", + "LogonId": "0x3E7", + "OriginalFileName": "MsMpEng.exe", + "ParentCommandLine": "C:\\Windows\\system32\\services.exe", + "ParentImage": "C:\\Windows\\System32\\services.exe", + "ParentIntegrityLevel": "System", + "ParentProcessGuid": "{515cd0d1-7666-6123-0b00-000000007300}", + "ParentProcessId": "692", + "ParentServices": "N/A", + "ParentUser": "NT AUTHORITY\\SYSTEM", "ProcessGuid": "{515cd0d1-7669-6123-4e00-000000007300}", "ProcessId": "3276", - "ProcessThreatScore": "56", + "Product": "Microsoft® Windows® Operating System", "RuleName": "-", "Services": "WinDefend", - "TargetObject": "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\WindowsDefender", + "TerminalSessionId": "0", "User": "NT AUTHORITY\\SYSTEM", - "UtcTime": "2021-08-23 10:20:26.175" + "UtcTime": "2021-08-23 10:20:25.475" }, "System": { "Channel": "Microsoft-Windows-Sysmon/Operational", @@ -3991,7 +4001,7 @@ var OpenAPIDefinition = ` "ActivityID": "", "RelatedActivityID": "" }, - "EventID": 13, + "EventID": 1, "Execution": { "ProcessID": 3220, "ThreadID": 3848 @@ -4017,7 +4027,7 @@ var OpenAPIDefinition = ` "Value": 0 }, "TimeCreated": { - "SystemTime": "2022-07-27T10:25:51.115761302+02:00" + "SystemTime": "2022-08-24T12:48:27.325122364+02:00" } } } @@ -4026,9 +4036,9 @@ var OpenAPIDefinition = ` "Event": { "Detection": { "Actions": [], - "Criticality": 8, + "Criticality": 4, "Signature": [ - "DefenderConfigChanged" + "SuspiciousService" ] }, "EdrData": { @@ -4040,27 +4050,51 @@ var OpenAPIDefinition = ` }, "Event": { "Detection": true, - "Hash": "20cd85ba5456e676316c46907efde7b71faf7706", - "ReceiptTime": "2022-07-27T08:25:52.162950825Z" + "Hash": "039f9f93b6f830ecb8be3a6be503c0a679d7f765", + "ReceiptTime": "2022-08-24T10:48:28.370602986Z" } }, "EventData": { - "New Value": "HKLM\\SOFTWARE\\Microsoft\\Windows Defender\\IsServiceRunning = 0x1", - "Old Value": "Default\\IsServiceRunning = 0x0", - "Product Name": "Windows Defender Antivirus", - "Product Version": "4.18.2106.6" + "Ancestors": "System|C:\\Windows\\System32\\smss.exe|C:\\Windows\\System32\\smss.exe|C:\\Windows\\System32\\wininit.exe|C:\\Windows\\System32\\services.exe", + "CommandLine": "\"C:\\ProgramData\\Microsoft\\Windows Defender\\Platform\\4.18.2106.6-0\\MsMpEng.exe\"", + "Company": "Microsoft Corporation", + "CurrentDirectory": "C:\\Windows\\system32\\", + "Description": "Antimalware Service Executable", + "FileVersion": "4.18.2106.6 (WinBuild.160101.0800)", + "Hashes": "SHA1=FBF03B5D6DC1A7EDAB0BA8D4DD27291C739E5813,MD5=B1C15F9DB942B373B2FC468B7048E63F,SHA256=1DC05B6DD6281840CEB822604B0E403E499180D636D02EC08AD77B4EB56F1B9C,IMPHASH=8AA2B8727E6858A3557A4C09970B9A5D", + "Image": "C:\\ProgramData\\Microsoft\\Windows Defender\\Platform\\4.18.2106.6-0\\MsMpEng.exe", + "ImageSize": "136640", + "IntegrityLevel": "System", + "LogonGuid": "{515cd0d1-7667-6123-e703-000000000000}", + "LogonId": "0x3E7", + "OriginalFileName": "MsMpEng.exe", + "ParentCommandLine": "C:\\Windows\\system32\\services.exe", + "ParentImage": "C:\\Windows\\System32\\services.exe", + "ParentIntegrityLevel": "System", + "ParentProcessGuid": "{515cd0d1-7666-6123-0b00-000000007300}", + "ParentProcessId": "692", + "ParentServices": "N/A", + "ParentUser": "NT AUTHORITY\\SYSTEM", + "ProcessGuid": "{515cd0d1-7669-6123-4e00-000000007300}", + "ProcessId": "3276", + "Product": "Microsoft® Windows® Operating System", + "RuleName": "-", + "Services": "WinDefend", + "TerminalSessionId": "0", + "User": "NT AUTHORITY\\SYSTEM", + "UtcTime": "2021-08-23 10:20:25.475" }, "System": { - "Channel": "Microsoft-Windows-Windows Defender/Operational", + "Channel": "Microsoft-Windows-Sysmon/Operational", "Computer": "DESKTOP-LJRVE06", "Correlation": { "ActivityID": "", "RelatedActivityID": "" }, - "EventID": 5007, + "EventID": 1, "Execution": { - "ProcessID": 3276, - "ThreadID": 3592 + "ProcessID": 3220, + "ThreadID": 3848 }, "Keywords": { "Name": "", @@ -4071,19 +4105,19 @@ var OpenAPIDefinition = ` "Value": 4 }, "Opcode": { - "Name": "", + "Name": "Info", "Value": 0 }, "Provider": { - "Guid": "{11CD958A-C507-4EF3-B3F2-5FD9DFBD2C78}", - "Name": "Microsoft-Windows-Windows Defender" + "Guid": "{5770385F-C22A-43E0-BF4C-06F5698FFBD9}", + "Name": "Microsoft-Windows-Sysmon" }, "Task": { "Name": "", "Value": 0 }, "TimeCreated": { - "SystemTime": "2022-07-27T10:25:51.115825869+02:00" + "SystemTime": "2022-08-24T12:48:27.325122364+02:00" } } } @@ -4209,14 +4243,14 @@ var OpenAPIDefinition = ` }, "Event": { "Detection": false, - "Hash": "c5a8e92135fbecbbfb6d631acf35be2e579450dc", - "ReceiptTime": "2022-07-27T08:25:52.156504719Z" + "Hash": "0a4077f1d13ff7d07dcc2fa4f458a63a2b950911", + "ReceiptTime": "2022-08-24T10:48:28.364112404Z" } }, "EventData": { "CommandLine": "C:\\Windows\\system32\\svchost.exe -k appmodel -p -s StateRepository", "CurrentDirectory": "C:\\Windows\\system32\\", - "Details": "Binary Data", + "Details": "S-1-15-2-2434737943-167758768-3180539153-984336765-1107280622-3591121930-2677285773", "EventType": "SetValue", "Image": "C:\\Windows\\system32\\svchost.exe", "ImageHashes": "SHA1=75C5A97F521F760E32A4A9639A653EED862E9C61,MD5=9520A99E77D6196D0D09833146424113,SHA256=DD191A5B23DF92E12A8852291F9FB5ED594B76A28A5A464418442584AFD1E048,IMPHASH=247B9220E5D9B720A82B2C8B5069AD69", @@ -4229,9 +4263,9 @@ var OpenAPIDefinition = ` "ProcessThreatScore": "0", "RuleName": "-", "Services": "StateRepository", - "TargetObject": "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModel\\StateRepository\\Cache\\Package\\Data\\1fa\\MutableLocation", + "TargetObject": "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModel\\StateRepository\\Cache\\PackageFamily\\Data\\15\\PackageSID", "User": "NT AUTHORITY\\SYSTEM", - "UtcTime": "2021-08-23 10:20:29.943" + "UtcTime": "2021-08-23 10:20:29.669" }, "System": { "Channel": "Microsoft-Windows-Sysmon/Operational", @@ -4266,7 +4300,7 @@ var OpenAPIDefinition = ` "Value": 0 }, "TimeCreated": { - "SystemTime": "2022-07-27T10:25:51.114803973+02:00" + "SystemTime": "2022-08-24T12:48:27.324288913+02:00" } } } @@ -4282,29 +4316,29 @@ var OpenAPIDefinition = ` }, "Event": { "Detection": false, - "Hash": "c0badd553bf8e9b2e8827392c42a3d5c4852b24f", - "ReceiptTime": "2022-07-27T08:25:52.156933046Z" + "Hash": "45f99356c67ddb05b3961580ddd05301c3de30d8", + "ReceiptTime": "2022-08-24T10:48:28.36456168Z" } }, "EventData": { - "CommandLine": "%%SystemRoot%%\\system32\\csrss.exe ObjectDirectory=\\Windows SharedSection=1024,20480,768 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=sxssrv,4 ProfileControl=Off MaxRequestThreads=16", + "CommandLine": "C:\\Windows\\system32\\svchost.exe -k appmodel -p -s StateRepository", "CurrentDirectory": "C:\\Windows\\system32\\", - "Details": "DWORD (0x00000000)", + "Details": "windows.protocol", "EventType": "SetValue", - "Image": "C:\\Windows\\system32\\csrss.exe", - "ImageHashes": "SHA1=2038501676866B87CEE4514CEFF77DAEA9729F30,MD5=23019322FFECB179746210BE52D6DE60,SHA256=F2C7D894ABE8AC0B4C2A597CAA6B3EFE7AD2BDB4226845798D954C5AB9C9BF15,IMPHASH=A96FA9912E09E361274AD77F1A4B252C", + "Image": "C:\\Windows\\system32\\svchost.exe", + "ImageHashes": "SHA1=75C5A97F521F760E32A4A9639A653EED862E9C61,MD5=9520A99E77D6196D0D09833146424113,SHA256=DD191A5B23DF92E12A8852291F9FB5ED594B76A28A5A464418442584AFD1E048,IMPHASH=247B9220E5D9B720A82B2C8B5069AD69", "ImageSignature": "?", "ImageSignatureStatus": "?", "ImageSigned": "false", "IntegrityLevel": "System", - "ProcessGuid": "{515cd0d1-7665-6123-0900-000000007300}", - "ProcessId": "556", + "ProcessGuid": "{515cd0d1-7668-6123-3c00-000000007300}", + "ProcessId": "2556", "ProcessThreatScore": "0", "RuleName": "-", - "Services": "N/A", - "TargetObject": "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AutoRotation\\LastOrientation", + "Services": "StateRepository", + "TargetObject": "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModel\\StateRepository\\Cache\\ApplicationExtension\\Data\\538\\Category", "User": "NT AUTHORITY\\SYSTEM", - "UtcTime": "2021-08-23 10:20:21.951" + "UtcTime": "2021-08-23 10:20:30.799" }, "System": { "Channel": "Microsoft-Windows-Sysmon/Operational", @@ -4339,7 +4373,7 @@ var OpenAPIDefinition = ` "Value": 0 }, "TimeCreated": { - "SystemTime": "2022-07-27T10:25:51.114804471+02:00" + "SystemTime": "2022-08-24T12:48:27.3242892+02:00" } } } @@ -4385,30 +4419,30 @@ var OpenAPIDefinition = ` "avg-signature-criticality": 0, "bounded-score": 0, "count-by-signature": { - "DefenderConfigChanged": 5, - "NewAutorun": 18, - "SuspiciousService": 11, - "UnknownServices": 7, - "UntrustedDriverLoaded": 9 + "DefenderConfigChanged": 4, + "NewAutorun": 19, + "SuspiciousService": 5, + "UnknownServices": 9, + "UntrustedDriverLoaded": 13 }, "count-uniq-signatures": 5, "identifier": "5a92baeb-9384-47d3-92b4-a0db6f9b8c6d", - "median-time": "2022-07-27T18:20:52.73721162+02:00", + "median-time": "2022-08-24T12:48:32.709584161+02:00", "score": 0, "signature-count": 50, "signature-criticality-metric": 0, "signature-diversity": 100, "signatures": [ + "DefenderConfigChanged", + "SuspiciousService", "UntrustedDriverLoaded", - "UnknownServices", "NewAutorun", - "SuspiciousService", - "DefenderConfigChanged" + "UnknownServices" ], - "start-time": "2022-07-27T18:20:52.735957283+02:00", + "start-time": "2022-08-24T12:48:32.708425432+02:00", "std-dev-alert-criticality": 0, "std-dev-signature-criticality": -92233720368547760, - "stop-time": "2022-07-27T18:20:52.738465958+02:00", + "stop-time": "2022-08-24T12:48:32.71074289+02:00", "sum-alert-criticality": 0, "sum-rule-criticality": 0, "tactics": null, @@ -4452,30 +4486,30 @@ var OpenAPIDefinition = ` "avg-signature-criticality": 0, "bounded-score": 0, "count-by-signature": { - "DefenderConfigChanged": 5, - "NewAutorun": 18, - "SuspiciousService": 11, - "UnknownServices": 7, - "UntrustedDriverLoaded": 9 + "DefenderConfigChanged": 4, + "NewAutorun": 19, + "SuspiciousService": 5, + "UnknownServices": 9, + "UntrustedDriverLoaded": 13 }, "count-uniq-signatures": 5, "identifier": "5a92baeb-9384-47d3-92b4-a0db6f9b8c6d", - "median-time": "2022-07-27T18:20:52.73721162+02:00", + "median-time": "2022-08-24T12:48:32.709584161+02:00", "score": 0, "signature-count": 50, "signature-criticality-metric": 0, "signature-diversity": 100, "signatures": [ - "UnknownServices", + "UntrustedDriverLoaded", "NewAutorun", - "SuspiciousService", + "UnknownServices", "DefenderConfigChanged", - "UntrustedDriverLoaded" + "SuspiciousService" ], - "start-time": "2022-07-27T18:20:52.735957283+02:00", + "start-time": "2022-08-24T12:48:32.708425432+02:00", "std-dev-alert-criticality": 0, "std-dev-signature-criticality": -92233720368547760, - "stop-time": "2022-07-27T18:20:52.738465958+02:00", + "stop-time": "2022-08-24T12:48:32.71074289+02:00", "sum-alert-criticality": 0, "sum-rule-criticality": 0, "tactics": null, @@ -4561,35 +4595,35 @@ var OpenAPIDefinition = ` { "alert-count": 50, "alert-criticality-metric": 0, - "archived-time": "2022-07-27T18:20:53.803018284+02:00", + "archived-time": "2022-08-24T12:48:33.777146389+02:00", "avg-alert-criticality": 0, "avg-signature-criticality": 0, "bounded-score": 0, "count-by-signature": { - "DefenderConfigChanged": 5, - "NewAutorun": 18, - "SuspiciousService": 11, - "UnknownServices": 7, - "UntrustedDriverLoaded": 9 + "DefenderConfigChanged": 4, + "NewAutorun": 19, + "SuspiciousService": 5, + "UnknownServices": 9, + "UntrustedDriverLoaded": 13 }, "count-uniq-signatures": 5, "identifier": "5a92baeb-9384-47d3-92b4-a0db6f9b8c6d", - "median-time": "2022-07-27T18:20:52.73721162+02:00", + "median-time": "2022-08-24T12:48:32.709584161+02:00", "score": 0, "signature-count": 50, "signature-criticality-metric": 0, "signature-diversity": 100, "signatures": [ - "UnknownServices", + "UntrustedDriverLoaded", "NewAutorun", - "SuspiciousService", + "UnknownServices", "DefenderConfigChanged", - "UntrustedDriverLoaded" + "SuspiciousService" ], - "start-time": "2022-07-27T18:20:52.735957283+02:00", + "start-time": "2022-08-24T12:48:32.708425432+02:00", "std-dev-alert-criticality": 0, "std-dev-signature-criticality": -92233720368547760, - "stop-time": "2022-07-27T18:20:52.738465958+02:00", + "stop-time": "2022-08-24T12:48:32.71074289+02:00", "sum-alert-criticality": 0, "sum-rule-criticality": 0, "tactics": null, @@ -4671,10 +4705,10 @@ var OpenAPIDefinition = ` "example": { "data": [ { - "guuid": "67f82e14-74d1-3d08-25df-12ca70576ea2", + "guuid": "871c086e-f3c7-5d12-76e6-7e109d30d648", "source": "XyzTIProvider", "type": "domain", - "uuid": "888119d0-3f5e-6cee-8cb1-4707ab7583b9", + "uuid": "e7b3aefe-f0ff-1861-55a2-bf6e693e1a06", "value": "some.random.domain" } ], @@ -4722,8 +4756,8 @@ var OpenAPIDefinition = ` }, "example": [ { - "uuid": "888119d0-3f5e-6cee-8cb1-4707ab7583b9", - "guuid": "67f82e14-74d1-3d08-25df-12ca70576ea2", + "uuid": "e7b3aefe-f0ff-1861-55a2-bf6e693e1a06", + "guuid": "871c086e-f3c7-5d12-76e6-7e109d30d648", "source": "XyzTIProvider", "value": "some.random.domain", "type": "domain" @@ -4741,10 +4775,10 @@ var OpenAPIDefinition = ` "example": { "data": [ { - "guuid": "67f82e14-74d1-3d08-25df-12ca70576ea2", + "guuid": "871c086e-f3c7-5d12-76e6-7e109d30d648", "source": "XyzTIProvider", "type": "domain", - "uuid": "888119d0-3f5e-6cee-8cb1-4707ab7583b9", + "uuid": "e7b3aefe-f0ff-1861-55a2-bf6e693e1a06", "value": "some.random.domain" } ], @@ -5241,8 +5275,8 @@ var OpenAPIDefinition = ` "description": "", "group": "", "identifier": "TestAdminUser", - "key": "G7D5TkW4XQl2Furm08Y8YHrBXVtVeB3XKoqnKbiKc3VOlhafMbzzi4LM4qkI0Cmw", - "uuid": "61cb4da0-f1d4-3fa8-794f-c42a480a3df3" + "key": "xkTKBxE6TgXPvszVUxCwmxwPE2BILBq3WNt1ex8UOooGpFfe9Ud8pFll1kURwV90", + "uuid": "54f050b8-6648-9aee-a2f4-23d51f592bee" }, "error": "", "message": "OK" @@ -5285,7 +5319,7 @@ var OpenAPIDefinition = ` } }, "example": { - "uuid": "27a57a4f-106f-5319-9f36-37f533c8e585", + "uuid": "ce3818bd-99d3-3571-6235-56fb9f0ed01f", "identifier": "SecondTestAdmin", "key": "ChangeMe", "group": "CSIRT", @@ -5306,7 +5340,7 @@ var OpenAPIDefinition = ` "group": "CSIRT", "identifier": "SecondTestAdmin", "key": "ChangeMe", - "uuid": "27a57a4f-106f-5319-9f36-37f533c8e585" + "uuid": "ce3818bd-99d3-3571-6235-56fb9f0ed01f" }, "error": "", "message": "OK" @@ -5394,7 +5428,7 @@ var OpenAPIDefinition = ` "group": "SOC", "identifier": "SecondTestAdmin", "key": "NewWeakKey", - "uuid": "27a57a4f-106f-5319-9f36-37f533c8e585" + "uuid": "ce3818bd-99d3-3571-6235-56fb9f0ed01f" }, "error": "", "message": "OK" @@ -5432,7 +5466,7 @@ var OpenAPIDefinition = ` "group": "SOC", "identifier": "SecondTestAdmin", "key": "NewWeakKey", - "uuid": "27a57a4f-106f-5319-9f36-37f533c8e585" + "uuid": "ce3818bd-99d3-3571-6235-56fb9f0ed01f" }, "error": "", "message": "OK" diff --git a/doc/admin.openapi.json b/doc/admin.openapi.json index 6a91973..3233811 100644 --- a/doc/admin.openapi.json +++ b/doc/admin.openapi.json @@ -72,10 +72,10 @@ "group": "", "hostname": "OpenHappy", "ip": "127.0.0.1", - "key": "LMOwHSiGhg1MNG57lJnlm1Pl9VuEL2nPhLg37D1M4L0DCJgnEgqQHGCYNwySoOcm", - "last-connection": "2022-07-27T16:16:22.005202458Z", - "last-detection": "2022-07-27T18:16:20.951172026+02:00", - "last-event": "2022-07-27T18:16:20.951172026+02:00", + "key": "gCx59uTlWsW9a4MX2yJOEN4NSCln3TOu58aTXJcbii5fSRvR34kmyBhN6JfbiJyw", + "last-connection": "2022-08-24T10:48:29.474420629Z", + "last-detection": "2022-08-24T12:48:28.433692184+02:00", + "last-event": "2022-08-24T12:48:28.433692184+02:00", "score": 0, "status": "", "system-info": { @@ -152,13 +152,13 @@ "group": "", "hostname": "", "ip": "", - "key": "T1CvqgGOawX0upc0RJP6544JfjJP0Sj38D4t8fYM1IXtbNaOKV5TUYwPeyMzkBKa", + "key": "8vDtCLSXvKqycbzcNj5j1lYvn0l2FmBz2YIg1WpYB6FwUSR50KDsgJxfQK6KQth3", "last-connection": "0001-01-01T00:00:00Z", "last-detection": "0001-01-01T00:00:00Z", "last-event": "0001-01-01T00:00:00Z", "score": 0, "status": "", - "uuid": "f5911ff9-704d-4b50-4a6b-f5f58bbe1a84" + "uuid": "1b98404b-b614-c91a-f351-4f8b4216838d" }, "error": "", "message": "OK" @@ -198,21 +198,21 @@ "5a92baeb-9384-47d3-92b4-a0db6f9b8c6d": [ { "base-url": "/endpoints/5a92baeb-9384-47d3-92b4-a0db6f9b8c6d/artifacts/5a92baeb-9384-47d3-92b4-a0db6f9b8c6d/3d8441643c204ba9b9dcb5c414b25a3129f66f6c/", - "creation": "2022-07-27T16:16:27.50137352Z", + "creation": "2022-08-24T10:48:34.904939052Z", "event-hash": "3d8441643c204ba9b9dcb5c414b25a3129f66f6c", "files": [ { "name": "bar.txt", "size": 4, - "timestamp": "2022-07-27T16:16:27.50137352Z" + "timestamp": "2022-08-24T10:48:34.904939052Z" }, { "name": "foo.txt", "size": 4, - "timestamp": "2022-07-27T16:16:27.50137352Z" + "timestamp": "2022-08-24T10:48:34.904939052Z" } ], - "modification": "2022-07-27T16:16:27.50137352Z", + "modification": "2022-08-24T10:48:34.904939052Z", "process-guid": "5a92baeb-9384-47d3-92b4-a0db6f9b8c6d" } ] @@ -247,29 +247,29 @@ "bounded-score": 0, "count-by-signature": { "DefenderConfigChanged": 4, - "NewAutorun": 21, - "SuspiciousService": 4, + "NewAutorun": 19, + "SuspiciousService": 5, "UnknownServices": 9, - "UntrustedDriverLoaded": 12 + "UntrustedDriverLoaded": 13 }, "count-uniq-signatures": 5, "identifier": "5a92baeb-9384-47d3-92b4-a0db6f9b8c6d", - "median-time": "2022-07-27T18:16:25.263455529+02:00", + "median-time": "2022-08-24T12:48:32.709584161+02:00", "score": 0, "signature-count": 50, "signature-criticality-metric": 0, "signature-diversity": 100, "signatures": [ - "NewAutorun", "UntrustedDriverLoaded", + "NewAutorun", "UnknownServices", - "SuspiciousService", - "DefenderConfigChanged" + "DefenderConfigChanged", + "SuspiciousService" ], - "start-time": "2022-07-27T18:16:25.261859405+02:00", + "start-time": "2022-08-24T12:48:32.708425432+02:00", "std-dev-alert-criticality": 0, "std-dev-signature-criticality": -92233720368547760, - "stop-time": "2022-07-27T18:16:25.265051653+02:00", + "stop-time": "2022-08-24T12:48:32.71074289+02:00", "sum-alert-criticality": 0, "sum-rule-criticality": 0, "tactics": null, @@ -330,7 +330,7 @@ }, "name": "osqueryi", "os": "windows", - "uuid": "c94bde56-2a28-cc0a-9f87-5ceda92b49b1" + "uuid": "2010ab6c-4bba-a535-8720-2d66feef4e90" }, "error": "", "message": "OK" @@ -397,7 +397,7 @@ }, "name": "osqueryi", "os": "windows", - "uuid": "c94bde56-2a28-cc0a-9f87-5ceda92b49b1" + "uuid": "2010ab6c-4bba-a535-8720-2d66feef4e90" }, "error": "", "message": "OK" @@ -451,7 +451,7 @@ }, "name": "osqueryi", "os": "windows", - "uuid": "c94bde56-2a28-cc0a-9f87-5ceda92b49b1" + "uuid": "2010ab6c-4bba-a535-8720-2d66feef4e90" }, "error": "", "message": "OK" @@ -507,7 +507,7 @@ }, "name": "sysmon", "os": "windows", - "uuid": "57937591-b3f4-489a-608f-24d6b5d49923" + "uuid": "c4c0a5ef-ada8-8f80-ff6c-928e70c925c2" }, "error": "", "message": "OK" @@ -574,7 +574,7 @@ }, "name": "sysmon", "os": "windows", - "uuid": "57937591-b3f4-489a-608f-24d6b5d49923" + "uuid": "c4c0a5ef-ada8-8f80-ff6c-928e70c925c2" }, "error": "", "message": "OK" @@ -628,7 +628,7 @@ }, "name": "sysmon", "os": "windows", - "uuid": "57937591-b3f4-489a-608f-24d6b5d49923" + "uuid": "c4c0a5ef-ada8-8f80-ff6c-928e70c925c2" }, "error": "", "message": "OK" @@ -1895,9 +1895,9 @@ "group": "", "hostname": "OpenHappy", "ip": "127.0.0.1", - "last-connection": "2022-07-27T16:16:22.005202458Z", - "last-detection": "2022-07-27T18:16:20.951172026+02:00", - "last-event": "2022-07-27T18:16:20.951172026+02:00", + "last-connection": "2022-08-24T10:48:29.474420629Z", + "last-detection": "2022-08-24T12:48:28.433692184+02:00", + "last-event": "2022-08-24T12:48:28.433692184+02:00", "score": 0, "status": "", "system-info": { @@ -2609,9 +2609,9 @@ "group": "New Group", "hostname": "OpenHappy", "ip": "127.0.0.1", - "last-connection": "2022-07-27T16:16:22.005202458Z", - "last-detection": "2022-07-27T18:16:20.951172026+02:00", - "last-event": "2022-07-27T18:16:20.951172026+02:00", + "last-connection": "2022-08-24T10:48:29.474420629Z", + "last-detection": "2022-08-24T12:48:28.433692184+02:00", + "last-event": "2022-08-24T12:48:28.433692184+02:00", "score": 0, "status": "New Status", "system-info": { @@ -2699,9 +2699,9 @@ "group": "New Group", "hostname": "OpenHappy", "ip": "127.0.0.1", - "last-connection": "2022-07-27T16:16:22.005202458Z", - "last-detection": "2022-07-27T18:16:20.951172026+02:00", - "last-event": "2022-07-27T18:16:20.951172026+02:00", + "last-connection": "2022-08-24T10:48:29.474420629Z", + "last-detection": "2022-08-24T12:48:28.433692184+02:00", + "last-event": "2022-08-24T12:48:28.433692184+02:00", "score": 0, "status": "New Status", "system-info": { @@ -2800,21 +2800,21 @@ "data": [ { "base-url": "/endpoints/5a92baeb-9384-47d3-92b4-a0db6f9b8c6d/artifacts/5a92baeb-9384-47d3-92b4-a0db6f9b8c6d/3d8441643c204ba9b9dcb5c414b25a3129f66f6c/", - "creation": "2022-07-27T16:16:27.50137352Z", + "creation": "2022-08-24T10:48:34.904939052Z", "event-hash": "3d8441643c204ba9b9dcb5c414b25a3129f66f6c", "files": [ { "name": "bar.txt", "size": 4, - "timestamp": "2022-07-27T16:16:27.50137352Z" + "timestamp": "2022-08-24T10:48:34.904939052Z" }, { "name": "foo.txt", "size": 4, - "timestamp": "2022-07-27T16:16:27.50137352Z" + "timestamp": "2022-08-24T10:48:34.904939052Z" } ], - "modification": "2022-07-27T16:16:27.50137352Z", + "modification": "2022-08-24T10:48:34.904939052Z", "process-guid": "5a92baeb-9384-47d3-92b4-a0db6f9b8c6d" } ], @@ -2959,11 +2959,11 @@ "json": null, "name": "/usr/bin/printf", "sent": true, - "sent-time": "2022-07-27T18:16:25.182782394+02:00", + "sent-time": "2022-08-24T12:48:32.653944225+02:00", "stderr": null, "stdout": "SGVsbG8gV29ybGQ=", "timeout": 0, - "uuid": "01bef0d3-40d1-381c-4bd6-763a54b05e8c" + "uuid": "d8f859cb-a5a6-f547-9e80-ae30ddfc3ef7" }, "error": "", "message": "OK" @@ -3051,16 +3051,16 @@ "stderr": null, "stdout": null, "timeout": 0, - "uuid": "01bef0d3-40d1-381c-4bd6-763a54b05e8c" + "uuid": "d8f859cb-a5a6-f547-9e80-ae30ddfc3ef7" }, "criticality": 0, "group": "", "hostname": "OpenHappy", "ip": "127.0.0.1", - "key": "NxIkjKFUuLsPw2TYN2hLkXoWy0hxwpxxkUsmklvMSWgJbjyqdNfgV4Y2G821HzXE", - "last-connection": "2022-07-27T16:16:24.179437494Z", - "last-detection": "2022-07-27T18:16:23.151266867+02:00", - "last-event": "2022-07-27T18:16:23.151266867+02:00", + "key": "CR7kBoCE8iNvFnbp7emRyNYMF2Ih9POtzNHkOC6iUsNURhR64NfUS22mESgBlFYr", + "last-connection": "2022-08-24T10:48:31.650949593Z", + "last-detection": "2022-08-24T12:48:30.602528676+02:00", + "last-event": "2022-08-24T12:48:30.602528676+02:00", "score": 0, "status": "", "system-info": { @@ -3191,6 +3191,16 @@ "schema": { "type": "string" } + }, + { + "name": "format", + "in": "query", + "description": "Select input and output format (allowed toml, json)", + "required": false, + "allowEmptyValue": true, + "schema": { + "type": "string" + } } ], "responses": { @@ -3295,6 +3305,16 @@ "schema": { "type": "string" } + }, + { + "name": "format", + "in": "query", + "description": "Select input and output format (allowed toml, json)", + "required": false, + "allowEmptyValue": true, + "schema": { + "type": "string" + } } ], "requestBody": { @@ -3792,6 +3812,16 @@ "schema": { "type": "string" } + }, + { + "name": "format", + "in": "query", + "description": "Select input and output format (allowed toml, json)", + "required": false, + "allowEmptyValue": true, + "schema": { + "type": "string" + } } ], "responses": { @@ -3914,9 +3944,9 @@ "Event": { "Detection": { "Actions": [], - "Criticality": 8, + "Criticality": 4, "Signature": [ - "NewAutorun" + "SuspiciousService" ] }, "EdrData": { @@ -3928,29 +3958,39 @@ }, "Event": { "Detection": true, - "Hash": "6edf48b18b3eefb73facc7376e8b9606de63933f", - "ReceiptTime": "2022-07-27T08:25:52.162327775Z" + "Hash": "039f9f93b6f830ecb8be3a6be503c0a679d7f765", + "ReceiptTime": "2022-08-24T10:48:28.371120128Z" } }, "EventData": { + "Ancestors": "System|C:\\Windows\\System32\\smss.exe|C:\\Windows\\System32\\smss.exe|C:\\Windows\\System32\\wininit.exe|C:\\Windows\\System32\\services.exe", "CommandLine": "\"C:\\ProgramData\\Microsoft\\Windows Defender\\Platform\\4.18.2106.6-0\\MsMpEng.exe\"", + "Company": "Microsoft Corporation", "CurrentDirectory": "C:\\Windows\\system32\\", - "Details": "\"%%ProgramFiles%%\\Windows Defender\\MSASCuiL.exe\"", - "EventType": "SetValue", + "Description": "Antimalware Service Executable", + "FileVersion": "4.18.2106.6 (WinBuild.160101.0800)", + "Hashes": "SHA1=FBF03B5D6DC1A7EDAB0BA8D4DD27291C739E5813,MD5=B1C15F9DB942B373B2FC468B7048E63F,SHA256=1DC05B6DD6281840CEB822604B0E403E499180D636D02EC08AD77B4EB56F1B9C,IMPHASH=8AA2B8727E6858A3557A4C09970B9A5D", "Image": "C:\\ProgramData\\Microsoft\\Windows Defender\\Platform\\4.18.2106.6-0\\MsMpEng.exe", - "ImageHashes": "SHA1=FBF03B5D6DC1A7EDAB0BA8D4DD27291C739E5813,MD5=B1C15F9DB942B373B2FC468B7048E63F,SHA256=1DC05B6DD6281840CEB822604B0E403E499180D636D02EC08AD77B4EB56F1B9C,IMPHASH=8AA2B8727E6858A3557A4C09970B9A5D", - "ImageSignature": "?", - "ImageSignatureStatus": "?", - "ImageSigned": "false", + "ImageSize": "136640", "IntegrityLevel": "System", + "LogonGuid": "{515cd0d1-7667-6123-e703-000000000000}", + "LogonId": "0x3E7", + "OriginalFileName": "MsMpEng.exe", + "ParentCommandLine": "C:\\Windows\\system32\\services.exe", + "ParentImage": "C:\\Windows\\System32\\services.exe", + "ParentIntegrityLevel": "System", + "ParentProcessGuid": "{515cd0d1-7666-6123-0b00-000000007300}", + "ParentProcessId": "692", + "ParentServices": "N/A", + "ParentUser": "NT AUTHORITY\\SYSTEM", "ProcessGuid": "{515cd0d1-7669-6123-4e00-000000007300}", "ProcessId": "3276", - "ProcessThreatScore": "56", + "Product": "Microsoft® Windows® Operating System", "RuleName": "-", "Services": "WinDefend", - "TargetObject": "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\WindowsDefender", + "TerminalSessionId": "0", "User": "NT AUTHORITY\\SYSTEM", - "UtcTime": "2021-08-23 10:20:26.175" + "UtcTime": "2021-08-23 10:20:25.475" }, "System": { "Channel": "Microsoft-Windows-Sysmon/Operational", @@ -3959,7 +3999,7 @@ "ActivityID": "", "RelatedActivityID": "" }, - "EventID": 13, + "EventID": 1, "Execution": { "ProcessID": 3220, "ThreadID": 3848 @@ -3985,7 +4025,7 @@ "Value": 0 }, "TimeCreated": { - "SystemTime": "2022-07-27T10:25:51.115761302+02:00" + "SystemTime": "2022-08-24T12:48:27.325122364+02:00" } } } @@ -3994,9 +4034,9 @@ "Event": { "Detection": { "Actions": [], - "Criticality": 8, + "Criticality": 4, "Signature": [ - "DefenderConfigChanged" + "SuspiciousService" ] }, "EdrData": { @@ -4008,27 +4048,51 @@ }, "Event": { "Detection": true, - "Hash": "20cd85ba5456e676316c46907efde7b71faf7706", - "ReceiptTime": "2022-07-27T08:25:52.162950825Z" + "Hash": "039f9f93b6f830ecb8be3a6be503c0a679d7f765", + "ReceiptTime": "2022-08-24T10:48:28.370602986Z" } }, "EventData": { - "New Value": "HKLM\\SOFTWARE\\Microsoft\\Windows Defender\\IsServiceRunning = 0x1", - "Old Value": "Default\\IsServiceRunning = 0x0", - "Product Name": "Windows Defender Antivirus", - "Product Version": "4.18.2106.6" + "Ancestors": "System|C:\\Windows\\System32\\smss.exe|C:\\Windows\\System32\\smss.exe|C:\\Windows\\System32\\wininit.exe|C:\\Windows\\System32\\services.exe", + "CommandLine": "\"C:\\ProgramData\\Microsoft\\Windows Defender\\Platform\\4.18.2106.6-0\\MsMpEng.exe\"", + "Company": "Microsoft Corporation", + "CurrentDirectory": "C:\\Windows\\system32\\", + "Description": "Antimalware Service Executable", + "FileVersion": "4.18.2106.6 (WinBuild.160101.0800)", + "Hashes": "SHA1=FBF03B5D6DC1A7EDAB0BA8D4DD27291C739E5813,MD5=B1C15F9DB942B373B2FC468B7048E63F,SHA256=1DC05B6DD6281840CEB822604B0E403E499180D636D02EC08AD77B4EB56F1B9C,IMPHASH=8AA2B8727E6858A3557A4C09970B9A5D", + "Image": "C:\\ProgramData\\Microsoft\\Windows Defender\\Platform\\4.18.2106.6-0\\MsMpEng.exe", + "ImageSize": "136640", + "IntegrityLevel": "System", + "LogonGuid": "{515cd0d1-7667-6123-e703-000000000000}", + "LogonId": "0x3E7", + "OriginalFileName": "MsMpEng.exe", + "ParentCommandLine": "C:\\Windows\\system32\\services.exe", + "ParentImage": "C:\\Windows\\System32\\services.exe", + "ParentIntegrityLevel": "System", + "ParentProcessGuid": "{515cd0d1-7666-6123-0b00-000000007300}", + "ParentProcessId": "692", + "ParentServices": "N/A", + "ParentUser": "NT AUTHORITY\\SYSTEM", + "ProcessGuid": "{515cd0d1-7669-6123-4e00-000000007300}", + "ProcessId": "3276", + "Product": "Microsoft® Windows® Operating System", + "RuleName": "-", + "Services": "WinDefend", + "TerminalSessionId": "0", + "User": "NT AUTHORITY\\SYSTEM", + "UtcTime": "2021-08-23 10:20:25.475" }, "System": { - "Channel": "Microsoft-Windows-Windows Defender/Operational", + "Channel": "Microsoft-Windows-Sysmon/Operational", "Computer": "DESKTOP-LJRVE06", "Correlation": { "ActivityID": "", "RelatedActivityID": "" }, - "EventID": 5007, + "EventID": 1, "Execution": { - "ProcessID": 3276, - "ThreadID": 3592 + "ProcessID": 3220, + "ThreadID": 3848 }, "Keywords": { "Name": "", @@ -4039,19 +4103,19 @@ "Value": 4 }, "Opcode": { - "Name": "", + "Name": "Info", "Value": 0 }, "Provider": { - "Guid": "{11CD958A-C507-4EF3-B3F2-5FD9DFBD2C78}", - "Name": "Microsoft-Windows-Windows Defender" + "Guid": "{5770385F-C22A-43E0-BF4C-06F5698FFBD9}", + "Name": "Microsoft-Windows-Sysmon" }, "Task": { "Name": "", "Value": 0 }, "TimeCreated": { - "SystemTime": "2022-07-27T10:25:51.115825869+02:00" + "SystemTime": "2022-08-24T12:48:27.325122364+02:00" } } } @@ -4177,14 +4241,14 @@ }, "Event": { "Detection": false, - "Hash": "c5a8e92135fbecbbfb6d631acf35be2e579450dc", - "ReceiptTime": "2022-07-27T08:25:52.156504719Z" + "Hash": "0a4077f1d13ff7d07dcc2fa4f458a63a2b950911", + "ReceiptTime": "2022-08-24T10:48:28.364112404Z" } }, "EventData": { "CommandLine": "C:\\Windows\\system32\\svchost.exe -k appmodel -p -s StateRepository", "CurrentDirectory": "C:\\Windows\\system32\\", - "Details": "Binary Data", + "Details": "S-1-15-2-2434737943-167758768-3180539153-984336765-1107280622-3591121930-2677285773", "EventType": "SetValue", "Image": "C:\\Windows\\system32\\svchost.exe", "ImageHashes": "SHA1=75C5A97F521F760E32A4A9639A653EED862E9C61,MD5=9520A99E77D6196D0D09833146424113,SHA256=DD191A5B23DF92E12A8852291F9FB5ED594B76A28A5A464418442584AFD1E048,IMPHASH=247B9220E5D9B720A82B2C8B5069AD69", @@ -4197,9 +4261,9 @@ "ProcessThreatScore": "0", "RuleName": "-", "Services": "StateRepository", - "TargetObject": "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModel\\StateRepository\\Cache\\Package\\Data\\1fa\\MutableLocation", + "TargetObject": "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModel\\StateRepository\\Cache\\PackageFamily\\Data\\15\\PackageSID", "User": "NT AUTHORITY\\SYSTEM", - "UtcTime": "2021-08-23 10:20:29.943" + "UtcTime": "2021-08-23 10:20:29.669" }, "System": { "Channel": "Microsoft-Windows-Sysmon/Operational", @@ -4234,7 +4298,7 @@ "Value": 0 }, "TimeCreated": { - "SystemTime": "2022-07-27T10:25:51.114803973+02:00" + "SystemTime": "2022-08-24T12:48:27.324288913+02:00" } } } @@ -4250,29 +4314,29 @@ }, "Event": { "Detection": false, - "Hash": "c0badd553bf8e9b2e8827392c42a3d5c4852b24f", - "ReceiptTime": "2022-07-27T08:25:52.156933046Z" + "Hash": "45f99356c67ddb05b3961580ddd05301c3de30d8", + "ReceiptTime": "2022-08-24T10:48:28.36456168Z" } }, "EventData": { - "CommandLine": "%%SystemRoot%%\\system32\\csrss.exe ObjectDirectory=\\Windows SharedSection=1024,20480,768 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=sxssrv,4 ProfileControl=Off MaxRequestThreads=16", + "CommandLine": "C:\\Windows\\system32\\svchost.exe -k appmodel -p -s StateRepository", "CurrentDirectory": "C:\\Windows\\system32\\", - "Details": "DWORD (0x00000000)", + "Details": "windows.protocol", "EventType": "SetValue", - "Image": "C:\\Windows\\system32\\csrss.exe", - "ImageHashes": "SHA1=2038501676866B87CEE4514CEFF77DAEA9729F30,MD5=23019322FFECB179746210BE52D6DE60,SHA256=F2C7D894ABE8AC0B4C2A597CAA6B3EFE7AD2BDB4226845798D954C5AB9C9BF15,IMPHASH=A96FA9912E09E361274AD77F1A4B252C", + "Image": "C:\\Windows\\system32\\svchost.exe", + "ImageHashes": "SHA1=75C5A97F521F760E32A4A9639A653EED862E9C61,MD5=9520A99E77D6196D0D09833146424113,SHA256=DD191A5B23DF92E12A8852291F9FB5ED594B76A28A5A464418442584AFD1E048,IMPHASH=247B9220E5D9B720A82B2C8B5069AD69", "ImageSignature": "?", "ImageSignatureStatus": "?", "ImageSigned": "false", "IntegrityLevel": "System", - "ProcessGuid": "{515cd0d1-7665-6123-0900-000000007300}", - "ProcessId": "556", + "ProcessGuid": "{515cd0d1-7668-6123-3c00-000000007300}", + "ProcessId": "2556", "ProcessThreatScore": "0", "RuleName": "-", - "Services": "N/A", - "TargetObject": "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AutoRotation\\LastOrientation", + "Services": "StateRepository", + "TargetObject": "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModel\\StateRepository\\Cache\\ApplicationExtension\\Data\\538\\Category", "User": "NT AUTHORITY\\SYSTEM", - "UtcTime": "2021-08-23 10:20:21.951" + "UtcTime": "2021-08-23 10:20:30.799" }, "System": { "Channel": "Microsoft-Windows-Sysmon/Operational", @@ -4307,7 +4371,7 @@ "Value": 0 }, "TimeCreated": { - "SystemTime": "2022-07-27T10:25:51.114804471+02:00" + "SystemTime": "2022-08-24T12:48:27.3242892+02:00" } } } @@ -4354,29 +4418,29 @@ "bounded-score": 0, "count-by-signature": { "DefenderConfigChanged": 4, - "NewAutorun": 21, - "SuspiciousService": 4, + "NewAutorun": 19, + "SuspiciousService": 5, "UnknownServices": 9, - "UntrustedDriverLoaded": 12 + "UntrustedDriverLoaded": 13 }, "count-uniq-signatures": 5, "identifier": "5a92baeb-9384-47d3-92b4-a0db6f9b8c6d", - "median-time": "2022-07-27T18:16:25.263455529+02:00", + "median-time": "2022-08-24T12:48:32.709584161+02:00", "score": 0, "signature-count": 50, "signature-criticality-metric": 0, "signature-diversity": 100, "signatures": [ - "UnknownServices", - "SuspiciousService", "DefenderConfigChanged", + "SuspiciousService", + "UntrustedDriverLoaded", "NewAutorun", - "UntrustedDriverLoaded" + "UnknownServices" ], - "start-time": "2022-07-27T18:16:25.261859405+02:00", + "start-time": "2022-08-24T12:48:32.708425432+02:00", "std-dev-alert-criticality": 0, "std-dev-signature-criticality": -92233720368547760, - "stop-time": "2022-07-27T18:16:25.265051653+02:00", + "stop-time": "2022-08-24T12:48:32.71074289+02:00", "sum-alert-criticality": 0, "sum-rule-criticality": 0, "tactics": null, @@ -4421,29 +4485,29 @@ "bounded-score": 0, "count-by-signature": { "DefenderConfigChanged": 4, - "NewAutorun": 21, - "SuspiciousService": 4, + "NewAutorun": 19, + "SuspiciousService": 5, "UnknownServices": 9, - "UntrustedDriverLoaded": 12 + "UntrustedDriverLoaded": 13 }, "count-uniq-signatures": 5, "identifier": "5a92baeb-9384-47d3-92b4-a0db6f9b8c6d", - "median-time": "2022-07-27T18:16:25.263455529+02:00", + "median-time": "2022-08-24T12:48:32.709584161+02:00", "score": 0, "signature-count": 50, "signature-criticality-metric": 0, "signature-diversity": 100, "signatures": [ - "NewAutorun", "UntrustedDriverLoaded", + "NewAutorun", "UnknownServices", - "SuspiciousService", - "DefenderConfigChanged" + "DefenderConfigChanged", + "SuspiciousService" ], - "start-time": "2022-07-27T18:16:25.261859405+02:00", + "start-time": "2022-08-24T12:48:32.708425432+02:00", "std-dev-alert-criticality": 0, "std-dev-signature-criticality": -92233720368547760, - "stop-time": "2022-07-27T18:16:25.265051653+02:00", + "stop-time": "2022-08-24T12:48:32.71074289+02:00", "sum-alert-criticality": 0, "sum-rule-criticality": 0, "tactics": null, @@ -4529,35 +4593,35 @@ { "alert-count": 50, "alert-criticality-metric": 0, - "archived-time": "2022-07-27T18:16:26.338676919+02:00", + "archived-time": "2022-08-24T12:48:33.777146389+02:00", "avg-alert-criticality": 0, "avg-signature-criticality": 0, "bounded-score": 0, "count-by-signature": { "DefenderConfigChanged": 4, - "NewAutorun": 21, - "SuspiciousService": 4, + "NewAutorun": 19, + "SuspiciousService": 5, "UnknownServices": 9, - "UntrustedDriverLoaded": 12 + "UntrustedDriverLoaded": 13 }, "count-uniq-signatures": 5, "identifier": "5a92baeb-9384-47d3-92b4-a0db6f9b8c6d", - "median-time": "2022-07-27T18:16:25.263455529+02:00", + "median-time": "2022-08-24T12:48:32.709584161+02:00", "score": 0, "signature-count": 50, "signature-criticality-metric": 0, "signature-diversity": 100, "signatures": [ - "NewAutorun", "UntrustedDriverLoaded", + "NewAutorun", "UnknownServices", - "SuspiciousService", - "DefenderConfigChanged" + "DefenderConfigChanged", + "SuspiciousService" ], - "start-time": "2022-07-27T18:16:25.261859405+02:00", + "start-time": "2022-08-24T12:48:32.708425432+02:00", "std-dev-alert-criticality": 0, "std-dev-signature-criticality": -92233720368547760, - "stop-time": "2022-07-27T18:16:25.265051653+02:00", + "stop-time": "2022-08-24T12:48:32.71074289+02:00", "sum-alert-criticality": 0, "sum-rule-criticality": 0, "tactics": null, @@ -4639,10 +4703,10 @@ "example": { "data": [ { - "guuid": "051252a8-8a81-e2ed-0244-9c691b39a457", + "guuid": "871c086e-f3c7-5d12-76e6-7e109d30d648", "source": "XyzTIProvider", "type": "domain", - "uuid": "3cb28ad5-0dea-60be-ee0f-a4780ad6cdf9", + "uuid": "e7b3aefe-f0ff-1861-55a2-bf6e693e1a06", "value": "some.random.domain" } ], @@ -4690,8 +4754,8 @@ }, "example": [ { - "uuid": "3cb28ad5-0dea-60be-ee0f-a4780ad6cdf9", - "guuid": "051252a8-8a81-e2ed-0244-9c691b39a457", + "uuid": "e7b3aefe-f0ff-1861-55a2-bf6e693e1a06", + "guuid": "871c086e-f3c7-5d12-76e6-7e109d30d648", "source": "XyzTIProvider", "value": "some.random.domain", "type": "domain" @@ -4709,10 +4773,10 @@ "example": { "data": [ { - "guuid": "051252a8-8a81-e2ed-0244-9c691b39a457", + "guuid": "871c086e-f3c7-5d12-76e6-7e109d30d648", "source": "XyzTIProvider", "type": "domain", - "uuid": "3cb28ad5-0dea-60be-ee0f-a4780ad6cdf9", + "uuid": "e7b3aefe-f0ff-1861-55a2-bf6e693e1a06", "value": "some.random.domain" } ], @@ -5209,8 +5273,8 @@ "description": "", "group": "", "identifier": "TestAdminUser", - "key": "xMcwCEYVJXnRohnXOUn4MEl0N3PWI2o1TwF8PK4TPyktkVK8h600SKSBWBt6lkle", - "uuid": "fdf82040-77ea-a86b-a3fc-278d434d9ca6" + "key": "xkTKBxE6TgXPvszVUxCwmxwPE2BILBq3WNt1ex8UOooGpFfe9Ud8pFll1kURwV90", + "uuid": "54f050b8-6648-9aee-a2f4-23d51f592bee" }, "error": "", "message": "OK" @@ -5253,7 +5317,7 @@ } }, "example": { - "uuid": "774d4102-5671-bf6f-7e5e-73afad8ce299", + "uuid": "ce3818bd-99d3-3571-6235-56fb9f0ed01f", "identifier": "SecondTestAdmin", "key": "ChangeMe", "group": "CSIRT", @@ -5274,7 +5338,7 @@ "group": "CSIRT", "identifier": "SecondTestAdmin", "key": "ChangeMe", - "uuid": "774d4102-5671-bf6f-7e5e-73afad8ce299" + "uuid": "ce3818bd-99d3-3571-6235-56fb9f0ed01f" }, "error": "", "message": "OK" @@ -5362,7 +5426,7 @@ "group": "SOC", "identifier": "SecondTestAdmin", "key": "NewWeakKey", - "uuid": "774d4102-5671-bf6f-7e5e-73afad8ce299" + "uuid": "ce3818bd-99d3-3571-6235-56fb9f0ed01f" }, "error": "", "message": "OK" @@ -5400,7 +5464,7 @@ "group": "SOC", "identifier": "SecondTestAdmin", "key": "NewWeakKey", - "uuid": "774d4102-5671-bf6f-7e5e-73afad8ce299" + "uuid": "ce3818bd-99d3-3571-6235-56fb9f0ed01f" }, "error": "", "message": "OK" diff --git a/event/event.go b/event/event.go index 40610f6..af6830e 100644 --- a/event/event.go +++ b/event/event.go @@ -47,7 +47,7 @@ func (e *EdrEvent) Hash() string { tmp := *e // null out EdrData as it does not come into hash calculation tmp.Event.EdrData = nil - return utils.HashEventBytes(utils.JsonOrPanic(tmp)) + return utils.Sha1EventBytes(utils.JsonOrPanic(tmp)) } func (e *EdrEvent) GetStringOr(p *engine.XPath, or string) string { diff --git a/go.mod b/go.mod index 0cb0562..2d6431b 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ module github.com/0xrawsec/whids require ( - github.com/0xrawsec/crony v1.0.1 + github.com/0xrawsec/crony v1.0.2 github.com/0xrawsec/gene/v2 v2.3.0 github.com/0xrawsec/golang-etw v1.5.3 github.com/0xrawsec/golang-utils v1.3.2 diff --git a/go.sum b/go.sum index 205741b..906c7a4 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/0xrawsec/crony v1.0.1 h1:DpkkcuvFYEgHyrm0CxeVYPxsRmEO2qX043s3SDTHaH8= github.com/0xrawsec/crony v1.0.1/go.mod h1:4MUBMHBeM5HKSUIDXYU7nkmny/pUBHXqg5ZXXC9coe0= +github.com/0xrawsec/crony v1.0.2 h1:MMAGXy/11MmXvfGOFmUmjSCrxDp0usrEMxOJqXApbmw= +github.com/0xrawsec/crony v1.0.2/go.mod h1:4MUBMHBeM5HKSUIDXYU7nkmny/pUBHXqg5ZXXC9coe0= github.com/0xrawsec/gene/v2 v2.3.0 h1:AuScsQ/PlD8DwPzIaJmRuhDB1SgGnKZaKBB95mih0Sc= github.com/0xrawsec/gene/v2 v2.3.0/go.mod h1:Ns5p9jwmvCAAmzIBSMOL5hhMIlszxTXqVxBdJU/jm/w= github.com/0xrawsec/golang-etw v1.5.1 h1:+d/n98k2jbcxVtPNddNDG8uLgnGgUeeEQIPqqEwpYq8= diff --git a/utilities/manager/whids-man.go b/utilities/manager/whids-man.go index 517bd02..e8f7028 100644 --- a/utilities/manager/whids-man.go +++ b/utilities/manager/whids-man.go @@ -1,24 +1,14 @@ package main import ( - "crypto/ecdsa" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" "flag" "fmt" "io" - "io/ioutil" - "math/big" - "net" "os" "os/signal" "path/filepath" "time" - "github.com/0xrawsec/golang-utils/crypto/data" "github.com/0xrawsec/golang-utils/log" "github.com/0xrawsec/whids/api" "github.com/0xrawsec/whids/api/server" @@ -60,127 +50,22 @@ var ( ) /////////////////////////// generate_cert.go /////////////////////////////////// -func publicKey(priv interface{}) interface{} { - switch k := priv.(type) { - case *rsa.PrivateKey: - return &k.PublicKey - case *ecdsa.PrivateKey: - return &k.PublicKey - default: - return nil - } -} - -func pemBlockForKey(priv interface{}) *pem.Block { - switch k := priv.(type) { - case *rsa.PrivateKey: - return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)} - case *ecdsa.PrivateKey: - b, err := x509.MarshalECPrivateKey(k) - if err != nil { - fmt.Fprintf(os.Stderr, "Unable to marshal ECDSA private key: %v", err) - os.Exit(2) - } - return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} - default: - return nil - } -} - -func generateCert(hosts []string) error { - if len(hosts) == 0 { - return fmt.Errorf("missing required --host parameter") - } - - var priv interface{} - var err error - - // generate RSA key - priv, err = rsa.GenerateKey(rand.Reader, 4096) - - if err != nil { - return fmt.Errorf("failed to generate private key: %s", err) - } - - notBefore := time.Now() - notAfter := notBefore.Add(defaultCertValidity) - - serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) - serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) - - if err != nil { - return fmt.Errorf("failed to generate serial number: %s", err) - } - - template := x509.Certificate{ - SerialNumber: serialNumber, - Subject: pkix.Name{ - Organization: []string{defaultOrg}, - }, - NotBefore: notBefore, - NotAfter: notAfter, - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - } - for _, h := range hosts { - if ip := net.ParseIP(h); ip != nil { - template.IPAddresses = append(template.IPAddresses, ip) - } else { - template.DNSNames = append(template.DNSNames, h) - } - } +func generateCert(hosts []string) (err error) { + var key, cert []byte - derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv) - - if err != nil { - return fmt.Errorf("failed to create certificate: %s", err) - } - - certOut, err := os.OpenFile("cert.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) - if err != nil { - return fmt.Errorf("failed to open cert.pem for writing: %s", err) - } - - pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) - - certOut.Close() - - log.Info("Written cert.pem") - - keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) - - if err != nil { - return fmt.Errorf("failed to open key.pem for writing: %s", err) - } - - pem.Encode(keyOut, pemBlockForKey(priv)) - - keyOut.Close() - - log.Info("Written key.pem") - return nil -} - -func computeFingerprint(certPath string) (fingerprint string, err error) { - pemBytes, err := ioutil.ReadFile(certPath) - if err != nil { + if key, cert, err = utils.GenerateCert(defaultOrg, hosts, defaultCertValidity); err != nil { return } - block, _ := pem.Decode(pemBytes) - - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { + if err = utils.HidsWriteData("key.pem", key); err != nil { return } - der, err := x509.MarshalPKIXPublicKey(cert.PublicKey) - if err != nil { + if err = utils.HidsWriteData("cert.pem", cert); err != nil { return } - fingerprint = data.Sha256(der) + return } @@ -229,7 +114,7 @@ func main() { } if fingerprint != "" { - fing, err := computeFingerprint(fingerprint) + fing, err := utils.CertFileSha256(fingerprint) if err != nil { log.Abort(exitFail, fmt.Errorf("failed at computing fingerprint: %s", err)) } diff --git a/utilities/whids/main.go b/utilities/whids/main.go index 576eba1..467a919 100644 --- a/utilities/whids/main.go +++ b/utilities/whids/main.go @@ -65,7 +65,7 @@ var ( flagRestore bool flagAutologger bool - hostIDS *agent.Agent + edrAgent *agent.Agent importRules string @@ -128,18 +128,18 @@ func runHids(service bool) { log.Infof("Running HIDS as Windows service: %t", service) - hidsConf, err = config.LoadsHIDSConfig(configFile) + hidsConf, err = config.LoadAgentConfig(configFile) if err != nil { log.Abort(exitFail, fmt.Errorf("failed to load configuration: %s", err)) } - hostIDS, err = agent.NewAgent(&hidsConf) + edrAgent, err = agent.NewAgent(&hidsConf) if err != nil { log.Abort(exitFail, fmt.Errorf("failed to create HIDS: %s", err)) } - hostIDS.DryRun = flagDryRun - hostIDS.PrintAll = flagPrintAll + edrAgent.DryRun = flagDryRun + edrAgent.PrintAll = flagPrintAll // If not a service we need to be able to stop the HIDS if !service { @@ -149,14 +149,14 @@ func runHids(service bool) { <-osSignals log.Infof("Received SIGINT") // runs stop on sigint - hostIDS.Stop() + edrAgent.Stop() }() } // Runs HIDS and wait for the output - hostIDS.Run() + edrAgent.Run() if !service { - hostIDS.Wait() + edrAgent.Wait() } } @@ -232,7 +232,7 @@ func main() { } } - conf, err := config.LoadsHIDSConfig(configFile) + conf, err := config.LoadAgentConfig(configFile) if err != nil { log.Errorf("failed to load configuration: %s", err) os.Exit(exitFail) @@ -258,7 +258,7 @@ func main() { rc := exitSuccess - if conf, err = config.LoadsHIDSConfig(configFile); err == nil { + if conf, err = config.LoadAgentConfig(configFile); err == nil { cleanCanaries(&conf) } else { log.Errorf("failed to load configuration: %s", err) @@ -301,7 +301,7 @@ func main() { log.InitLogger(log.LDebug) } - hidsConf, err := config.LoadsHIDSConfig(configFile) + hidsConf, err := config.LoadAgentConfig(configFile) if err != nil { log.Abort(exitFail, fmt.Sprintf("failed to load configuration: %s", err)) } @@ -357,6 +357,6 @@ func main() { return } else { runHids(false) - hostIDS.LogStats() + edrAgent.LogStats() } } diff --git a/utilities/whids/service.go b/utilities/whids/service.go index e20396d..f66275b 100644 --- a/utilities/whids/service.go +++ b/utilities/whids/service.go @@ -17,10 +17,8 @@ func (m *WhidsService) Execute(args []string, r <-chan svc.ChangeRequest, change runHids(true) changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted} + loop: - /*for { - select { - case c := <-r:*/ for c := range r { switch c.Cmd { case svc.Interrogate: @@ -28,13 +26,13 @@ loop: case svc.Stop: changes <- svc.Status{State: svc.StopPending} // Stop WHIDS there - hostIDS.Stop() - hostIDS.Wait() - hostIDS.LogStats() + edrAgent.Stop() + edrAgent.Wait() + edrAgent.LogStats() break loop } - // } } + changes <- svc.Status{State: svc.Stopped} return } diff --git a/utils/crypto.go b/utils/crypto.go new file mode 100644 index 0000000..5269b1a --- /dev/null +++ b/utils/crypto.go @@ -0,0 +1,152 @@ +package utils + +import ( + "bytes" + "crypto/ecdsa" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "fmt" + "io" + "io/ioutil" + "math/big" + "net" + "os" + "time" + + "github.com/0xrawsec/golang-utils/crypto/data" +) + +func publicKey(priv interface{}) interface{} { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &k.PublicKey + case *ecdsa.PrivateKey: + return &k.PublicKey + default: + return nil + } +} + +func pemBlockForKey(priv interface{}) *pem.Block { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)} + case *ecdsa.PrivateKey: + b, err := x509.MarshalECPrivateKey(k) + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to marshal ECDSA private key: %v", err) + os.Exit(2) + } + return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} + default: + return nil + } +} + +func GenerateCert(org string, hosts []string, validity time.Duration) (key, cert []byte, err error) { + var priv interface{} + + if len(hosts) == 0 { + err = fmt.Errorf("no host specified") + return + } + + // generate RSA key + priv, err = rsa.GenerateKey(rand.Reader, 4096) + + if err != nil { + err = fmt.Errorf("failed to generate private key: %s", err) + return + } + + notBefore := time.Now() + notAfter := notBefore.Add(validity) + + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + + if err != nil { + err = fmt.Errorf("failed to generate serial number: %s", err) + return + } + + template := x509.Certificate{ + SerialNumber: serialNumber, + Subject: pkix.Name{ + Organization: []string{org}, + }, + NotBefore: notBefore, + NotAfter: notAfter, + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + for _, h := range hosts { + if ip := net.ParseIP(h); ip != nil { + template.IPAddresses = append(template.IPAddresses, ip) + } else { + template.DNSNames = append(template.DNSNames, h) + } + } + + derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv) + + if err != nil { + err = fmt.Errorf("failed to create certificate: %s", err) + return + } + + certOut := new(bytes.Buffer) + + if err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { + return + } + + cert = certOut.Bytes() + + keyOut := new(bytes.Buffer) + + if err = pem.Encode(keyOut, pemBlockForKey(priv)); err != nil { + return + } + + key = keyOut.Bytes() + + return +} + +func CertFileSha256(certPath string) (fingerprint string, err error) { + var certFd *os.File + + if certFd, err = os.Open(certPath); err != nil { + return + } + + fingerprint, err = CertSha256(certFd) + return +} + +func CertSha256(r io.Reader) (fingerprint string, err error) { + pemBytes, err := ioutil.ReadAll(r) + if err != nil { + return + } + + block, _ := pem.Decode(pemBytes) + + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return + } + + der, err := x509.MarshalPKIXPublicKey(cert.PublicKey) + if err != nil { + return + } + fingerprint = data.Sha256(der) + return +} diff --git a/utils/utils.go b/utils/utils.go index 1713ca8..289f834 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -103,21 +103,40 @@ func Sha256StringArray(array []string) string { return hex.EncodeToString(sha256.Sum(nil)) } +func toBytes(i any) (b []byte, err error) { + if b, err = json.Marshal(i); err != nil { + return + } + + b = bytes.Trim(b, " \n\r\t") + return +} + // HashEventBytes return a hash from a byte slice assuming // the event has been JSON encoded with the json.Marshal -func HashEventBytes(b []byte) string { +func Sha1EventBytes(b []byte) string { return data.Sha1(bytes.Trim(b, " \n\r\t")) } -// HashInterface return a sha1 hash from an interface -func HashInterface(i interface{}) (h string, err error) { +// Sha1Interface return a sha1 hash from an interface +func Sha1Interface(i interface{}) (h string, err error) { var b []byte - if b, err = json.Marshal(i); err != nil { + if b, err = toBytes(i); err != nil { + return + } + + return data.Sha1(b), nil +} + +func Sha256Interface(i interface{}) (h string, err error) { + var b []byte + + if b, err = toBytes(i); err != nil { return } - return data.Sha1(bytes.Trim(b, " \n\r\t")), nil + return data.Sha256(b), nil } func GetCurFuncName() string {