Recently I have been trying to better understand Windows Service Security.
Starting with Windows Vista, Windows Services were able to have a SID Associated with the service so you could have Service Isolation and reduce the required privileges needed and to still have the ability to access the required registry and files it needed to, and also have the ability of restricting other SID’s to it’s resources.
So I was wondering, how do you get a SID for a service you create ?
The only built in tool I could find was the SC.Exe utility console application and use the command “sc.exe showsid ServiceName”
I then got wondering how does that program get the SID for the service ? Has it already been created and its just getting it from some location ?
After some internet searching I ran across a Wikipedia page for Security Identifier and it said the the SID is created using the service name in uppercase and running it thru the SHA-1 Hash function.
So I created a small application that did that but it was not producing the same output as the SC.Exe utility. So I was still missing something.
I then started cmd.exe with a debugger, then ran the command “sc.exe showsid ServiceName” , that gave me a little bit of information but not enough to solve my problem of outputting the wrong results.
Next I turned to a Utility named EXE Explorer to view what the imports were for the Sc.exe utility and found that it imported a function from ntdll.dll named RtlCreateServiceSid. That function Is undocumented.
Next I copied the ntdll.dll to another folder and opened it with a program named PEBrowser64 Professional. Then found and decompiled that function and seen it was in fact using the Sha1 has function.
Next I Looked at the RFC 3174 SHA1 specification to see if they were doing anything different.(They were not,best I could tell)
Going back to PEBrowser64 Professional and after tracing that function thru several other functions you can get the basic steps required to output a Service SID from the input service name.
1: Input service same.
2: Convert service name to upper case.
3: Get the Unicode bytes() from the upper case service name.
4: Run bytes() thru the sha1 hash function.
5: Reverse the byte() string returned from the SHA1 hash function (on Little Endian systems Not tested on Big Endian systems)
6: Split the reversed string into 5 blocks of 4 bytes each.
7: Convert each block of hex bytes() to Decimal
8: Reverse the Position of the blocks
9: Create the first part of the SID “S-1-5-80-“
10: Tack on each block of Decimal strings with a “-“ in between each block that was converted and reversed.
11: Finally out put the complete SID for the service.
This is not the exact order that the API call used but the order I used in my test application.
Here is what the final test application looks like.
This test application currently only takes input from the combo box that is filled with the service names it found.
The next problem was to figure out why I was getting a Different result so I broke down an Existing SID to Hex to be able to compare and to help figure this out.
391397178 = 0x17543F3A ,Reverse Order = 0x3A3F5417
1713532359 = 0x66226DC7 ,Reverse Order = 0xC76D2266
3388783719 = 0xC9FCBC67 ,Reverse Order = 0x67BCFCC9
1671243502 = 0x639D26EE ,Reverse Order = 0xEE269D63
2983178441 = 0xB1CFB0C9 ,Reverse Order = 0xC9B0CFB1
My initial output looked like.
Wrong results, But it agreed with all SHA1 Utility’s I tried.
After some more internet searching I ran across a question on Stack Overflow named Unicode, UTF, ASCII, ANSI format differences down at the bottom there was a link to another article named Joel on Software: The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
After reading that I then searched on Code project for “RFC 3174” and ended up with this article http://www.codeproject.com/Articles/2463/CSHA1-A-C-Class-Implementation-of-the-SHA-1-Hash-A
I Read the article, downloaded the sample project and built it, and then ran it inputting the uppercase service name and it returned,
Enter the string to hash:
Hash of the ANSI representation of the string:
Hash of the Unicode representation of the string:
Now looking at that confirmed the the RtlCreateServiceSid function was not doing anything strange with the SHA1 function.
The top one matched what I was outputting in the original version but the bottom was lining up with the SID I had broken down.
So what was the problem of the different results ?
I then went back to my code and took a look and made a change on the Input Decoder from.
Dim encoder As New System.Text.ASCIIEncoding
Dim encoder As New System.Text.UnicodeEncoding
After that I was getting the results of .
Now I knew I was onto something and the rest was a matter of following the steps mentioned above.
Lets take a closer look to understand why I was getting the wrong results.
A while back I created a utility that input a string and output as hex string encoded with various Unicode encoders.
As you can see from the screenshot above that using the ASCII encoder output as :
4D 53 4D 50 53 56 43 And the Unicode output as 4D 0 53 0 4D 0 50 0 53 0 56 0 43 0
The first is 7 bytes long but the second one is padded with zeros and is 14 bytes long.
Looking thru the RFC 3174 you find that the whole thing starts with the length of the “message” in binary bits and using a different format will drastically change the outcome of the hash function due to the different lengths..
Another thing you may notice in this application is the BigEndianUnicode.
If you will take a close look of that, the bytes are going the same direction but the lead and trailing Zeros are on opposite ends.That would lead me to believe that the “Plain” Unicode is considered Little Endian byte order. Correct me if I am wrong.
The last part of the puzzle is after you create a SID how do you associate it with the service name ?
The answer can be found on Service Changes for Windows Vista under the sub section “Service Isolation”.
The last part reads : “To set the service SID, call ChangeServiceConfig2 with SERVICE_CONFIG_SERVICE_SID_INFO.”
In order to have your service have a SID set automatically you must set a value for “SERVICE_SID_INFO structure” to either “SERVICE_SID_TYPE_RESTRICTED” or “SERVICE_SID_TYPE_UNRESTRICTED” if you set it as “SERVICE_SID_TYPE_NONE” then it will not automatically be set and available for use by your service to aid in securing it.
Just being able to create a SID using this tool does not enable you to be able to use that SID without setting the required parameters above, It would only show you the same SID that the “sc.exe showsid ServiceName” does.
For instance If I was to run a service name like “mySuperService” thru the SC.exe utility it returns.
SERVICE SID: S-1-5-80-1956725871-603941828-2318551034-3950094706-3826225633
But that does not mean the service is installed on the system or the SID could be used.
It is just the SID created from the name.
Although it may help to know what it will be after being set or while building a Security Descriptor and setting the rights.
I have not found a command using the SC.Exe utility to set the service SID yet.
It may need to be done thru your service installer or a controller application.
The “Sc config servicename” does not seem to have the setting in it for setting the Service SID Type. I’m still looking into it.
That’s it for now I’m still working on a more overall service security article mainly aimed towards understanding why my program stopped working for shutting down Microsoft Security Essentials. Windows 8.1 has something new for Anti-Malware programs.