Follow The Bouncing Malware: Gone With the WINS

Published: 2009-05-06
Last Updated: 2009-05-07 07:09:40 UTC
by Tom Liston (Version: 1)
0 comment(s)

"Isn't it kind of noisy?", his wife shouted over the roar of the new server's cooling fans.

"It just needs to warm up," he replied, "It'll quiet down in a bit."

His wife pointed at her ears, and shrugged as if to say "I can't hear you" and wandered out of his upstairs office, shaking her head.

She didn't understand.  She never understood.

Joe Sixpack caressed the shiny black case of the server as it sat tipped between his desk and the filing cabinet, tilted at an awkward angle.  It was a beautiful thing, and it had been such a bargain.  He had found it on a whim, wandering through a sale liquidating the assets of a small data processing startup just up the street from his house.  When he asked the bored clerk about it, he had reluctantly dug though an enormous pile of papers and had handed Joe a copy of the machine's original documentation.  The itemized description on the purchase order was pretty much gibberish as far as Joe was concerned, but his eyes were drawn to one phrase in particular: "Operating System: Windows Server 2003."

Never mind the fact that it was a "rackmount" machine, whatever that meant.  It was a SERVER, and that was COOL.  Besides, as a victim of the economic downturn, the company was selling off it's assets at pennies on the dollar.  He had paid only a fraction of what the purchase order said the machine had originally cost.

"Look," the clerk had said as he was writing up a receipt, "if you're thinking of trying to get information off of the hard drive, understand that this thing never actually saw service."  Perhaps it was Joe's blank expression that had prompted him to add, "You understand...this machine is kinda old... it's been sitting on the shelf for a long time... and all sales are final."

Even when he was counting out the money to pay for the machine, Joe wasn't entirely sure what he would use it for.  He had, in the past, kicked around the idea of setting up a server and hosting a website of his own-- maybe he might even start one of those blog things.  He also had an amazingly diverse and extensive collection of porn-- he thought about how cool it would be to start his own "adult site."  On the drive home, he even came up with a name: Sixpack's SexPics.

Despite the clerk's stern warning, the server had powered up just fine and Joe eventually moved it from his desk to what he finally decided was the perfect spot: sitting upright, between the edge of his desk and the filing cabinet.  Unfortunately, he was wrong about the machine quieting down over time-- if anything, as the evening wore on, it seemed to get louder. 

Joe swapped over the monitor, mouse, and keyboard cables from his desktop machine and, after a few false starts (he had never noticed before that the end of a USB cable fit perfectly into a network jack1), was able to get a picture up on the screen.

The clerk had been right: it looked like the machine had never been booted up.  Joe worked his way down through the setup dialog, answering the questions as best he could.  He had to unhook everything and switch back to his desktop machine a couple of times to look up what something meant on Google, but the hassle was worth it when he was finally able to log in as "Administrator."  He was running his own server.

He dug around in the box of stuff that the guy from his ISP had left behind when he installed his Internet service and found what he wanted: a network cable.  He had to move some things around on his desk, but he was finally able to stretch the cable enough to plug it between the back of the server and the back of the router.  The little light on the front of the router instantly lit up and began blinking-- and Joe was pretty sure that was a good sign.  He tried firing up Internet Explorer, and sure enough, he was able to get to his server was connected to the Internet.

Or, it was "sort of" connected.  Joe had spent some time playing with the settings on his router-- so much so that he had to do a hard-reset-- twice now-- but he remembered something interesting that he had seen.  He pointed IE at the IP address of the router and logged in, after looking through the router's manual for the default password (like he would ever change THAT again!).  He clicked around a bit until finally finding the setting he was looking for.  It took him another forty minutes of searching on Google, but he was finally able to figure out how to find the IP address of the new machine and enter it into the router's "DMZ" setting.  It was nearing midnight and he was getting sleepy, so he clicked "OK," truly connecting his server to the Internet.  He switched off the monitor and the lights and went to bed-- a brand new server administrator who was hoping to dream about the photo shoots he would direct for Sixpack's SexPics.

