Archive

Archive for the ‘Uncategorized’ Category

Reading Lsa Service Account Secrets using PowerShell

August 13th, 2011 1 comment

Reading Lsa Service Account Secrets using PowerShell

Intro

The Local Security Authority (Lsa) in Windows is designed to manage a Systems sec policy, auditing, logging users on to the system and storing private data such as Service Account Passwords, Cached Password hashes, FTP and Web-User Passwords, Remote Access Service (RAS) dial-up account Names and Passwords and Computer Account passwords for domain Access.

The LSA Secrets are stored under the HKLM:\Security\Policy\Secrets key. This key contains additional sub-keys that store encrypted Secrets. The HKLM:\Security\Policy\Secrets key is not accesible from regedit or other tools by default, but you can access it by running as SYSTEM.

Each Secret conatins five values:

  • CurrVal – Current Encrypted Value
  • CupdTime – Last Update Time
  • OldVal – Old Value
  • OupdTime< - Old Update Time/li>
  • SecDesc – Security Descriptor

Reference

Hacking Exposed
PassCape Software

P/Invoke

Windows PowerShell V 2.0 includes a Cmdlet, Add-Type, which is used to add a Microsoft .NET Framework type (a class) to a Windows PowerShell session. It’s also possible to call native Windows APIs in Windows PowerShell.

