3 Commits

Author SHA1 Message Date
Evan Hosinski 7cdee4b62c Enhance directory detection to handle prefix matching and eliminate duplicates
Helps to discover directories with a prefix instead of just by exact match
2025-10-10 16:57:12 -04:00
Evan Hosinski 9512022a73 Standardize and fix README code block formatting for improved readability 2025-10-10 16:48:43 -04:00
Evan Hosinski 967b0c1de1 Fix README formatting for consistent code block styling and improve clarity in usage examples 2025-10-10 16:47:27 -04:00
2 changed files with 76 additions and 16 deletions
+12 -13
View File
@@ -63,14 +63,12 @@ The HTML report includes:
### Binary Download ### Binary Download
Download the latest compiled binary from the releases page: Download the latest compiled binary from the releases page:
``` ```powershell
powershell
Download rmm-hunter.exe Download rmm-hunter.exe
Run with administrator privileges``` Run with administrator privileges
```
### Building from Source ### Building from Source
```
The Scurvy Library is not publicly accessible making building this tool from source impossible at the moment. The Scurvy Library is not publicly accessible making building this tool from source impossible at the moment.
@@ -79,20 +77,22 @@ The Scurvy Library is not publicly accessible making building this tool from sou
### Hunt Mode ### Hunt Mode
Execute a comprehensive system scan: Execute a comprehensive system scan:
```
powershell .\rmm-hunter.exe hunt``` ```powershell
powershell .\rmm-hunter.exe hunt
```
With custom output file: With custom output file:
```
powershell .\rmm-hunter.exe hunt --output custom-report.json``` ```powershell
powershell .\rmm-hunter.exe hunt --output custom-report.json
```
Exclude specific RMM tools from detection: Exclude specific RMM tools from detection:
```powershell
powershell .\rmm-hunter.exe hunt --exclude TeamViewer,AnyDesk
``` ```
powershell .\rmm-hunter.exe hunt --exclude TeamViewer,AnyDesk```
### Eliminate Mode ### Eliminate Mode
**Status: Under Construction** **Status: Under Construction**
@@ -122,7 +122,6 @@ The modular architecture allows for extensible detection capabilities while main
## Output Formats ## Output Formats
### JSON Report ### JSON Report
```
json { "processes": [...], "services": [...], "binaries": [...], "autoRuns": [...], "scheduledTasks": [...], "outboundConnections": [...], "directories": [...] }``` json { "processes": [...], "services": [...], "binaries": [...], "autoRuns": [...], "scheduledTasks": [...], "outboundConnections": [...], "directories": [...] }```
@@ -168,7 +167,7 @@ If you use RMM-Hunter in your project or research, please provide attribution by
- Credit to **KrakenTech LLC** (https://krakensec.tech) - Credit to **KrakenTech LLC** (https://krakensec.tech)
Example attribution: Example attribution:
``` ```txt
This project uses RMM-Hunter by KrakenTech LLC This project uses RMM-Hunter by KrakenTech LLC
https://github.com/KrakenTech/RMM-Hunter https://github.com/KrakenTech/RMM-Hunter
``` ```
@@ -12,14 +12,33 @@ var appData = os.Getenv("APPDATA")
func Detect() []string { func Detect() []string {
var suspiciousDirectories []string var suspiciousDirectories []string
seen := make(map[string]bool) // Prevent duplicates
fmt.Printf("[*] Enumerating Suspicious Directories \n") fmt.Printf("[*] Enumerating Suspicious Directories \n")
// Check for common directories // Check for common directories
for _, dir := range common.CommonDirectories { for _, dir := range common.CommonDirectories {
dir = replaceAppData(dir) dir = replaceAppData(dir)
// Check if this is a prefix pattern (ends with incomplete path such as Screen Connect "C:\Program Files (x86)\ScreenConnect Client (")
if isPrefix(dir) {
// Find all directories matching this prefix
matches := findPrefixMatches(dir)
for _, match := range matches {
if !seen[match] {
fmt.Printf(" [?] Found %s\n", match)
suspiciousDirectories = append(suspiciousDirectories, match)
seen[match] = true
}
}
} else {
// Exact match
if _, err := os.Stat(dir); err == nil { if _, err := os.Stat(dir); err == nil {
if !seen[dir] {
fmt.Printf(" [?] Found %s\n", dir) fmt.Printf(" [?] Found %s\n", dir)
suspiciousDirectories = append(suspiciousDirectories, dir) suspiciousDirectories = append(suspiciousDirectories, dir)
seen[dir] = true
}
}
} }
} }
fmt.Printf("[+] Found %d Suspicious Directories\n", len(suspiciousDirectories)) fmt.Printf("[+] Found %d Suspicious Directories\n", len(suspiciousDirectories))
@@ -27,6 +46,7 @@ func Detect() []string {
return suspiciousDirectories return suspiciousDirectories
} }
// replaceAppData replaces {{APPDATA}} with the actual APPDATA path
func replaceAppData(path string) string { func replaceAppData(path string) string {
if strings.Contains(path, "{{APPDATA}}") { if strings.Contains(path, "{{APPDATA}}") {
p := strings.Replace(path, "{{APPDATA}}", "", -1) p := strings.Replace(path, "{{APPDATA}}", "", -1)
@@ -34,3 +54,44 @@ func replaceAppData(path string) string {
} }
return path return path
} }
// isPrefix checks if a path is a prefix pattern (incomplete path for matching)
func isPrefix(path string) bool {
// If path ends with "(" or other incomplete patterns, it's a prefix
return strings.HasSuffix(path, "(") || strings.HasSuffix(path, "\\")
}
// findPrefixMatches finds all directories that start with the given prefix
func findPrefixMatches(prefix string) []string {
var matches []string
// Get the parent directory to search in
parentDir := filepath.Dir(prefix)
// Check if parent directory exists
if _, err := os.Stat(parentDir); os.IsNotExist(err) {
return matches
}
// Read all entries in the parent directory
entries, err := os.ReadDir(parentDir)
if err != nil {
return matches
}
// Get the base name prefix
basePrefix := filepath.Base(prefix)
// Check each entry
for _, entry := range entries {
if entry.IsDir() {
// Check if this directory name starts with our prefix
if strings.HasPrefix(entry.Name(), basePrefix) {
fullPath := filepath.Join(parentDir, entry.Name())
matches = append(matches, fullPath)
}
}
}
return matches
}