But, while Joe was drifting off to dreams of the "action" in his first big photo shoot, something eerily similar was happening to the freshly minted Sixpack's SexPics' server.  A fun and interesting conversation was taking place on port 42/TCP between Joe's "new" machine (a machine that had been sitting on a shelf when Microsoft released MS04-045) and another machine somewhere in Korea.


  1. They do.  But don't try it.  Really.  This means you.  Yes you.  Don't look at me like that.  You know that you're just sitting there, fighting the urge to go try it-- acting all nonchalant, like you don't care. It's slowly eating away at you.  We both know that you're trying to think of something... anything else... just to keep your mind off of wanting to rip the nearest USB cable out its jack so you can go check to see if I'm telling you the truth.  But I am.  I am.  Would I lie to you? 

It Happened One Night

At this point in most of the other FTBM postings, I would-- in a rare display of lucidity-- take a moment to step aside from my normally disjointed prose to warn you, my dear reader, of the perils of embarking on any attempt to "play around" with the malicious code we're about to examine.  Having discovered, over these many years, that none of you actually pay one damn bit of attention to what I say, I've decided to say "t'hell with it..."  Have fun! Launch the malware! Run with scissors!  Play with matches!  Swim right after eating!  Don't wear clean underwear, you'll never be in an accident!  Your mother was WRONG!

