mirror of
https://github.com/FourCoreLabs/EDRHunt
synced 2026-08-09 12:06:42 +00:00
Merge pull request #4 from FourCoreLabs/fix-remove-struct
refactor: remove EDRHunt structure; doc: add comments for various functions; move scanners global to pkg/edrRecon
This commit is contained in:
+7
-16
@@ -14,17 +14,8 @@ var (
|
||||
services bool
|
||||
registry bool
|
||||
all bool
|
||||
versionStr string = "1.0"
|
||||
versionStr string = "1.1"
|
||||
versionCheck bool
|
||||
recon edrRecon.EdrHunt
|
||||
scanners = []edrRecon.EDRDetection{
|
||||
&edrRecon.WinDefenderDetection{},
|
||||
&edrRecon.KaskperskyDetection{},
|
||||
&edrRecon.CrowdstrikeDetection{},
|
||||
&edrRecon.CylanceDetection{},
|
||||
&edrRecon.McafeeDetection{},
|
||||
&edrRecon.SymantecDetection{},
|
||||
}
|
||||
)
|
||||
|
||||
func printBanner() {
|
||||
@@ -57,25 +48,25 @@ func edrCommand(cmd *cobra.Command, args []string) {
|
||||
|
||||
if processes {
|
||||
fmt.Println("[PROCESSES]")
|
||||
summary, _ := recon.CheckProcesses()
|
||||
summary, _ := edrRecon.CheckProcesses()
|
||||
printProcess(summary)
|
||||
fmt.Println()
|
||||
}
|
||||
if drivers {
|
||||
fmt.Println("[DRIVERS]")
|
||||
summary, _ := recon.CheckDrivers()
|
||||
summary, _ := edrRecon.CheckDrivers()
|
||||
printDrivers(summary)
|
||||
fmt.Println()
|
||||
}
|
||||
if services {
|
||||
fmt.Println("[SERVICES]")
|
||||
summary, _ := recon.CheckServices()
|
||||
summary, _ := edrRecon.CheckServices()
|
||||
printServices(summary)
|
||||
fmt.Println()
|
||||
}
|
||||
if registry {
|
||||
fmt.Println("[REGISTRY]")
|
||||
summary, _ := recon.CheckRegistry()
|
||||
summary, _ := edrRecon.CheckRegistry()
|
||||
printRegistry(summary)
|
||||
fmt.Println()
|
||||
}
|
||||
@@ -87,9 +78,9 @@ func versionCommand(cmd *cobra.Command, args []string) {
|
||||
|
||||
func scanEDRCommand(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("[EDR]")
|
||||
systemData, _ := recon.GetSystemData()
|
||||
systemData, _ := edrRecon.GetSystemData()
|
||||
|
||||
for _, scanner := range scanners {
|
||||
for _, scanner := range edrRecon.Scanners {
|
||||
_, ok := scanner.Detect(systemData)
|
||||
if ok {
|
||||
fmt.Printf("Detected EDR: %s\n", scanner.Name())
|
||||
|
||||
@@ -2,6 +2,6 @@ package edrRecon
|
||||
|
||||
import "fmt"
|
||||
|
||||
func (edr *EdrHunt) CheckDirectory() (string, error) {
|
||||
func CheckDirectory() (string, error) {
|
||||
return "", fmt.Errorf("directory scan is not implemented: unnecessarily slow, genrates false positives, also, monitoring command line so, reduntant, again")
|
||||
}
|
||||
|
||||
@@ -231,8 +231,8 @@ func AnalyzeDriver(driverFileName string, driverBaseName string) (DriverMetaData
|
||||
return DriverMetaData{ScanMatch: make([]string, 0)}, err
|
||||
}
|
||||
|
||||
func (edr *EdrHunt) CheckDrivers() ([]DriverMetaData, error) {
|
||||
|
||||
// CheckDrivers return a list of drivers matching any suspicious driver names present in edrdata.go.
|
||||
func CheckDrivers() ([]DriverMetaData, error) {
|
||||
sizeOfDriverArrayInBytes, err := GetSizeOfDriversArray()
|
||||
if err != nil {
|
||||
return []DriverMetaData{}, err
|
||||
|
||||
@@ -8,8 +8,6 @@ type Recon interface {
|
||||
CheckDirectory() (string, error)
|
||||
}
|
||||
|
||||
type EdrHunt struct{}
|
||||
|
||||
type FileMetaData struct {
|
||||
ProductName string
|
||||
OriginalFilename string
|
||||
|
||||
@@ -6,11 +6,9 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var recon EdrHunt
|
||||
|
||||
func TestCheckDrivers(t *testing.T) {
|
||||
|
||||
summary, err := recon.CheckDrivers()
|
||||
summary, err := CheckDrivers()
|
||||
for _, driver := range summary {
|
||||
output := fmt.Sprintf("\nSuspicious Driver Module: %s\nDriver FilePath: %s\nDriver File Metadata: %s\nMatched Keyword: %s\n", driver.DriverBaseName, driver.DriverFilePath, FileMetaDataParser(driver.DriverSysMetaData), driver.ScanMatch)
|
||||
fmt.Println(output)
|
||||
@@ -21,7 +19,7 @@ func TestCheckDrivers(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCheckRegistry(t *testing.T) {
|
||||
summary, err := recon.CheckRegistry()
|
||||
summary, err := CheckRegistry()
|
||||
fmt.Println("Scanning registry: ")
|
||||
for _, match := range summary.ScanMatch {
|
||||
fmt.Printf("\t%s\n", match)
|
||||
@@ -33,7 +31,7 @@ func TestCheckRegistry(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCheckServices(t *testing.T) {
|
||||
summary, err := recon.CheckServices()
|
||||
summary, err := CheckServices()
|
||||
for _, service := range summary {
|
||||
output := fmt.Sprintf("\nSuspicious Service Name: %s\nDisplay Name: %s\nDescription: %s\nCaption: %s\nCommandLine: %s\nStatus: %s\nProcessID: %s\nFile Metadata: %s\nMatched Keyword: %s\n", service.ServiceName, service.ServiceDisplayName, service.ServiceDescription, service.ServiceCaption, service.ServicePathName, service.ServiceState, service.ServiceProcessId, FileMetaDataParser(service.ServiceExeMetaData), service.ScanMatch)
|
||||
fmt.Println(output)
|
||||
@@ -44,7 +42,7 @@ func TestCheckServices(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCheckProcesses(t *testing.T) {
|
||||
summary, err := recon.CheckProcesses()
|
||||
summary, err := CheckProcesses()
|
||||
for _, process := range summary {
|
||||
output := fmt.Sprintf("\nSuspicious Process Name: %s\nDescription: %s\nCaption: %s\nBinary: %s\nProcessID: %s\nParent Process: %s\nProcess CmdLine : %s\nFile Metadata: %s\nMatched Keyword: %s\n", process.ProcessName, process.ProcessDescription, process.ProcessCaption, process.ProcessPath, process.ProcessPID, process.ProcessParentPID, process.ProcessCmdLine, FileMetaDataParser(process.ProcessExeMetaData), process.ScanMatch)
|
||||
fmt.Println(output)
|
||||
@@ -64,7 +62,7 @@ func TestGetFileMetaData(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGetDirectory(t *testing.T) {
|
||||
_, err := recon.CheckDirectory()
|
||||
_, err := CheckDirectory()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ var (
|
||||
err error
|
||||
)
|
||||
|
||||
// crashes at line 334 sometimes.
|
||||
// GetFileMetaData retuns the metadata of a file at filepath from the windows version information resources using the go-fileversion library.
|
||||
// TODO: crashes at line 334 sometimes.
|
||||
func GetFileMetaData(filepath string) (FileMetaData, error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// CheckIfAdmin checks if the process has administrator privileges by trying to open the PHYSICALDRIVE0 (C:\\) raw device on Windows.
|
||||
func CheckIfAdmin() bool {
|
||||
f, err := os.Open("\\\\.\\PHYSICALDRIVE0")
|
||||
if err != nil {
|
||||
|
||||
@@ -20,7 +20,8 @@ type Win32_Process struct {
|
||||
// StartMode string
|
||||
}
|
||||
|
||||
func (edr *EdrHunt) CheckProcesses() ([]ProcessMetaData, error) {
|
||||
// CheckProcesses returns a list of processes matching any suspicious running process names present in edrdata.go.
|
||||
func CheckProcesses() ([]ProcessMetaData, error) {
|
||||
var (
|
||||
processList []Win32_Process
|
||||
errArray []string
|
||||
@@ -56,9 +57,11 @@ func AnalyzeProcess(process Win32_Process) (ProcessMetaData, error) {
|
||||
ProcessPID: fmt.Sprint(process.ProcessId),
|
||||
ProcessParentPID: fmt.Sprint(process.ParentProcessId),
|
||||
}
|
||||
|
||||
if analysis.ProcessPath != "" {
|
||||
analysis.ProcessExeMetaData, err = GetFileMetaData(analysis.ProcessPath)
|
||||
}
|
||||
|
||||
for _, edr := range EdrList {
|
||||
if strings.Contains(
|
||||
strings.ToLower(fmt.Sprint(analysis)),
|
||||
|
||||
@@ -60,7 +60,7 @@ func EnumRegistry() []string {
|
||||
return output
|
||||
}
|
||||
|
||||
func (edr *EdrHunt) CheckRegistry() (RegistryMetaData, error) {
|
||||
func CheckRegistry() (RegistryMetaData, error) {
|
||||
|
||||
output := strings.Join(EnumRegistry(), " ")
|
||||
var analysis RegistryMetaData
|
||||
|
||||
+40
-24
@@ -1,30 +1,18 @@
|
||||
package edrRecon
|
||||
|
||||
func (e *EdrHunt) GetSystemData() (SystemData, error) {
|
||||
var systemData SystemData
|
||||
|
||||
systemData.Processes, err = e.CheckProcesses()
|
||||
if err != nil {
|
||||
return systemData, err
|
||||
var (
|
||||
Scanners = []EDRDetection{
|
||||
&CarbonBlackDetection{},
|
||||
&CrowdstrikeDetection{},
|
||||
&CylanceDetection{},
|
||||
&FireEyeDetection{},
|
||||
&KaskperskyDetection{},
|
||||
&McafeeDetection{},
|
||||
&SymantecDetection{},
|
||||
&SentinelOneDetection{},
|
||||
&WinDefenderDetection{},
|
||||
}
|
||||
|
||||
systemData.Services, err = e.CheckServices()
|
||||
if err != nil {
|
||||
return systemData, err
|
||||
}
|
||||
|
||||
systemData.Registry, err = e.CheckRegistry()
|
||||
if err != nil {
|
||||
return systemData, err
|
||||
}
|
||||
|
||||
systemData.Drivers, err = e.CheckDrivers()
|
||||
if err != nil {
|
||||
return systemData, err
|
||||
}
|
||||
|
||||
return systemData, nil
|
||||
}
|
||||
)
|
||||
|
||||
type SystemData struct {
|
||||
Processes []ProcessMetaData
|
||||
@@ -33,6 +21,7 @@ type SystemData struct {
|
||||
Drivers []DriverMetaData
|
||||
}
|
||||
|
||||
// CountMatchesAll collects all the scanned matches of suspicious names and checks for passed keywords in the matches.
|
||||
func (s *SystemData) CountMatchesAll(keywords ...[]string) (int, bool) {
|
||||
var match bool
|
||||
var count int
|
||||
@@ -74,6 +63,33 @@ func (s *SystemData) CountMatchesAll(keywords ...[]string) (int, bool) {
|
||||
return count, match
|
||||
}
|
||||
|
||||
// GetSystemData collects the parsed list of processes, services, drivers and registry keys to be used for EDR heuristics.
|
||||
func GetSystemData() (SystemData, error) {
|
||||
var systemData SystemData
|
||||
|
||||
systemData.Processes, err = CheckProcesses()
|
||||
if err != nil {
|
||||
return systemData, err
|
||||
}
|
||||
|
||||
systemData.Services, err = CheckServices()
|
||||
if err != nil {
|
||||
return systemData, err
|
||||
}
|
||||
|
||||
systemData.Registry, err = CheckRegistry()
|
||||
if err != nil {
|
||||
return systemData, err
|
||||
}
|
||||
|
||||
systemData.Drivers, err = CheckDrivers()
|
||||
if err != nil {
|
||||
return systemData, err
|
||||
}
|
||||
|
||||
return systemData, nil
|
||||
}
|
||||
|
||||
type EDRDetection interface {
|
||||
Detect(data SystemData) (EDRType, bool)
|
||||
Name() string
|
||||
|
||||
@@ -19,7 +19,8 @@ type Win32_Service struct {
|
||||
// StartMode string
|
||||
}
|
||||
|
||||
func (edr *EdrHunt) CheckServices() ([]ServiceMetaData, error) {
|
||||
// CheckServices return a list of installed services matching any suspicious service names present in edrdata.go.
|
||||
func CheckServices() ([]ServiceMetaData, error) {
|
||||
var (
|
||||
serviceList []Win32_Service
|
||||
errArray []string
|
||||
|
||||
@@ -2,6 +2,7 @@ package edrRecon
|
||||
|
||||
import "strings"
|
||||
|
||||
// StrSliceEqual checks wheter slice s contains a string exactly like e.
|
||||
func StrSliceEqual(s []string, e string) bool {
|
||||
for _, a := range s {
|
||||
if strings.EqualFold(a, e) {
|
||||
@@ -11,6 +12,7 @@ func StrSliceEqual(s []string, e string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// StrSliceContains checks wheter slice s contains a string which contains e.
|
||||
func StrSliceContains(s []string, e string) bool {
|
||||
for _, a := range s {
|
||||
if strings.Contains(a, e) {
|
||||
|
||||
Reference in New Issue
Block a user