 So, our next speaker is going to be talking about modern Windows user space exploitation. He is a security researcher at MSRC Israel. Please give a big round of applause to Sa'aul Amal. Okay. Hi. So, first of all, thanks a lot for all of you to come up here. I know that there is a great competition, so I really, really appreciate it. So my name is Sa'aul Amal. I am at the MSRC, like, based in Israel. And so, actually, I'm here to talk with you today, like, about how we can execute arbitrary code on the latest Windows system. And so, just a little bit, like, about myself, I am a security researcher. My whole point in life is about reversing and exploiting vulnerabilities. I'm also highly addicted to CTFs. I'm in the CTF team, which I hope that you, like, probably heard of us by now. And I actually want to, like, kick off the talk with a very important, like, question. So, like, what do you think the point in life is? So, of course, the point in life is to execute arbitrary code, yeah? And there is actually a very simple and trivial process for that, right? I mean, all you need to do is to find some really awesome KCAS zero-day vulnerability, and you will have something in the middle and then profit. And back then, about 200 years ago, it was really, really easy. I do hope that you all do recall the times that the stack in the heap were executable, and everything is fixed, and you have no SLR whatsoever, and you can corrupt function pointers and jump to them, and basically nothing stops you. Well, those times were fun, easy, but also really, really dangerous. Well, we don't have that anymore, right? Since we have mitigations. We have mitigations everywhere. And actually, we have quite a bunch of them. And the thing that I really want to do today is to talk about the internals of the mitigations, understand them. And most importantly, see all of the primitives that you need to gain in order to bypass them, since it's really known a trivial process. And I feel, personally, that the best way in order to achieve that is to find one single vulnerability and to exploit it on many different operating systems with increasing and increasing amounts of different mitigations. So that's exactly what we are going to do right now. So actually, my intentions were to take a real Windows vulnerability and to exploit it, because it's fun. But sadly, I saw that if I would, the talk will probably last three hours, and we don't have time because there is a great, like, a CTF that is going right now, and I have to go. But instead, we will take a really, really awesome Windows CTF challenge from the Insomniac CTF teaser from 2017. And on the way, we will send the message that I personally really want to see more Windows CTF challenges, since it's awesome, so please do that. And we are going to achieve code execution on many different operating systems and take together the journey to bypass many, many mitigations. Okay, so what we are dealing here with, the Windworld challenge. It was a great challenge based on the Westworld PV series. Sadly, I didn't watch it, since I was extremely busy in the last two years just, like, reversing Hyper-V. But the challenge is really cool. It basically tried to implement some kind of neurato, which basically, like, lets you create both robots and humans, and you can move them, like, on some map, and you can make them talk to each other and interact to each other and fight and do, like, awesome stuff. And the important note here is that both robots and humans have, like, a best-class shared, which is person. And the interface simply, like, lets you do those actions, those operations on any person's instance. Each time that I will state person's instance, I mean, of course, like, robots are human. They are simply inheritance from person. Now, this is not how to find vulnerabilities talk. This is an exploitation talk, so let's cut to the chase and dump all of the vulnerabilities. So vulnerability number one. We have an uninitialized attribute in the person instance. Each person has, like, a member of his conscience that tells you if the person is conscious or it isn't. So the person constructor keeps in mind to initialize that value to false, but the person copy constructor forgets it. So if you can trigger the person copy constructor, and of course you can, you have an uninitialized value which takes whatever was on the heap before, which is cool, and we have also a use-after-free bug. In the challenge, we need to share pointers to person instance and between many, many different objects and components, but it's kind of like a problem since you have to know when you can free the chunk. So the challenge is to use shared pointers, which is kind of some wrapper for pointer which has the ref count, which simply counts the amount of objects that took a reference to you. So each time some other object took a reference to you, it incremented the pointer by one. Each time it leave you, it's like that pointer by one. And when the ref count reaches zero, the object can be freed. The problem is that there is some flow in the challenge that you can take a robot and to transform it to a human. And now, this is really cool, but the problem is that the code that does that use std move which actually duplicates the object and those duplicate the shared pointer. Now, this is really, really wrong because this actually break the whole point of shared pointers. The right thing to do here is to increment the ref count and that's it. And instead, you duplicate the shared pointer and you have two different shared pointers which points to the same chunk in memory. And of course, this is really, really wrong since when one of those shared pointers will reach zero, the person chunk in memory will be freed and you have a dangling pointer from the other shared pointer to a freed chunk. And then the fun begins. So cool, awesome. So yeah, the problem is that you can say that you have a vulnerability if you don't have a flow, right? You have to trigger the flow. So we actually can do it by taking a robot and to transform it to a human just like I told you. And this happens when you have both robots and human in the center of the maze, okay? And you have those preconditions to be met. And you see that one of the preconditions is that the person's conscience will be set, meaning not false. And we can do that by the first vulnerability of the initialized value. So combine those two vulnerabilities together. We can make the flow of transform a robot to human and we have dangling pointer from the other shared pointer to a freed chunk in memory. Okay, and now after that we armed with use after free vulnerability, let the actual fun begin. Okay, so let's start to work. We start with execute code on Windows 7. The first thing that we need to do is to understand the allocator, right? Because we have like use after free bug and like trivially the thing that we need to do first is to trigger some allocation, some other object allocation to fall in the exact same spot on the heap that the last person chunk got freed, okay? This is usually how we exploit use after free bugs. And the problem is that we have many, many different allocators and each allocator has its own logic and the way tracks free chunks and you have to understand the allocator that you are dealing with if you want to exploit the vulnerability. So of course we are in Windows, so we work with the LFH, the low fragmentation heap. This is the font and allocator in like use of space since Windows Vista. Now, I don't want to talk about LFH internals since highly documented all, like basically all over the internet. I will simply say that it's really like JMLock if you are familiar. And you have this track which called user blocks which is a pool of same sized chunks in the heap and every time you do a malock, you get a chunk from there and like every time you free, the chunk like goes back and you have no coalescing, no consolidate, no fragmentation like whatsoever. Cool, the problem is that in back then, in Windows 7, we have like a metadata which called free entry offset which sets in the first two bytes inside the free chunk after the header which means that it has no encoding and no soar and no protection whatsoever. And this metadata indicates to the allocator which chunk needs to be returned to the user in the next allocation and simply like corrupting this field is like give you extremely strong primitive. The second problem is that the LFH in Windows 7, it allocates chunks continuously in memory. So shipping LFH in like Windows 7 is basically not really a problem. And you can see it if you take some tester and execute it on like a Windows 7 machine. So you can see on the left side that I simply spray some size on the heap and on the right side, you can see that all of the chunks, all of the allocations for one after the other very, very nicely, everything is like predictable. And the most fun point here is that thanks to the free entry offset, the LFH keeps free chunk in last in first out fashion. So this tab, like malloc, free malloc, will actually for sure return the same chunk so we can exploit the use after free bug here very, very easily. Okay, now that we can allocate some other objects on the same freed person address in memory, we can start like any primitives because if we want, and of course you want because it's the goal in life to get arbitrary execution, we need to gain probably like relative or arbitrary read-write. So each person has a name, a SDD string name, and the interface simply like let you dump the name. It's printed over the socket with the info command, but the name is like simply SDD string. It's a pointer in the person instance, but I can allocate whatever I want there, like string event, which I basically can control every single byte there. So I can fake the name pointer and set it to fixed address in memory, arbitrary address for my choice, and then I can dump it. The great thing here is that the length of the name is also a field in the SDD string, which sits in the person instance. So we basically have arbitrary read with arbitrary length and it's cool. In the very same way and in the very same fashion, we have arbitrary write with arbitrary relent, right? Because the interface basically let you to update the name as well. So yeah, it's cool. And now that's not enough because we want to execute code. So we can corrupt some pointers, but it's actually way, way easier. We have a function, a virtual function in the class. It's not even in the VTable, you don't need to deal with double the references. It's function pointer inside the class called on and counter, which gets triggered each time two different persons meet on the map. So by basically spray string set in the relevant offset, fixed address, and then move two different persons to the same spot, we have the ability to jump to arbitrary address and execute code. Okay, cool. But I know that I will probably need to read more than one address, right? You will probably need to read more than once. So we can make a really, really elegant trick. I really like this stuff in exploits. It's like really, really cool. You can corrupt the on and counter function to points to actually get S and then move persons on the map and each time they meet, the getS function will be triggered as the on and counter function. But it's really cool since the getS gets the first argument that on and counter would get which is a person address in memory. So I can send data over the socket which will write all the fields, all the attributes of the person instance. And I do that without trigger any other vulnerability whatsoever, okay? I simply trigger the vulnerability once and then I can write on all of the fields of the structure over the socket, which is really cool. Tricks like that is the exact stuff that make exploits reliable. And it's really, really important to make sure that we trigger the vulnerability as few times as possible. Okay, fantastic. Let's keep going. So we have arbitrary read, write, jump primitives. It's cool, yeah. Basically, life is easy. But we have SLR. Everything is under SLR. The DLLs, the main binary, the heap, the stack. We don't know where everything is. So we need to start like licking pointers. The problem is that I don't have the primitive to read something relative to me. I read absolute addresses and I don't know which address to put there. So I really need to trigger some allocation of some other object, which is the same offset as the SD name in the person class. It has some other pointer to heap, to stack, to library, to function pointer, whatever you want. Well, SDVector actually meets those demands. So by basically trigger SDVector, we can do this trick. And now apparently, person in reality have friends, okay? And like person in the challenge also have friends. And each person has a vector of all of its friends. So by simply taking single person and like add seven different friends to it, the SDVector containing all of its friends will be the exact same size as the person instance. And it's really, really important because we are in the LFH and the chunks are like organized together when they are in the same size. So we can trigger the location of some SDVector, dump the name of the person and we get the Vtable of the SDVector which is in the R data section of the main binary. Well, that's easy but the problem is that from obvious reasons I can control on the fields, on the attributes of the SDVector. So the length, the fake length of the name will be huge number and I don't have any control over that. So I do leak the pointer, but the process dies during the copy. Now, this is fine because we are in a CTF and the process basically relaunches and takes to the fact that in like user space all of the DLLs and all of the binaries get randomized in boot that's correct but they still where they are in virtual memory for the entire system lifetime. So the process dies, it relaunched and every pointer that you leak stay where it was except of course for the stack and the heap that gets like randomized in the process creation. But all of the DLLs in the main binary will stay where they were. Okay, now we need to choose the course to execute our real code, right? Well, we can call out function pointers, Vtables, we can call the stack into Rope, we can basically even load some DLL, some unsigned DLL with our code and it will be executed. We can to allocate a read write execute chunk, we can do basically whatever we want and nothing stops us. So let's do the Rope, okay? Let's create some chunk, read and execute, write shell code and jump to it and now it's time for demo. I do hope that on stage the demo behave just like they did downstairs. If not, I will publish all of the code and you can execute it at home, please do so. So let's go to the Windows 7 exploit. I have the IP right here, somewhere. Okay, awesome and let's launch the VM. Since we are in a CTF, I simply decided that the arbitrary code that we will execute will be to read the flag and the flag is iLavida since we all Lavida and let's execute the challenge just to make sure. What's happened? Okay, yeah, 84. Let's hope that again the physics on stage is just like downstairs. So we leak the address of the main binary, we leak the address of the user database since I have some people there, kernel 32, the heap, the stack and if we do Rope, we have the flag. Okay, so the first demo works, thank you. Awesome, yeah, the process of course, it's like a CTF, it's cool and we go to the journey to the next operating system. Windows 10, pressure one. So we take the very simple C that we executed just now and if you try to execute it, trust me, it will fail and it will fail since the shape fails and the shape fails since we have a lot of change, a massive change like between the allocator, the LFH between Windows 7 and in Windows 8. And seriously, like a lot of really cool and awesome engineers, like they invested like a lot of time in that and the LFH looks extremely different. First of all, we don't have this free entry offset field which is really, really good. Instead, we have a bitmap which simply indicates or we chunk in the user blocks if it's allocated or if it's freed. And moreover, all of the allocations are randomized. The order of the allocations cannot be predicted so easily as it was before and if you take the very same tester that you had in Windows 7 and execute it on like Windows 10, pressure one or eight, yeah, it's like basically the same, you can see on the right side that all of the addresses are in complete chaos. You can't know what comes after what and the state is really not predictable as it was before. Now, since we don't have the free entry offset field, the start like malloc free malloc won't return the same chunk, right? Because the allocation are randomized. So it's not that trivial anymore to call malloc and to get the last free chunk. Actually, with extremely high probability, you won't get this chunk, okay? Cool. Now, I want to bypass it, right? Because we agree together that the point in life is to execute arbitrary code. So we need to bypass the mitigation. Like otherwise, we don't have a reason to live. So in order to bypass the mitigation, we have to understand the implementation and to see where the random comes from. Okay, so it's really, really interesting and from now on, we have the beat map which indicates for each chunk if it's freed or if it's allocated. So the allocator choose a random position on the beat map, it scans from there in a linear fashion until it sees beats that indicates free chunk. It simply flips the beats and returns this chunk to the user and there you go. And of course, since the position in the beat map is random, the allocation order will be random. But the question remains how the random position is chosen. So we have like any symbol in NTDLL which called RTLP low-frag heap random data which is a fixed address of 100 hex values which are random, truly random. Seriously, guys, this is not the issue here, okay? All those values are simply created from kreibgen32 random in kreib32.dll. And that's fine, they are cryptographic random. And each time we hold a pointer to this random data array and every time you do a maloc, I take the current random value from the array and this random value is used as the index for scan in the beat map. So of course, you can see from here that the allocation like order will be random. Let's see this happens. So, sorry. So here on the right side, you see the user blocks which are the chunks on the heap and you can see the beat map which describe it. Now let's call maloc, okay? So we choose some random position in the beat map and we start to scan from there. Now we happen to choose zero which indicates free chunk. We simply flip the beat and return the chunk to the user. Now we call another maloc and we take another random value. This random value, like it happens to be allocated chunk right there. So we start to scan from there in a linear fashion until we see free chunk and there we flip the beat and return the chunk to the user. Now of course, there is a serious, very serious issue here because all of the random values are in static array which size of 100 hex. So what's happen if we try to allocate more than like 100 hex allocations which basically happen really, really fast. Like even if you don't do it, your process will probably does allocations all the time. So the pointer will wrap around the array but the values were random before but they stay intact and they're the exact same values. So if you try to execute this POC which like simply does allocation, free the chunk and then for FF times do like alloc free, alloc free, alloc free and do the allocation again. The second allocation after the loop will use the exact same random value from the array in the beat map and does for sure by definition it will return to you the exact same chunk that got like returned in the first allocation. The whole point of the loop is just to increment the pointer on the random data array and to make it overlap. That's it. And this is really, really deterministic, okay? This kind of like my passes is like really, really cool. It's extremely like makes me happy to see tricks like that. And of course, that's exactly solve my problem since I can execute this POC and see that it works perfectly with probability one. We get the same chunk. Okay, awesome. So we solve the shape issue and now we can continue with exploit because this is the point of the talk, right? So yeah, now we need to like execute code. So I probably want to call to some function which will make me the address of the stack since it is easy to leak all of the DLLs and the main binary just like I did, but in the heap of course it's again, it's pretty easy to leak. The stack is like a little more complicated in this challenge. So let's call to RTLP get stack limits in like any DLL, it should leak me the stack. Crash in 29. And in 29 is the fast fail feature. We have it since Windows 8 and basically if your process does that, it means, hey dude, I detected some really inappropriate behavior or something really, really bad happened. I don't know like what to do, game over, I'm out, bye. And yeah, if your process does that, something bad happened, okay? And okay, let's go simple bits up in the stack and see like where it comes from and it comes from guard check, I call FPTR. And it's kind of interesting since the first argument to this function was the address that I tried to jump to. You see that is actual byte code in NTDLL. So we have save G which is control flow guard. The job of save G is to basically make sure that every indirect branch is okay in the sense that every time that you try to jump or call to some address, two function pointer, again indirect branch, call rdx, call rbx, symbols in your binary, you have a white list of function that the address that you try to jump to has to be in this white list. If it doesn't, abort. And this is exactly what happened here. There are many known like bypasses and rocker runs for it. Joe Bialik gave a great and awesome talk about it in the last offensive con, about CFG, CFI internals, issues, we have there how to fix them. If you are into it, please check it out. It's really, really awesome talk. Okay, but again, the point in life, execute arbitrary code and like all of this stuff, we need to bypass CFG. And it's not that bad because CFG does make the life way, way harder because we don't have any pivots, right? I can't jump to the middle of function because for sure it's not in the white list. I can't jump to RTL restore context and all of the functions that give me controlling of the RSP or that leak it to me and all of the problematic functions are like forbidden now. Okay, but we don't have yet something that checks the integrity of the return addresses on the stack. So if we leak the stack and use the arbitrary write primitive that we have already and write Rop, it's fine because we don't have yet something that validate the integrity of the return addresses. Okay, so let's do it. Again, it's really, really important to see a demo. I had some random going on with like threshold one VM here. Something happened there. I hope that on stage it will be fine. If not, again, the code will be published. You can execute it at home and see that it is cool. So let's go to threshold one. Again, we are in like a CTF. So we should have a flag and of course, post 10, because post 10. Yeah, I love IDA, blah, blah, blah. Okay, so we do have a flag. Let's try to execute the POC. This is the right IP, yeah? And again, let's hope that everything will be fine. Okay, so we leak the address of the main binary and we leak the address of the UCRT, NDDL, Rop, oh man, okay. Interesting, yeah. Sometimes the VM does some problems, let's try it again. Yeah, okay. Yeah, the VM does like some problems. Okay, sorry about you can execute it at home and check it out there. Let's see if now it will work. Yeah, code has run down. So this is why we have vulnerabilities, right? Again, the leaks work fine. We have the flag. Honestly, I think that I'm about to have heart attacks of sorry for that, but it works eventually. So cool, okay. Fantastic, I love IDA so much and Hyper-V is the best thing ever, is a great flag indeed. Okay, so let's keep going. Windows 10, Redstone 5, the last test, kind of. If we try again to execute this POC on Redstone 5, you see that it will fail, it will fail deterministically. And this is because the shape fails again. We fixed the issue in the random, in the LFH, it's got service of course, because it is a very serious issue. And since build 16.179, we don't have this issue anymore and the random got fixed. If you want to check it out, all of the internal spin different stuff you can see in this tweet link. I like what about it, you have everything there. Please check it out. But again, we need to bypass the random. Now, please keep in mind that the demand that I have here is not really to... It's not to restrict, right? I don't have to take two different chunks and they need to be continuously one after the other. All I need is to spray some allocations and I just want one of them to fall in the person-free chunk, that's it. So even if you have random, I can try to spray and see if it will succeed, right? Now, of course that one allocation won't do it. Then, 10 allocations probably not. A million allocations will definitely work. So the question is where is the threshold? And for that, I simply wrote some tests there, okay? Those are the numbers of the allocations that I had to spray in order to catch the last free chunk. And you see that the numbers aren't so bad, right? Okay, so let's simply try. Sorry for that. Let's try to spray not FF double than that. Works great. I really like the times when theory and practice meet and it's basically work with... Multiply the account of the spray in the code and like that's it. So the shape works. And now we try to execute arbitrary code just like we did before and everything should be fine. Well, not. We have in 29 again and we crash and, like we said, because we have ACG, which stands for arbitrary code guard. This mitigation does exactly what its name suggests, okay? It's basically forbids you to execute arbitrary code by like introduces two new restrictions. The first is, sorry, the first one is that you can't allocate and you can M up plus X pages at all. It will simply fail. VirtualAlockEX will fail if you try to give it the flag of page execute. This is exactly what would happen if you try to like execute this. This is like POC, okay? I don't have time for that, but I will publish it. The second restriction is that you can edit the permissions of existing code. So those new restrictions combined, you can't execute arbitrary code unless you bypass the mitigations. And now there were some like knowing cool bypasses for that in other versions. They of course got service and fixed, but keep in mind that again, there is nothing that makes share the integrity of the return addresses on the stack. So Rope on the stack works 2000 years ago. It works today and it's still cool. Now, it's not really a problem, right? Because I can call load library EX and try to load some unsigned DLL. So I have CIG, which is code integrity guard, which basically forbids you to load unsigned DLL, okay? We make sure that the digital signature is fine, and if not, abort. So load unsigned DLL wants to do the trick. Now, I really wanted to talk about Edge since Edge is a really, really cool use case for that. Edge has CIG, ACG, CFG, and many, many XYGs in it, many, many guards, but I don't have the time. Great shout out for Patrick from Google Project Zero. He found many bypasses, really, really cool. And he like wrote a really cool PDF about it. And please check it out. I don't have time for that. It will be here. I published the slides and all of the links so you can see it at home. Alex and Esco, my best buddy, found a really cool core bypass for ACG, not just for Edge. Okay? He found a really cool bypass for ACG inside the operating system. And he had a great talk about it. Every talk of Alex is awesome. So check it out. Alex, I love you. And now we have to go back to the point in life, up with record and stuff. So let's bypass ACG and CIG. So just to make sure that we can do something, let's do rope on the stack, but I don't want to do a very long rope chain because it's hard to maintain and offset change and it's cool like in CTF when you have a very short rope chain, but in real world scenario, probably you want to do some complex stuff and try to implement a long logic in rope. It's not like... It's not like pretty fun. It's very dirty work. We do it in iOS Explorer all the time, but if I can avoid it, I want. So let's try to call create process, shell execute EX system or something like that just to make sure that we still can control what's going on here. So we have the Redstone 5VM. Let's kick it off and go to Redstone 5. And let's try to call system. I have the IPM? Yeah, something. Okay. And we have the exploit for system. Again, I will publish the POC. You can actually see that the POC is really, really, really elegant and you can see that the rope... Sorry for that. The rope is simply called system. Okay, system with the command type flag. Okay? So let's do it. This is the VM. Yeah, of course, we don't have memory. Cool. Good point. Are we ready? Sorry for the delay. Come on, come on. It was faster before. Yeah. Okay. So, yeah, so the flag right now will be AAA. Okay, because we don't have time for that. Fantastic type flag. Okay. I'm sure that you will see the AAA like once it leaked. We have the challenge and we try the POC out. Yeah, the IP is 93, not 83. Okay. Let's hope again that the physics is like still fine. The base of the main binary, the base of the UCRT command. Fantastic. And I also need NTDLL. And now before we execute the ROP, please just let me execute WendyBug and to like attach the process, because I have a feeling that we will need it. And let's breakpoint on system. Okay? We have a breakpoint on system. I'm so sorry for the team. It's like inside the VM called ROP. And we have a hit on system. And of course, I do expect that the first argument will be type flag. Now, if we do go, we need to see the flag, right? Access violation and the process dies. And we are inside system. What the fuck? Okay. Yeah. Yeah. So what's the heck is going on here? So of course, we have another mitigation. If the slide will work, yeah, it works. Fantastic. Yeah. Child process restriction. This exact behavior that I expect to see, because you really don't be allowed to call system in like many processes. You don't have a very good reason to do it. I mean, I have because I exploit vulnerabilities, but you at home don't really want that Alsace will be able to call system. It is really non-point in order to do that. So child process restriction is really, really cool mitigation because it's very, very simple. It's one bit in the process that forbids the process to create children as sub-processes. That's it. It's really, really cool because it kills a lot of different exploits and make, of course, the life way, way, way difficult. Of course, I can't not leak the flag in front of you on, like, Hudson 5. So let's make sure that we still have the AAA we do, and we have an exploit that leaked the flag. Ah, sorry. Thank you. Now you should see it. Okay, awesome. Yeah, the laptop doesn't respond. Sorry. Is everything fine? Okay. So we have the VM and we have the exploit. Now, you kind of already know how I like about to leak the flag, right? We saw all of the mitigations. We see how much harder it gets, but I always get to the same technique, right? Do rope on the stack. So instead of the very simple rope that I just showed you, it's very, very short. It's very elegant. Like, one of the shortest rope I ever did, just called system. Instead of that, I have a different rope. Again, the main looks the same. Just leak the, like, address and, like, the rope. But the rope now do open, read, put S, flash all in order to leak the flag. So the rope is, like, way, way longer and still it's fine because it's a CTF in real world. This kind of, like, approach to implement everything like in rope works, but it's really, really kind of last resort, right? I really want to do more, like, elegant stuff. Okay. Again, physics on stage, like a lot of random, should be fine. And let's leak the address of the main binary. Done. UCRT base. Command. Stastic. NTDLL. Rope. A.A.A. Thank you. Thank you so much. Again, everything will be published. It's a CTF challenge, but of course the point is to learn how to do it and to do it, like, in a good way. So this is for the demo. Okay. So what's going on right now before we go back to the CTF? There is much more than I could have told you in this 45, 60-minute talk. I really wanted to talk about Edge and about, like, a lot of stuff, but I didn't have the time. You can always, like, DM me on Twitter, come and talk to me, come to Tel Aviv, we have great food, and we can talk. Yeah, we have containers and, like, sandboxing. We are actually, like, working right now on some really serious, like, improvements for CFG. It should be awesome. We will keep you posted. I kept telling you that, yet, we have nothing that checks the integrity of the return addresses on the stack. Yet. We tried RFG, which is return flow guard. Just like wrap in Linux, okay? But we had to pull it off, actually, since we had a very reliable built-in rest condition in that feature. It was really, really reliable to exploit it, basically, trivial. Joe Bialik gave a great talk about it with the POC, with the example, internal details. Again, check his talk. It's really awesome. So we are, like, waiting for sets by Intel. Basically, RFG did a very, very simple trick. It implemented Shadow Stack, which is a separate stack for only the return addresses in software. And then, when you do rats in your code, you will compare the return address for the main stack, and the return address saved on the Shadow Stack. So we don't know where the Shadow Stack is, and if the, like others, are different, abort. Again, we had some trivial rest condition there, so we pulled it off, but set by Intel is a Shadow Stack in the processor, in the processor itself. So it should, like, mitigate ropes, like, all together. Actually, I really, really like Kernel and, like, below kernels and, like, hypervisors, and we have awesome stuff going in Ring Zero. We actually introduced LFH in, like, kernel space, which is a life changer for kernel corruptions, really, seriously. A life changer, since the LFH is way more secure than the way the, like, Windows pools worked before. We have VBS and VSM, which is crazy. We actually have SMAP only for plus-up dispatch flows, because it's kind of, like, limited, like, right now, it is a start, and it works great. There is great documentation about it all over the place, all over the Internet. Check it out. But more importantly is that we want your help. So I don't know. I just love to wake up in the morning and talk to awesome people about awesome stuff that I reverse. So if you find some cool bypass, talk to us. It's, like, really cool. You can always DM me and Twitter, mail, come to me right now. I really, really, like, open to stuff, and I, like, love to talk to, like, cool people about, like, cool exploits. So do that. There is something else that we are trying to do, and it actually works great. There is the approach of trying to kill a bar class all together, okay? If you saw Joe Bialik tweeted about his init all mitigation, which basically do, like, memset zero for all of the structures, it should kill a lot of information disclosure. It, like, works great. And the guy, AWE, which is awesome, great challenge. So in his write-up, he actually wrote that in the first space, the challenge, like, did at work because Visual Studio 2015, by default, has the slash SDL combination flag, which memset zero all of the structure. So the first vulnerability of the uninitialized value of the is-conscience in the person didn't work. It simply didn't happen. You have the vulnerability, but it's basically have zeroes. So we had to disable the flag. So it's really cool to see that we don't intend and cool stuff like that happen. So, yeah. And it's time for shutouts. Again, so AWE is the guy who wrote the challenge and the write-up. Again, like, great work. And please do more, like, Windows CTF challenges. Tomasz, my best friend for exploits, Whiskey, and Burgers, thank you for all of your help. And thank you for all of the brilliant engineers that actually keep track of Twitter, see all of the stuff that we wrote, and keep fixing that. It's really cool. And we have many, many examples that I simply tweet something, and, like, three months later, I've been defined and I see it fixed. It's, like, wasn't even some kind of serious, like, vulnerability, but they do also awesome stuff. So keep do that. You have some reference for all of the stuff that we did here. I think that the last link got down, like, a week before, I sent a message to the Insomniac. I hope that it will be up. If not, we will ask them. They are really, really nice guys. And thanks.