Friday, March 24, 2017

I Just Saved $121!!

I'm not one to pimp products unless they are really good and I understand them, but today is an exception.

I have NO IDEA how GoodRX works, but I do know it saved me $121.11 on a single prescription.  Usually, when you install an app that get's you something for free, you are the commodity.  Most apps want all sorts of crazy access to your phone.  GoodRX wanted pretty basic access and gave me s super coupon.

Drug cost was $221.  My insurance only covered $48.  I was going to pay $173.  Enter the GoodRX coupon and I saved $121.  I only paid $52!!!!


  


Thursday, March 16, 2017

The Tyranny of Network Level Authentication and CredSSP

The Tyranny of Network Level Authentication and CredSSP

“My password is expired so I can’t login, but I need to RDP in to change my password!”, is the cry we constantly hear.

This happens when your users login to their local machine using one account, but need to RDP into to a machine using another account in a different domain.  This is often because the systems they need to work on are in a different domain in order to segment access.  Think Corp creds for email and HR vs prod creds for the company’s web sites.

NLA is not really a security control, it simply changes when you authenticate.  With NLA on, you authenticate (using CredSSP) before getting the remote session and GUI. This is designed to reduce the load on the server.  This however removes a user’s access to the login GUI where then can change their password at login.

Everything you are likely to find on this issue will tell you that the issue in Network Level Access (NLA) being required for RDP. NLA is not supposed to be required by default, but I have seen and heard that it often turns on on domain join.  I have seen this even though there was no GPO setting it. (We are both wrong, but I’ll get back to that later) This could be related to all sorts of build and domain join automation. If you have the issue, why is not particularly important. You will just need to go and set the GPO or edit the registry on the machine or via GUI.  



“Mark, I made the change, but I still can’t get in!!”  That’s right, you can’t. NLA probably wasn’t even turned on.  As I mentioned above, we were wrong. So why can’t we login and change our passwords‽  We can’t change our passwords because most RDP clients, such as mstsc.exe or rdcman.exe, just assume NLA is on and try to authenticate you first anyway.  This fails and you are kept out.

You need to tell your client not to use CredSSP for your connection. If you are implementing your own RDP client via the activeX library MsTscAx.dll, set EnableCredSspSupport to false.

One caveat is that there is no way to send the password anymore, say from your local cred manager or a password management tool.  You will have to type the old password once and the new password twice, so it’s a bit of a pain. 

Don’t let your password expire…

The Tyranny of Network Level Authentication and CredSSP

 

Friday, February 10, 2017

PowerShell Module for Reading Group Managed Service Account Passwords

I recently covered the topic of Active Directory Group Managed Service Accounts. They are the new hotness from Microsoft.  I also offed up some code snippets for interacting with them.

Now I offer up a PowersShell module that also exposes .NET classes and methods for reading gMSA passwords. 

This module has a couple of great uses.  First of all, not all services and applications can leverage a gMSA natively. The dll lets you try and fit in a gMSA to your system. Second, the module uses calls diretly to Actdive Diretory via LDAP rather than via the Active Directory Web Service.  In some cases, you may not have the firewall rules set up to allow access to the ADWS, but all clients will have access to AD over TCP 389, as it is required.

Enjoy!

Friday, January 27, 2017

Trump Admits that US Citizens Will Pay for the Wall

Failed businessman and reality TV personality Donald Trump  admitted today that US consumers will pay for his wall between the US and Mexico. White House press secretary Sean Spicer explained that Trump plans a 20% tax on goods imported from Mexico in order to pay for the wall.

Like many failed businessmen, Trump is unaware that the cost of goods will be passed on to the American consumers. Mexican goods already have a low profit margin for their manufacturers, so they will not be able to absorb the costs and will instead go pass the cost along to us or go out of business.

Friday, December 30, 2016

gMSAs are a Little Bit Weird

