Submind YouTube summaries
Thumbnail for DEF CON SG1 - CSIT Village -   Ernest Ang - From Chrome Renderer, To Mouse To System

DEF CON SG1 - CSIT Village - Ernest Ang - From Chrome Renderer, To Mouse To System

Watch on YouTube

Video summary

Ernest Ang opens his presentation by outlining a complex browser-to-system exploitation chain that begins within the Chrome renderer process and escalates to full kernel-level access on Windows. He clarifies that while the vulnerabilities discussed have been patched in modern versions, the demonstration relies on older Chromium builds to illustrate a theoretical attack path that is technically intricate but not representative of current "zero-click" threats used by advanced persistent groups. The core of his research focuses on the V8 JavaScript engine, specifically targeting a bug in its parser where unused variables are mistakenly treated as used during the lazy parsing phase. This flaw allows an attacker to generate incorrect bytecode, which can be further manipulated through garbage collection cycles to create inconsistent code generation and ultimately achieve arbitrary read-write access within the V8 heap, bypassing standard sandbox protections like Uber cage by exploiting misconfigurations in the external pointer table. Once code execution is established within the untrusted renderer process, Ang demonstrates how to escalate privileges by leveraging a logical vulnerability in Chrome's drag-and-drop API. By manipulating the `startDragging` function, he can synthesize arbitrary mouse events and force the user's cursor to click on malicious executables downloaded via JavaScript, effectively bypassing browser sandbox boundaries to achieve medium integrity code execution. This step is crucial because it bridges the gap between the restricted renderer environment and the more privileged browser process. However, Ang notes that this chain requires significant engineering, including patching Chrome functionalities to call internal APIs like `startDragging` directly from a payload, as well as handling memory corruption issues related to heap allocator decompression algorithms that initially caused crashes during execution. The final stage of the attack involves exploiting a race condition in the CRFS Windows kernel driver to achieve system-level privilege escalation. By manipulating handle counts and reference counts for file objects, Ang triggers a use-after-free vulnerability where a dangling FS context object is replaced with a controlled pipe buffer before it can be cleaned up. This allows him to inject arbitrary values into specific registers, including the instruction pointer (RIP), enabling control over kernel execution flow. With this level of access, he can modify security tokens to gain full administrative rights, though he emphasizes that the entire chain remains unstable in practice due to Windows Defender SmartScreen protections and Endpoint Detection and Response (EDR) tools, making it an educational proof-of-concept rather than a deployable weapon for modern systems.
Read the full video transcript
And now to close off day one, we start off deceptively simple but escalate quickly from Chrome renderer to mouse to system. Ernest Ang will share how what begins as a simple click turns into full system compromise, chaining multiple vulnerabilities from the Chromium renderer all the way to kernel level access. It's technical, it's creative, and yes, it's a little bit terrifying. Let's welcome our final speaker for today. >> [applause] >> Okay. So, a very good evening to everyone. Thank you for making the time to come for my sharing. Uh, I'll try to make it as brief as possible so we don't take up the full 1 hour. Uh, yeah. So, today I'll be sharing a browser full chain exploitation from Chroman renderer to actually the Chrome browser, not the mouse. Uh, to eventually obtain system level privilege on the Windows operating system. So just a bit of caveats. Number one, all the vulnerabilities that I'll be going through are all patched. So don't worry about me or anyone controlling your mouse after this. Uh and as a result, we'll be looking at older versions of Chromium and Windows. And last but not least, this is strictly an unrealistic expert chain as you will see later on. So if you are looking for something which is AP grade such as the one used a few months ago by UNCC 386 against our telos uh you will not find it here. But if you are looking for something interesting and something to learn more about complex systems about browsers and the kernel um do stay to the end of the presentation and uh you get to see something funny in 30 to 40 slides or more. Okay. Okay, so a little bit about background about sorry who am I? Uh I've been with CSIT for 3 years under the mobile security department and we mainly deal with VAP of mobile apps which is used throughout CSIT and Mindv and from time to time we are tasked to do evaluation of uh mobile applications which are used throughout the whole of government of Singapore. Aside from that we also do a bit of esoteric uh research against the Android operating system. So things like the uh binder kernel zygote and a bit of the mitigations which are implemented there and as a byproduct of it we also have to do a bit of product and tooling development here and there. Okay. So some motivations of why browser food chain well um I think browsers are used every day and everywhere. I think even my grandmother uses browsers. Uh yet they under research due to its complex nature. Right. Okay, never mind. So, due to its complex nature, sorry. So, um yeah, and you will see that there are a lot of weird bugs that come from browsers and which leads to even weirder exploitation techniques. Also, there are not a lot of full chain proof of concepts available. So, I thought why not be one of the few that manage to demonstrate one. It'll be hard to dive into each and every component. So, but I'll still try nonetheless. Okay. Uh and then as of why did I choose Chrome? Well, it has the biggest market share uh today. And apart from that, I think personally for me uh one click exploit chains has always been very fascinating. And if we look at the trends of other exploit chains such as the zero click used in operation um triangulation I think on the iOS operating system. Um there is also the element of browser and uh also three years ago I think theory also did a full chain but their full chain was from from a renderer process in a guest VM and they escaped and managed to add system level privileges in host. So I thought this was also quite interesting and uh I thought of doing something similar at a smaller scale. Okay. So now um since we are going to be targeting Chrome, I think it'll be good to share a bit of context on how Chrome works. So every time you click that green, blue, red, yellow icon um a lot of processes run underneath the hood. We will skip the utility, GPU and plug-in process and just focus on the renderer and browser process because these are the two processes which we'll be exploiting. So the renderer process is in charge of two things, executing your JavaScript and rendering your web content. And usually it runs with the lowest amount of privileges because of the fact that um there's a lot of attack surface there. And then on the other end of the spectrum we have the browser process which is the most privileged process uh in the Windows operating system. And it is in charge of performing the more privileged actions such as read write to this network connections and stuff like that. And as with every multipprocess architecture there is the concept of IPC which is interprocess communication and the IPC for Chrome is module. Okay. So now with some context let's start with the first bug. Uh this is an issue within the V8 parcel which eventually gives us code execution with untrusted integrity. Okay. So what is V8? For the uninitiated V8 is basically the JavaScript execution engine for Chromium. It is highly complex and uh it in charge of taking your JavaScript passing it interpreting it optimizing it deoptimizing it so and so forth and eventually uh well executing it. Uh there's many many different components and with each component there is a tech surface. So but the thing is that the issue is within the vessel. So we'll be looking at the V passer only and this diagram by is also quite outdated. I think it's uh done in 2017. The VA today is highly complex and has more components such as part plug maclo tool uh scanner and then the optimizer to has been superseded by turbos shaft. Okay. So what is the TLDDR of this bug? We can basically trick the passer into thinking that this is being used by a parent function when it is actually unused and so we'll wrongly generate a and bite code for it. So in this example here you can see that the function I do not use this doesn't use this but we can basically trick the VA engine into thinking that I do not use this uses this. Uh there are some caveats to triggering this bug. Uh you need to use error functions. You need to use classes which are statically initialized and use this in the static initialization. And we also need to make sure that the whole function can be lazily passed but uh more on that later on. Okay. And so now we have a very weird bug which is that we can generate bite code that is not supposed to be there. So how do we basically escalate our privilege and upgrade it so that we get something stronger. So to do so we will need to understand two concepts. The first concept is the concept of b flushing which is the fancy term for bico garbage collection. So what is garbage collection is just in computer science or complex computer systems. Uh garbage collection is a system which helps program save space via automated memory reclaim and uh is triggered in V8 is triggered when the B code B codes age gets too old and when your bite codes get flashed uh you will need to recompile it and repass it. Okay. So the next concept is the concept of um lazy passing or pre-passing. So to understand lazy passing or and pre-passing you have to understand full passing first. So it comes to full passing uh your what the parser will do is that it will check your code for grammatical errors and this is not the same grammar as your English language grammar your was this those that it is a programming language grammar right it checks your code for syntax errors which is specific to your uh programming language and then once it's grammatically correct we'll generate a when it comes to prepassing we only check for syntax errors and the rest of passing is done by the pre-passer when the function is called or use. Okay. So when you are prepassing a function the your function will use that uses variables um the metadata of them will be saved and will be saved during prepassing and then loaded when the function is called. So some of these important metadata which is relevant to the bug is things like the is used field since we are dealing with a vulnerability which can trick your fun which can trick the passer into thinking that something is used when it is actually unused. So this is quite important for the vulnerability and exploitation of this bug. Okay. So looking at V8 um we come across this function known as pass function literal. And this function within the V8 passer is in charge of well doing passing doing function passing. And if we dive deeper into this function eventually the the passer will determine if this function that we are currently passing can be prepassed and if it is lazy. And if it's lazy and it can be prepassed, we should prepassseass it. And if we should repass it, we'll call skip function. And as you can guess, skip function will basically mark the current function that it is passing that that VA passer is passing because it is identified that this function meets the requirements for prepassing and it would set certain metadata or flex within the function to indicate that yes, this function is prepassing. do prepass it and it do so using the set must use prepass data flag. Okay, so putting everything together we can control a simple P uh which involves code that is written by our trigger function that we have written a few slides ago. We'll call the trigger function with the vulnerable passing code. We'll flush his bite code and then we'll trigger it again and let's see what happens. Okay, so initially uh pass function lit is called on our vulnerable function and the passer determines that this function can be repass and it is lazy and hence we should repass it and skip function technically will be called on this function and you can see that after this the rest of passing stops which confirms our hypothesis right when it comes to pre-passing we only check for syntax errors and the rest of the passing and the generation of bite code is skipped until we call the trigger fun until we call our function. And when we call our function, you can see that on this instance um the passer detects that uh we have to that this function is marked for pre-passing and then it restores all the metadata of all the variables uh that he has saved during prepassing. And over here you can see the vulnerability in the flesh right that even though this trigger function doesn't use this the prepasser mistakenly thinks that it is using this and hence um you'll see what happened later on. Okay. So after this we'll flush his white code and then we call the function again. And what happens here in this instance of in this instance of second passing this function uh the passer determines that this function can't be prepassed anymore because it has already been prepassed and hence it doesn't prepass. Okay. And then this leads to a very interesting uh primitive right. So on the first instance of passing this function we can see that um the bite code because the fun because the passer thinks that this is being used by the function it will generate bite code for it and on the second instance after we flush its bite code on the second instance of passing this function again the bite code is not generated right because of the fact that in this instance on this second passing of this function uh pre-passing is not done and hence no prepassing means no wrong bite code generated. So over here you can see that we have upgraded our primitive actually right we have upgraded our primitive from a incorrect bite code uh generation to a inconsistent bite code generation because for the same exact function that we are passing there are two different set of by codes that are generated and the thing is that we can further upgrade this primitive because a VA will think that the bite code is still there when it is actually not. So this sort of constructs some form of outbound rewrite that we can further exploit. And to further further prove our hypothesis, what we can do is that we can generate a simple patch which just forces V8 to not prepass any function. And let's see what happens. You can see that the moment we don't prepassse uh any function which includes our valable function um the by code is never wrongly generated. And if we can never wrongly generate bite code then we can never inconsistently generate bite code and we can never outbound rewrite. Yes. Okay. So after we upgraded our primitive again to outbound rewrite the sort of holy grail or the golden path to getting code execution in well the chrome render process is try to upgrade it to a V8 rewrite. That means a rewrite throughout the vap space and I'll very briefly show you how. So typically what we will do is that we'll allocate two JavaScript arrays. So uh we have the target array and victim array on your right here or left. So and on your left or right you see how the arrays look like in memory. There's four important fields map properties elements and length. We'll skip the map and property few for now because even though it is quite important when you're exploiting other types of bugs such as turban bugs. So the element pointer is actually the pointer to the backing store of the array and backing store in browser research very briefly refers to the memory location where your array stores its data. So in this case every when you allocate your target array first what happens is that VA will allocate the packing store to the target array which is 1.1 1.21 2 1.3 and 1.4 and after that you will locate the actual array object. Then uh you will allocate the backing store for your victim array which is 2.1 2.2 2.3 then you'll allocate the actual victim object. So and typically the backing store is usually allocated before the actual object and then for the length field length just refers to the length of your backing store. So what we can do is that using our outbound readr and some V8 heat manipulation on massaging we can out read write to the exact location of the length field of the first array and we can corrupt it to make it bigger than it actually is. So then because of this um the V8 engine will also be tricked into thinking that the target array can read and write out of bounds of the backing store. Right? So after we do this, we can actually corrupt out of bounds of the backing store and even corrupt the elements of the second arrays backing store. So what we can do is that we can update the second element to 4.4. And in JavaScript, the second index of the victim array would actually be updated as well. But more insidiously, what we can do is that we can corrupt the elements pointer of the second uh array and make it point to any arbitrary location inside the V8 heat. And this will give us a V8 rewrite. But unfortunately this readwrite is sandboxed within the V8 tip. And this is due to the V8 sandbox which is uh code name as Uber cage. So what is Uber cage? Okay. So to understand what is Uber cage uh let's take a step back because this is a mitigation which was implemented quite uh not so recent actually. This was implemented quite a while ago I think in 2021. So in the past before 2021 or before this V8 sandbox um there were a lot of trusted pointers which were allocated inside the V8 heat and once you obtain V8 rewrite throughout this region you can basically corrupt this trust pointer and then you can get code execution quite quickly. Right. So the objective of Uber cage is to isolate these pointers outside of the vit. So things like your pointer to your bite code, pointer to your DOM node and pointer to g code. We isolate these pointers out of the vit and instead of leaving these pointers, we will just leave text and these texts are to be converted into indices to the pointer table which will then store the actual pointer to the trust object. And obviously all of the pointer tables are also allocated outside the VA. And this will effectively render V8 box as useless unless you have a V8 sandbox escape primitive which we so happen to have for this version of V8. So for this version of V8 uh we will actually abuse one of the pointer tables which were not implemented correctly known as the external pointer table. Okay. So before talking about the external pointer table, let's talk about blink. So previously I mentioned that the renderer process is in charge of executing JavaScript and rendering web content. So V8 handles JavaScript and Blink handles um web content right and there are two main he allocators for blink. Number one is partition allocator and oil pen. So oil pen is in charge of the memory license for DOM objects. So it is quite relevant here. And every time you allocate a DOM object, the actual object is allocated inside the bling oil pan heat. Uh but there will be a V8 representation of that same object allocated inside the V8 heat. And the reason why Chroma developers probably did this is to allow it is to make a way for us to be able to manipulate DOM objects from JavaScript, right? And in the past these four pointers, so the bling red pointer and the bling type array op pointer these were all inside the VAT. And the EP or the external pointer table aims to isolate the bling pointers out uh by storing the pointers inside this table instead of the vit. However, the tag remains inside the V8 heat and in this version of V8 um the tag there's no strict strict type checking for the DOM objects. So what we can do is that using our V rewrite primitive we can corrupt the tech of DOM object to create a DOM object type confusion. And in this case what we do is that we will type confuse the DOM red object with a DOM type array object by writing the DOM by writing the EP tag of the DOM type array to the DOM rate object. And then after this subsequent operations on the DOM rack through JavaScript will not write to the DOM object in the blink but it will write to the DOM type array object in the blink. And what we can do is that the DOM type array will also have a backing store and we can corrupt the packing store and this will give us arbitrary rewrite throughout not just the vit but the whole chromium renderer process. Okay. So from here um I think if you were there from Kenoon's talk I think code execution is quite straightforward and it's quite generic throughout browsers. We will allocate a Wom object and because all when every time you allocate a Wom object the Wom function the WM function associated with the WOM object is mapped by RWX memory. So it's readable, writable and executable. So what you can do is that using your arbitrary write you can write in your shell code inside the WOM space and then you can get code execution. But just to take note from 2023 onwards the RWX memory associated with resm instances has also been isolated out of the VA and into the trusted space. So it's the trusted pointer table. So you will have to repeat the steps that we did for the EP on the TPT. But as I've already shown that uh I will not do it here. Yes. Okay. Okay. So with this we have coexecution in untrusted integrity. Okay. So but untrusted integrity uh doesn't give us a lot of uh space to do a lot of actions. So we will need to escape the renderer process and exploit bugs in other processes in chromium which are more privileged and get stronger code execution privileges. So what we do is that using our renderer bug, we will trigger this bug which is a logical bug in the Chrome browser process which basically allows us to control and click the user's mouse at any arbitrary coordinate. So what we would do is that we would download an executable using JavaScript. We'll force the user to click on it and uh we'll get code execution with integrity level of the user which we will just assume as medium. Okay. So the vulnerable function starts from here which is start dragging which is a modum API that is exposed on the renderer process end and this function will eventually call this function in the browser process which is start drag and drop and if we specify the field if we spec if we can set the fuel source of the start drag and drop function as K touch which we can because um this value is derived from drag event source info pointer. Um we will be able to call start touch drag um with arbitrary coordinates and then start touch drag will call send mouse event and send mouse event will eventually call send input which is a native windows API which synthesizes keystrokes mouse motions and button clicks. So basically we'll be able to control the user's mouse and at no point from the renderer process to the browser process will there any bounce check and even if there was a bounce check the bounce checks needs to be implemented at the browser process end because if you have render code execution and you implement checks on the renderer process end you can just patch out the checks. Okay. So all we need to do is to call this function with arbitrary arguments and then we can trigger the bug. So as this function is found in the local framework proxy object, we need a pointer to the local framework proxy object which we can get if we can get a pointer to the local frame object and we can and to get the local frame object, we will need a pointer to the document object which is very convenient because um in JavaScript the VA representation of this DOM object is um found in the window object. We just need to do the conversion which I will very quickly do. So, [clears throat] so first we get the address of the V8 representation of the document object and then we find the tag for this object. We convert the tag to index and then we index the EP table. Then we can find the bling pointer to the DOM object and then we do some shifting and then we can find the object and then um you can just implement it in C or C++ code depending on your preference and after this uh you can just call the function right because all of as you have seen in the previous slides all of the arguments to this function are static values so you can just craft them in C or C++ code And the last thing you need is the address to the start dragging function which you can get because on Windows Chromium they release the symbols. So you can just download the symbols and find the address to the function. And then we crash unfortunately one second. Okay. So let's analyze why we crash, right? And to understand why we crash just let's take a step back and and know that every heap allocator in chromium implements some form of pointer compression in order to save memory space. In so in V8 the compressed pointers are an offset from the V8 heat base whereas in oil pen uh the compressed pointers function more of an index which are converted to an offset from the oil pen base address. It's all pen heat base address. And you can see here in the first orange square that actually this is the all pen decompression algorithm. And as part of the decompression algorithm you will need the base address of the all pen heat. But the thing is that this value uh has a symbol inside the chrome.dl binary and it is updated at runtime. But the thing is that um for our sb payload we also have a symbol which stores the base address of this open heat. But because we are not running our sbx payload at runtime uh it was remain uninitialized. So the fix for this is just you can just find that str reference to pointer and update our reference to the open uh heatbased address and then we'll be able to call the function but there's no process continuation because when we try to return from the function and continue we crash and this is because of a stack frame issue. I think when we return from the function the stack frame was sort of corrupted and to uncorrupt it you just shift the stack upwards and downwards. Okay. So at this point um assuming that we can do all the steps all the downloading of the exe controlling his mouse to click on the exe uh we basically have SBX because we can launch any executable and and you'll see what exe executable we launch later but I would like to take a few minutes to share about the concept of compromise renderer. So majority of the SBX triggers cannot be called from JavaScript, right? As have as you have seen in this example whereby the vulnerable function is start dragging and start dragging can't be called from JavaScript. So we will require some form of native code execution and sometimes we may also require to modify the Chrome renderer process. So in our context we patched various Chrome functionalities to be able to call start dragging in an arbitrary and control fashion. Right? So usually you will need a renderer code execution but sometimes researchers who are doing SBX uh they don't have access to a renderer bug. So what they do is that they shortcut this process by generating a patch file which would simulate what they would have done if they had a renderer bug. But because we are trying to constru of sort of shortcut this and that's why you encounter all the errors that you have seen or all the issues that we have seen in the previous few slides. Okay. So, okay. So, how do we chain this bug with the previous buck? What we do is that we'll compile this payload as a DL. Then we convert the DL to shell code using any generic open source framework. We store the shell code as an array buffer using fetch and then we find the SBX shell code in memory. We map it as executable and then we execute and then we execute it. Yes. Okay. So now we have coexecution with medium integrity. Let's try to escalate it to system level privilege. So we'll be exploiting a bug in the CRFS driver which is a race condition leading to a use after free of the FS context to object. Okay. So to understand vulnerabilities uh I think patch diffing is a very common technique. So uh in the vulnerable in the unpatched version of the driver we basically call the release function which eventually frees the fs context to object in the cleanup driver routine and in the patch version of this uh driver. We will shift the releasing of this or the free of the fs context to object to the closed um clfs driver routine. And then if we look at release, it also reveals certain information of where this FS context to object is allocated, right? Which is in this case the non-page pool. Okay. So what is the difference between the cleanup driver routine and the closed driver routine. So every time you call create file and you retrieve a handle to a kernel file object, uh it represents an open instance of the file or the device. And basically when the handle count of this object reaches zero then the sort of cleanup driver routine is called and then when the reference count of that same file object reaches zero which means that this object is no longer being referenced by any uh user mode handles or references then the close driver routine is called. So TLDDR when your hand when your handle count reaches zero you'll call cleanup and when your pointer count reaches zero you'll call close. So in the vulnerable version of this driver we are basically freeing the FS context to object when the handle count of the file object associated with the FS context to object reaches zero. But there could be some system references to that file object. And means that that file object which is now referencing the dangling FS context to object could still be used between cleanup and close. And then this and if we can use it, we if we can use it and use the dangling FS context to object in the process, we can achieve some use after free of this object, right? And in starabs actually did a very good uh deep dive into this bug and in their PC they opted for rearchive metadata which is a driver routine which would free the already free FS context to object and what happens is that the Windows kernel catches this double free attempt and it just bs this. Okay. But in our context we are not looking for a proof of concept. We are looking to get system level privilege and actually the object itself is quite useless and undocumented. So we need to find creative ways to build stronger primitive. So arbitary rewrite is the holy grail and is the best but quite hard to find and uh arbitrary call was more possible in my context but uh there are a few obstacles to overcome such as KCFG and to exploit arbitrary call you will need some for register control. Okay. So after searching the driver uh we come across this function which seems to be a good candidate for arbitrary call and uh it is actually the read notification function which is a async device IO control function and it's reachable using the 8007702A op code and as long as we satisfy three other caveats we will be able to call this function which is at number one. Um we the input buffer length needs to be more than zero and the output buffer length needs to be more than hex 18 and basically at offset 108 of the object which is the FS context to object it needs to be a non uh it needs to be a non-zero value. So assume that you can free the FS context to object in the cleanup. Replace it, win the race, call read notification on the replace FS context to object. You should kind of look like this, right? Where now our FS context to object is replaced by a pipe buffer and then offset 108 is a pointer which is a pointer to values that we can control. Okay. So to reach the part of the driver function which allows us to control the RIP value all we need to do is that we need to construct a fake object chain. So at offset 108 we set it to a pointer but this pointer will actually point to another object which points to another object which points to another object which points to another another object which points to the last object which eventually uh allows us to control the RP value which would look something like this where we will control RAX uh we control RBX we RBX is quite useless to us but more importantly we also control the value of RCX right so we have we basically can control the value of RIP which is the instruction pointer and we have one register control which is nice because um there is a publicly publicly known technique to exploit this sort of um bugs or this of conditions which is RTL set orbits. So this is a legitimate kernel function but this legitimate kernel function will give us write fff fff n number of times at any location that we want as long as we control rcx right and which we do if you can see in the previous few slides. So um what we do is that we will set the location of where we are writing to to the token property of the current er and then we will write fff three number of times. So this will enable all privileged bits on our current E process and then uh at this point getting system is uh I think it's quite trivial but take note that we are still subjected to the security model of the Windows operating system. So we are still operating from medium. We still have to we still need to abide by deco cycle security descriptors and so forth. But since we have all privileges um you can abuse SE impersonate, you can abuse SE debug or even SE load driver uh privilege and then to get our system. And if we put everything together, so our solution kind of looks like this. We have a main thread which starts off with some heat manipulation in in it. We'll create thread one and thread two in suspender mode and then we'll start and then we'll pin each of the threads to different CPUs. Then we'll start both threads. So the first thread okay we talk about thread two first. So what thread two will do is that we'll close the handle to the CL to the CL FS driver and then this will free the FS context to object and then we'll try to we will try to quickly replace this object using write file and then hopefully uh thread one will call read notification which would uh win the race and which would use the replace FS context to object and then uh after that thread one and thread two will do some form of cleanup and then the main thread will check if we have all privileges or we have a certain privilege page that's not supposed to be there. If we have it, we exploit. If not, we just restart. Okay. So, coming to the end of the presentation. Um, so now we need to chain this bug with our previous bug. So, to do so, what we do is that we compile the LP as a .exe because the victim is going to click on it forcefully. But in reality, uh, where you have a SBX which deals with memory corruption, you will need to abuse some form of shared memory. So share memory between the renderer process and the browser process. So you need to transfer your PE from the renderer to the browser. And after that you also need to find the location of the PE inside the browser process virtual address space. And then there are certain logic bugs such as the one used in operation form control that can make the chaining easier. But uh in general you I I think you will have to do the first option. Okay. So now we'll we'll do a demo which is a video and you'll see why it's a video in the next few slides. Okay, over here I'm just showing that I'm exporting a chromium from the Google store or the Google website, not a Chromium that I built myself. So then now I'm going to serve oh oops okay never mind after which I will serve my renderer payload which will give me code execution in the renderer process which is over here now okay after which I will run my sbx payload which will control the mouse to click on the LP I'll run my LP and then I'll get system level privilege Right. Okay. So, some reflections. Is this realistic? Well, not really. The SBX pillow was actually quite unstable. I managed to only get it up to a 30% success rate. And the POC also doesn't deal with mark of the web. So, in real in real life, when you do the clicking on the popup, there should be a smart screen defender thing that will come up. And this is due to mark of the web. And as I've said before, SBX involving Chrome browser or the other Chrome process is that involve memory capture are more common. Next, the LP runs with a visual queue due to the SBX. So, and the LP will take time to run and has a 5% chance of dying and also the LP will not survive under EDR. So, you'll need to build stronger primitive to disable the EDRs. Okay. But I think personally I learned a lot from uh writing this exploit chain. Uh I got to dive into the Chrome source code uh and compilation study the V passer and some of the Windows kernel in Windows kernel internals and also deal with a lot of weird export engineering issues where in theory I thought something was possible but actually it is not so easy or not so straightforward. Yeah. And with that I come to the end of my talk. Uh thank you for tolerating me and I hope that uh you had the first great day at Defcon and you and I hope to see you tomorrow and the day after. Thank you. [applause] Thank you Ernest for that wild ride and a strong finish to day one. And that brings us to the end of day one here at CSIT's C517 village stage. We've explored hidden assumptions, invisible attack surfaces, and the subtle flaws that can lead to major compromises. But we're just getting started at Defcon Singapore. So join us again for day two and three for even more insights, even more research, and even more opportunities to learn, connect, and get inspired.