(Ok, jus' so you know... the running-with-scissors thing sorta freaks me out... so don't.  And don't play with matches-- you'll tick off the people at  But, that being said, if you really wanna eat a big, honkin' meal, put on your dirtiest underwear, and go swimming-- be my guest.  Just tell me what pool you were in so I can avoid it like the plague.)

The impetus for this new, malwarerific installment was the "compromise" of a honeypot machine that I run.  Thus, if you found the whole "backstory" of Joe Sixpack gettin' him some "server" to be a bit contrived, you're probably right.  And you can bite me.  Everybody's a critic...

Two vulnerabilities in the WINS service (Windows Internet Naming Service - a service that maps IP addresses to NetBIOS computer names and vice versa) were first described by Microsoft in the MS04-045 bulletin, released on December 14, 2004.  Now if you're saying, "Tom, that's ancient history!  No one would STILL be vulnerable to that!", I would first tell you that you don't know me well enough to call me "Tom"-- it's "Mr. Liston" to you-- and then I would mock you heartily and ask you what Internet you've been hanging out on lately.  My honeypot got hit two weeks ago: and if it was the only machine on the Internet that was vulnerable, do you think the kiddyz would still be lookin'?

The crux of the vulnerability that will be 'sploited on Joe's machine is an issue with how the WINS service deals with information that is exchanged as part of what is known as "WINS Replication"-- a feature of the WINS service that allows multiple WINS servers to keep their information synchronized.  Think of it as DNS "zone transfers" being done in a... well... a pretty dumb way.  The stupidity comes from the fact that in WINS Replication, the server actually sends the client a record that contains memory pointers (a value that says to the client, "hey, you need to go this far forward or backward in this chunk of memory to find this particular information").  Compound that stupidity by the fact that on an unpatched machine, ain't nobody checkin' to see that the memory pointer received isn't pointing somewhere outside of the data being sent.  The upshot: a specially crafted WINS Replication packet can be used by an attacker to hijack the memory pointer, overflow a buffer, and execute arbitrary code on a vulnerable machine.

Just so you're aware, we're about to embark on a rather high-speed journey deep into the innards of a malware attack.  Like all cool suff, some assembly may be required.  Please keep your arms and legs inside the car and do not unfasten your safety harness until the ride has come to a complete stop.

(Assembly language purists out there... I cut some corners in the following to keep this at a level where -- hopefully -- everyone can follow along.  Forgive me.)


When the Korean server hits the Sixpack's SexPics server, it fires over a series of specially crafted WINS Replication packets, designed to diddle with the memory pointers used by the WINS service. Being a mindless piece of code, the WINS service takes the bogus memory pointers, does exactly what it they tell it to do, and overwrites a chunk of it's own memory.  The WINS service ends up getting whacked because it trusts the data that it is sent-- and that trust ends up being betrayed-- which leads to it eventually executing the attacker's code buried deep inside that data.  Let's take a look at the hexidecimal representation of the beginning of that code:

90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 EB 10 5A 4A 33 C9 66 B9 77 01 80 34
0A 99 E2 FA EB 05 E8 EB FF FF FF CD 12 75 1A 75
B1 12 6D 71 60 99 99 99 10 9F 66 AF F1 17 D7 97
75 71 9D 98 99 99 10 DF 9D 66 AF F1 EB 67 2A 8F

Right up front, we notice a pretty long string of hex 90's... let's talk a little about why that's there.  Overwriting memory and overflowing buffers to execute code isn't what you would call an "exact" science.  There are differences in architectures (i.e. having the words in a program be in different language will change the exact layout of the code... also, there are different versions of code on different versions of operating systems, etc...) so there's a little "slop" in even the most calculated attack.  Those hex 90's make up what we in the biz call a "NOP Sled."  The idea is this: when the attacker overwrites memory, due to the differences in the various classes of machines that they're attacking, they may not be entirely sure of where their overwritten memory will land.  So, rather than having an exact point to jump to when they want to execute their code, the attackers create a little "cushion" for themselves.  Those hex 90s represents a special instruction on the x86 architecture called the NOP (pronounced "NO-OP").  That instruction does pretty much what it sounds like it does: nothing-- it exists, primarily, to allow for padding and synchronization within programs.  The really cool thing about the NOP instruction is that, in addition to doing nothing, it is only one byte long (most x86 instructions require multiple bytes).  By placing a field of NOP instructions in front of the code that they want to execute, the attacker needs only to land "somewhere" in that field to ensure that he will eventually land at the correct starting point for his malicious code.  The execution, in essence, "slides" down the sled right to the place where the attacker's code is waiting.

Any Number Can Play

So, at the bottom of our NOP sled, what do we find?  Looking at the code in a disassembler, we see this:

00000458                 jmp     short loc_46A
0000045A ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
0000045A sub_45A         proc near        ; CODE XREF: sub_45A+10 p
0000045A                 pop     edx
0000045B                 dec     edx
0000045C                 xor     ecx, ecx
0000045E                 mov     cx, 177h
00000462 loc_462:                         ; CODE XREF: sub_45A+C j
00000462                 xor     byte ptr [edx+ecx], 99h
00000466                 loop    loc_462
00000468                 jmp     short loc_46F
0000046A ; --------------------------------------------------------
0000046A loc_46A:                         ; CODE XREF: 00000458 j
0000046A                 call    sub_45A
0000046F loc_46F:                         ; CODE XREF: sub_45A+E j
0000046F                 int     12h

The hex numbers at the left (and the other "location" references) represent an offset into the data that I pulled from the attack.  The first instruction that we run into at the bottom of the NOP slide tells us to jump ahead (JMP) to location 0x46A.  Looking there, we see that the code "calls" a subroutine (another chunk of code), at location 0x45A.  Let's take a look at what that subroutine does.

The first thing that the subroutine does is perform a POP operation.  To understand what the POP instruction does, you need to know a little about a programming structure known as "the stack."  The stack is a temporary storage area that your computer's processor uses to hold onto values with a fairly limited lifetime.  If you've ever gone through the line at a cafeteria, you might remember a magical device that holds a big stack of plates and yet somehow, whenever you remove one, another one pops up to take it's place.  If you put the plate you just took back on the stack, it somehow, remarkably, adjusts itself so that the plates sink below it, leaving your plate right back where it started. (Note: Yes, I'm easily amused...)  Well, that "stack" of plates is an incredibly good analogy for the "stack" used by a computer processor.  We "PUSH" values onto the stack and we then "POP" them back off again.  Remember, however, just like in a cafeteria, even if the top plate isn't the one you want (you know the one... all crusty with some sort of unidentifiable goo), you can't get to the one below it, without taking the yucky one off first.  Thus, like the stack in the computer, the plate stack is a "Last In, First Out" (or "LIFO") stack.

