Added WMI AV Support

This commit is contained in:
Hardik Manocha
2022-08-17 03:12:14 +05:30
parent 1acbce9f15
commit 19a27b522f
17 changed files with 362 additions and 24 deletions
+3 -2
View File
@@ -1,2 +1,3 @@
dist
EDRHunt.exe
dist
EDRHunt.exe
.vscode
+14 -12
View File
@@ -1,12 +1,14 @@
all: build
build:
go build -ldflags="-w -s" -o EDRHunt.exe github.com/FourCoreLabs/EDRHunt/cmd/EDRHunt
garble-build:
garble -literals build -ldflags="-w -s" -o EDRHunt.exe github.com/FourCoreLabs/EDRHunt/cmd/EDRHunt
local:
go build -ldflags="-w -s" -o EDRHunt.exe github.com/FourCoreLabs/EDRHunt/cmd/EDRHunt
run:
go run -ldflags="-w -s" github.com/FourCoreLabs/EDRHunt/cmd/EDRHunt all
drivers:
go run -ldflags="-w -s" github.com/FourCoreLabs/EDRHunt/cmd/EDRHunt -d
all: build
build:
go build -ldflags="-w -s" -o EDRHunt.exe github.com/FourCoreLabs/EDRHunt/cmd/EDRHunt
garble-build:
garble -literals build -ldflags="-w -s" -o EDRHunt.exe github.com/FourCoreLabs/EDRHunt/cmd/EDRHunt
local:
go build -ldflags="-w -s" -o EDRHunt.exe github.com/FourCoreLabs/EDRHunt/cmd/EDRHunt
run:
go run -ldflags="-w -s" github.com/FourCoreLabs/EDRHunt/cmd/EDRHunt all
drivers:
go run -ldflags="-w -s" github.com/FourCoreLabs/EDRHunt/cmd/EDRHunt -d
avwmi:
go run -ldflags="-w -s" github.com/FourCoreLabs/EDRHunt/cmd/EDRHunt -w
+12 -2
View File
@@ -2,7 +2,7 @@
[![goreleaser](https://github.com/FourCoreLabs/EDRHunt/actions/workflows/goreleaser.yml/badge.svg)](https://github.com/FourCoreLabs/EDRHunt/actions/workflows/goreleaser.yml)
EDRHunt scans Windows services, drivers, processes, registry for installed EDRs (Endpoint Detection And Response). Read more about EDRHunt [here](https://www.fourcore.vision/blogs/red-team-adventure-windows-endpoints-edr-edrhunt).
EDRHunt scans Windows services, drivers, processes, registry, wmi for installed EDRs (Endpoint Detection And Response). Read more about EDRHunt [here](https://www.fourcore.vision/blogs/red-team-adventure-windows-endpoints-edr-edrhunt).
[![asciicast](https://asciinema.org/a/P8i99w9mI497qUPTNbdwYWcwQ.svg)](https://asciinema.org/a/P8i99w9mI497qUPTNbdwYWcwQ)
@@ -30,7 +30,7 @@ Detected EDR: Kaspersky Security
```
$ .\EDRHunt.exe all
Running in user mode, escalate to admin for more details.
Scanning processes, services, drivers, and registry...
Scanning processes, services, drivers, wmi, and registry...
[PROCESSES]
Suspicious Process Name: MsMpEng.exe
@@ -131,6 +131,13 @@ $ .\EDRHunt.exe -d
$ .\EDRHunt.exe -r
```
- Find WMI Repository keys matching EDR keywords
```
$ .\EDRHunt.exe -w
```
## Detections
EDR Detections Currently Available
@@ -145,6 +152,9 @@ EDR Detections Currently Available
- SentinelOne
- FireEye
- Elastic EDR
- Qualys EDR
- Trend Micro EDR
- ESET EDR
More to be added soon.
+26 -3
View File
@@ -16,8 +16,9 @@ var (
processes bool
services bool
registry bool
avwmi bool
all bool
versionStr string = "1.3.1"
versionStr string = "1.4.0"
versionCheck bool
)
@@ -46,7 +47,8 @@ func edrCommand(cmd *cobra.Command, args []string) {
drivers = true
services = true
registry = true
fmt.Println("Scanning processes, services, drivers, and registry...")
avwmi = true
fmt.Println("Scanning processes, services, drivers, wmi, and registry...")
}
if processes {
@@ -67,6 +69,12 @@ func edrCommand(cmd *cobra.Command, args []string) {
printServices(summary)
fmt.Println()
}
if avwmi {
fmt.Println("[WMI-REPO]")
summary, _ := edrRecon.CheckAVWmiRepo()
printAVWmi(summary)
fmt.Println()
}
if registry {
fmt.Println("[REGISTRY]")
summary, _ := edrRecon.CheckRegistry(context.Background())
@@ -100,7 +108,7 @@ func allCommand(cmd *cobra.Command, args []string) {
var rootCmd = &cobra.Command{
Use: "EDRHunt",
Short: "scans EDR/AV",
Long: `EDRHunt scans and finds the installed EDR/AV by scanning services, processes, registry, and drivers.`,
Long: `EDRHunt scans and finds the installed EDR/AV by scanning services, processes, registry, wmi, and drivers.`,
Run: edrCommand,
}
@@ -125,6 +133,20 @@ var allCmd = &cobra.Command{
Run: allCommand,
}
func printAVWmi(summary []resources.AVWmiMetaData) {
for _, antivirus := range summary {
fmt.Printf("Suspicious Product Name: %s\n", antivirus.ProductName)
fmt.Printf("Suspicious Product GUID: %s\n", antivirus.ProductGUID)
fmt.Printf("Path to Suspicious Product Exe: %s\n", antivirus.PathToProductExe)
fmt.Printf("Suspicious Product Exe Metadata: \t%s\n", edrRecon.FileMetaDataParser(antivirus.ProductExeMetaData))
fmt.Printf("Path to Suspicious Reporting Exe: %s\n", antivirus.PathToReportingExe)
fmt.Printf("Suspicious Reporting Exe Metadata: \t%s\n", edrRecon.FileMetaDataParser(antivirus.ReportingExeMetaData))
fmt.Printf("Suspicious Product State: %d\n", antivirus.ProductState)
fmt.Printf("Matched Keyword: %s\n", antivirus.ScanMatch)
fmt.Println()
}
}
func printProcess(summary []resources.ProcessMetaData) {
for _, process := range summary {
fmt.Printf("Suspicious Process Name: %s\n", process.ProcessName)
@@ -184,6 +206,7 @@ func init() {
rootCmd.PersistentFlags().BoolVarP(&processes, "processes", "p", processes, "Scan installed processes")
rootCmd.PersistentFlags().BoolVarP(&services, "services", "s", services, "Scan installed services")
rootCmd.PersistentFlags().BoolVarP(&registry, "registry", "r", registry, "Scan installed registry")
rootCmd.PersistentFlags().BoolVarP(&avwmi, "avwmi", "w", avwmi, "Scan installed AntiVirus Providers")
rootCmd.PersistentFlags().BoolVarP(&versionCheck, "version", "v", versionCheck, "Output version information and exit")
rootCmd.AddCommand(versionCmd)
+5 -1
View File
@@ -7,7 +7,7 @@ import (
"github.com/FourCoreLabs/EDRHunt/pkg/resources"
)
// GetSystemData collects the parsed list of processes, services, drivers and registry keys to be used for EDR heuristics.
// GetSystemData collects the parsed list of processes, services, drivers, wmi and registry keys to be used for EDR heuristics.
func GetSystemData(ctx context.Context) (resources.SystemData, error) {
var err error
var systemData resources.SystemData
@@ -32,5 +32,9 @@ func GetSystemData(ctx context.Context) (resources.SystemData, error) {
return systemData, fmt.Errorf("failed to check drivers: %w", err)
}
systemData.AVProviders, err = CheckAVWmiRepo()
if err != nil {
return systemData, fmt.Errorf("failed to check wmi repo: %w", err)
}
return systemData, nil
}
+10
View File
@@ -55,6 +55,16 @@ func TestCheckProcesses(t *testing.T) {
}
}
func TestCheckAVWMI(t *testing.T) {
summary, _ := CheckAVWmiRepo()
for _, av := range summary {
fmt.Println(av)
}
// if err.Error() != "" {
// fmt.Println("error", err)
// }
}
func TestGetFileMetaData(t *testing.T) {
fileMetaData, err := GetFileMetaData(`C:\Users\hardi\AnyDesk.exe`)
if err != nil {
+9
View File
@@ -289,6 +289,15 @@ var EdrList = []string{
"elastic-endpoint.exe",
"elastic-endpoint-driver",
"ElasticEndpoint",
"ecmd.exe",
"ekrn.exe",
"ESET",
"mcupdate.exe",
"ProtectedModuleHost.exe",
"dsa.exe",
"Notifier.exe",
"qualys",
"qualysagent.exe",
}
var ReconList = []string{
+113
View File
@@ -0,0 +1,113 @@
package edrRecon
import (
"errors"
"fmt"
"strings"
"time"
"github.com/FourCoreLabs/EDRHunt/pkg/resources"
"github.com/hashicorp/go-multierror"
"github.com/yusufpapurcu/wmi"
)
type AntiVirusProduct struct {
DisplayName string
InstanceGuid string
PathToSignedProductExe string
PathToSignedReportingExe string
ProductState uint32
}
type AvResult struct {
AvProduct []AntiVirusProduct
Err error
}
const (
namespace = "root\\SecurityCenter2"
class = "AntiVirusProduct"
wmiErr = "wmi query timed out"
)
func CheckAVWmiRepo() ([]resources.AVWmiMetaData, error) {
var (
avList []AntiVirusProduct
multiErr error
summary []resources.AVWmiMetaData = make([]resources.AVWmiMetaData, 0)
err error
)
avList, err = GetAVwithWMI()
if err != nil {
return summary, err
}
for _, av := range avList {
if av.DisplayName == "" {
continue
}
output, err := AnalyzeAVProduct(av)
if err != nil {
multiErr = multierror.Append(multiErr, err)
continue
}
if len(output.ScanMatch) > 0 {
summary = append(summary, output)
}
}
return summary, multiErr
}
func AnalyzeAVProduct(av AntiVirusProduct) (resources.AVWmiMetaData, error) {
analysis := resources.AVWmiMetaData{
ProductName: av.DisplayName,
ProductGUID: av.InstanceGuid,
PathToProductExe: av.PathToSignedProductExe,
PathToReportingExe: av.PathToSignedReportingExe,
ProductState: av.ProductState,
}
if analysis.PathToProductExe != "" {
analysis.ProductExeMetaData, _ = GetFileMetaData(analysis.PathToProductExe)
}
if analysis.PathToReportingExe != "" {
analysis.ReportingExeMetaData, _ = GetFileMetaData(analysis.PathToReportingExe)
}
for _, edr := range EdrList {
if strings.Contains(
strings.ToLower(fmt.Sprint(analysis)),
strings.ToLower(edr)) {
analysis.ScanMatch = append(analysis.ScanMatch, edr)
}
}
return analysis, nil
}
func GetAVwithWMI() ([]AntiVirusProduct, error) {
result := make(chan AvResult, 1)
go func() {
result <- WMIQuery()
}()
select {
case <-time.After(6 * time.Second):
return nil, errors.New(wmiErr)
case result := <-result:
return result.AvProduct, result.Err
}
}
func WMIQuery() AvResult {
var avResults []AntiVirusProduct
query := wmi.CreateQuery(&avResults, "", class)
err := wmi.QueryNamespace(query, &avResults, namespace)
return AvResult{
AvProduct: avResults,
Err: err,
}
}
+12
View File
@@ -5,6 +5,7 @@ type Recon interface {
CheckServices() ([]ServiceMetaData, error)
CheckDrivers() ([]DriverMetaData, error)
CheckRegistry() (RegistryMetaData, error)
CheckAVWmiRepo() ([]AVWmiMetaData, error)
CheckDirectory() (string, error)
}
@@ -32,6 +33,17 @@ type ServiceMetaData struct {
ScanMatch []string
}
type AVWmiMetaData struct {
ProductName string
ProductGUID string
PathToProductExe string
ProductExeMetaData FileMetaData
PathToReportingExe string
ReportingExeMetaData FileMetaData
ProductState uint32
ScanMatch []string
}
type ProcessMetaData struct {
ProcessName string
ProcessPath string
+3
View File
@@ -19,4 +19,7 @@ var (
SentinelOneEDR EDRType = "sentinel_one"
FireEyeEDR EDRType = "fireeye"
ElasticAgentEDR EDRType = "elastic_agent"
QualysEDR EDRType = "qualys"
TrendMicroEDR EDRType = "trend_micro"
ESETEDR EDRType = "eset"
)
+9 -4
View File
@@ -5,10 +5,11 @@ import (
)
type SystemData struct {
Processes []ProcessMetaData
Registry RegistryMetaData
Services []ServiceMetaData
Drivers []DriverMetaData
Processes []ProcessMetaData
Registry RegistryMetaData
Services []ServiceMetaData
Drivers []DriverMetaData
AVProviders []AVWmiMetaData
}
// CountMatchesAll collects all the scanned matches of suspicious names and checks for passed keywords in the matches.
@@ -30,6 +31,10 @@ func (s *SystemData) CountMatchesAll(keywords ...[]string) (int, bool) {
scanMatchList = append(scanMatchList, v.ScanMatch...)
}
for _, v := range s.AVProviders {
scanMatchList = append(scanMatchList, v.ScanMatch...)
}
scanMatchList = append(scanMatchList, s.Registry.ScanMatch...)
var totalLen int
+29
View File
@@ -0,0 +1,29 @@
package scanners
import "github.com/FourCoreLabs/EDRHunt/pkg/resources"
type ESETEDRDetection struct{}
func (w *ESETEDRDetection) Name() string {
return "ESET Endpoint Security"
}
func (w *ESETEDRDetection) Type() resources.EDRType {
return resources.ESETEDR
}
var ESETHeuristic = []string{
"ESET",
"ESET Endpoint Security",
"ecmd",
"ekrn",
}
func (w *ESETEDRDetection) Detect(data resources.SystemData) (resources.EDRType, bool) {
_, ok := data.CountMatchesAll(ESETHeuristic)
if !ok {
return "", false
}
return resources.QualysEDR, true
}
+2
View File
@@ -14,6 +14,8 @@ func (w *McafeeDetection) Type() resources.EDRType {
var McafeeHeuristic = []string{
"Mcafee\\",
"mcupdate.exe",
"ProtectedModuleHost.exe",
"McAfeeAgent\\",
"APPolicyName",
"EPPolicyName",
+29
View File
@@ -0,0 +1,29 @@
package scanners
import "github.com/FourCoreLabs/EDRHunt/pkg/resources"
type QualysDetection struct{}
func (w *QualysDetection) Name() string {
return "Qualys Cloud Agent EDR"
}
func (w *QualysDetection) Type() resources.EDRType {
return resources.QualysEDR
}
var QualysHeuristic = []string{
"Qualys",
"QualysAgent.exe",
"qualysagent.exe",
"qualys",
}
func (w *QualysDetection) Detect(data resources.SystemData) (resources.EDRType, bool) {
_, ok := data.CountMatchesAll(QualysHeuristic)
if !ok {
return "", false
}
return resources.QualysEDR, true
}
+29
View File
@@ -0,0 +1,29 @@
package scanners
import "github.com/FourCoreLabs/EDRHunt/pkg/resources"
type TrendMicroDetection struct{}
func (w *TrendMicroDetection) Name() string {
return "Trend Micro Deep Security"
}
func (w *TrendMicroDetection) Type() resources.EDRType {
return resources.TrendMicroEDR
}
var TrendMicroHeuristic = []string{
"Deep Security Agent\\",
"dsa",
"Notifier",
"Trend Micro",
}
func (w *TrendMicroDetection) Detect(data resources.SystemData) (resources.EDRType, bool) {
_, ok := data.CountMatchesAll(TrendMicroHeuristic)
if !ok {
return "", false
}
return resources.QualysEDR, true
}
+3
View File
@@ -14,5 +14,8 @@ var (
&SentinelOneDetection{},
&WinDefenderDetection{},
&ElasticAgentDetection{},
&ESETEDRDetection{},
&QualysDetection{},
&TrendMicroDetection{},
}
)
+54
View File
@@ -0,0 +1,54 @@
package main
import (
"errors"
"time"
"github.com/yusufpapurcu/wmi"
)
type AntiVirusProduct struct {
DisplayName string
InstanceGuid string
PathToSignedProductExe string
PathToSignedReportingExe string
ProductState uint32
}
type AvResult struct {
AvProduct []AntiVirusProduct
Err error
}
func WMIQuery() AvResult {
var avResults []AntiVirusProduct
query := wmi.CreateQuery(&avResults, "", "AntiVirusProduct")
err := wmi.QueryNamespace(query, &avResults, "root\\SecurityCenter2")
return AvResult{
AvProduct: avResults,
Err: err,
}
}
func GetAVwithWMI() ([]AntiVirusProduct, error) {
result := make(chan AvResult, 1)
go func() {
result <- WMIQuery()
}()
select {
case <-time.After(10 * time.Second):
return nil, errors.New("wmi query timed out")
case result := <-result:
return result.AvProduct, result.Err
}
}
func main() {
query, queryErr := GetAVwithWMI()
if queryErr != nil {
panic(queryErr)
}
for i, v := range query {
println(i+1, v.DisplayName, v.InstanceGuid, v.PathToSignedProductExe, v.PathToSignedReportingExe, v.ProductState)
}
}