Saturday, January 25 was, without exaggeration, the day the internet decided to close up shop. ATMs down halfway around the world, brand-new ADSL connections running at the speeds of a 90s 56k modem (or worse, not connecting at all).
The culprit of all this disaster wasn't some highly sophisticated attack straight out of the movie Hackers, but a botched security job exploited by a ridiculously small piece of code. Today I want us to dissect a bit of what happened with the Slammer worm (or Sapphire, as some analysts call it) to try and understand how something so tiny turned the technological world upside down.
A 376-byte UDP packet
The technical beauty (if you can call it that from a computer scientist's perspective) and the terror of Slammer lie in its size: it occupies exactly 376 bytes. The entire worm fits seamlessly into a single network packet. And herein lies the evil genius and the reason for its incredible propagation speed.
Unlike other recent nightmares we've dealt with, like Code Red or Nimda, which used the TCP protocol and had to waste precious time on the three-way handshake (the famous SYN, SYN-ACK, ACK greeting to establish the connection), Slammer uses UDP.
This protocol works by shooting blindly. The worm generates random IP addresses using a routine of code it carries in its own guts, and spits out copies of itself not caring whether they reach their destination or not. Since the payload takes up so little space, an infected server with a decent internet connection can launch hundreds or thousands of these packets per second. The result is the total saturation of the bandwidth and the routing tables of the carriers' routers. That's why the global network collapsed. Not because it wiped hard drives or stole passwords, but out of pure garbage traffic noise.
The hole: Buffer overflow in SQL Server
But how the hell does it get into the system? The worm attacks port 1434 (UDP). This port is used by the Microsoft SQL Server 2000 resolution service (and, watch out, also by MSDE 2000 which is sometimes secretly installed by other "third-party" programs without you knowing) to inform clients which database instances are running on the machine.
The way the buffer overflow works is textbook. If you send a carefully crafted packet to that 1434 port starting with the byte 0x04, followed by a text string much longer than what the Microsoft programmer allocated in memory, the buffer simply blows up. That excess data overwrites the program's execution stack, altering the processor's instruction pointer. This way, the CPU, instead of continuing with the normal execution of the SQL service, takes a leap and executes the malicious code hiding right behind it in that same packet.
At a very conceptual level, the anatomy of the attack in memory is something like this:
[Cabecera UDP destino 1434] + [0x04] + [A + A + A... (Desborda el búfer)] + [Código ensamblador del gusano]
Once the worm runs, it stays resident in your server's memory (a huge advantage for it: it doesn't write a single byte to the hard drive, meaning the desktop antiviruses we usually run don't even notice) and starts bombarding the internet in an infinite loop. The good part is that, by rebooting the computer or killing the process, the worm disappears. The bad part is that, if you don't patch the system or unplug the network cable, you get re-infected in a matter of milliseconds because the internet is still swarming with lost packets looking for victims.
To tinker around a bit and make sure your dev machine isn't exposing the cursed port without you knowing, open MS-DOS and run a quick command:
netstat -an | find "1434"
If it shows up listening on your public IP... pack it up. And if you're like me, one of those who trusts an old Linux box acting as a firewall for the perimeter network more, you better have added a rule like this over the weekend to stop the bleeding:
iptables -A FORWARD -p udp --dport 1434 -j DROP
The reflection it leaves us
What makes me feel the most helpless about this whole story is that the technical vulnerability Slammer exploits is absolutely nothing new. Microsoft released the official patch, the famous MS02-039, in July of last year! It had been gathering dust on their download page for six months. Why did so many thousands of corporate servers fall then? Simply because in our world, updating systems in production still causes panic. Nobody wants to touch a database server that is running and providing service 24/7 in case something breaks or the accounting software stops working, but then what happens, happens.
I think we're getting into the bad habit of connecting everything to the internet "just in case" or purely for the convenience of sysadmins working from home. Tinkering locally with hardware is fine, but having an SQL Server 2000 exposed directly to the public internet without a restrictive firewall in front of it, in the middle of 2003, is straight-up professional suicide.
We have to learn the lesson the hard way. It's time to start taking the policy of applying patches as soon as they come out seriously, and above all, adopting a philosophy of closing everything that isn't strictly necessary.