Most enterprises expend significant effort to ensure that when employees leave the firm, all computer access has been disabled by the time they make their final exit. When IT staff members leave the firm, some enterprises might even change the Administrator account passwords for the domains to prevent unauthorized access through a shared account. Unfortunately, those same IT staff members are likely to have set up Microsoft Systems Management Server (SMS), Microsoft Exchange Server, and other applications that require an administrative account in the domain. But few enterprises modify the service account passwords when IT staff members leave.
Adding to the security risk that service accounts pose, consider that setting the Password Never Expires flag for service accounts is typically considered good practice. Although setting this flag typically reduces the probability of a service logon failure, it provides password hash-comparison utilities such as L0phtCrack an infinite amount of time to obtain the password for a privileged account.
The solution to mitigate both these risks seems quite simple in theory: Change the service account passwords regularly to an unknown value. In practice, however, most IT shops are unwilling to do so because of the potential risk of compromising the functionality of their core infrastructure services. However, you can automate the process of managing service account passwords. By writing a service-account-password management script, you not only reduce the security risk that privileged accounts pose but also reduce the risk of incurring downtime as a result of changing service account passwords.
To automate the process for managing service account passwords, you can use Active Directory Service Interfaces (ADSI) to write a script that
- Enumerates machines in a domain to find the services that use domain accounts
- Binds to a specific service for further management
- Changes the service logon password
- Changes the account password in the namespace
- Cycles the service to activate changes
Like many ADSI code segments, the code to find services with domain accounts begins with an enumeration function. As Listing 1 shows, you enumerate a Windows NT domain to determine the accounts that support various enterprise services. First, you enumerate the namespace ("WinNT://TargetDomain", where TargetDomain is your domain's name) and establish bindings to each computer in the domain. Then, you enumerate each service and query whether a domain account has been assigned to the IADsService::ServiceAccountName property.
Binding to a Service
If you know the ADsPath for the service to which you want to bind, you can use the direct binding method, which Listing 2 shows. To use this code, you need to customize the TargetDomain, TargetComputer, and ServiceProgrammaticName entries in the ADsPath that VBScript's GetObject function uses to bind to the service.
When you customize the ServiceProgrammaticName entry, make sure you use the service's programmatic name and not its display name. Typically, systems administrators are most familiar with the display name, which appears in the Control Panel Services applet (in NT) or the Microsoft Management Console (MMC) Computer Management snap-in (in Windows 2000). Unfortunately, you can't use a display name to bind to a service. Instead, you must use the service's programmatic name. Quite often, this name matches the relative name of the executable (without the extension) in the host computer's file system. However, this isn't always the case, so you might want to use an alternative way to find the programmatic name. A fail-safe approach is to bind to the computer, enumerate all services, and display the IADs::Name and IADsService::DisplayName properties for each service. The IADs::Name property contains the programmatic name.
Changing the Service Logon Password
After you bind to the desired service, you can change the password that the service account uses to authenticate. As Listing 3 shows, you use the IADsServiceOperations::SetPassword method to establish the new password that the service uses to log on to the namespace.
To use this code, you need to customize it in several places. First, you need to customize the TargetDomain and TargetComputer entries in the GetObject function's ADsPath. Next, you need to replace domain\administrator with the name of the domain containing the user account and the relative name of the user account. Finally, you need to replace New_Password with your new service logon password.
Changing the Account Password in the Namespace
After you change the password at the service level, you need to change the password for the corresponding User object in either the SAM or in Active Directory (AD), depending on the type of domain. For user accounts in the SAM, you use the WinNT: ADSI service provider to bind to the User object, then use the IADsUser::SetPassword method to set a new password in the namespace. For example, the code in Listing 4 binds to the user account svc_exchange_server1 in the domain User_Domain, then sets the new password. (If you don't have Administrator rights in the user domain but know the current account password, you can also bind to the User object, then use the IADsUser::ChangePassword method.)
You can use the WinNT: ADSI service provider to bind to the SAM on NT 4.0 and NT 3.51 machines and to bind to the local SAM on Win2K workstations and standalone servers. (Because service definitions aren't stored in AD, you use the WinNT: ADSI service provider to bind to services on Win2K machines as well.)
For user accounts in AD, you still use the IADsUser::SetPassword or IADsUser::ChangePassword methods to change the password for the account. However, the ADsPath you use to bind the User object differs based on where you defined the account. For accounts in AD, the ADsPath must specify the exact location of the object in the namespace. For example, Listing 5 shows how to bind to an object called svc_exchange_server1 that's located in the ServiceAccounts organizational unit (OU).
Cycling the Service to Activate the Changes
Until you stop and restart the targeted service, it continues to use the old credentials. So, after you change the password at the service level and in the user account namespace, you need to use the script CycleService in the Code Library on the Windows Scripting Solutions Web site (http://www.winscriptingsolutions.com) to cycle the service so that the service uses the new password. To prevent significant interruptions to business activities, you can schedule this script to run during off-hours.
When you use this script, note that you need to customize an additional entry in the ADsPath. As Listing 6 shows, you need to replace ServiceProgrammaticName with the service's programmatic name.
Last month, I showed you how to assign a different random password to each local Administrator account for each machine in a domain. You can use a similar random password-generation function to assign a password to the service account. This way, IT staff members won't know the service account password, which significantly reduces the threat of system compromise by IT staff members who have left the company or are disgruntled. (No one needs to know the service account password because only the service uses the password to log on.) In addition, because no person needs to remember the password, you can have the random password generation function assign a strong password (40 characters, mixed case, symbols). In the Code Library on the Windows Scripting Solutions Web site, you'll find the code that assigns such a password.
The code uses the WinNT: provider, so it works with accounts defined in the SAM. You can easily adapt the code to work with AD by changing the binding string. (The code describes how to change the string.)
Excel Service Account Management Tool
Many enterprises use one service account for multiple machines and even for multiple services. This can present a more difficult situation for administrators. For example, suppose you and another administrator assign users\svc_iis to the personal Web servers running on your respective workstations. You might not know that the other administrator is also using that account and if that person changes the account password, you'll lose access to your Web server after a reboot. To prevent problems when you change the service account password, you can enumerate the entire domain to ensure that when you change the password for your service account, you also change the password on the other administrator's machine. By using Microsoft Excel 2000 as an administrative front-end tool, you can collect information about the service accounts on a particular domain, then modify the services and service accounts accordingly.
I created a fully functional application that performs the password-administration tasks I've discussed here and generates a report that details the results. You can download this application from the Code Library on the Windows Scripting Solutions Web site. To view the application's code, open the application in Excel 2000, then press Alt+F11 to access the Visual Basic Editor. To use the Excel application, follow the directions in the workbook's Instructions sheet.
Prevent Downtime; Save Time and Money
If you haven't changed the passwords for those privileged service accounts in your enterprise, you're exposing your firm to needless risk from these easily compromised accounts. By adapting the code I've presented to suit your enterprise's needs, you can reduce the security risks, reduce the time you spend changing service accounts, and reduce the risk of downtime when changing these passwords. If you're contemplating purchasing a third-party product that automates managing passwords, you might want to reconsider. In all but the smallest of firms, the cost to develop your own solution using the techniques I've presented will be far less than the cost to license a third-party product.