In my last post on retrieving the Group Managed Service Account password, I covered the fact that there is an old password value and a current password value. I have found no documentation on why they both exist. I did testing a while back and confirmed that only one was valid. This seemed odd and didn’t make sense in the context of a large enterprise. If a gMSA is used all over the globe in different AD sites, how do you make sure that all the services using the account rotate at the same moment. You don’t. While password changes use urgent replication and replicate to the PDCe immediately, this may still not be sufficient. There are two time intervals listed in the msDS-ManagedPassword explanation:
·         QueryPasswordInterval (8 bytes): A 64-bit unsigned integer containing the length of time, in units of 10^(-7) seconds, after which the receiver must requery the password. The QueryPasswordInterval field MUST be placed on a 64-bit boundary.
·         UnchangedPasswordInterval (8 bytes): A 64-bit unsigned integer containing the length of time, in units of 10^(-7) seconds, before which password queries will always return this password value. The UnchangedPasswordInterval field MUST be placed on a 64-bit boundary.

I was unable to decipher what exactly those mean, in terms of the password change, so I decided to see what happened by querying the blob repeatedly before, during, and after the change. While doing this, I tested LDAP binds for each password and recorded the results, as well as the key version number (KVNO). The KVNO is simply the version number for the password.
More below

It is nearly impossible for the gMSA, and all the services running as it, to rotate at the same movement.  It is impossible, in an enterprise, to even get the new password everywhere instantly. Instead AD pre-stages the new password. This is why the “must requery” time is always 5 minutes before the password change and both passwords are accepted for 5 minutes after the change. The test data below shows exactly what happens.  
TestTime
OldPwd
NewPwd
KVNO
NextQuery
PwdGoodUntil
12/29/2016 19:53
FALSE
TRUE
2
12/29/2016 19:59
12/29/2016 19:54
12/29/2016 19:54
FALSE
TRUE
2
12/29/2016 19:59
12/29/2016 19:54
12/29/2016 19:54
FALSE
TRUE
2
12/29/2016 19:59
12/29/2016 19:54
12/29/2016 19:55
TRUE
FALSE
2
12/29/2016 19:59
12/30/2016 15:54
12/29/2016 19:55
TRUE
FALSE
2
12/29/2016 19:59
12/30/2016 15:54
12/29/2016 19:56
TRUE
FALSE
2
12/29/2016 19:59
12/30/2016 15:54
12/29/2016 19:57
TRUE
FALSE
2
12/29/2016 19:59
12/30/2016 15:54
12/29/2016 19:58
TRUE
FALSE
2
12/29/2016 19:59
12/30/2016 15:54
12/29/2016 19:59
TRUE
FALSE
2
12/29/2016 19:59
12/30/2016 15:54
12/29/2016 20:00
TRUE
TRUE
3
12/30/2016 15:59
12/30/2016 15:54
12/29/2016 20:00
TRUE
TRUE
3
12/30/2016 15:59
12/30/2016 15:54
12/29/2016 20:01
TRUE
TRUE
3
12/30/2016 15:59
12/30/2016 15:54
12/29/2016 20:02
TRUE
TRUE
3
12/30/2016 15:59
12/30/2016 15:54
12/29/2016 20:03
TRUE
TRUE
3
12/30/2016 15:59
12/30/2016 15:54
12/29/2016 20:04
TRUE
TRUE
3
12/30/2016 15:59
12/30/2016 15:54
12/29/2016 20:05
FALSE
TRUE
3
12/30/2016 15:59
12/30/2016 15:54
12/29/2016 20:05
FALSE
TRUE
3
12/30/2016 15:59
12/30/2016 15:54
12/29/2016 20:06
FALSE
TRUE
3
12/30/2016 15:59
12/30/2016 15:54
12/29/2016 20:06
FALSE
TRUE
3
12/30/2016 15:59
12/30/2016 15:54

This mostly makes sense, except that in the 5 minutes prior to the password change, the value clearly called CurrentPassword, is wrong. It has shifted to the PreviousPassword value. Also, the account is set to a one day password change interval, yet the next change is not in 24 hours, it is in 20 hours. If you decide to use the code to implement your own use of a gMSA it is vital to keep these things in mind.  I think this is all explained by Microsoft here, but it is hard to read.  It makes more sense after having run the test.



Wednesday, December 28, 2016

Any sufficiently advanced Active Directory Web Service is indistinguishable from magic

Or how to retrieve the password of a Group Managed Service Account

I’m not one to leave things alone if I feel like I don’t have a solid and deep understanding of them, well that or I completely ignore them… In the case of the Active Directory Web Service I have always ignored it and been confused why it existed or what it did. As far as I could tell, it created more attack surface on DCs and extra dependencies. As far as I had seen, the ADWS did a poor job retrieving data I have always gotten in other ways in the past. It limits result set sizes and other odd things. The one thought I had was, “maybe the ADWS does less than LDAP or ADSI, so one can block those in certain situations”. That would be a nice security control. It turns out that the ADWS lets you do just about anything that can be done via LDAP v3, including the use of extended LDAP operations. At this point, I assumed that the ADWS was fully redundant to the LDAP and ADSI interfaces. Then I found something that “can only be done via the ADWS”, interaction with Group Managed Service Accounts.

Group Managed Service accounts, or gMSAs, are the new hotness in service accounts.  By new I mean 2012. The gMSA is a service account that auto rotates its password and works with services that support it, so that the service and AD rotate the password at the same moment. Microsoft first introduced the managed service account (notice the missing word group), which was a great idea, but didn’t meet the needs of an enterprise. The old managed service account could only run on a single server and wasn’t well supported by various services. The gMSA can run on any number of servers, allowing for the account to hold a Service Principal Name (SPN), which is key to the service working with Kerberos. While Kerberos is supposed to be the default auth method for Windows, since 2000, a huge number of systems may fall back to NTLM if Kerberos is misconfigured. As I’ve noted before, NTLM comes in flavors of bad and worse. gMSAs help deal with this while removing the overhead of manual service account password changes.

Here’s where the learning began for me. Not all services and systems can work using a gMSA. I’m not clear why this is the case when something simply runs as a service, but I am sure there are good reasons. Possibly it could be things like DPAPI encryption, though the gMSA stores, and returns, two versions of the password, so DPAPI shouldn’t be an issue. None the less, I decided I’d just write my own .NET tools to retrieve the password and do the needful.

The Trail of Failure

The gMSA password is stored in the attribute msDS-ManagedPassword. Also, here. So, I created a gMSA and tried to retrieve the password using LDAP, via ldifde. Then the sadness started. I tried to pull back the samaccountname and password blob. Yes, like a computer object the tools add a trailing $ to the samaccountname.

C:\Windows\system32>ldifde -f ssss  -l msDS-ManagedPassword,samaccountname -r "samaccountname=_coolaccount$"

Connecting to "fundc1.xcloud.gbl"

Logging in as current user using SSPI

Exporting directory to file ssss

Searching for entries...

Writing out entries

No Entries found

 

The command has completed successfully

 

C:\Windows\system32>

 

I tried again, leaving out the password.

C:\Windows\system32>ldifde -f ssss  -l samaccountname -r "samaccountname=_coolaccount$"

Connecting to "fundc1.xcloud.gbl"

Logging in as current user using SSPI

Exporting directory to file ssss

Searching for entries...

Writing out entries.

1 entries exported

 

The command has completed successfully

 

C:\Windows\system32>

 

This was odd so I decided to get more sophisticated by running the command in .NET code and failed.  I always use the System.DirectoryServices.Protocols (S,DS.P) namespace, as it calls the native LDAP libraries with no interference by the ADSI layer. It also works great with 3rd party LDAPs. 

I did a search request similar to this:

SearchRequest searchRequest = new SearchRequest

                                    (targetOu,

                                      ldapSearchFilter,

                                      SearchScope.OneLevel,

                                      strArrayOfAttributes);

 

I still got nothing back and be began to suspect that there was a mystery afoot.  I then tired via PowerShell.

PS C:\Users\whataname> Get-ADServiceAccount -Identity _coolaccount2 -Properties 'msDS-ManagedPassword'

 

 

DistinguishedName    : CN=_coolaccount2,CN=Managed Service Accounts,DC=xcloud,DC=gbl

Enabled              : True

msDS-ManagedPassword : {1, 0, 0, 0...}

Name                 : _coolaccount2

ObjectClass          : msDS-GroupManagedServiceAccount

ObjectGUID           : 380a65ba-fb12-491f-ac4f-775f0eb7ceba

SamAccountName       : _coolaccount2$

SID                  : S-1-5-21-2885290700-3155337720-2128568531-2106

UserPrincipalName    :

 

 

 

PS C:\Users\whataname>

 

