Technical Panacea
Curing your IT ailments
September 8, 2010
Robert Hansen: Snakeoil Security
http://threatpost.com/en_us/blogs/effect-snake-oil-security-090710
While the write-up is decent, I was left with one question: What do we do about it? He does mention that security firms need to work together, to help each other out; but that defies any commercial firm's tendency to make money, especially at a competitor's disadvantage.
I'm definitely a strong proponent of the open source software movement (FOSS) and perhaps, in some way, Hansen was suggesting a similar movement in the IT security world; I think that FOSS's benefits greatly outweigh any of its negatives. However, businesses are formed to make money because money is the medium for goods and services that people need and want. For security firms to cooperate at any significant level, there has to be a significant carrot. One that mutually benefits those corporations that share information and resources. And that has to compete with a company's desire to differentiate itself from its competition and turn a profit.
I certainly don't have the answer to that dilemma, but it's an interesting thought exercise.
August 26, 2010
I Shot the Server, But I Did not Shoot the UPS...
http://www.sltrib.com/sltrib/home/50159264-76/campbell-computer-police-server.html.csp
It's a little funny and scary at the same time, but an employee shot up his employer's expensive server with a .45!
August 21, 2010
Web Load Balancing: IIS+ARR Revisited
Network Load Balancing (NLB) is an unfortunately named feature available in Windows Server that is used to create a simple server "cluster". I say that it is an unfortunate name because it does not accurately reflect the purpose of the feature. In my experiments, I found it to be a simple heartbeat service between defined cluster members that was very chatty over the link layer (Ethernet) and not very responsive (even after configuration tweaks) to failed hosts in the cluster.
So what does NLB have to do with ARR? Well, ARR was designed to set up routing at the application layer (i.e. HTTP). If a backend host is down, ARR happily sends packets along. NLB is required to sense a failed backend using the simple heartbeat mechanism. It appeared to be very clumsy and an incomplete solution.
So, what now? How does one implement a web load balancing solution without purchasing an expensive appliance? You deploy an nginx + haproxy + keepalived combination.
And that, ladies and gentlemen is a topic for another post.
New Blog Template
July 8, 2009
IIS with ARR: Initial Impression
Sent from my Verizon Wireless BlackBerry
November 7, 2008
Sudowin: One Answer to the Struggle Between Security and Usability
I've always longed for Windows equivalents to many Unix utilities that I use, one of them being the excellent 'sudo' (a full treatment of sudo is beyond the scope of this post so I'd encourage readers to research the utility further for more information). I've seen several attempts to implement sudo or sudo-like functionality for Windows but I never found anything that _was_ sudo. I gave up looking for a while.
Recently, I had a need to revisit the subject and found, among many options, sudowin. It's a slick implementation of sudo available for Windows systems and so far has not disappointed. The project provides an MSI file for easy installation as well as the source code for the curious hacker. The project site (on Sourceforge) doesn't provide documentation, but the folks at SANS have posted a PDF version of the help file.
The current version is 0.4.2-r208 and was released on 9/30/2008. Written in C#, the program installs itself as a service that monitors calls to the sudo command. By default, the service verifies that the user is part of the local 'sudoers' group before checking that the user is authorized to execute the target command/program. Authorized users and commands can be configured in the 'sudoers.xml' file beneath the project's program directory (C:\Program Files\Sudowin). One caveat: the current version of sudowin does not yet support resolving group membership for either local groups or Active Directory groups. You must explicitly define _each_ user that is authorized via the local PC's 'sudoers' group. This does not scale well in large environments, but again, it's open source so feel free to contribute.
The documentation provides great guidance on the configuration file, so I won't go into great detail. However, I will suggest some guidelines:
- Set the top-level value 'allowAllCommands' to "false". A "default deny" policy is the safest bet.
- Make use of the
block to group sets of commands for groups of users. It will help organize your configuration file. - For all
values, note the 'argumentString' and 'md5sum' attributes. Use these to further restrict execution of commands to prevent crafty users from implementing workarounds to sudowin. - Test. Test. Test. Verify that your configuration works before rolling it out to your users. There's nothing more frustrating (to you _and_ the users) than dealing with something that doesn't work (especially when those users had elevated privileges before).
- For all
So far, I've had great luck with sudowin and the users I've deployed it to are able to do the work they always have done. Despite some minor annoyances such as a very short password cache time and some quirks with how some commands handle arguments (not sudowin's problem), this solution works well. I continue to test its application in other scenarios and am finding it to be very useful. If anyone has used sudowin and would like to provide feedback, feel free to do so (especially if you know how to increase that pesky password cache time period).
September 27, 2008
Using Perl and ADSI to Update Active Directory
Recently, the CEO of my company informed me that he's been really loving our VoIP-based phone system (Enterprise Interaction Center from Interactive Intelligence). In particular, he really digs the available company directory provided by the front-end application, Interaction Client. It allows users to click on a phone number to automatically dial out. It's extremely convenient and many users don't even touch their handsets anymore. On top of that, the built-in company directory integrates with Active Directory and can display many of the attributes available for user objects (i.e. department, title, address). Now that we've expanded into additional office space and have a significant body of telecommuting staff, it's become very important to be able to organize and locate information on all of those users. So the question came: "Can we include additional information in the company directory that displays each employee's department, title, and location?" Yes, my friend, yes.
Centralized Management
I'd like to pause for a moment to provide some background. We use Active Directory for domain accounts, printers, permission/ACL administration, group policy definitions, etc. It's a great tool in our IT belt. And since, at its core, it's LDAP, I've been lobbying for a while now to leverage its capabilities in other areas of our environment. I despise the duplication of effort (i.e. reinventing the wheel) so when we need to provide directory-related services (i.e. organizing contact information or authentication), I prefer to use Active Directory (or OpenLDAP, depending). I've provided proofs of concept, attempted to influence developers' designs, and used it whereever I possibly can. My argument has fallen on deaf ears, until now.
Updating Active Directory
The request was simple enough: we needed each employee's department, title, and some location information added to their respective accounts so that they would display in Interaction Client. And since there is already integration between the phone system and Active Directory (AD), I just needed to update a few attributes and wait for the two to sync. I decided to do so programmatically. Especially because we have 140 employees. Especially because I don't trust my typing skills across a large enough body of data.
All we need is an input file that contains the employees' names, and all the attributes that need to be updated. That's simple enough; HR provided everything I needed in a simple spreadsheet. I simply stripped out any needless headers and then exported the file as a pipe-delimited text file (I chose the '|' symbol as my delimiter because some names may contain commas and this would cause a big headache if I tried to export the data as a comma-separated file).
One last thing: we need access to the 'dsquery' command. This is a simple command that queries AD and returns information on the object specified. We'll need to grab the distinguished name for our user objects before we can update them. You can find the 'dsquery' command in the Windows Server Resource Kit.
Perl and ADSI
My language of choice is Perl. It's partly because that was one of the first languages I was introduced to and partly because of its utility; its cross-platform capabilities are crucial for me as I work in a heterogeneous environment. To interface with Active Directory, I decided to use the ADSI API (a COM derivative). I could have used Perl's LDAP support (Net::LDAP) for this project, but where possible, I always try to use native functionality. Perl supports COM interaction via its Win32::OLE module. For those that haven't used Win32::OLE, note that if you're handy with VBScript, it's usually a very easy matter to convert VBScript code to Perl using this module. In fact, the Microsoft Scripting Guys provide a handy utility that demonstrates how easy it is to write COM-related programs in various languages via their Scriptomatic tool. Download it and give it a go.
NOTE: Neither a discussion of Perl nor ADSI is within the scope of this post. For more information, see perl.org and msdn.microsoft.com.
The Code
The script is short and sweet. It will open our input file for reading, find the DN for each user object (the full name is created from the first and last names for each user), instantiate a COM object based on the DN, and finally, update the attributes we need (please forgive any ugly line wraps):
#!/usr/bin/perl
#
# adUpdate.pl - Update Active Directory using the ADSI API (via the LDAP provider)
#
use warnings;
use strict;
use Win32::OLE qw( in );
my $employeeAttributeFile = 'employeeAttributes.txt'; # our pipe-delimited input
open( ATTRIBUTES, $employeeAttributeFile ) or die "Unable to open \'$employeeAttributeFile\' for reading: $!\n";
while ( < ATTRIBUTES > ) {
   my ( $lastName, $firstName, $streetAddress, $department, $title ) = split(/\|/); # our input is pipe-delimited
   my $fullName = $firstName . ' ' . $lastName; # combine the first and last name for queries later
   print "name: " . $fullName . "\n"; # debug
   # call 'dsquery' to hunt for this user object in our directory and return the DN
   # 'dsquery' is available in the Windows 200x Resource Kit
   my $dsqueryCMD = "dsquery user -name \"$fullName\"";
   my $dn = qx( $dsqueryCMD ); # qx// allows us to shell out and grab the results/output (unlike 'system()')
   $dn =~ s/"//g; # strip the surrounding double-quotes from dsquery's output
   #print "DN: $dn\n"; # debug
   my $adsPath = "LDAP://$dn"; # ADSI path using the LDAP provider
   #print "\$objUser = Win32::OLE->GetObject( $adsPath );\n"; # debug
   my $objUser = Win32::OLE->GetObject( $adsPath );
   # if $objUser isn't set, we have a problem; report it and jump to the next record in our file
   if ( ! $objUser ) {
      print "ERROR: " . Win32::OLE->LastError() . "\n\n";
      next;
   } # end "if ( ! $objUser )..."
   # update the attributes we need and set them
   $objUser->Put( "streetAddress", $streetAddress );
   $objUser->Put( "department", $department );
   $objUser->Put( "title", $title );
   $objUser->SetInfo();
   print "ADDRESS: " . $objUser->{streetAddress} . "\n"; # debug
   print "DEPT: " . $objUser->{department} . "\n"; # debug
   print "TITLE: " . $objUser->{title} . "\n"; # debug
} # end "while ( < ATTRIBUTES > )..."
close ATTRIBUTES;
# fin!
At this point, I've successfully updated specific attributes for all users in AD without any manual data entry. I'm happy and more importantly, the CEO is too.
Disclaimer
This code is provided "as-is" and is simply meant to demonstrate a solution to a problem I needed to solve. As such it carries no warranties or guaranties regarding its use. You can use this code as you see fit; it's hereby in the public domain.