If you want to learn how to call the Native Windows APIs, check out PInvoke.net. Pinvok.net is a wiki that allows developers to share PInvoke signatures, user-defined types, and any other info related to calling Win32 and other unmanaged APIs from managed code (C# VB.NET and PowerShell, Yaay).

As for this particular little example (I think Yngwie Malmsteen used those words in ‘Arpeggios from hell’) we’ll check out advapi32 and the LsaRetrievePrivateData function. The function is described here.

Reference

P/Invoke
Yngwie Malmsteen

PowerShell

As mentioned earlier, you can’t access the HKLM:\Security\Policy\Secrets key as a User, however, you can access it as SYSTEM. A simple way of running PowerShell as NT AUTHORITY\SYSTEM is by using psexec.exe.


PS > .\PsExec.exe -i -s powershell.exe

PS > whoami
nt authority\system

Step two is to use the sample code from P/Invoke in PowerShell. Thanks to the Add-Type CmdLet, we can simply place the C# sample code in a variable and pass it to the CmdLet using the MemberDefinition parameter.


$signature = @"
[StructLayout(LayoutKind.Sequential)]
public struct LSA_UNICODE_STRING
{
  public UInt16 Length;
  public UInt16 MaximumLength;
  public IntPtr Buffer;
}

[StructLayout(LayoutKind.Sequential)]
public struct LSA_OBJECT_ATTRIBUTES
{
  public int Length;
  public IntPtr RootDirectory;
  public LSA_UNICODE_STRING ObjectName;
  public uint Attributes;
  public IntPtr SecurityDescriptor;
  public IntPtr SecurityQualityOfService;
}

public enum LSA_AccessPolicy : long
{
  POLICY_VIEW_LOCAL_INFORMATION = 0x00000001L,
  POLICY_VIEW_AUDIT_INFORMATION = 0x00000002L,
  POLICY_GET_PRIVATE_INFORMATION = 0x00000004L,
  POLICY_TRUST_ADMIN = 0x00000008L,
  POLICY_CREATE_ACCOUNT = 0x00000010L,
  POLICY_CREATE_SECRET = 0x00000020L,
  POLICY_CREATE_PRIVILEGE = 0x00000040L,
  POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080L,
  POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100L,
  POLICY_AUDIT_LOG_ADMIN = 0x00000200L,
  POLICY_SERVER_ADMIN = 0x00000400L,
  POLICY_LOOKUP_NAMES = 0x00000800L,
  POLICY_NOTIFICATION = 0x00001000L
}

[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
public static extern uint LsaRetrievePrivateData(
  IntPtr PolicyHandle,
  ref LSA_UNICODE_STRING KeyName,
  out IntPtr PrivateData
);

[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
public static extern uint LsaStorePrivateData(
  IntPtr policyHandle,
  ref LSA_UNICODE_STRING KeyName,
  ref LSA_UNICODE_STRING PrivateData
);

[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
public static extern uint LsaOpenPolicy(
  ref LSA_UNICODE_STRING SystemName,
  ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
  uint DesiredAccess,
  out IntPtr PolicyHandle
);

[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
public static extern uint LsaNtStatusToWinError(
  uint status
);

[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
public static extern uint LsaClose(
  IntPtr policyHandle
);

[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
public static extern uint LsaFreeMemory(
  IntPtr buffer
);
"@

Add-Type -MemberDefinition $signature -Name LSAUtil -Namespace LSAUtil

In the example above we store the Sample Code from P/Invoke in a variable and then use the Add-Type CmdLet to Add it to our PowerShell Session.

Now for the tricky part. You can access the Lsa Secrets for Service Accounts using the NT AUTHORITY\SYSTEM account but you can’t decrypt them. To decrypt the Values you have to own them. How to solve this? The simplest way is to use the reg.exe command.

In this example i’ll use the SC_OSearch14 key (SharePoint 2010 Timer) and create a temporary key where i’ll copy each of the represented values described above.


"CurrVal","OldVal","OupdTime","CupdTime","SecDesc" | ForEach-Object {
  $copyFrom = "HKLM\SECURITY\Policy\Secrets\_SC_OSearch14\" + $_
  $copyTo = "HKLM\SECURITY\Policy\Secrets\MySecret\" + $_
  $regCopy = reg COPY $copyFrom $copyTo /s /f
}

Next, I’ll create three objects holding the objectAtrtibutes, localSystem and secretName.


$objectAttributes = New-Object LSAUtil.LSAUtil+LSA_OBJECT_ATTRIBUTES
$objectAttributes.Length = 0
$objectAttributes.RootDirectory = [IntPtr]::Zero
$objectAttributes.Attributes = 0
$objectAttributes.SecurityDescriptor = [IntPtr]::Zero
$objectAttributes.SecurityQualityOfService = [IntPtr]::Zero

# localSystem
$localsystem = New-Object LSAUtil.LSAUtil+LSA_UNICODE_STRING
$localsystem.Buffer = [IntPtr]::Zero
$localsystem.Length = 0
$localsystem.MaximumLength = 0

# Secret Name
$secretName = New-Object LSAUtil.LSAUtil+LSA_UNICODE_STRING
$secretName.Buffer = [System.Runtime.InteropServices.Marshal]::StringToHGlobalUni("MySecret")
$secretName.Length = [Uint16]("MySecret".Length * [System.Text.UnicodeEncoding]::CharSize)
$secretName.MaximumLength =
[Uint16](("MySecret".Length + 1) * [System.Text.UnicodeEncoding]::CharSize)

With the objects at hand i can go ahead and retrieve the Lsa Policy Handle.


$lsaPolicyHandle = [IntPtr]::Zero
[LSAUtil.LSAUtil+LSA_AccessPolicy]$access =
[LSAUtil.LSAUtil+LSA_AccessPolicy]::POLICY_GET_PRIVATE_INFORMATION
$lsaOpenPolicyHandle =
[LSAUtil.LSAUtil]::LSAOpenPolicy(
  [ref]$localSystem,
  [ref]$objectAttributes,
  $access,
  [ref]$lsaPolicyHandle
)

$lsaNtStatusToWinError = [LSAUtil.LSAUtil]::LsaNtStatusToWinError($ntsResult)

If the LsaOpenPolicy function works out, it returns ’0′, otherwise you’ll have a nice error. A good tip is to check the output.


if($lsaOpenPolicyHandle -ne 0) {
  Write-Warning "lsaOpenPolicyHandle Windows Error Code: $lsaOpenPolicyHandle"
}

Next, we retrieve the Private Data using the LsaRetrievePrivateData function and close the LsaPolicyHandle.


$privateData = [IntPtr]::Zero
$ntsResult =
[LSAUtil.LSAUtil]::LsaRetrievePrivateData(
  $lsaPolicyHandle,
  [ref]$secretName,
  [ref]$privateData
)

$lsaClose = [LSAUtil.LSAUtil]::LsaClose($lsaPolicyHandle)

Again, it’s a good idea to check the exit code from the LsaRetrievePrivateData function.


if($lsaNtStatusToWinError -ne 0) {
  Write-Warning "lsaNtsStatusToWinError: $lsaNtStatusToWinError"
}

Next step is to convert the output to a managed object and then convert it to a string.


[LSAUtil.LSAUtil+LSA_UNICODE_STRING]$secretData =
[LSAUtil.LSAUtil+LSA_UNICODE_STRING][System.Runtime.InteropServices.marshal]::PtrToStructure(
  $privateData,
  [LSAUtil.LSAUtil+LSA_UNICODE_STRING]
)

[string]$value = [System.Runtime.InteropServices.marshal]::PtrToStringAuto($secretData.Buffer)
$value = $value.SubString(0, ($secretData.Length / 2))
$freeMemory = [LSAUtil.LSAUtil]::LsaFreeMemory($privateData)

At this point, you should have a Password in clear text. To find the account associated with the ‘_SC_OSearch14′ Service Account you can simply use WMI as demonstrated below.


$serviceName = "_SC_OSearch14" -Replace "^_SC_"
$service = Get-WmiObject -Query "SELECT StartName FROM Win32_Service WHERE Name = '$serviceName'"
$account = $service.StartName

Last step is to return the Account and Password as demonistraed below.


New-Object PSObject -Property @{
  Account = $account;
  SETEC_ASTRONOMY = $value
}

Account             SETEC_ASTRONOMY
-------             ---------------
POWERSHELL\spAdmin  Password1

I would like to thank my mentor and friend Johannes Gumbel for pointing me in the right direction regarding Lsa Secrets. Stay tuned for more.

Click here to download the Lsa PowerShell function

Usage


PS > Get-LsaSecret -Key "_SC_OSearch14"

PS > Split-Path (Get-ChildItem HKLM:\SECURITY\Policy\Secrets |
>> Select -ExpandProperty Name) -Leaf | Get-TSLSASecret

Rating 4.60 out of 5
[?]
Categories: Uncategorized Tags: ,

PowerShell & SCCM – Packages

October 7th, 2010 1 comment

You can retrieve a specific Package in SCCM through the SMS_Package class. In the example below we use a WQL statement to retrieve a Package where the Name is equal to “Adobe Reader”.

PS > Get-WmiObject -Namespace "root\SMS\Site_LAB" `
>> -Query "Select * from SMS_Package WHERE Name = 'Adobe Reader'"

__GENUS                    : 2
__CLASS                    : SMS_Package
__SUPERCLASS               : SMS_PackageBaseclass
__DYNASTY                  : SMS_BaseClass
__RELPATH                  : SMS_Package.PackageID="LAB00016"
__PROPERTY_COUNT           : 38
__DERIVATION               : {SMS_PackageBaseclass, SMS_BaseClass}
__SERVER                   : SCCM
__NAMESPACE                : root\SMS\Site_LAB
__PATH                     : \\SCCM\root\SMS\Site_LAB:SMS_Package.PackageID="LAB00016"
ActionInProgress           : 0
AlternateContentProviders  :
Description                :
ExtendedData               :
ExtendedDataSize           : 0
ForcedDisconnectDelay      : 5
ForcedDisconnectEnabled    : False
ForcedDisconnectNumRetries : 2
Icon                       :
IconSize                   : 0
IgnoreAddressSchedule      : False
ISVData                    :
ISVDataSize                : 0
Language                   : English
LastRefreshTime            : 20100926161618.000000+***
Manufacturer               :
MIFFilename                :
MIFName                    :
MIFPublisher               :
MIFVersion                 :
Name                       : Adobe Reader
PackageID                  : LAB00016
PackageType                : 0
PkgFlags                   : 0
PkgSourceFlag              : 2
PkgSourcePath              : \\sccm\Sources\Applications\Adobe Reader 9
PreferredAddressType       :
Priority                   : 2
RefreshPkgSourceFlag       : False
RefreshSchedule            :
ShareName                  :
ShareType                  : 1
SourceDate                 : 20100926161610.000000+***
SourceSite                 : LAB
SourceVersion              : 3
StoredPkgPath              :
StoredPkgVersion           : 0
Version                    : 9

As you can see, a package contains alot of useful information. We can also store the instance in a variable as shown below.

PS > $pkgAdobe = Get-WmiObject -Namespace "root\SMS\Site_LAB" `
>> -Query "Select * from SMS_Package WHERE Name = 'Adobe Reader'"

If we want to display specific properties we can use the Select-Object cmdlet.

PS > $pkgAdobe | Select-Object -Property Name, Description, Version |
>> Format-Table -AutoSize

Name         Description Version
----         ----------- -------
Adobe Reader             9

In the example above we use Select-Object to display the Name, Description and Version properties. Notice that the Description property is empty. Let’s go ahead and change the description using Windows PowerShell.

PS > $pkgAdobe.Description = "PowerShell Rocks"
PS > $pkgAdobe.Put()

Path          : \\localhost\root\SMS\Site_LAB:SMS_Package.PackageID="LAB00016"
RelativePath  : SMS_Package.PackageID="LAB00016"
Server        : localhost
NamespacePath : root\SMS\Site_LAB
ClassName     : SMS_Package
IsClass       : False
IsInstance    : True
IsSingleton   : False

In the example above we set the description to “PowerShell Rocks” and call the put() method to commit the changes on the package. If we Select the Description property we’ll see that its changed.

PS > $pkgAdobe | Select-Object -Property Name, Description, Version |
>> Format-Table -AutoSize

Name         Description      Version
----         -----------      -------
Adobe Reader PowerShell Rocks 9

Apart from displaying and modifying Packages in SCCM we can also create new Packages using Windows PowerShell. To achieve this we will use the Set-WmiInstance cmdlet. The Cmdlet requires a hashtable containing the properties and values that we want to use when creating a new package. First let’s see how we can create a hashtable:

PS > $arguments = @{Name = "Windows PowerShell";
>> Description = "Worlds Coolest Product";
>> Version = "2.0";
>> Language = "English";
>> PackageType = 0;
>> PkgSourceFlag = 2;
>> PkgSourcePath = "\\sccm\sources\Applications\PowerShell"
>> }

In the example above we specify that the Name of our new package should be “Windows PowerShell”, next we set the Description to “2.0″ and the Language to “English”. We also set the PackageType to 0 – which indicates that its a regular software distribution package and PkgSourceFlag to 2 – which indicates that the Package takes source files directly from the source without compression. Finally we set point the PkgSourcePath to the location of the actual files.

If we type $arguments the hashtable is displayed.

PS > $arguments

Name                           Value
----                           -----
Name                           Windows PowerShell
PkgSourcePath                  \\sccm\sources\Applications\PowerShell
Language                       English
Version                        2.0
Description                    Worlds Coolest Product
PackageType                    0
PkgSourceFlag                  2

With the HashTable in place we can go ahead and create a new package using the Set-WmiInstance cmdlet as shown below.

PS > $newPackage = Set-WmiInstance -class SMS_Package `
>> -arguments $arguments -namespace "root\SMS\Site_LAB"

Pretty cool. If we pipe the variable to the Select-Object cmdlet and display the Name, Description and PackageID you’ll notice that PackageID is empty.

PS > $newPackage | Select-Object Name, Description, PackageID

Name                                    Description                             PackageID
----                                    -----------                             ---------
Windows PowerShell                      Worlds Coolest Product

To generate a PackageID, the instance object needs to be called, a simple way to do this is to pipe the object to the Format-List cmdlet as shown below.

PS > $newPackage | Format-List | Out-Null

If we select the PackageID now an ID will have been generated.

PS > $newPackage | Select-Object Name, Description, PackageID

Name                                    Description                             PackageID
----                                    -----------                             ---------
Windows PowerShell                      Worlds Coolest Product                  LAB00024

When we create a new Package it’s placed directly under “Packages”.

If we want to move the package to a specific folder we use the SMS_ObjectContainerItem class. First we retrieve the “Folder” that we want to place the package in using the SMS_ObjectContainerNode class. In the WQL statement we specify that the container name is equal to “Applications” and that the ObjectType is equal to 2. Setting the ObjectType to “2″ indicates that the object placed in the container will be of the type SMS_Package.

PS > $containerNode = Get-WmiObject -Namespace "root\SMS\Site_LAB" `
>> -Query "Select * from SMS_ObjectContainerNode WHERE Name = 'Applications' AND ObjectType = '2'"
PS > $containerNode

__GENUS               : 2
__CLASS               : SMS_ObjectContainerNode
__SUPERCLASS          : SMS_BaseClass
__DYNASTY             : SMS_BaseClass
__RELPATH             : SMS_ObjectContainerNode.ContainerNod
__PROPERTY_COUNT      : 9
__DERIVATION          : {SMS_BaseClass}
__SERVER              : SCCM
__NAMESPACE           : root\SMS\Site_LAB
__PATH                : \\SCCM\root\SMS\Site_LAB:SMS_ObjectC
ContainerNodeID       : 11
FolderFlags           : 0
FolderGuid            : 32538291-DAB7-4E9C-92F4-58CAE9B641C1
Name                  : Applications
ObjectType            : 2
ParentContainerNodeID : 0
SearchFolder          : False
SearchString          :
SourceSite            : LAB

Next we build up a HashTable containing the Property Names and Values that we want to use. In this example we use InstanceKey and set the value to the PackageID, ObjectType points to “2″ and finally we set the COntainerNodeID to the COntainerNodes ID.

PS > $arguments = @{
>> InstanceKey = $newPackage.PackageID;
>> ObjectType = 2;
>> ContainerNodeID = $containerNode.ContainerNodeID
>> }

PS > $arguments

Name                           Value
----                           -----
ObjectType                     2
InstanceKey                    LAB00024
ContainerNodeID                11

Finally we use the SMS_ObjectContainerItem class to move the package as demonstrated below.

PS > Set-WmiInstance -Class SMS_ObjectContainerItem `
>> -arguments $arguments -namespace "root\SMS\Site_LAB"

__GENUS          : 2
__CLASS          : SMS_ObjectContainerItem
__SUPERCLASS     : SMS_BaseClass
__DYNASTY        : SMS_BaseClass
__RELPATH        : SMS_ObjectContainerItem.MemberID=137
__PROPERTY_COUNT : 6
__DERIVATION     : {SMS_BaseClass}
__SERVER         : SCCM
__NAMESPACE      : root\SMS\Site_LAB
__PATH           : \\SCCM\root\SMS\Site_LAB:SMS_ObjectContainerItem.MemberID=137
ContainerNodeID  : 11
InstanceKey      : LAB00024
MemberGuid       : 06032D6C-6426-411E-912F-462DF35D2ADE
MemberID         : 137
ObjectType       : 2
SourceSite       : LAB

If we take a look in the Configuration Manager Console we’ll see that the Package is moved to the “Applications” folder.

In the next post we’ll see how to work with Programs using Windows PowerShell.

Rating 4.00 out of 5
[?]
Categories: Uncategorized Tags:

#SEF09

November 19th, 2009 No comments

First of all I would like o thank all the great people that attended the SharePoint and Exchange Forum 2009 here in Stockholm, Sweden.
Special Thanks to Göran Husman, Everyone at Humandata and all sponsors. Great work!

The international Speakers included Joel Oleson, Eric Shupps, Todd Klindt, Steve Smith and Penny Coventry.
On the Swedish team we got some great sessions from Wictor Wilén, Tobias Zimmergren and, of course, Göran Husman.

My session on SharePoint & PowerShell went well.. almost. The night before my presentation I decided to run through all my code examples one last time, which resultet in a USB-Disc crash. Unlucky for me was that my VMWare was stored on the USB-Disc.
So after half an hour of panic, 3 hours of installation and 1 hour of testing i finally got everything in place, just in time to get my morning coffee and head off to SEF. Anyway, you can download my presentation here or on www.seforum.se

Hope to see all y’all next year!

Rating 4.00 out of 5
[?]
Categories: Uncategorized Tags:

StarTrek and PowerShell:TNG

March 24th, 2009 No comments

So I’ve been watching a couple of episodes from ST:TNG Season 6 between PowerShelling. At first i thought I had been sitting in front of my computer a little to long..

Anyway, the image from the episode menu says it all!! The USS Enterprise (NCC-1701-D) is obviously powered by: PowerShell

startrek01

Rating 3.00 out of 5
[?]
Categories: Uncategorized Tags: