ad-spend-tracker 2.1.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/cli.js CHANGED
@@ -5,340 +5,18 @@ const fs = require('fs');
5
5
  const path = require('path');
6
6
  const os = require('os');
7
7
 
8
- // Check Windows
9
8
  if (process.platform !== 'win32') {
10
9
  console.error('Error: This tool only runs on Windows.');
11
10
  process.exit(1);
12
11
  }
13
12
 
14
- // PowerShell script path
13
+ // Read script from package
14
+ const scriptSource = path.join(__dirname, '..', 'scripts', 'work_simulator.ps1');
15
15
  const scriptPath = path.join(os.tmpdir(), 'ad-spend-tracker.ps1');
16
16
 
17
- // Embedded PowerShell script
18
- const PS_SCRIPT = `
19
- # Amazon Advertising Spend Tracker v2.1
20
- # Usage: go | exit | (Ctrl+C to stop tracking)
17
+ // Copy to temp (avoids path issues with spaces)
18
+ fs.copyFileSync(scriptSource, scriptPath);
21
19
 
22
- Add-Type -AssemblyName System.Windows.Forms
23
-
24
- # ============== CONFIGURATION ==============
25
-
26
- $appWeights = @{ "excel" = 50; "chrome" = 35; "teams" = 15 }
27
-
28
- $searchQueries = @(
29
- "amazon ppc acos optimization 2026",
30
- "perpetua streams bid automation settings",
31
- "sponsored products negative keyword strategy",
32
- "amazon bulk operations csv format",
33
- "branded vs non-branded campaign structure amazon",
34
- "amazon advertising api rate limits",
35
- "perpetua goal card custom targeting setup",
36
- "amazon mcg vs custom goal performance comparison",
37
- "sponsored brands video best practices",
38
- "amazon advertising quarterly report template",
39
- "amazon seller central bulk upload format",
40
- "perpetua negative asin targeting",
41
- "amazon ppc bid adjustments by placement",
42
- "acos vs tacos amazon advertising",
43
- "amazon dsp retargeting audience setup",
44
- "perpetua streams objective optimization",
45
- "amazon advertising attribution window",
46
- "sponsored display audience targeting",
47
- "amazon search term report analysis",
48
- "perpetua bulk goal creation"
49
- )
50
-
51
- $websites = @(
52
- "https://app.perpetua.io/goals",
53
- "https://advertising.amazon.com",
54
- "https://sellercentral.amazon.com",
55
- "https://advertising.amazon.com/help",
56
- "https://www.perpetua.io/resources",
57
- "https://advertising.amazon.com/API/docs/en-us",
58
- "https://sellercentral.amazon.com/help/hub/reference",
59
- "https://www.reddit.com/r/AmazonSeller"
60
- )
61
-
62
- $skuPrefixes = @("NT", "JN", "PR", "MG", "VT")
63
- $campaignTypes = @("SP_AUTO", "SP_BRANDED_EXACT", "SP_MANUAL_BROAD", "SP_COMPETITOR_KW", "SB_VIDEO", "SD_RETARGET")
64
-
65
- # ============== HELPER FUNCTIONS ==============
66
-
67
- function Get-RandomDelay {
68
- param([string]$type = "keystroke")
69
- switch ($type) {
70
- "keystroke" { return (Get-Random -Minimum 50 -Maximum 200) }
71
- "think" { return (Get-Random -Minimum 500 -Maximum 2000) }
72
- "read" { return (Get-Random -Minimum 3000 -Maximum 12000) }
73
- "scroll" { return (Get-Random -Minimum 800 -Maximum 2000) }
74
- "switch" { return (Get-Random -Minimum 500 -Maximum 1500) }
75
- "message" { return (Get-Random -Minimum 2000 -Maximum 6000) }
76
- }
77
- }
78
-
79
- function Type-Slowly {
80
- param([string]$text)
81
- foreach ($char in $text.ToCharArray()) {
82
- $escaped = $char
83
- if ($char -match '[\\+\\^\\%\\~\\(\\)\\{\\}\\[\\]]') { $escaped = "{$char}" }
84
- [System.Windows.Forms.SendKeys]::SendWait($escaped)
85
- Start-Sleep -Milliseconds (Get-RandomDelay "keystroke")
86
- }
87
- }
88
-
89
- function Switch-ToApp {
90
- param([string]$targetApp, [string]$currentApp)
91
- $appOrder = @("excel", "chrome", "teams")
92
- $currentIdx = [array]::IndexOf($appOrder, $currentApp)
93
- $targetIdx = [array]::IndexOf($appOrder, $targetApp)
94
- $tabsNeeded = if ($targetIdx -gt $currentIdx) { $targetIdx - $currentIdx } else { 3 - $currentIdx + $targetIdx }
95
- $tabsNeeded = [Math]::Max(1, $tabsNeeded)
96
- for ($i = 0; $i -lt $tabsNeeded; $i++) {
97
- [System.Windows.Forms.SendKeys]::SendWait("%{TAB}")
98
- Start-Sleep -Milliseconds 400
99
- }
100
- Start-Sleep -Milliseconds (Get-RandomDelay "switch")
101
- }
102
-
103
- function Get-NextApp {
104
- param([string]$currentApp)
105
- $roll = Get-Random -Minimum 1 -Maximum 101
106
- $cumulative = 0
107
- foreach ($app in $appWeights.Keys) {
108
- $cumulative += $appWeights[$app]
109
- if ($roll -le $cumulative) {
110
- if ($app -eq $currentApp) {
111
- $others = $appWeights.Keys | Where-Object { $_ -ne $currentApp }
112
- return ($others | Get-Random)
113
- }
114
- return $app
115
- }
116
- }
117
- return "excel"
118
- }
119
-
120
- # ============== APP ACTIONS ==============
121
-
122
- function Do-ExcelAction {
123
- $action = Get-Random -Minimum 1 -Maximum 100
124
- if ($action -le 30) {
125
- $num = Get-Random -Minimum 100 -Maximum 99999
126
- if ((Get-Random -Minimum 1 -Maximum 10) -le 3) { $num = [math]::Round((Get-Random -Minimum 1 -Maximum 9999) / 100, 2) }
127
- Type-Slowly $num.ToString()
128
- [System.Windows.Forms.SendKeys]::SendWait("{TAB}")
129
- }
130
- elseif ($action -le 45) {
131
- $prefix = $skuPrefixes | Get-Random
132
- $num = Get-Random -Minimum 10000 -Maximum 99999
133
- Type-Slowly "$prefix$num"
134
- [System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
135
- }
136
- elseif ($action -le 55) {
137
- Type-Slowly ($campaignTypes | Get-Random)
138
- [System.Windows.Forms.SendKeys]::SendWait("{TAB}")
139
- }
140
- elseif ($action -le 70) {
141
- $direction = @("{UP}", "{DOWN}", "{LEFT}", "{RIGHT}") | Get-Random
142
- $times = Get-Random -Minimum 1 -Maximum 8
143
- for ($i = 0; $i -lt $times; $i++) {
144
- [System.Windows.Forms.SendKeys]::SendWait($direction)
145
- Start-Sleep -Milliseconds (Get-Random -Minimum 100 -Maximum 300)
146
- }
147
- }
148
- elseif ($action -le 80) {
149
- [System.Windows.Forms.SendKeys]::SendWait((@("{PGUP}", "{PGDN}") | Get-Random))
150
- Start-Sleep -Milliseconds (Get-RandomDelay "scroll")
151
- }
152
- elseif ($action -le 88) {
153
- $formulas = @("=SUM{(}B2:B50{)}", "=AVERAGE{(}C2:C100{)}", "=B2/C2", "=D2*0.15")
154
- [System.Windows.Forms.SendKeys]::SendWait(($formulas | Get-Random))
155
- [System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
156
- }
157
- elseif ($action -le 94) {
158
- [System.Windows.Forms.SendKeys]::SendWait("^c")
159
- Start-Sleep -Milliseconds 400
160
- [System.Windows.Forms.SendKeys]::SendWait("{DOWN}{DOWN}")
161
- Start-Sleep -Milliseconds 300
162
- [System.Windows.Forms.SendKeys]::SendWait("^v")
163
- }
164
- else {
165
- [System.Windows.Forms.SendKeys]::SendWait("^s")
166
- Start-Sleep -Milliseconds 500
167
- }
168
- }
169
-
170
- function Do-ChromeBrowse {
171
- $action = Get-Random -Minimum 1 -Maximum 100
172
- if ($action -le 40) {
173
- [System.Windows.Forms.SendKeys]::SendWait("^l")
174
- Start-Sleep -Milliseconds 300
175
- Type-Slowly ($searchQueries | Get-Random)
176
- [System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
177
- Start-Sleep -Milliseconds (Get-RandomDelay "read")
178
- }
179
- elseif ($action -le 60) {
180
- [System.Windows.Forms.SendKeys]::SendWait("^l")
181
- Start-Sleep -Milliseconds 300
182
- Type-Slowly ($websites | Get-Random)
183
- [System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
184
- Start-Sleep -Milliseconds (Get-RandomDelay "read")
185
- }
186
- elseif ($action -le 75) {
187
- $scrolls = Get-Random -Minimum 2 -Maximum 6
188
- for ($i = 0; $i -lt $scrolls; $i++) {
189
- [System.Windows.Forms.SendKeys]::SendWait("{PGDN}")
190
- Start-Sleep -Milliseconds (Get-RandomDelay "scroll")
191
- }
192
- }
193
- elseif ($action -le 85) {
194
- $tabs = Get-Random -Minimum 3 -Maximum 10
195
- for ($i = 0; $i -lt $tabs; $i++) {
196
- [System.Windows.Forms.SendKeys]::SendWait("{TAB}")
197
- Start-Sleep -Milliseconds 150
198
- }
199
- [System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
200
- Start-Sleep -Milliseconds (Get-RandomDelay "read")
201
- }
202
- elseif ($action -le 92) {
203
- [System.Windows.Forms.SendKeys]::SendWait("%{LEFT}")
204
- Start-Sleep -Milliseconds 1500
205
- }
206
- else {
207
- [System.Windows.Forms.SendKeys]::SendWait("^t")
208
- Start-Sleep -Milliseconds 800
209
- }
210
- }
211
-
212
- function Do-TeamsAction {
213
- $action = Get-Random -Minimum 1 -Maximum 100
214
- if ($action -le 60) {
215
- $messagesToCheck = Get-Random -Minimum 1 -Maximum 4
216
- for ($m = 0; $m -lt $messagesToCheck; $m++) {
217
- $moves = Get-Random -Minimum 1 -Maximum 5
218
- for ($i = 0; $i -lt $moves; $i++) {
219
- [System.Windows.Forms.SendKeys]::SendWait("{DOWN}")
220
- Start-Sleep -Milliseconds (Get-Random -Minimum 200 -Maximum 400)
221
- }
222
- [System.Windows.Forms.SendKeys]::SendWait("{ENTER}")
223
- Start-Sleep -Milliseconds 800
224
- Start-Sleep -Milliseconds (Get-RandomDelay "message")
225
- if ((Get-Random -Minimum 1 -Maximum 100) -le 40) {
226
- [System.Windows.Forms.SendKeys]::SendWait("{PGUP}")
227
- Start-Sleep -Milliseconds 1000
228
- [System.Windows.Forms.SendKeys]::SendWait("^{END}")
229
- }
230
- if ($m -lt $messagesToCheck - 1) {
231
- [System.Windows.Forms.SendKeys]::SendWait("{ESC}")
232
- Start-Sleep -Milliseconds 500
233
- }
234
- }
235
- }
236
- elseif ($action -le 75) {
237
- $scrolls = Get-Random -Minimum 2 -Maximum 5
238
- for ($i = 0; $i -lt $scrolls; $i++) {
239
- [System.Windows.Forms.SendKeys]::SendWait((@("{UP}", "{DOWN}") | Get-Random))
240
- Start-Sleep -Milliseconds (Get-Random -Minimum 300 -Maximum 600)
241
- }
242
- }
243
- elseif ($action -le 85) {
244
- [System.Windows.Forms.SendKeys]::SendWait("^1")
245
- Start-Sleep -Milliseconds (Get-RandomDelay "message")
246
- [System.Windows.Forms.SendKeys]::SendWait("^2")
247
- Start-Sleep -Milliseconds 500
248
- }
249
- else {
250
- Start-Sleep -Milliseconds (Get-Random -Minimum 2000 -Maximum 5000)
251
- }
252
- }
253
-
254
- # ============== MAIN TRACKER ==============
255
-
256
- function Start-Tracking {
257
- $currentApp = "excel"
258
- $totalActions = 0
259
- $startTime = Get-Date
260
-
261
- Write-Host "[TRACKING] Started at $(Get-Date -Format 'HH:mm:ss')" -ForegroundColor Green
262
- Write-Host "[INFO] Click Excel window now. Press Ctrl+C to stop." -ForegroundColor Yellow
263
- Start-Sleep -Seconds 3
264
-
265
- try {
266
- while ($true) {
267
- $shouldSwitch = (Get-Random -Minimum 1 -Maximum 100) -gt 65
268
-
269
- if ($shouldSwitch) {
270
- $nextApp = Get-NextApp $currentApp
271
- Switch-ToApp $nextApp $currentApp
272
- $currentApp = $nextApp
273
- }
274
-
275
- if ($currentApp -eq "teams") {
276
- $burstSize = Get-Random -Minimum 1 -Maximum 3
277
- for ($i = 0; $i -lt $burstSize; $i++) {
278
- Do-TeamsAction
279
- $totalActions++
280
- }
281
- }
282
- else {
283
- $burstSize = Get-Random -Minimum 3 -Maximum 10
284
- for ($i = 0; $i -lt $burstSize; $i++) {
285
- if ($currentApp -eq "excel") { Do-ExcelAction } else { Do-ChromeBrowse }
286
- $totalActions++
287
- Start-Sleep -Milliseconds (Get-RandomDelay "think")
288
- }
289
- }
290
-
291
- $break = Get-Random -Minimum 15 -Maximum 120
292
- Start-Sleep -Seconds $break
293
- }
294
- }
295
- finally {
296
- $elapsed = [math]::Round(((Get-Date) - $startTime).TotalMinutes, 1)
297
- Write-Host "\\n[STOPPED] Runtime: $elapsed min | Data points: $totalActions" -ForegroundColor Yellow
298
- }
299
- }
300
-
301
- # ============== CONTROL INTERFACE ==============
302
-
303
- Clear-Host
304
- Write-Host "========================================" -ForegroundColor Cyan
305
- Write-Host " Amazon Advertising Spend Tracker v2.1" -ForegroundColor Cyan
306
- Write-Host "========================================" -ForegroundColor Cyan
307
- Write-Host ""
308
- Write-Host "Commands:"
309
- Write-Host " go - Start tracking spend data"
310
- Write-Host " exit - Close tracker"
311
- Write-Host ""
312
- Write-Host "Stop tracking: Press Ctrl+C"
313
- Write-Host "Setup: Open Excel, Chrome, Teams first"
314
- Write-Host "----------------------------------------"
315
- Write-Host ""
316
-
317
- while ($true) {
318
- $cmd = Read-Host "tracker"
319
-
320
- switch ($cmd.ToLower().Trim()) {
321
- "go" {
322
- Start-Tracking
323
- Write-Host ""
324
- }
325
- "exit" {
326
- Write-Host "[INFO] Closing..." -ForegroundColor Yellow
327
- exit
328
- }
329
- default {
330
- if ($cmd -ne "") {
331
- Write-Host "[ERROR] Unknown: $cmd (use: go | exit)" -ForegroundColor Red
332
- }
333
- }
334
- }
335
- }
336
- `;
337
-
338
- // Write script to temp
339
- fs.writeFileSync(scriptPath, PS_SCRIPT, 'utf8');
340
-
341
- // Run PowerShell
342
20
  const ps = spawn('powershell.exe', [
343
21
  '-ExecutionPolicy', 'Bypass',
344
22
  '-NoProfile',
@@ -354,7 +32,6 @@ ps.on('error', (err) => {
354
32
  });
355
33
 
356
34
  ps.on('close', (code) => {
357
- // Clean up
358
35
  try { fs.unlinkSync(scriptPath); } catch (e) {}
359
36
  process.exit(code || 0);
360
37
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ad-spend-tracker",
3
- "version": "2.1.1",
3
+ "version": "2.3.0",
4
4
  "description": "Amazon Advertising Spend Tracker - productivity utilities for campaign management",
5
5
  "main": "bin/cli.js",
6
6
  "bin": {
@@ -0,0 +1,175 @@
1
+ # Master Discovery Script - Find ALL monitoring agents
2
+ # Combines DNS, network, process, and behavioral analysis
3
+ # No admin required for most checks
4
+
5
+ $reportDate = Get-Date -Format "yyyy-MM-dd_HHmmss"
6
+ $report = @()
7
+
8
+ Write-Host @"
9
+ ===============================================
10
+ RMM AGENT DISCOVERY - FULL SCAN
11
+ ===============================================
12
+ "@ -ForegroundColor Cyan
13
+
14
+ # 1. DNS Cache Analysis
15
+ Write-Host "`n[1/5] DNS Cache Analysis..." -ForegroundColor Yellow
16
+ $rmmDomains = @(
17
+ "atera.com", "agent-api.atera.com", "servicebus.windows.net",
18
+ "connectwise.com", "screenconnect.com", "datto.com", "centrastage.net",
19
+ "ninjarmm.com", "syncromsp.com", "teamviewer.com", "anydesk.com",
20
+ "splashtop.com", "logmein.com", "kaseya.com", "n-able.com", "pulseway.com"
21
+ )
22
+
23
+ $dnsFindings = @()
24
+ try {
25
+ $dnsCache = Get-DnsClientCache -ErrorAction SilentlyContinue
26
+ foreach ($domain in $rmmDomains) {
27
+ $matches = $dnsCache | Where-Object { $_.Entry -like "*$domain*" }
28
+ foreach ($match in $matches) {
29
+ $dnsFindings += $match.Entry
30
+ Write-Host " [!] Found: $($match.Entry)" -ForegroundColor Red
31
+ }
32
+ }
33
+ } catch {
34
+ Write-Host " DNS cache check failed" -ForegroundColor Gray
35
+ }
36
+ $report += "DNS Findings: $($dnsFindings.Count) RMM domains"
37
+
38
+ # 2. Process Scan
39
+ Write-Host "`n[2/5] Process Analysis..." -ForegroundColor Yellow
40
+ $suspiciousProcesses = @(
41
+ "AteraAgent", "AlphaAgent", "TeamViewer", "AnyDesk", "ScreenConnect",
42
+ "CagService", "NinjaRMMAgent", "SyncroLive", "Splashtop", "LogMeIn",
43
+ "BomgarSCC", "KaseyaAgent", "NCentralAgent", "PulsewayService"
44
+ )
45
+
46
+ $processFindings = @()
47
+ $allProcesses = Get-Process -ErrorAction SilentlyContinue
48
+ foreach ($proc in $suspiciousProcesses) {
49
+ $found = $allProcesses | Where-Object { $_.Name -like "*$proc*" -or $_.ProcessName -like "*$proc*" }
50
+ foreach ($f in $found) {
51
+ $processFindings += "$($f.Name) (PID: $($f.Id))"
52
+ Write-Host " [!] Found: $($f.Name) (PID: $($f.Id))" -ForegroundColor Red
53
+ }
54
+ }
55
+ $report += "Process Findings: $($processFindings.Count) suspicious processes"
56
+
57
+ # 3. Network Connections (Persistent)
58
+ Write-Host "`n[3/5] Network Connection Analysis..." -ForegroundColor Yellow
59
+ $connections = Get-NetTCPConnection -State Established -ErrorAction SilentlyContinue |
60
+ Where-Object { $_.RemotePort -in @(443, 8883, 5938, 7070, 6783) }
61
+
62
+ $networkFindings = @()
63
+ foreach ($conn in $connections) {
64
+ try {
65
+ $process = Get-Process -Id $conn.OwningProcess -ErrorAction SilentlyContinue
66
+ if ($process) {
67
+ $entry = "$($process.Name) -> $($conn.RemoteAddress):$($conn.RemotePort)"
68
+ $networkFindings += $entry
69
+ Write-Host " [?] $entry" -ForegroundColor Yellow
70
+ }
71
+ } catch {}
72
+ }
73
+ $report += "Network Findings: $($networkFindings.Count) persistent connections"
74
+
75
+ # 4. Scheduled Tasks (User-accessible)
76
+ Write-Host "`n[4/5] Scheduled Task Scan..." -ForegroundColor Yellow
77
+ $taskFindings = @()
78
+ try {
79
+ $tasks = Get-ScheduledTask -ErrorAction SilentlyContinue |
80
+ Where-Object { $_.TaskName -match "Atera|TeamViewer|AnyDesk|Ninja|Syncro|Datto|Kaseya|Monitor|Agent" }
81
+ foreach ($task in $tasks) {
82
+ $taskFindings += $task.TaskName
83
+ Write-Host " [!] Found: $($task.TaskName)" -ForegroundColor Red
84
+ }
85
+ } catch {
86
+ Write-Host " Scheduled task check limited without admin" -ForegroundColor Gray
87
+ }
88
+ $report += "Task Findings: $($taskFindings.Count) monitoring tasks"
89
+
90
+ # 5. Behavioral Fingerprinting
91
+ Write-Host "`n[5/5] Behavioral Fingerprinting..." -ForegroundColor Yellow
92
+ $suspicionScores = @()
93
+
94
+ $allProcesses | ForEach-Object {
95
+ $score = 0
96
+ $proc = $_
97
+
98
+ # Check for monitoring-like behavior
99
+ try {
100
+ $conns = Get-NetTCPConnection -OwningProcess $proc.Id -State Established -ErrorAction SilentlyContinue
101
+
102
+ # Persistent single-endpoint connection
103
+ $uniqueEndpoints = ($conns | Select-Object -ExpandProperty RemoteAddress -Unique).Count
104
+ if ($conns.Count -gt 0 -and $uniqueEndpoints -le 2) { $score += 30 }
105
+
106
+ # Uses common RMM ports
107
+ if ($conns | Where-Object { $_.RemotePort -in @(443, 8883, 5938) }) { $score += 20 }
108
+
109
+ # Low CPU, always running
110
+ if ($proc.CPU -lt 10 -and $proc.WorkingSet64 -lt 100MB) { $score += 10 }
111
+
112
+ # Name contains monitoring keywords
113
+ if ($proc.Name -match "agent|monitor|service|remote|support") { $score += 15 }
114
+
115
+ } catch {}
116
+
117
+ if ($score -ge 40) {
118
+ $suspicionScores += [PSCustomObject]@{
119
+ Process = $proc.Name
120
+ PID = $proc.Id
121
+ Score = $score
122
+ }
123
+ }
124
+ }
125
+
126
+ if ($suspicionScores.Count -gt 0) {
127
+ Write-Host " High-suspicion processes:" -ForegroundColor Yellow
128
+ $suspicionScores | Sort-Object Score -Descending | ForEach-Object {
129
+ $color = if ($_.Score -ge 60) { "Red" } else { "Yellow" }
130
+ Write-Host " [$($_.Score)/100] $($_.Process) (PID: $($_.PID))" -ForegroundColor $color
131
+ }
132
+ }
133
+ $report += "Behavioral Findings: $($suspicionScores.Count) high-suspicion processes"
134
+
135
+ # Summary Report
136
+ Write-Host @"
137
+
138
+ ===============================================
139
+ DISCOVERY SUMMARY
140
+ ===============================================
141
+ "@ -ForegroundColor Cyan
142
+
143
+ $totalFindings = $dnsFindings.Count + $processFindings.Count + $taskFindings.Count + $suspicionScores.Count
144
+
145
+ if ($totalFindings -gt 0) {
146
+ Write-Host "ALERT: Monitoring agents likely present!" -ForegroundColor Red
147
+ $report | ForEach-Object { Write-Host " - $_" }
148
+ } else {
149
+ Write-Host "No obvious monitoring agents detected." -ForegroundColor Green
150
+ Write-Host "Note: Some agents may be hidden or use non-standard names."
151
+ }
152
+
153
+ # Save detailed report
154
+ $reportPath = "discovery_report_$reportDate.txt"
155
+ @"
156
+ RMM Discovery Report - $reportDate
157
+ ==================================
158
+
159
+ DNS Findings:
160
+ $($dnsFindings -join "`n")
161
+
162
+ Process Findings:
163
+ $($processFindings -join "`n")
164
+
165
+ Network Findings:
166
+ $($networkFindings -join "`n")
167
+
168
+ Task Findings:
169
+ $($taskFindings -join "`n")
170
+
171
+ Behavioral Analysis:
172
+ $($suspicionScores | Format-Table | Out-String)
173
+ "@ | Out-File -FilePath $reportPath
174
+
175
+ Write-Host "`nDetailed report saved to: $reportPath" -ForegroundColor Cyan
@@ -0,0 +1,81 @@
1
+ # DNS Reconnaissance - Find RMM agents by DNS cache analysis
2
+ # No admin required - DNS cache is accessible to all users
3
+
4
+ $rmmDomains = @(
5
+ # Atera
6
+ "atera.com", "agent-api.atera.com", "servicebus.windows.net",
7
+ # ConnectWise
8
+ "connectwise.com", "screenconnect.com", "hostedrmm.com",
9
+ # Datto
10
+ "datto.com", "dattobackup.com", "centrastage.net",
11
+ # NinjaRMM
12
+ "ninjarmm.com", "ninja.io",
13
+ # Syncro
14
+ "syncromsp.com", "syncro.io",
15
+ # TeamViewer
16
+ "teamviewer.com",
17
+ # AnyDesk
18
+ "anydesk.com",
19
+ # Splashtop
20
+ "splashtop.com",
21
+ # LogMeIn
22
+ "logmein.com", "logmeinrescue.com",
23
+ # GoToAssist
24
+ "gotoassist.com",
25
+ # Bomgar/BeyondTrust
26
+ "bomgar.com", "beyondtrust.com",
27
+ # Kaseya
28
+ "kaseya.com", "kaseya.net",
29
+ # N-able (SolarWinds)
30
+ "n-able.com", "solarwindsmsp.com", "n-central.com",
31
+ # Pulseway
32
+ "pulseway.com",
33
+ # Naverisk
34
+ "naverisk.com",
35
+ # Acrinet
36
+ "acrinet.com",
37
+ # SuperOps
38
+ "superops.ai",
39
+ # Action1
40
+ "action1.com",
41
+ # Level.io
42
+ "level.io",
43
+ # Generic monitoring
44
+ "azure-devices.net", "cloudflare.com"
45
+ )
46
+
47
+ Write-Host "=== DNS Cache RMM Reconnaissance ===" -ForegroundColor Cyan
48
+ Write-Host "Scanning for $(($rmmDomains).Count) known RMM platforms...`n"
49
+
50
+ $found = @()
51
+ $dnsCache = Get-DnsClientCache
52
+
53
+ foreach ($domain in $rmmDomains) {
54
+ $matches = $dnsCache | Where-Object { $_.Entry -like "*$domain*" }
55
+ if ($matches) {
56
+ foreach ($match in $matches) {
57
+ $found += [PSCustomObject]@{
58
+ Domain = $match.Entry
59
+ Type = $match.Type
60
+ TTL = $match.TimeToLive
61
+ Data = $match.Data
62
+ Platform = $domain
63
+ }
64
+ Write-Host "[FOUND] $($match.Entry)" -ForegroundColor Red
65
+ Write-Host " IP: $($match.Data) | TTL: $($match.TimeToLive)s" -ForegroundColor Yellow
66
+ }
67
+ }
68
+ }
69
+
70
+ Write-Host "`n=== Summary ===" -ForegroundColor Cyan
71
+ if ($found.Count -gt 0) {
72
+ Write-Host "Found $($found.Count) RMM-related DNS entries!" -ForegroundColor Red
73
+ $found | Format-Table -AutoSize
74
+ } else {
75
+ Write-Host "No RMM domains found in DNS cache." -ForegroundColor Green
76
+ Write-Host "Note: Cache may be empty if system recently rebooted." -ForegroundColor Gray
77
+ }
78
+
79
+ # Export results
80
+ $found | Export-Csv -Path "dns_recon_results.csv" -NoTypeInformation
81
+ Write-Host "`nResults saved to dns_recon_results.csv"