So, if our first action upon hitting the malicious code is to "call" a subroutine, what's on the stack?  We're popping a value out, but we didn't push a value in there to begin with!  Ah... here is where it's important to know and understand a little bit about what goes on behind the scenes when you "call" a subroutine.  Remember, when I said that the stack was used for temporary storage?  Well, not only do programmers explicitly use the stack for storing values temporarily, but the processor itself uses the stack as well.  When we "call" a subroutine, we're actually asking the processor to temporarily suspend the current "flow" of the program and to go off and do something else for a bit.  When its done doing that "something else," we expect that it will return to the original program flow.  But how does the processor know where to go back to?  It uses the stack to store a temporary value, pointing back to the instruction that it should return to when the work of the subroutine is finished.  Think of it like this: you're reading along in a book (this is the normal program flow...), and you get a phone call (the program "calls" a subroutine).  What do you do?  You use a bookmark, to save your location in the book...  or, if you're a cretin, you fold down the corner of the page.  When you're done with the phone call (the subroutine finishes), you go back to your place in the book.

In this case, the malware author needs to find out where his code is.  Remember, we talked earlier about using a NOP sled to get around not having exact knowledge about the location of the code, but now we really need to firm up our grasp of where, EXACTLY, we are, and there ain't no binary-level Tom-Tom (me-me) available.  So what's a locationally-challenged malware author to do?  Call a subroutine and steal the processor's "bookmark" off of the stack!  We see that, immediately after entering the subroutine, the code pops a value off of the stack into the register EDX (registers are another temporary storage location upon which the processor is able to perform various operations...).  It then decrements (DEC) that value by one and voila! We now have a pointer to the exact memory location where we came from. 

Having done all of that, the code then XORs the value in another register, ECX, with itself.  XOR?

The XOR function is pretty simple, actually.  It's a bit-wise operation, meaning that it takes two numbers and compares them at the bit level.  If the bits match, then, in the resulting value, that bit is turned "off" (0).  If the bits are different, then that bit will be turned "on" (1) in the resulting value.  So, if you XOR any number with itself, the resulting value has every bit turned off (really... think about it...).  So, XORing a register with itself is simply a fast way for the code to completely clear the register.  Another interesting result of the XOR function is that, if you take any number, XOR it with any other value (we'll call that value the "key"), and then XOR the result with the "key" value again, you get back the original number.  Pretty cool, eh?  XORing is a cheap and dirty (and easily broken) means of "encrypting" things. (And double-XOR encryption is... well... a joke.)

