Software & Apps

How is my Browser blocking the execution of RWX?

While testing payloads, I stumbled upon a security feature implemented within a popular browser, which acts like an EDR. By hooking into a key Windows API, it checks the thread’s creation at runtime and then decides whether it should run or not.

Failed to run RWX shellcode in a common browser

I tried a new type of process injection method. It may be published in this blog in the near future but the purpose here is not the particular injection technique, but how I randomly found a mechanism inside a browser that acts like a you EDR.

While injecting and executing successfully against something as simple as notepad.exe is a nice start, the real test consists of confirming that it still works correctly against more complex applications (.NET, large multi-threaded apps like browsers, etc…).

This is especially important for injection techniques because they can in a way interrupt the target process. Therefore, ensuring stability is key.

To that effect, I wrote a simple shellcode in a RWX memory range, and then tried to make it implement a new technique against many common apps. It works in all the applications I tried APART against a browser.

Note: this might be overkill but to avoid legal issues I won’t name the browser or the files/functions involved

It became apparent that even when trying to execute the shellcode in a very small way (with CreateRemoteThread()), it still fails silently, with the thread being created but the shellcode never being executed.

At first I thought it was due to a technicality in the target process (browsers can implement funky things, modify native DLLs, etc…)

Making the hooking thread

As do many security products in usermode through hooksthe browser is hooked BaseThreadInitThunk() to have visibility (and control) of what is happening. it BaseThreadInitThunk The call is one of the first steps involved in creating a thread, and you’ll see it in most Process Hacker callstacks, for example this one for my current Sublime application:

Here is the normal API of kernel32.dll:

And here is the modified one used in our browser:

Any creation of the thread will be redirected through that jmp instructions, jumping somewhere to a custom third-party DLL that is loaded in the browser, and about which I found very little information online (which prompted me to look deeper).

Note that at this point, the intended address of the thread creation (where our shellcode is in memory), is stored in rdx register.

Reverse-engineering the hook

As mentioned above, any thread creation that takes place within the browser first goes through a custom check within one of its third-party DLLs. That DLL is big and has many of exports. This surprises me, but for what concerns us here, only one of the routines matters. It is quite simple and quite consists of a call to VirtualQuery() (in red), to get the memory attributes for the address where our shellcode is:

Note the arguments for this API callit takes three arguments, moving the address of the shellcode to rcx (rationale 1, green).

Further down the line, some checks will verify if this memory address is a PAGE_EXECUTE_READ one (0x20 value as seen HERE).

Depending on the result (it is included in cmovnz instruction), the following occurs:

  • If yes, it does not interfere with the intended flow of execution and rdx (which contains the shellcode to be executed at the start of the thread) is unchanged for the downstream code.

  • Otherwise, it will change the starting point of the string and overwrite rdx it is with whatever is available r8which in this case is a kind of sinkhole that just keeps coming back:

To summarize: if an RWX Tried to execute the thread, it will be neutralized.

CONCLUSION

This check is pretty simple and basic to skip (don’t run a RWX address), but I found this kind of feature unexpected and worthy of a blogpost because I couldn’t find any other reference to it online. I’m not 100% sure it’s just a security control but it seems like the only reasonable explanation. Browsers are one of the applications that have RWX memory sections (check this previous blogpost…), so this is probably a deterrent that will make exploit development more difficult if an exploit chain tries to use one of the RWX places for killing. If you have other theories or guesses… let me start!


https://rwxstoned.github.io/assets/img/5/mj.png

2025-01-05 11:08:00

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button