About | Buy Stuff | News | Products | Rants | Search | Security
Home » Resources » Rants

An Ethic of Excellence

Week of September 19, 2003

So MS Blast is in the news again - more correctly, Dog of Bride of Son of MS Blast is in the news. Father-in-law had its fifteen minutes of fame the past weeks. Now we've got more RPC vulnerabilities, and I don't know about you, but I'm sick and tired of hearing about it.

(I'm also sick and tired of all the wimps who are too wussy to switch away from Windows and help make the Internet a better place, but that's another story for another time.)

I mean really - assuming these exploits work on unchecked buffers which can be overrun, how hard can this be for the geniuses in Redmond?

It's not as if others in Redmond are not aware of the potential for not so much exploits as program crashes - remember, an exploit is basically a controlled crash.

Every time a program uses that obsequious 'open file' dialog in Windows, or the equally obsequious 'save as' dialog, it's passing a controlled structure to an MS DLL (comctl32.dll). This structure is as follows (don't get scared away - there's a very neat, very simple point to it all).

typedef struct tagOFN {
  DWORD         lStructSize;      <-- This one!
  HWND          hwndOwner;
  HINSTANCE     hInstance;
  LPCTSTR       lpstrFilter;
  LPTSTR        lpstrCustomFilter;
  DWORD         nMaxCustFilter;
  DWORD         nFilterIndex;
  LPTSTR        lpstrFile;
  DWORD         nMaxFile;
  LPTSTR        lpstrFileTitle;
  DWORD         nMaxFileTitle;
  LPCTSTR       lpstrInitialDir;
  LPCTSTR       lpstrTitle;
  DWORD         Flags;
  WORD          nFileOffset;
  WORD          nFileExtension;
  LPCTSTR       lpstrDefExt;
  LPARAM        lCustData;
  LPOFNHOOKPROC lpfnHook;
  LPCTSTR       lpTemplateName;
#if (_WIN32_WINNT >= 0x0500)
  void *        pvReserved;
  DWORD         dwReserved;
  DWORD         FlagsEx;
#endif // (_WIN32_WINNT >= 0x0500)
} OPENFILENAME, *LPOPENFILENAME;  <-- Click here to see the official MS documentation!

OK - see that very first member, lStructSize? Know what that is? That's a failsafe. If you're the programmer, you fill it in with the size of the structure you're sending to the DLL.

How do you determine that? Let's say your code looks like this:

{
    OPENFILENAME of;

Then you just write like this:

of.lStructSize = sizeof(of);

The first thing the DLL will do is make sure he has access to all the members of your struct. As long as the memory you pass is big enough, he's all right. But you have to fill that first field in and tell the DLL, JUST TO MAKE SURE.

That is what is called 'defensive programming' in the business, and yes, it's a very good thing - in fact, it's totally necessary, and you shouldn't be able to keep a programming job without it.

OK, now let's look at another choice example from the Windows API - GetDlgItemText. This is an obsequious function that is used to get text from almost everything. In contrast to its underlying message, WM_GETTEXT, GetDlgItemText assumes you have a 'handle' to a parent window and the ID of the control you want text from. Look here - and again, don't panic: This is very easy!

UINT GetDlgItemText(  <-- Click here to see the official MS documentation!
    HWND hDlg,        // handle of parent window
    int nIDDlgItem,   // ID of control with text
    LPTSTR lpString,  // where your buffer is
    int nMaxCount     // how big your buffer is    <-- This one!
);

It's all laid out clearly: After the first two arguments, which identify your target, you have information for the function you're calling - namely, where your buffer is AND HOW BIG IT IS. As long as you write the code properly, you can't get in trouble.

The return value, a so-called UINT or 'unsigned integer', tells you the number of bytes transfered. It's IDIOT-PROOF. There is no way you can screw this up if you take the same care as the programmer who created the API.

{
    BYTE b[1000];

    GetDlgItemText(hParentHandle, nTargetControl, b, sizeof(b));

Again, you don't take any chances and put a magic number in there for nMaxCount - you let the compiler fix all that with sizeof.

You can't go wrong. You CANNOT get an overflow.

The same holds true for the underlying Windows message, WM_GETTEXT.

lResult = SendMessage(
   (HWND) hWndControl, // handle to target
   (UINT) WM_GETTEXT,  // the message  <-- Click here to see the official MS documentation!
   (WPARAM) wParam,    // size of buffer
   (LPARAM) lParam     // location of buffer
);

Dealing with this message in the proper way is no more difficult than dealing with GetDlgItemText.

Both the function GetDlgItemText and the message WM_GETTEXT are intelligent enough to deal with the situation where your buffer is not big enough: By telling them how big your buffer is, you are making sure they don't overrun it - and, in the case of GetDlgItemText, you get a few more goodies served up on your platter, for if the string is as long or longer than the buffer, the buffer will contain the truncated string (by at least one byte) with a terminating 0 character - precisely to prevent overflow.

And still, good defensive programmers might go even further:

{
    BYTE b[1001];

    GetDlgItemText(hParentHandle, nTargetControl, b, sizeof(b) - 1);
    b[sizeof(b) - 1] = 0;

Just put another 0 byte in there just in case, just for added security.

All of which is nothing out of the ordinary at all, not when it comes to programming. After all, we don't want our programs to crash, do we? And if we program well, so our programs don't crash, then we have obviated most, if not all, of the ways they could otherwise have been exploited.

Finally, if we don't know how big to make our buffers for this fantastic text we're getting, we can call functions and send messages - GetWindowTextLength and WM_GETTEXTLENGTH. They both send back a number which tells us how long the text in the window/control is; we allocate a buffer of that size (plus one more byte for the terminating 0), then send it off to either GetDlgItemText or WM_GETTEXT.

All of which should make the possibility of an overrun not only slim, but literally non-existent.


Way way back, several years now, there was talk of a vulnerability in Internet Explorer. It turned out that this class act of a browser had a severe limitation on how many characters could be input into its location bar. In other words, a malicious piece of HTML could provide a link with a total length which made Internet Explorer explode.

Netscape came right out and boasted that their browser wouldn't do that, as they allocated 4KB (4,096 bytes) for all URLs.

Then John and I at Radsoft sat down and thought about it all. 'Why settle for dinky 4KB?' was our reasoning. Never mind we'd never seen a URL that long - why pick 4KB out of a hat? It was ridiculous!

The real limitation came with the location bar itself - on Windows, this sucker cannot contain more than 30,000 characters.

That was it. In similar code we used ourselves, we set an internal buffer size of 30,001 bytes - and we still kept our protective code. I have never seen a Radsoft app crashed like that, or worse yet exploited, and yet what we did was no big deal - all we did was THINK a bit. With our BRAINS.

Now we come to the forty-some vulnerabilities Microsoft have announced this year alone. We remember MS Blast and SoBig and we remember the predecessors. Why all this grief? Where does it all come from?

The APIs are safe enough - letting exploits through in the face of this demands sheer stupidity, ignorance, laziness, and arrogance. It's that simple.

A few years back when Microsoft's RTF vulnerability was made known, I wrote a very impassioned rant which was published in RISKS Digest. I deliberately turned up the volume, because I knew that the great majority of readers were programmers themselves, and I sincerely believe there should be no way dumb mistakes like Microsoft's RTF vulnerability should be possible.

PG Neumann, who ran the digest, agreed to publish my rant, but he also let me know one Russ Cooper, Chief Hacking Surgeon Superman or whatever he likes to call himself, had written a letter of protest. Vulnerabilities like this are commonplace, whined Cooper. That's why I have a bug tracking site. People shouldn't get so worked up about a little puny RTF vulnerability.

But of course we should get worked up - look at what our world looks like today: If more people got more worked up and STOPPED all this idiocy, the world would be better off.

Unfortunately, the Russ Coopers of this world would lose out greatly. Russ Cooper, you know the guy? Every time there's a major worm outbreak, he holds champagne parties in his 'humble' abode?

What happened with MS Blast should never have happened. Programmers worth their salaries would never have allowed it. Programmers with BRAINS would have been hard put - as the above tutorial should show - to make such egregious mistakes.

AnnaK should never have happened. Nimda should never have happened. Code Red should never have happened.

It's not enough to have a lot of twisted - how did Steve Ballmer put it? 'thieves, con artists, terrorists and hackers' (great one, Thade) - out there. You need the vulnerabilities too.

Properly written code will not have these vulnerabilities. PERIOD. In fact, they'll be so rare that the prospect of finding one will be so slim, that the kiddies will look for something else to do.

I've said it before and I will say it again, and I don't think people REALLY GET how serious this is: Microsoft have the DUMBEST programmers on the planet.

What's the matter with them? Are they congenitally stupid? Some undoubtedly are, but for the most part it's corporate mentality - a fanatical arrogance, a 'fascist' mentality that's totally without the 'names' in the business that new recruits can look up to and learn from.

Microsoft programmers have no experience or anyone experienced to build on - they're 'scrambling' all the time. Many don't even know what a flowchart is, and many demonstrably lack the cerebral power to think logically for any extended period of time.

'When it gets too slow, we just throw more hardware at it.' That's a direct Microsoft quote. That's how poor they are.

Robin Keir knows - he lent one of his excellent programs to a Microsoft programmer and saw it totally ruined. The Microsoftie couldn't even make it work right, and it got bloated all over the place. THESE GUYS CAN'T PROGRAM.

Or take Nancy Winnick Klutz - she wrote the Windows 95 book on programming. She never even knew how to use Windows. Her code is 'borrowed' from other installations all over the internal network there - she even took the mistakes in the code along, never bothered to check to see if it was correct.

Nancy does one of the dumbest things I have ever seen: She takes return values on function calls she never uses. She assembles tonnes of local variables she has no use for.

Only someone who is TERMINALLY CLUELESS could do such a thing, and only a company like Microsoft could publish that horrendous book, sight unseen, with their own stamp of approval on it, as the 'official' programming book for Windows 95.

Please understand me, I am not ranting about Microsoft: I mean every word. You must believe me, that they are truly the worst imaginable programmers on this planet, and that this is no exaggeration.

Watch out for Dog of Bride of Son. Batten the hatches. Better yet, abandon ship - the Windows ship, that is. There truly is no hope for it.

Thank you for your attention. Now I think I'll either go vomit, or soak my head in a rain barrel. If Microsoft had cultivated an ethic of excellence, none of this would ever have happened. But Microsoft don't want that ethic - for reasons of their own, they don't care.

And all the felling quotes by Thade won't change a thing.

Rick

About | Buy | News | Products | Rants | Search | Security
Copyright © Radsoft. All rights reserved.