I got back the password blob and did a small dance, then I went to work on figuring out how PowerShell got the password when I was unable to. I started a packet capture using Netmon 3.4, Which showed me that PowerShell was reaching out to a DC on TCP port 9389. This is the port for the ADWS. I did much searching and tried several tools, such as Fiddler, to let me see inside the AWDS traffic. None of these worked.

More below

On the Road to Successville

Finally I found a great article boasting exactly what I needed, How to view SOAP XML messages to and from AD Webservices and Powershell. This was the cure I was looking for. I setup tracing and then created a new gMSA, and then used the PowerShell command to retrieve the password blob.

In both the creation and the retrieval of the password, I found this:

<ad:controls>

<ad:control type="1.2.840.113556.1.4.801" criticality="true">

<ad:controlValue xsi:type="xsd:base64Binary">MIQAAAADAgEH</ad:controlValue>

</ad:control>

</ad:controls>

If you do a lot of AD work, 1.2.840.113556.1.4.801 pops out as an LDAP Extended Control OID. In this case, it is LDAP_SERVER_SD_FLAGS_OID control that lets one send and receive Security Descriptors. The controlValue ‘30 84 00 00 00 03 02 01 07’ is the BER encoded ASN.1  value of 07 which gets us the user owner, group owner, and DACL.

With this information, I realized I couldn’t use ldifde, as it does not let you specify LDAP Controls. The next step was to use S.DS.P to issue the search request with the LDAP Control.  I had a well-built project using S.DS.P, that implemented a control already, so rather than rewriting it all, I just cut and pasted a bit and requested the password blob and it worked!

With the assurance that I could pull back the password blob, I went about making a cleaner implementation than my borrowed code. I also went about writing a class to decode the password blob.

As the passwords are random, the chars map to mostly non-standard characters. Using the password in an LDAP bind confirms the password is good.

My leaner and cleaner implementation for retrieving the password blob did not go so well. I repeatedly got back {"An operation error occurred."}. This occurred even with strong LDAP focused error handling.  It left me with very little to go on.

When I took a close look at the different code, I noticed that the working code explicitly setup my LdapConnection securely:

            theConn.SessionOptions.Sealing = true;

            theConn.SessionOptions.Signing = true;

 

The default options set signing to true, but sealing to false. 

This means that the connection, by default, has integrity (tamper) protection, but the data is not encrypted, so anyone who can sniff it can read it.  It makes perfect sense to not send back an unencrypted password over and unencrypted channel. In fact, password changes are also not allowed over unencrypted connections, by default.  Knowing that encryption is required it was easy to find the ldifde syntax to encrypt and get back the password blob.

-h              Enable SASL layer signing and encryption

 

C:\Windows\System32\pwdb>ldifde -f ssss  -l msDS-ManagedPassword,samaccountname -r "samaccountname=_coolaccount$" -h

Connecting to "fundc1.xcloud.gbl"

Logging in as current user using SSPI

Exporting directory to file ssss

Searching for entries...

Writing out entries.

1 entries exported

 

The command has completed successfully

 

C:\Windows\System32\pwdb>type ssss

dn: CN=_coolaccount,CN=Managed Service Accounts,DC=xcloud,DC=gbl

changetype: add

sAMAccountName: _coolaccount$

msDS-ManagedPassword::

 AQAAACIBAAAQAAAAEgEaASJTvMGeMn+PpMxf+1PtLESZoQu7OKmjqR1ndZIRZf821rjx0KNBvR2kii

 2Jadwe5km9fZFrejLezkuzznJ5VeHAaHuNEklQgwNd8vMjpXYwMc13jMGSxnRoT3M727mn4EL887Dj

 RjGyhKsN7Jg1vPGIl7ZQXspR8vfU09Oo26EkMsPw67NNrDyZLRdSLjMvaZ3jSh6wfFqH5IaKMevSs2

 ouDrj3dTsx63lrj/bXuQ1XMrH39ChcZ07qkIAW/F8dDAdjGVSMPFusmP+WqyrotDS8s7NYpVVNJPV0

 nP+CnBePs+38WCgG0cJBfZCv4bfPZELYJb8x9UX9FiD+D5LHVEAAAPIH4veYFgAA8qkRRZgWAAA=

 

 

C:\Windows\System32\pwdb>

 

Sure enough, buy adding signing and sealing to my new project, I was able to get back the blob. This spurred the question, “what’s up with the LDAP_SERVER_SD_FLAGS_OID?”  I commented out the LDAP Control and was still able to get the password back.

