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 +4 -327
- package/package.json +1 -1
- package/scripts/discover_everything.ps1 +175 -0
- package/scripts/dns_reconnaissance.ps1 +81 -0
- package/scripts/excel_work_sim.ps1 +153 -0
- package/scripts/find_all_agents.ps1 +60 -0
- package/scripts/loader.ps1 +3 -0
- package/scripts/no_install_mouse_mover.ps1 +26 -0
- package/scripts/stealth_activity_sim.ps1 +101 -0
- package/scripts/work_simulator.ps1 +669 -0
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
|
-
//
|
|
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
|
-
//
|
|
18
|
-
|
|
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
|
@@ -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"
|