It's a memory debugging aid. Specifically, when you set NSZombieEnabled then whenever an object reaches retain count 0, rather than being deallocated it morphs itself into an NSZombie instance. Whenever such a zombie receives a message, it logs a warning rather than crashing or behaving in an unpredictable way. As such, you can debug subtle over-release/autorelease problems without advanced tools or painstaking needle in haystack searches.
The name is a fairly obvious play on the fact that objects are normally considered "dead" when they reach retain count 0. With this setting, they continue to exist in a strange half-life - neither living, nor quite dead. Much like real zombies, except they eat rather fewer brains.
Adam did a great job explaining what Zombies are, but using the environment variable is not the best way to find and track these.
A much better approach to zombie detection, is just to use Instruments - from XCode start with "Run with Instrument" and choose "Allocations".
Then stop the recording right after it starts, press the "i" button on the Allocations instrument, and turn on "enable reference counts" and "Enable NSZombie Detection". Now hit Record again in the instrument, and your app will start up - if any zombie objects are sent messages recording will stop, and a dialog box will pop up in the recording timeline - you can click on that to find every place an object was retained or released.
Edit: Previous advice was for XCode 3, here's an addition for XCode 4:
In XCode 4.2, there's an even easier mechanism to make use of Zombie detection - the Zombie Instrument. Instead of "Run" to start the app, use "Profile" and an instrument selector will come up. Select "Zombie", and the app will start running - do whatever causes your crash, an a dialog will pop up saying "Zombie Messaged".
From there, click the small arrow in the dialog box. That will take to a list of all the times that zombie object was created, retained, or released. Pull up the side bar and you can go to each entry, looking at the stack trace for the code that was responsible for each adjustment in the retain count.
I agree with what Kendall added, it's very useful, but I'll suggest still doing the environment variable so you don't forget they're enabled. Similar to the (now expired) link at Cocoa Dev, I put this so I don't miss it:
if(getenv("NSZombieEnabled") || getenv("NSAutoreleaseFreedObjectCheckEnabled")) {
NSLog(@"ZOMBIES/AFOC ARE ENABLED!!! AAAAARRRRRRGH!!! BRAINS!!!");
}