A technical walkthrough of a new offensive technique that activates the Chrome Debugging Protocol directly in memory, bypassing Google's --remote-debugging-port mitigations. Covers chrome.dll signature scanning, DevToolsSocketFactory vtable reconstruction, PartitionAlloc constraints, and Special APC-based shellcode injection into the Chrome parent process.
[Wipeload Step 6.] How to Escape the SandBox Painlessly (EN) - hackyboiz
pHello! This is gongjae, back with Step 6 of the Wipeload project~!! We’re already at Step 6…! Shall we look back at the road we’ve walked so far?/p
pimg src="/2026/08/01/gongjae/Wipeload_step6/EN/image.png" alt="image"/p
blockquote
pPrevious articlesbra href="https://hackyboiz.github.io/2026/06/06/OUYA77/Wipeload_step1/en/"https://hackyboiz.github.io/2026/06/06/OUYA77/Wipeload_step1/en//abra href="https://hackyboiz.github.io/2026/06/21/ji9umi/Wipeload_step2/en/"https://hackyboiz.github.io/2026/06/21/ji9umi/Wipeload_step2/en//abra href="https://hackyboiz.github.io/2026/06/26/ji9umi/Wipeload_step3/en/"https://hackyboiz.github.io/2026/06/26/ji9umi/Wipeload_step3/en//abra href="https://hackyboiz.github.io/2026/07/13/OUYA77/Wipeload_step4/en/"https://hackyboiz.github.io/2026/07/13/OUYA77/Wipeload_step4/en//abra href="https://hackyboiz.github.io/2026/07/19/gongjae/Wipeload_step5/EN/"https://hackyboiz.github.io/2026/07/19/gongjae/Wipeload_step5/EN//a/p
/blockquote
pIn Step 1, OUYA77 drew the picture of the entire chain, and in Steps 2~3, ji9umi showed us renderer RCE and the V8 heap sandbox bypass. In Step 4, OUYA77 came back to take apart how the Chrome sandbox locks itself down, and in Step 5, I covered ALPC and the codeALPC_MSGFLG_SYNC_REQUEST/code Use-After-Free. Today, in Step 6, we’re going to revive that UAF into an arbitrary strongRead/Write primitive/strong, use it as a foothold to reach strongMedium-integrity code execution/strong, and finally pull off a real strongSandBox Escape/strong — on our way to meet Master Shifu!/p
h1 id="1-From-Crash-to-Primitive"a href="#1-From-Crash-to-Primitive" class="headerlink" title="1. From Crash to Primitive"/a1. From Crash to Primitive/h1pAlright, shall we pull up the final scene from Step 5 once more?/p
pWe planted the trigger DLL inside the renderer with sRDI, then killed — mid-flight — the thread that had a SYNC message posted via codeNtWaitForWorkViaWorkerFactory/code, which freed the code_ETHREAD/code. And the moment we closed the port, codeAlpcpCancelMessage/code fired a write at code+0x578/code of that already-dead address. And this was the result./p
pimg src="/2026/08/01/gongjae/Wipeload_step6/EN/image2.png" alt="image"/p
blockquote
pA BSOD means we’re done, right..? delit blew up in the kernel, so it counts as an escape/del/p
/blockquote
pYeah.. honestly, this is where I started overthinking too.. As I hinted at the end of Step 5, Theori’s blog post also said something like “use the file picker, do a thread spray, blah blah blah, and you get code execution at Medium integrity”~../p
pA BSOD only proves one thing: “the kernel stepped on a dead pointer.” But that’s not what we want! We have to turn that dead pointer into stronga tool that reads and writes values we choose, at addresses we choose/strong. A crash and a primitive really are completely different things. The road from the blue screen to cmd is much longer than you’d think~..🥲/p
pBut gongjae isn’t one to back down. I put my brain to work and first picked out what we’d actually need for a SandBox Escape./p
ol
liHow do we turn the UAF into reading and writing the values we want, at the addresses we want? - reclaim?/li
liWhich process do we get to perform that reclaim for us? - file picker?/li
liOnce we can read and write, what do we overwrite to take over execution flow? - vtable?/li
/ol
pIt’s funny that they all end in question marks, but erasing those question marks one by one is exactly the goal of today’s article~!😄 So let’s start with number 1!/p
pWhat we freed in Step 5 was the kernel pool slab that an code_ETHREAD/code object was sitting in. The kernel takes that memory back right away and gets it ready to hand out to the next allocation. So there’s exactly one thing left for us to do: fill that spot back up with a fresh code_ETHREAD/code belonging to a process of our choosing! That is exactly what reclaim is./p
pWhat happens if this succeeds? The codeWaitingThread/code pointer left behind in the message stops being a “dead address”. strongIt now points at a live code_ETHREAD/code/strong inside a process we control. At that moment, the UAF transforms from a mere crash generator into a cross-process R/W window!!/p
pWhy is this hard, you ask? Because the kernel pool isn’t that naive.. You have to know, down to the bone, where a freed slab actually goes and by what rules it gets reused… 🙃 Before we dive in: the native code running inside the renderer today is a modified version of that trigger DLL from Step 5, so for convenience I’ll just call it the strongexploit DLL/strong./p
pThe test environment is identical to Step 5./p
precode class="hljs apache"span class="hljs-attribute"Windows/span span class="hljs-number"11/span span class="hljs-number"22/spanHspan class="hljs-number"2/span · ntoskrnl span class="hljs-number"22621/span.span class="hljs-number"963/span
span class="hljs-attribute"Chrome/span for Testing span class="hljs-number"114/span.span class="hljs-number"0/span.span class="hljs-number"5708/span.span class="hljs-number"0/span/code/pre
pAlso, the Driver Verifier we turned on in Step 5 to make sure we’d see the BSOD is turned off this time. Special pool unmaps freed slabs entirely, so leaving it on would make today’s whole topic — reclaim — impossible!!/p
h2 id="1-1-VS-allocator-ETHREAD-slab"a href="#1-1-VS-allocator-ETHREAD-slab" class="headerlink" title="1.1 VS allocator _ETHREAD slab"/a1.1 strongVS allocator/strong _ETHREAD slab/h2pFirst, let’s confirm the identity of the slab we’re up against./p
precode class="hljs sqf"span class="hljs-built_in"sizeof/span(span class="hljs-variable"_ETHREAD/span) = span class="hljs-number"0/spanx900 span class="hljs-comment"// object size the kernel allocates/span
pool block (actual) = span class="hljs-number"0/spanxa80 span class="hljs-comment"// what !pool reports/span
tag = span class="hljs-string"'Thre'/span span class="hljs-comment"// protected/span
pool span class="hljs-built_in"type/span = NonPagedPoolNx/code/pre
pThese two numbers are exactly where it gets confusing. code0x900/code is only ever the object size; the block that actually comes off the pool is code0xa80/code. code_POOL_HEADER/code, code_OBJECT_HEADER/code, sub-headers, and the VS chunk header all get piled on before and after, and then it gets rounded up to the VS allocator’s size class./p
pimg src="/2026/08/01/gongjae/Wipeload_step6/EN/image3.png" alt="image"/p
pSo the size class we’re competing over during reclaim is not code0x900/code but strongcode0xa80/code/strong. When picking the slab out by eye, it’s easiest to scan the code!pool/code output for the size codea80/code + code*Thre/code combination. The code(Protected)/code printed next to it means the pool tag carries a protection bit — a kernel-side safeguard that only accepts a free when the tag matches. We aren’t calling free ourselves; we’re targeting a spot the kernel freed while tearing a thread down, so this never gets in our way./p
pimg src="/2026/08/01/gongjae/Wipeload_step6/EN/image4.png" alt="image"/p
pAlso, since Win10 19H1 the kernel pool is a segment heap, so which allocator handles a request depends on the size. Anything under code0x200/code goes to kLFH, code0x200/code through code0x20000/code goes to the strongVS allocator/strong, and anything larger goes to segment/large. The block-code0xa80/code code_ETHREAD/code falls into the second one — in other words, the strongVS allocator/strong manages it. Everything in today’s reclaim happens inside this allocator./p
pAnd the allocation path looks like this./p
precode class="hljs apache"span class="hljs-attribute"NtCreateThreadEx/span → PspAllocateThread → ObpAllocateObject → ExAllocatePoolspan class="hljs-number"2/span/code/pre
pThe only entrance that hands this slab out is, in the end, codeNtCreateThreadEx/code — which means strongif anybody creates one thread, one code0xa80/code block goes out/strong. The answer to why the thread spray I teased earlier actually works is packed entirely into this one line./p
h2 id="1-2-Dynamic-Lookaside"a href="#1-2-Dynamic-Lookaside" class="headerlink" title="1.2 Dynamic Lookaside"/a1.2 Dynamic Lookaside/h2pBut here’s the thing — there’s one more layer of cache sitting in front of the VS allocator. It’s the code_RTL_DYNAMIC_LOOKASIDE/code structure that code_SEGMENT_HEAP.UserContext/code points to, and honestly, this guy is the real main character of today’s story!/p
pShall we check the structure directly in kd first?/p
precode class="hljs angelscript"span class="hljs-number"0/span: kd> dt nt!_RTL_DYNAMIC_LOOKASIDE
+span class="hljs-number"0x000/span EnabledBucketBitmap : Uint8B
+span class="hljs-number"0x008/span BucketCount : Uint4B
+span class="hljs-number"0x00c/span ActiveBucketCount : Uint4B
+span class="hljs-number"0x040/span Buckets : [span class="hljs-number"64/span] _RTL_LOOKASIDE
span class="hljs-number"0/span: kd> dt nt!_RTL_LOOKASIDE
+span class="hljs-number"0x000/span ListHead : _SLIST_HEADER
+span class="hljs-number"0x010/span Dep
Breaking Out of Chrome's Sandbox: A Native Messaging Backdoor Observed in Italy
A malicious Chrome extension observed in an Italian malspam campaign used Native Messaging to escape the browser sandbox, steal session data and execute remote PowerShell commands on Windows. This analysis explains the infection chain,
its command-and-control channel and the main detection opportu
A firsthand analysis of three modern Chrome-specific exploit mitigations — MiraclePtr, v8 sandbox, and PartitionAlloc — from actual zero day research targeting Google Chrome.
Authored by stratan
In Part 1, we went over the background details that are needed to follow along, as well as the trigger specifics of the bug. In Part 2, we'll go through the relevant code paths, analyze the patch, and develop an in-cage read/write primitive.
Disclaimer
This article has been prepared for
Parse and Parse: MIME Validation Bypass to XSS via Parser Differential
This research is an extension of Content-Type research from BlackFan. More specifically, the response Content-Type tricks. Unfortunately, the multiple Content-Type trick is not clearly explained by BlackFan. Therefore, I’ll explain and demonstrate how a single comma character can cause a parsing difference between the browser and different MIME type parser libraries.
Arc Browser UXSS, Local File Read, Arbitrary File Creation and Path Traversal to RCE
Arc Browser UXSS, Local File Read, Arbitrary File Creation and Path Traversal to RCE After announcing the bug bounty program I downloaded the browser and started looking for vulnerabilities, using my …
Out-of-bound read in ANGLE CopyNativeVertexData from Compromised Renderer
Introduction Back in the beginning of the year 2024, we started our project on ANGLE, it is a chromium graphic library, handling rendering stuff on chrome process. Fortunately, our team found some of the vulnerabilities in different areas (suto has shared some information on his tweet previously). In this blog post, we will explain how a libANGLE integer underflow bug can be turned into a powerful primitive that allows us to read the Chrome WebGPU process.
Mutation-Based XSS + V8 type confusion + V8 sandbox escape = RCE on Basecamp.
Disclosed it on Hackerone: https://t.co/slsv3j4jXx
go read the comments if you wanna see what a week of exploit dev pain looks like.