Wednesday, March 12, 2008

Managing Local Admin Passwords

The company I work for often seeks out the worst and most vexing solution to any given situation. That probably stems from the fact that although the corporate line is that we hire 'quality people', most of the people in my building have an IQ approximating that of a canteloupe.

In fact, I would wager that many of the IT staff here would be quite content to sit and drool on their keyboards for much of the day. Sad, but there ya go. The plus side of that is that it's not terribly difficult for a slightly below average bloke such as myself to look like a shining star.

"Hey CG, I really like the way you tied your shoes. You keep that up and the sky is the limit for you here."

Seriously.

So anyways, one of the most short-bus-esque practices that goes on here is that all of the servers in the environment have the same admin password. Yeah.. not only that, but nearly everyone in the building knows about since it hasn't changed in two years. It even showed up in a Google search the other day. I wish I was kidding.

So it's been a constant pain in the ass for me that when odd stuff happens on the server the trail stops at the admin account. So I decided to take the law in my own hands and change it.

Here's the quandry. I don't want to have to manage several hundred admin ids and passwords. I wanted a password that I could get to quickly, that was unique for each server, and that did not require some kind of database to manage. Here's what I came up with. I set the password to a combination of the servername, a special character, and the last octet of the server IP address. It's easy to figure out the password if you know the formula and the formula can be quickly updated by tweaking the script.

Here's the script I used to do it. (Special thanks to E, who helped me fix a bug in the error handling) This pulls a list of servers from MFCOM and loops through them. Enjoy.

'//Resets the local password using the formula:
'// servername + @ + last octet of IP
'// Run this using cscript. If you use wscript you will be innundated with popups

'-------------------------------------------------------------------------------------
'// Compensate for crappy coding and diminutive manhood.
On Error Resume Next


'//Set the Username
'------------------------------------------------------------------------------------------
LocalAdmin = "Admin"
'------------------------------------------------------------------------------------------


'// Get the farm 411
Set theFarm = CreateObject("MetaFrameCOM.MetaFrameFarm")
theFarm.Initialize 1

'// If this doesn't work we're screwed so exit
if Err.Number <> 0 Then
WScript.Echo "Can't create MetaFrameFarm object"
WScript.Echo "(" & Err.Number & ") " & Err.Description
WScript.Echo ""
WScript.Quit Err.Number
End if

'// Loop through the name o' server
For each Server in thefarm.servers

'// set the hostname based on where we are in the loop
strComputer = ""
strComputer = Server.servername

'invoke the dnslookup because the datastore IP could be for some other nic if we pulled it from MFCOM.
strIP = DNSLookup(strComputer)
strOctet = Right(strIP,3)
StrOctet = Replace(strOctet,".","")
strPassword = strComputer & "@" & strOctet
strPassword = LCase(strPassword)

'//now that we have the password, let evil ensue

On error resume next
IF not strComputer = "" then

'//Clear any error condition that may have existed from the last loop
Err.Clear

' //Connect to the computer\administrator account
Set objUser = GetObject("WinNT://" & strComputer & "/" & LocalAdmin, user)
if Err.Number <> 0 Then
wscript.echo "Error on " & strComputer
if WScript.Echo "(" & Err.Number & ") " & Err.Description
WScript.Echo ""

End If

'//Set the password for the account
wscript.echo
wscript.echo "Setting password on " & strComputer
objUser.SetPassword strPassword
objUser.SetInfo
if Err.Number <> 0 Then
wscript.echo "Error on " & strComputer & "!!!"
WScript.Echo "(" & Err.Number & ") " & Err.Description
Else
wscript.echo strComputer & " - " & localadin & " password has been set to: " & strPassword
End If
End if

' //senseless destruction of objects
Set objWMIService = nothing
Set objuser = nothing

Next


'-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
'Functions
'-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Function DNSLookup(sAlias)

If len(sAlias) = 0 Then
DNSLookup = "Failed."
End If

Const OpenAsDefault = -2
Const FailIfNotExist = 0
Const ForReading = 1

Set oShell = CreateObject("WScript.Shell")
Set oFSO = CreateObject("Scripting.FileSystemObject")
sTemp = oShell.ExpandEnvironmentStrings("%TEMP%")
sTempFile = sTemp & "\" & oFSO.GetTempName

oShell.Run "%comspec% /c nslookup " & sAlias & ">" & sTempFile, 0, True

Set fFile = oFSO.OpenTextFile(sTempFile, ForReading, FailIfNotExist, OpenAsDefault)
sResults = fFile.ReadAll
fFile.Close
oFSO.DeleteFile (sTempFile)

aIP = Split(sResults, "Address:")

If UBound(aIP) < 2 Then
DNSLookup = "Failed."
Else
aIPTemp = Split(aIP(2), Chr(13))
DNSLookup = trim(aIPTemp(0))
End If

Set oShell = Nothing
Set oFSO = Nothing
End Function

----------------------------------------------------

Happy Clicking!

4 comments:

Anonymous said...

IF you can work out the password once you know the formulae, how is this any more secure than having the same password on every server?

Citrix Guy said...

Thanks for the comment. I think you're the first one to ever comment on my blog.

Good point. And I'm the first to admit that it's not perfect. I guess the better solution would be to use a password generator to store strong passwords in an encrypted file on a secure file server somewhere.

But it is better than what we have now. Not only that, but when I get called at 3am, no way am I going to go digging through that shit trying to figure out what the password is.

That more conventional approach also introduces dependencies around keeping track of the password list and being able to get to it in emergencies. We manage 750+ Citrix servers, so it's either one admin password or a password that can be derived by knowing the recipe. The list of passwords is just not workable.

You're absolutley correct though, the weak link is the formula. But..

Since we're using a script, it's trivial to update the formula and run it again. Now if I worked in an organization full of talented and intelligent people, this would indeed seem like a silly exercise, but If we get on a schedule of changing the formula regularly, then we're already lightyears ahead of the rest of the server groups. Remember that the admin password hasn't changed in 2 years.

I'm certainly open to suggestions and would be interested in getting your ideas on how to go about implementing a more robust design.

Thanks again for the post.
-CG

Anonymous said...

There should be no real need to use the local admin account on of your servers.

Most large organisations choose a very long and secure password at build time which is then gets locked away and can only be accessed by an emergency change control process. Don't forget to rename the admin account at the same time too.

You then setup domain groups for your server administrators, and use a GPO to add these groups to the local admin groups of your servers.

You then have full administrative access to do your job without having to know the actual local admin password - you are happy and security ops are happy.

I love the cynicism and sense of humour in your blog posts - you tell it like it is :)

Neil.

Citrix Guy said...

You're preaching to the choir brother. I think at one time someone tried to implement such a policy. But it's gone horribly wrong, and the password has been leaked out and passed around to the point that it's become common knowledge. Also as you mentioned, we don't make it a practice of using the local admin password. We have our own administrative accounts at the domain level that we use, but if a server is offline or off the network for some reason, it's helpful to have a local administrative account. More importantly, these measures keep other people from jacking around with our servers - which was the overall goal.

Thanks for the complements on the site. If ya like it, tell your friends.

-CG