Having cleared out the ECX register, the code then loads it up with 0x177 (that's 375 in decimal...) and then proceeds to use that value plus the "bookmark" location it stole off the stack (in EDX) as an offset for which to begin XORing memory values with 0x99 (153 decimal). 

What the heck?

Remember when I said that XOR could be used as cheap and dirty "encryption"?  Well, that's exactly what they've done here.  They've "encrypted" their code (using 0x99 as their "key" -- nothing special about it, any number will do) and now they're decrypting it.  The "LOOP" operation in the following step decreases the value in ECX by one-- and then, if ECX isn't yet zero, it loops back to 0x462, otherwise, it continues on.  This will result in "decrypting" 375 bytes of code.

Let's see what we find in that code...

Key to the City

"But Tom," I hear you cry, "the code is encrypted!  How will you ever be able to look at it?"  Putting aside, for the moment, our recent discussion on "familiarity," I'll explain that, while the code is "encrypted," it's not really trying hard enough to keep me (or anyone else for that matter) out.  The reason that malware authors XOR "encrypt" their stuff is to keep IDS systems from easily recognizing specific code signatures as they fly by.  I already have the "key," it was sitting right out there in the open before... 0x99.  So all I need to do is to write myself a short program that will use that "key" to "unlock" the real, unencrypted code. And so, 4.5 minutes (I timed it...) of C coding, compiling, fixing a damned missing semicolon (why, if the compiler is smart enough to tell me EXACTLY where the missing semicolon goes, doesn't it just PUT it there for me?), and compiling again, and I have some newly "decrypted" code in front of me.

Let's see here...

0000046F                 push    esp
00000470                 mov     ebp, esp
00000472                 sub     esp, 28h
00000475                 mov     esi, esp
00000477                 call    sub_575

The code starts off by pushing the value of the stack pointer (a register that holds the memory location of the top "plate" in the stack) onto the stack.  It then copies it to another register (EBP), and then subtracts 0x28 (40 decimal) from the value and saves that to another register (ESI) as well.  Why?  Well, the malicious code is creating it's own new chunk o' stack space where it can do its work without disturbing the real stack... Hopefully, before everything is said and done, it'll put everything back in place so that the WINS service will be able to carry on about its business as though nothing untoward had happened.  After doing all of that, it then jumps off into another subroutine.

00000575 sub_575         proc near     
00000575                 push    ebp
00000576                 push    esi
00000577                 mov     eax, fs:30h
0000057D                 mov     eax, [eax+0Ch]
00000580                 mov     esi, [eax+1Ch]
00000583                 lodsd
00000584                 mov     ebp, [eax+8]
00000587                 mov     eax, ebp
00000589                 pop     esi
0000058A                 pop     ebp
0000058B                 retn    4
0000058B sub_575         endp

Holy crud! What the heck is that?

Well that, my dear reader, is the means by which the malcode finds some much-needed information.  Let's walk through it... To begin with, whenever you start a subroutine, before you screw up the contents of any of the registers you might need later, you always want to save the information that's in them. Later, as you exit the subroutine, you can put things back in place.  To that end, you'll notice that the code pushed some values onto the stack at the beginning of the subroutine and then pulls them off (in the opposite order... remember LIFO!) at then end.  Having done that, we then see a really funky looking instruction: mov eax, fs:30h.  To understand what's happening here, you need to understand a little bit about something called the Windows Process Environment Block (PEB).  


The Process Environment Block is a memory-based data structure that contains all sorts of interesting user-writable information on the running process.  For you programming-types out there, here is the structure of the PEB:

typedef struct _PEB {
BOOLEAN InheritedAddressSpace;  //0x00
BOOLEAN ReadImageFileExecOptions;  //0x02
BOOLEAN BeingDebugged;  //0x04
BOOLEAN Spare;   //0x06
HANDLE Mutant;   //0x08
PVOID ImageBaseAddress; //0x0A  
PPEB_LDR_DATA LoaderData; //0x0C
PVOID SubSystemData;
PVOID ProcessHeap;
PVOID FastPebLock;
ULONG EnvironmentUpdateCount;
PPVOID KernelCallbackTable;
PVOID EventLogSection;
PVOID EventLog;
ULONG TlsExpansionCounter;
PVOID TlsBitmap;
ULONG TlsBitmapBits[0x2];
PVOID ReadOnlySharedMemoryBase;
PVOID ReadOnlySharedMemoryHeap;
PPVOID ReadOnlyStaticServerData;
PVOID AnsiCodePageData;
PVOID OemCodePageData;
PVOID UnicodeCaseTableData;
ULONG NumberOfProcessors;
ULONG NtGlobalFlag;
BYTE Spare2[0x4];
LARGE_INTEGER CriticalSectionTimeout;
ULONG HeapSegmentReserve;
ULONG HeapSegmentCommit;
ULONG HeapDeCommitTotalFreeThreshold;
ULONG HeapDeCommitFreeBlockThreshold;
ULONG NumberOfHeaps;
ULONG MaximumNumberOfHeaps;
PPVOID *ProcessHeaps;
PVOID GdiSharedHandleTable;
PVOID ProcessStarterHelper;
PVOID GdiDCAttributeList;
PVOID LoaderLock;
ULONG OSMajorVersion;
ULONG OSMinorVersion;
ULONG OSBuildNumber;
ULONG OSPlatformId;
ULONG ImageSubSystem;
ULONG ImageSubSystemMajorVersion;
ULONG ImageSubSystemMinorVersion;
ULONG GdiHandleBuffer[0x22];
ULONG PostProcessInitRoutine;
ULONG TlsExpansionBitmap;
BYTE TlsExpansionBitmapBits[0x80];
ULONG SessionId;

Notice that the PEB contains all sorts of information that might be of use to a chunk of code that just found itself being executed inside of a process on a machine and in an environment that it knows little to nothing about (hey... lookie there: OSMajorVersion, OSMinorVersion, OSBuildNumber, OSPlatformID...).  The address of the PEB itself can always be found on Windows (>=NT) by loading it from fs:30h (why that's so is beyond the scope of this article... but trust me...). So, once we've loaded up the location of the PEB, we see that the code is looking at a particular location offset into the PEB itself-- in fact, it's looking at a location 0x0C (12 decimal) from the beginning of the PEB structure. The offset from the beginning of the structure is referenced above, so we can see that offset 0x0C is a pointer to something called "LoaderData," which is itself, another in-memory data structure.

The LoaderData structure looks like this:

typedef struct _PEB_LDR_DATA {
ULONG Length; //0x00
BOOLEAN Initialized; //0x04
PVOID SsHandle; //0x08
LIST_ENTRY InLoadOrderModuleList; //0x0C
LIST_ENTRY InMemoryOrderModuleList; //0x14
LIST_ENTRY InInitializationOrderModuleList; //0x1C

Steppin' on along, we see that what we're really looking for is again, something offset into this particular structure... actually something at offset 0x1C (28 decimal) (Note: I'm getting these offsets by looking at what is being added to EAX at each step).  Those LIST_ENTRIES actually contain two memory pointers, and make up what is known as a doubly linked list-- the first pointer is to the "previous" module and the second to the "next" module. So the 28 byte offset points us to the LIST_ENTRY for the "InInitializationOrderModuleList."  Each entry in that list points to the InInitializationOrderModuleList entry in a listing of these structures:

typedef struct _LDR_MODULE {
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID BaseAddress;
PVOID EntryPoint;
ULONG SizeOfImage;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;

and this linked list, strings together all of the information for the modules (.DLL files) in their initialization order.  The first module initialized for ANY Windows program is... kernel32.dll. The LODSD operand then loads the address pointed to in ESI into EAX..., and we then bump that by 8 bytes to point to the "BaseAddress" entry...

So, what do all of these machinations accomplish?  Well, when you're an evil piece o' malware, and you would like to use any of the nice functions provided to you by the operating system under Windows, you've got a problem.  Normally, when a piece of software loads and runs under Windows, the Windows Loader takes care of things like loading DLLs and fixing up the program's import table so that the functions that you use from kernel32.dll or user.dll, etc... all just automatically work.  For evil malware exploiting a vulnerability to run itself as part of a vulnerable process, such niceties aren't available... worse still, you don't really even have a way to find something like GetProcAddress so you can load up imports yourself.  What we have here is a nifty way to find the BaseAddress of kernel32.dll... and that's exactly what's in EAX when this subroutine returns.

Another way of looking at this is that, in the code we're looking at, the PEB chains us to the LoaderData, and the LoaderData chains us to module information, which chains us to the BaseAddress of kernel32.dll...  Now the malware needs to move from knowing the BaseAddress of kernel32.dll to being able to call the functions that it needs to make Joe's life miserable...

So, at this point, our evil code has managed to insinuate itself into our running process (the WINS service) and has found the BaseAddress of the kernel32.dll file... and... well, 'splainin' all of this has pretty much worn me out...

So, how about if we both take a break and take this up again in the next installment?

And, because I absolutely love getting a bunch of you to write in and annoy the next Handler on Duty (hi Deb!), I've been dropping some hints pointing towards a particular person throughout my ramblings... anyone know who that is?

Tom Liston - InGuardians - Handler on Duty
Follow me on Twitter

P.S.: For Adrien- Oompah Loompahs!

Keywords: Exploit FTBM WINS
0 comment(s)


Diary Archives