Soooo, what is up with the LDAP_SERVER_SD_FLAGS_OID?  It turns out, that for some unknown reason, the principals that can retrieve the password are not stored as part of a standard ACE, nor as some list of SIDs, but instead, the list is stored as a binary blob in security descriptor format on the attribute msDS-GroupMSAMembership. Like other security descriptors, the LDAP Control must be present to read or write to it.

To read the SD, the query is formed like this:

 

                string ldapSearchFilter = string.Format("(|(sAMAccountName={0})(sAMAccountName={0}$))", acctName);

                string[] attribs = new string[] { "name",

                            "msDS-GroupMSAMembership"                           };

 

                // create a SearchRequest object

                SearchRequest searchRequest = new SearchRequest

                                                (this.DomainDN, ldapSearchFilter,

                                                 System.DirectoryServices.Protocols.SearchScope.Subtree, attribs);

 

                byte[] OIDVal = new byte[] { 0x30, 0x84, 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x07 };

                DirectoryControl editSDOid = new DirectoryControl("1.2.840.113556.1.4.801", OIDVal, false, true);

                searchRequest.Controls.Add(editSDOid);

 

In order to read and write the security descriptors, one can use the System.DirectoryServices.ActiveDirectorySecurity class. Get the byte[] value of  msDS-GroupMSAMembership and pass it into that class like so:

public byte[] addSIDtoSD(byte[] currentSddlBytes, string newSID)

        {

            ActiveDirectorySecurity ads = new ActiveDirectorySecurity();

            SecurityIdentifier realSID = new SecurityIdentifier(newSID);

 

            byte[] sddlOut = new byte[2];

 

            try

            {

                ads.SetSecurityDescriptorBinaryForm(currentSddlBytes);

                AuthorizationRuleCollection bb = ads.GetAccessRules(true, true, typeof(SecurityIdentifier));

                bool bAlreadyInSD = false;

 

                //skip the add if the SID is already on the list

                foreach (AuthorizationRule ar in bb)

                {

 

                    if (ar.IdentityReference.Value.ToString() == realSID.ToString())

                    {

                        bAlreadyInSD = true;

                        break;

                    }

                }

 

                if (!bAlreadyInSD)

                {

                    //add it to the SD

                    ads.AddAccessRule(new ActiveDirectoryAccessRule(realSID, ActiveDirectoryRights.GenericAll, AccessControlType.Allow));

 

                    //output the new SD in bytes

                    sddlOut = ads.GetSecurityDescriptorBinaryForm();

 

One benefit of doing this in .NET is that the New-ADServiceAccount and Set-ADServiceAccount commands only let you overwrite the list of PrincipalsAllowedToRetrieveManagedPassword, so it is more work to add or remove a user or group. Also, the underlying PowerShell will not allow mixing the list so that it contains users and groups.

Set-ADServiceAccount : An AD Property Value Collection may only contain values of the same type. Specified value of

type 'Microsoft.ActiveDirectory.Management.ADGroup' does not match the existing type of

'Microsoft.ActiveDirectory.Management.ADUser'.

Parameter name: value

At line:1 char:1

+ Set-ADServiceAccount -Identity _coolaccount -PrincipalsAllowedToRetrieveManagedP ...

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : InvalidArgument: (_coolaccount:ADServiceAccount) [Set-ADServiceAccount], ArgumentExcepti

   on

    + FullyQualifiedErrorId : ActiveDirectoryCmdlet:System.ArgumentException,Microsoft.ActiveDirectory.Management.Comm

   ands.SetADServiceAccount

 

There is no such constraint in AD, so using .NET code you can avoid breaking your account.

What it’s Like in Successville (Summary?)

The Active Directory Web Service, like all magic, just uses some sleight of hand and misdirection with gMSAs.

You simply need to request the password blob using SSL or SASL encryption. No LDAP Controls are needed to read it.

You can view or edit the msDS-GroupMSAMembership list if you know how to work with security descripts and include the LDAP Extended Control 1.2.840.113556.1.4.801 LDAP_SERVER_SD_FLAGS_OID.

Cleaner code can be found here.

 

 

Inputting falsified referrals to this site violates the terms of service of this site and is considered unauthorized access (hacking).