This site uses advanced css techniques
Last Updated: Wed Aug 22 12:44:08 PDT 2001
Others have done a much more complete job of analyzing this, so we've left it in the incomplete state where we stopped working on it.
22 Aug 2001 - There are reports of a new, minor variant of Code Red II, and its has only very small changes. The "CodeRedII" string was changed to "_________" so it could coexist with a "real" Code Red II worm, and it slightly changed the algorithm for scanning the network to less favor the local network. This is no big deal at all, and if you were protected before, you're still protected.
11 Aug 2001 - These reports of a new Code Red in Korea are false: it's the same Code Red II that we've come to know and love. It seems that nobody in Korea worked last weekend or read the newspapers. This is pretty lame reporting.
7 Aug 2001 1200 PST - there have been reports of a "new" Code Red II, but these are almost certainly false. It turns out that Code Red II has some interesting behavior on cable modem networks, but it's an accident and not intentional. In addition, there are reports from Reuters that suggest a second Code Red II infecting China and parts East, but this is almost certainly just very delayed reaction to the released-Saturday Code Red II. Why this is news on Tuesday instead of Saturday is curious.
On Saturday morning, August 4 2001, a new variant of the Code Red worm started showing up in web server logfiles. The "real" work to analyze this is being done by the folks at eEye Digital Security, but until they release their big-time analysis I'd like to offer a minor-league running commentary. I believe this was the first comprehensive information available on this worm for the better part of Saturday.
Keep in mind that I am not an assembler guru, and though I've been doing C and Win32 programming for a long time, I am bound to get some of the details wrong here. Please let me know if you catch any of my mistakes.
The traditional signature of Code Red in web server logs has been:
GET /default.ida?NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN%u9090%u6858%ucbd3 %u7801%u9090%u6858%ucbd3%u7801%u9090%u6858%ucbd3%u7801 %u9090%u9090%u8190%u00c3%u0003%u8b00%u531b%u53ff %u0078%u0000%u00=a HTTP/1.0
but the new strain is showing up as:
GET /default.ida?XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%u9090%u6858%ucbd3 %u7801%u9090%u6858%ucbd3%u7801%u9090%u6858%ucbd3%u7801 %u9090%u9090%u8190%u00c3%u0003%u8b00%u531b%u53ff %u0078%u0000%u00=a HTTP/1.0
The only difference here is the use of XXXX instead of NNNN, but this is only the initial infection code. The payload is a different story: I used my websnarf tool to capture the full text of the request, and instead of the usual 4039 or 4112 byte payloads, this one is 3818 and quite different. When running the "strings" command on this binary we see:
GET /default.ida?XX{220 x X}XX%u9090%u6858%ucbd3%u7801%u9090%u6858%ucbd3%u7801%u9090%u6858%ucbd3%u7801\ %u9090%u9090%u8190%u00c3%u0003%u8b00%u531b%u53ff%u0078%u0000%u00=a HTTP/1.0 Content-type: text/xml Content-length: 3379 CodeRedII <--- hence the name: Code Red II F4)E Th~f Th~f ;MZu KERNu EL32u GetPu rocAu D$$dg LoadLibraryA CreateThread GetTickCount Sleep GetSystemDefaultLangID GetSystemDirectoryA CopyFileA GlobalFindAtomA GlobalAddAtomA CloseHandle _lcreat _lwrite _lclose GetSystemTime WS2_32.DLL socket closesocket ioctlsocket connect select send recv gethostname gethostbyname WSAGetLastError USER32.DLL ExitWindowsEx \CMD.EXE d:\inetpub\scripts\root.exe d:\progra~1\common~1\system\MSADC\root.exe hT @ hH @ hX @ t6Ff %`0@ %d0@ %h0@ %p0@ %t0@ %x0@ %|0@ \EXPLORER.EXE SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon SFCDisable SYSTEM\CurrentControlSet\Services\W3SVC\Parameters\Virtual Roots /Scripts /MSADC c:\,,217 d:\,,217 KERNEL32.dll ADVAPI32.dll Sleep GetWindowsDirectoryA WinExec <--- troubling RegQueryValueExA RegSetValueExA <--- troubling RegOpenKeyExA RegCloseKey d:\explorer.exe 8>u'j
In particular, there doesn't appear to be any "sample" HTML code that replaces the current home page, and the references to the registry API functions are troubling. I've not picked apart the code yet, but it would not surprise me if (unlike the previous variants), this one was actually persistent.
There are several threads going on in the DSLReports Security Forum, and there are reports of much higher than usual probe attempts. Based on many reports there, we have a very strong suspicion that Code Red II has a different algorithm for scanning its targets, and it favors machines "close" to itself (roughly: "same ISP").
Update (1700 PST) - I'm having a lot of trouble with my disassembler (not very good with it anyway), but this just doesn't look structurally at all like the first one that went around. This suggests that we will find very little in common with the first one.
In particular, the fact that it has "CodeRedII" inside means that it couldn't possibly be the original worm -- the name wasn't attached until after it was released.
Update: 1819 PST - The worm queries and sets a "global atom" of the name CodeRedII. I'm not sure what this is, but it's a form of interprocess communication that's (perhaps) used by IIS. Not yet sure what this implies.
It seems that the IP address calculation starts with the machine's local IP address, and this gives a bit of strength to the notion that scanning tends to be to "local" machines (something I'm very much seeing in my logs). It also skips IP addresses ending in dot-0 and dot-255.
If anybody else is trying to disassemble this, these values seem to reference the Win32 API functions used, plus a few additional special variables.
DWORD PTR [EBP-8] FindLibrary DWORD PTR [EBP-0CH] LoadLibraryA DWORD PTR [EBP-10H] CreateThread DWORD PTR [EBP-14H] GetTickCount DWORD PTR [EBP-18H] Sleep DWORD PTR [EBP-1CH] GetSystemDefaultLangID DWORD PTR [EBP-20H] GetSystemDirectoryA DWORD PTR [EBP-24H] CopyFileA DWORD PTR [EBP-28H] GlobalFindAtomA DWORD PTR [EBP-2CH] GlobalAddAtomA DWORD PTR [EBP-30H] CloseHandle DWORD PTR [EBP-34H] _lcreat DWORD PTR [EBP-38H] _lwrite DWORD PTR [EBP-3CH] _lclose DWORD PTR [EBP-40H] GetSystemTime DWORD PTR [EBP-44H] WS2_32.DLL DWORD PTR [EBP-48H] socket DWORD PTR [EBP-4CH] closesocket DWORD PTR [EBP-50H] ioctlsocket DWORD PTR [EBP-54H] connect DWORD PTR [EBP-58H] select DWORD PTR [EBP-5CH] send DWORD PTR [EBP-60H] recv DWORD PTR [EBP-64H] gethostname DWORD PTR [EBP-68H] gethostbyname DWORD PTR [EBP-6CH] WSAGetLastError DWORD PTR [EBP-70H] USER32.DLL DWORD PTR [EBP-74H] ExitWindowsEx DWORD PTR [EBP-7CH] RandomSeed DWORD PTR [EBP-80H] socketFD DWORD PTR DS:[0FFFFFE58] my IP address
Update: 1900 PST -- it seems that the worm will exit if the current month is 10/2001 or later. EDIT: - Not true: Starting at 10/2001 it reboots immediately upon being probed. Slight difference!
Update: 1945 PST -- minor tidbit: whether the machine is installed with Chinese as its language seems to be a factor in the random number generator. How curious.
Update: 2053 PST -- the worm sets the CodeRedII global atom, and if it finds that this is already set, it simply goes to sleep forever without touching anything else. It's still presumably eating up a thread, but at least it won't walk on its siblings.
Update: 2137 PST -- it seems that the worm spawns 18 threads for most systems, but spawns 36 if the current language is Chinese. What an interesting turn. Edit: - it's 300 and 600, respectively.
Update: 2244 PST -- it's clear that the worm has an interesting pattern of scanning that favors the local network. The worm generates a target address that depends on a random number and the user's IP address.
[SEE BELOW - got the details wrong]
Localhost (127.X.X.X), multicast (224.X.X.X) and the machine itself are never scanned.
BUT: if a machine inside a firewall is cracked through NAT, it will simply go nuts inside the company firewall as it tries to scan the private range (192.168.X.X or 10.X.X.X). For a company with lots of NT systems inside, they will positively go nuts trying to infect each other.
Update: 2341 PST -- pretty sure I got the scanning pattern backwards. Am still hand-checking the code, but don't bet the farm on four-out-of-eight scanning the local subnet :-(
Update: 0010 PST -- got the algorithm backwards, see the next section for the details.
Update: 0120 PST -- The top-level controlling loop works roughly like this (not literal translation of the asm, but conveys the same idea):
bool is_Chinese = (GetSystemDefaultLangID() matches CHINESE) nthreads = is_Chinese ? 600 : 300; sleeptime = is_Chinese ? 2 Days : 1 Day; while ( nthreads-- > 0 ) spawn_thread; Sleep(sleeptime); ExitWindowsEx(EXW_FORCEIFHUNG | EXW_REBOOT | EXW_FORCE, 0 );
So these machines will all reboot a day after infection, at which time they are available for new infections (but the Chinese go two days between reboots). I suspect that this reboot business has something to do with the Windows File Protection scheme that is subverted by the worm. I believe that disabling WFP requires a reboot in some circumstances, so this may take care of this.
Update: = This is now old news, but I'm including a note here in case people use this as their "standard reference" for Code Red II. It has a nasty back door that allows the bad guy to get into the machine via HTTP even if it's been rebooted. See the eEye advisory for information on this. It's ugly.
The algorithm used by this new variant is designed to infect lots of "local" machines that are presumably more fully populated than picking random IPs out there. A blend of the local IP and a random number is used, and the number of octets in each depends on yet another random number that can go eight ways:
The code to do this starts with a table of masks, but remember that on the Intel platform, "network" byte order is the inverse of the native CPU order, so we have to think backwards. This made it much more difficult for a non-assembler guy like me to follow :-(
mtable[] = { 0xFFFFFFFF // go anywhere 0xFFFFFF00 // stay in class A 0xFFFFFF00 // stay in class A 0xFFFFFF00 // stay in class A 0xFFFFFF00 // stay in class A 0xFFFF0000 // stay in class B 0xFFFF0000 // stay in class B 0xFFFF0000 }; // stay in class B # start with a random number that will be our new IP address. # I presume the random number generator is "random enough". newip = random(); # zero the UPPER octets of the random IP, which means that the # random number won't participate in the class A or class B # address mask = mtable[ random() & 0x7 ]; // locate a mask newip &= mask; // throw away rightmost bits # flip the mask around to operate on LOWER octets mask = ~mask; // flip the mask around myip = LOCAL_IP & mask; // throw away leftmost bits # newip contains the upper bits # myip contains the lower bits # join them: newip |= myip; if (newip starts with 127) try again // localhost if (newip starts with 224) try again // multicast if (newip matches LOCAL_IP) try again Connect to "newip" and try to infect
This algorithm certainly has been effective in hammering the poor cable modem users...
At the moment I am not working terribly hard to track down when all this started happening, but I do want to record what I know. People have been sending me logfile (please don't!) that shows earlier timestamps. but the first public report I know of on DSL Reports in this posting. Member dwmorris at email.com reported this at 0730 PST on August 4, 2001.
I'm no longer tracking earlier log entries -- others will do that -- but I am curious about earlier public reports.
All indications are that this worm has the same infection mechanism as the original Code Red, which means that it exploits the same vulnerability in IIS. The different payload only comes into play if the infection attempt succeeds: otherwise it's ignored. This means that machines patched to protect itself from Code Red are safe from this variant.
Update: - there are credible reports that this worm also infects the Personal Web Server in Windows 2000 Professional. Not sure if the same patches apply.
Over the last couple of days there has been much better analysis of the worm that I've been able to do myself. This is a compilation of the collective wisdom of the net at large.
There are two schools of thought as to what to do with your firewall settings to deal with Code Red (all versions). On one hand, but allowing the firewall to send an ICMP port unreachable for the disallowed traffic, you get only one attempt before it gives up and moves on. By stealthing the port (dropping the inbound SYN packet), you will get three before the worm gives up and moves on. But if you stealth the port, you "stall" the worker thread on the other end for a while. My general feeling is for correct operation of the IP protocol (e.g., "no stealth").
Update: Patrick Schaaf (bof at bof.de) points out that stealth will aggravate the trouble transparent web proxies already have, with their connection caches filling up faster than normal usage. Quoting him: "Blackholes hurt". I agree. Stealth is overrated and counterproductive. Just say "no" to stealth.
Cable modem users are getting positively hammered. Since most of them are on the 24.X.X.X class A block, as soon as one of them gets infected it will make very quick work out of infecting all the other available systems. What's curious is that the vast majority of the cable-modem ISPs do not permit their customers to run servers of any kind, certainly not web servers. Whether Code Red II will cause @Home and others to clamp down on this violation of their terms & conditions remains to be seen. @Home (at least) regularly scans for open news servers, so extending this to web servers doesn't seem that far fetched.
In addition, since cable modem networks are shared media, the ARP ( Address Resolution Protocol) traffic is quite substantial. This ARP traffic shows up in flickering lights on the cable modems, but typically does not show up in personal firewalls such as ZoneAlarm. Cable modem users are positively freaking out about Code Red II.
Sadly, there is some confusion of what to call this thing. The previous Code Red had two slightly different flavors, and they were dubbed CRv1 and v2 by eEye. This new worm has the string "CodeRedII" inside, which obviously suggested a name as well. But "2" and "II" sound the same over the phone, so many are calling this "CRv3" even though it's a new worm and not a variant.
In retrospect, we could have maybe avoided this whole nomenclatural conundrum by my calling it "Diet Code Red" early on Saturday. Too late :-(
It's clearly possible for Code Red II to infect a machine that already has any of the original variants. These worms don't know anything about each other, so it's possible for an end user to get both kinds of probes from the same infected machine (though not terribly likely).
But if Code Red II is first on the system, it's unlikely that CRv1 will join it. This is because CRII spawns so many threads that the web server simply won't accept any more requests (worm or not). So in practice, once Code Red II is on the system, that's the end of inbound activity for HTTP. Very large machines or those with very slow network connections might
The binary code captured via websnarf can be found in the binary file CodeRedII.bin. You can see a text dump of the binary worm at CodeRedII.txt.
Here I'll put links to other things I found interesting. Note that all of these leave my site, and unless my link is actually broken, kindly contact the remote site owners if you have issues with their pages: