 So, I will hopefully finish out the software I secured for, and I can pick back up, or the marketplace, and then I can pick back up next time that he manages to recover from his ordeal. No, he's just not made it, right? No, he's just not made it. Yeah, I can do that. He's not made it. I can guarantee you that the last time I saw him, he was not made. Why? Could happen in a little short amount of time. Who knows? Okay. Anyway, I'm Johnson, and I'm a assistant professor here at ASU, with a study of some binary security, which is, you know, a research office rather than a binary security, which is what we are going to talk about. So, hopefully, I won't compare myself too much, because how is this what I do? So, as I understand it, last time, I took you guys through walker over clothes, and he mentioned, hey, what happens if the stack is not used? And of course, the point of walker over clothes, you have the stack, and by the way, I haven't drawn the stack vertically. With the volume, and, you know, let's think of what happens if the stack goes down. This is correct now, probably. This is a stupid way to write the stack. Don't tell that. Well, I can tell that myself. I need to walk. You're one of those people that are political. In my opinion, the stack should grow sideways. We read sideways. Why not have the stack go sideways? It makes sense. I think to the right are bigger. When you write stuff, it makes sense. If you write it to the right, you know. But, okay. Adam does this with a real stick with this. And from here on out, I'm going to write you the stack I made through the rest of the class on this whole improper thing here. Anyways, so the traditional that you have, you guys went over how to end something for a lot. And here you've got the return. And the way this works is when the function gets called and saves a return address onto the stack, the stack, the save base pointer, et cetera, et cetera, the variable. And eventually, when the function returns, it just reads this address and it jumps in. The idea being, if you have in foo, calling in bar, then the return address will point right here after foo. When bar returns, it'll read that. It jumps there and executes it. This is nothing new. Of course, you've covered a lot of bloats. If you override this with something evil, that's called shellcode on the stack. You override that to your shellcode. That's the classical buffer code that's good. And then people came out and said, hey, here's an easy way to prevent this. No one should really be executing code on the stack, the stack through data. So let's, in fact, I should be able to do that. That's how I covered this last time. Hackers responded to this, said, do that. There's going to be two little, yeah, this is all about the next. And so, all about the next. Hackers said, you know what? In that cell, we call it return into libc. And the idea is we don't need this code. Do that. We don't need shellcode. What we have is somewhere in libc there is something, a function called system, who here has used this function to call out to shell command. Yeah, awesome. And we just point this to system, and then what's the arguments over here to that system that we see arguments as OK. And then, you know, a libc function that has been called by some messed up code, and it just runs it. So we've now avoided this and that. So this is all last, right? And we can run through how this looks like with that vulnerable program. So let's go through this right now because we'll be using the same vulnerable program in today's lecture beyond return to libc. But basically what this program does is it pushes the base pointer onto the stack that saves the current base pointer. It creates a new base pointer by moving the stack pointer into EPD. You're familiar with the base pointer, right? This is nothing new. It makes room on the stack. So you have to do this super awkward thing where we're telling you to go down and set it off or set it to the right. So there's a return address. Someone remind me, I don't know what's there. There's a return address on the stack here. It pushes the same frame pointer and that makes some room for local variables. This is called the stir copy. Or, anyway, so it sets up the call for the stir copy. Did that have to tell you guys about AT&T versus the county syntax? Yeah. Well, AT&T syntax is not used by anyone in their right mind. So that's going to be my excuse. And so I have to constantly be like, OK, we're right here. No, we don't, right? We read from people. So let's see. OK, this is, yes. OK, good. So this is, we are getting rv1. And then eventually you're voting where to go. That's minus 0x32, which is 50. So there's two variables. That's 0x32 for the basic wonder. And then you call it stir copy. Which, of course, overflows our buffer, our return address. We move the tab to the ADX and we remount the stack and return. We're going to disable a whole lot of security protection because this is not working. But what this creates an output that has a bunch of arguments. You talked about this last time, right? So these arguments are beautiful, some are not. And if we run, look at the systems. Here's where system is. In our loaded programming, if we actually look at, you can see the map over here at v7e2500 and v7e66310. So we actually move the map in this one. v7e, yeah. And this is a readable and beautiful set of code. And this makes sense. So then we try to find somewhere in libc that has a string vnsh. We found it. It's somewhere in the scene as expected. And we're going to put that out. And so what we want to do is call the system with this string, the map with the string vnsh, which is here, right? This is the return to libc. Explode? I have a quick question. In GDB, how do you find a popular type of map with a GDB app? Which is a popular type of map? Is this info inferior? Mm-hmm. Or? Oh, a popular type of map. Yeah. Also, what you can do, there's a map PDF. You can execute it from outside of GDB. Or you can just look at the process table, look it up. Or slash proc, slash self, slash maps. Right now, you need to have that content from GDB. And it wouldn't be usually good to have GDB measures put in. It's the process you're analyzing. If you want to know your shelves mapping, for example, to go around with that or whatever other product that you have exploited, if you're trying to understand where stuff is in memory or something. Next thing you have to do, you can use slash proc, slash self. It's a similar thing. Right? I don't know how to say it. Cool. So the exploit is basically this. You print 58, and then you print some graph to overflow the base address. And then you print the address of, this should be the address of system. And then you print the argument. The system, which is the address of the NSH or a print. Yeah. You're printing it in Python, but then it's all given as an input to the program. So then you start running. Here's our screen copy. Boom. You overflow the buffer. Messed it up pretty good. So this is our case. All right. Here is VCD. This is just some graph that we wrote over the base address. And here is the system address. And here is the NSH address. Then the directory. You do a leaf. Boom. You found that off. Pop off. This address here. You do a wrap. It returns into system here. And now this is the top of the stack. What should it be? And then the system runs. Right? I'm going to go through the system of an athlete. But then the system runs, and the system will actually execute itself with argument. This argument does the program. Cool. Okay. So then let's move forward. We're going to be going to see what runs here then at this complaint because we have a new project running. It's been updated. Wait. No, we don't. What is the stack? Yeah, the stack got fucked up. You don't know the stack. You're active. So why does the stack get fucked up? The stack... The next step is to return to system and expect to return as to be the next thing. And so when we put our database right after that it's a system then a system. And when a system goes past, the argument goes as if we have a path and the argument is no good. So we do it right. Okay. We do it right. And we actually add another page, one of the data before we put our... This page runs with data. This work report, why does it work? It works because the plan system gets run and sees this as a return address to return process and then it sees this as the address of the first argument. And so that hit work. So this allowed us to do something interesting, right, which is called function change. Instead of that thing, EBCD, we can put the address of any other function and system will return to it when it returns. And we can make arbitrary long teams of this to execute libc function after libc function and do whatever we want. We now don't need shell code, right? We can just program this stack in some sense like you're gonna program a normal application using... I see now, you know, grabbing the return value of things is a little tricky but realistically speaking, if you can actually do library golf and you pretty much want an attacker. Of course, we have to think about, you know, how the stack goes and all that, but things are pretty good. They work like Christmas time, right? And so attackers would be moved on to returning to libc and, of course, the batter said, oh, no, you don't, and they came up with something to counter that called address-based layout randomization. Then you hear any symbol, right? The return to libc is possible because you can tell where system is. The first step of that, I suppose, was, hey, let's pronounce that as a system. And if systems go into the same spot, then, of course, that's trivial. You print it out locally or you just have a very similar environment to your remote victim figured out where system is on your environment, attack, move, you win. So the idea is let's make that the longer true. Let's put system or help. Let's put all libraries on it. Or while they're at it, you can also do the stack and so forth and so on in some random area every time where you can predict its location. And this is actually already possible because the way that libraries are written, a program that has a link against multiple libraries at the same time, any combination of libraries, right? And so, when you have a memory space, don't do very well. If you have a memory space, from left to right, you have your program somewhere in memory here, that program was 80 something earlier and this is the program. You got your stack, your backwards, all good. You have your library somewhere, right? The same program, A, uses libc, libmat and libgl, right? So if you put libc, libmat, libgl, you might just use libc and libgl. So, you know, libc, libgl. Now libgl is two different ways, right? You might say, okay, well we can say I always closed libgl at a given offset and then you're okay if something doesn't use libmat that it just stays empty. That doesn't quite work either because programs, you can't just assign these locations to a library that takes a lot of information that no one has, you will eventually have a program that uses two libraries and an offset to be loaded at the same address, right? So as a result, libraries are really to be provisioned in time. The library expects to be loaded somewhere and to actually get that software generally does not have original intent is that somewhere that is loaded is that one of these slots, libmat, if we load it in this slot we're really happy or can we load it in somewhere else in memory and it's perfectly happy to support many different programs and many different dependencies using the same set of libraries. So this conveys the people offset to put libraries anywhere, right? So the idea of that is to make better information and say when we start out the program let's choose a random spot it might be here, it might be here, it might be there, but then it's loaded together and it loads libraries there. And then when, as an attacker, you hide that control what you want to return to the scene and then you want to return into some random place where nothing is at and you're screwed because the program back because, not actually with no system you just jump into a map section of memory. And so this was a very effective a very short amount of time, and there are a couple of reasons why one of these reasons is that there's not that much wiggle room where you can load library memory. For one thing, you can't load a library into the top half of memory that's reserved to the right away that's one bit of entropy less. You can only load library straight off the back to the 31 bits of memory. There are other constraints. Generally speaking, you want some large data for data for key. You don't want it to interfere with the stack. Realistically speaking, libraries, depending on the implementation of SLR and so forth, have anywhere, depending on the system, have anywhere from 8 to 19 bits of entropy where they're in the way. 8 is obviously trivial, right? That's 256 times just what's on there. This sort of 16 bits of entropy number that often back is thrown around also easy, you know, depending on how long you're exploiting runs in some easy amount of time. They're not like hours, you can parallelize it by the connection of ones. It's noted that on the 64 bit platform, now they're talking, right? On 64 bit platform, there's much, much higher amount of MDIs thrown at the exact number, but it's not something that you're able to do full. So there are a couple of reasons. I can't make a claim for where Durandis comes from, but it's not based on like, you know, the starter problem. It is a good super random source. You know, the 4 bit architectures are not most secure. And then, you know, while we're at it, we can, at least for example, we can randomize other things in memory, right? So libraries aren't needed to come in, right? But the stack, things on the stack, things on the stack are always addressed militarily because, you know, a function could be bought from an number of contacts. You can't assume exactly where it is on the stack. So the stack can be ran online. Dynamic memory, the key, right? You always allocate the key if you don't make a assumption where it's going to be, but you're right, the key could be ran online. Almost everything can be ran online. And ASR, you're enabled in Linux by default, nowadays. This started happening probably around 2010, 2011, when a lot of new attacks, you know, returning from the sea and so forth, made a promise. And I remember, two years from then, we were catching a blackout. Yeah, so, Adam and I competed together on a deep-sea shellfish back in the day. And around 2011, ASLR was pretty widespread, competition. Didn't really use it or consider it too difficult to bypass. So at one point, if you were acting something, you realize that, hey, ASLR, oh, shit, these guys are serious. And the message, the organizers said, hey, just so you know, you accidentally left ASLR in. Like, oh crap, thank you for reminding us. And then they turned ASLR on. So things have progressed quite a bit. ASLR now enabled the default of our default and, you know, assumed to be present in every introductory and hacking challenge and so forth. It can be turned off by writing a view of this kernel configuration parameter inside of Rock. It's implemented using this combination of support in the kernel and support in the Linux motor. So, you know, the stack will be mapped in somewhere around the kernel and the libraries, the kind of collaboration people load in the kernel. Specifically, I wanted to, you can, when you memory map something, you can have it give you the base address and you'll be able to jump back to this a little bit later. When you map the memory in Linux, the base address starts out, ran a micro process and then it is offset from there. You can even minimize the location of your executable. This is called position independent executable code. And nowadays, it is done by default, but this was not the case for a while. Very few of the platforms just have some overhead because I might mention if we literally, I should have mentioned briefly now, on 64-bit platforms, you can actually access here what we have, let's say this call, right? Obviously, this can be done offset, but then in 32-bit platforms, there's no support for accessing memory relative to the instruction pointer, right? So, it's very hard to have mobile data in a program that is going to be moved around. You actually have to lose some performance overhead by deploying your register to always get around your location and memory. On 64-bit platforms, there's no longer the case, so it has a large amount of performance and it is really open to people. The more things are randomized, the more resilient you will put your processes to be explored in. So, how would we exploit, first of all, how do we, you know, practice actualization in the modern world where SLR is enabled? As I mentioned, it's been turned off in SLR. For your whole system, you can turn it off for one shelf or for one process with this command with the same way as SLR in the NSA that is running on the map that you run with it. Sometimes, to mention, you can, if you use SLR when you're forcing, you can control how the process starts up. You can often screw up the amount of bits available for SLR. You can, for example, use a limit, a limit command to set process limits. You can set an insanely huge stack that will take up so much room that there won't be any room left for SLR. But in the general case, you have to do a two-step attack. One, you have to leak an address to, you know, format string out of boundary, whatever, that, and then you do the client of the control flow to where you want. So, if you can leak the address of the receipt, then, conceptually, you have the same attack that you were doing in GP where you rented out systems, and then you use that to, you know, what, yeah, and then you use that to jump. Or, you can do something a little more interesting called return-oriented programming. Return-oriented programming is basically a generalization of the return-to-lipsy approach. And that, again, here is return-to-lipsy allows us to execute library function. But we don't need library. Library functions are for jumps. They're for programs. They're not for hackers. Right? We can actually use little tiny pieces of library function. If you have a function that does something something something, so they can return, we can actually jump here and do one little thing and return. And then do another little thing and return. And you can actually combine these, like a sort of frankest side, to carry out whatever we want to happen during exploitation. I introduced a while back to work around these defenses. And it was in a paper called the Geometry of Innocent Flesh on the Bone, which is a very kind of punk rock title here. This paper recently won the task of time award at CCS, or whatever the tool that the task of time award is there. Because this paper basically said, hey, as long as you have enough code, by taking these little snippets and changing them together the same way that we saw that system will return to software after it's done. By taking a bunch of these guys, you can do anything. We're a manipulator. So, let's see how this works. We have our old friend in the Monovo program. Combined now with even fuel protection, because now they're pretty major hackers. And we want to carry out a return going to programming attack. The idea is, first we define gadgets in the binary. This little guy is called a gadget, a piece of a function, ending in a control flow transfer that you can control that will do, bit by bit, what we want to do. So, the essential idea is we find out these gadgets and we put them together in a way that our shell code is now built from these little pieces of code in the program. And at the end, we want to call exactly, just like we did in our old style of shell code that may not understand. And so, what do we need to do that? We need 11 in the AIS, the number of the system call for exact V. We need the address of the NSA somewhere in DPS, the first argument of exact V. We need an RV set up in ECS, the second argument of exact V, and we need a null purchase document, or a pointer of the null for an environment that exists with exact V, and the third argument to exact V. Cool. That makes sense, everybody? Perfect. So, the first question we're faced with is where to put the NSA. And we're here, we're going to assume that EIE is not enabled. So, we're going to assume that this is our binary and that we know where at least the binary is in that tree. Okay? We know where the binary is in that tree, so now, where do you want to put the NSA? Well, there are some places that are rightful, right? And one of these places is not in that tree. So, that's the global variables, the kind of physical variables of the program. It's rightful, base address is 80860, and it's pretty big. It's OXF20 in size, how big is this? And definitely, it should be almost four kilobytes, right? Anyway, it's pretty big, it's very fine to play with. So, let's decide to write stuff there. Now that you have where you want to write to, now you need a gadget that will do what right. And again, you're not going to find a gadget that's not quite true, but let's assume for now that you're not going to find a gadget that will do that. So, the reason to build it out a little gadget is the first thing you need to figure out is, hey, how are we going to write benefit to money? And so, after a lot of searching, especially if you do a minam, what we use to do that is you find a little gadget. At 809a670 in the program, you'll have something that writes the value of BAS into EVX. Again, I apologize for this poor taste of a family format that's out of my hands. And then you return. And if you do that exploitation and not, you will very quickly memorize C3 as a write. So, you do this and this gadget gives you the ability to write four bytes anywhere you want to write. So, you control EVX here. Basically, you put slash min right into EAS, that's four bytes, put the data assignment into EVX, that's wrong. Okay, so we put that data into EVX and then trigger that gadget then you run the slash min. And that's what we need a couple of gadgets to make this happen. So now, if you figure out the right, that's, you know, this last step, the first steps are still a little mysterious. You're not fully sure how you'll accomplish that. So first, let's figure out how to get data into EVX. Well, a good way to get data into something is to pop it on the stack, especially when you control the stack. And so if you find a gadget that's pop EVX and there's C3 again. If you do this enough enough, this knowledge never really stayed around with 5A as a critical character. You start being able to see it in an extra. Most of that has popped some random register as a single critical character that you end up being in your team. So this gadget, of course, is what's on the top and they call it December, just ask for it. Yeah, maybe a nightmare. So, of course, the top of the stack is this crazy way of drawing exactly at the bottom. It makes a lot more sense that the top of the stack is on the left, not really good. So it takes what's on the top of the stack and puts it into EVX. I don't know how does this help us, but it helps us because it gets us that much closer to actually writing data. So here, this 08, 06, 09, 1a is pop EVX. And so, let's see what happened when we actually went through it. We start out with, so, we have here, that's the pop EVX. We do a leave after we do the overflow. That's what's here at the rest. When we do the rest, we jump to pop EVX and when we pop EVX, it'll pop off this slash bit into EVX. So, look at the value of, but there's no value of EVX in here before now, there is a value of EVX around here. So, over here, EVX after we pop it, boom, EVX is finished. Awesome. So, this is the same as what's on the stack. So now, we're triggering a gadget that does pop EVX. We have now gain control of the value of EVX. And in terms of programming, it's all about the slow battle to gain more and more control, right? Sometimes you have to do it bit by bit. Sometimes the only gadget available in your program is increment EVX. It's actually very often true for EAM, for example. So, if you have increment EVX, if you want to set EVX this value, there's, it's half, right? There are other things you can do around those like, you know, maybe you can control EVX and then you can somehow move that into EVX and maybe you are able to trigger a multiply instruction, which actually puts some value in EVX explicitly. And so, anyway, so then this returns and we continue executing. And in this case, we will execute this, what was over here as EDCB. And, oh, this was, yeah, this was without this, I had it. This was EDCB. So now, EDX is EDCB. And when we return, we return to the BFF best transfer ever, the address of the old tools, the location of the stack you work at randomizer way. Now, there you go. So now we have control the value of EDX. And the point is, we have the address of our gadget, where I did everything I thought, we're just missing a data to because the addresses of the data are in the binary cell. So you can, of course, expect the binary cell to have a function that says, don't get you in here to shell. But of course, any binary that's sufficiently large is going down a bunch of these little gandas that actually do some useful stuff, some stuff that the program is supposed to do, but when you pull them all out and put them in together in a specific way, they allow you to achieve that. The question I just said, you said I'm not right. Yes, exactly. Exactly. And really, it depends on the size of the program. Realistically speaking, I forgot the exact, you know, the program is over 50 kilobytes and magic happens to take it to explicitly reduce the amount of gadgets in there. You will have gadgets do anything you want. And there are too many tools that will do all the searching for you on the map. You build the entire s.com. Yeah, I might need them down if you have not. So, we've got a gadget to get our data into EDS, you guys know what I'm after. And now we need to get whatever you want to write into EAS. And it's the same for today. There's another gadget at 8.0, VDD6, P6. I don't know, maybe this is the made up gadget, we're going to have to do the binary. Presumably, the binary can be bought earlier today. It'll be somewhere else. And there's, you know, a gadget that will do the exact same thing for EAS. There's one for EVX. There's one for VCX. We have quite a few things that we can work with. There's one to XOR, V-A-M-E-X, and V-A-M-E-R-O. That's a very common thing you want to do. There's one that you can make EAS. Okay, all right. You can mention this pattern in front of your V-A-X breath. And what you'll see, I do look at more and more binaries, is that there are gadgets that are very hot. You can almost always, obviously, find pop, EVV, red, right? You can often find pop, in EDI, 64-bit, I'd say, you can find pop, RSI, pop, RDI, red. Pretty, pretty reliable. And so, there are these many of these types of gadgets that exist. Often times, when you just find programs that set EAS to some specific return value, red, and this sort of thing. And, of course, the ever-important system called gadget in EAS, all those that were on the stack, you've got to know all that system called pop. All right, now, let's say you have all these building blocks, you can build your cell phone, and you go on to building your block, pick a chain. Of course, you're going to continue doing this in this hacky-ass way, where we have to do that and then converge in our cell and give us a big headache. But that's a pain in the ass. So, let's actually use some real Python to make our library a little simpler. Python ships standard, in the standard distribution of Python, you have a library on struct. It does a lot of structure, packing and unpacking. And one of the things it does is it allows you to take an integer and display it converted to a little entity. So, this less than capital Y means create a little entity and unsign through if you make an integer or a path on time. So, basically, here's our table, you start out with our buffer and some garbage value for our rate pointer, and then you say, okay, let's copy bin to another string, slash bin, into the data set. Okay, and first we jump to this pop ebs return, then what it goes into ebs, ebs will be the address of our data sign, where you want to write to. Then it'll return, and when it returns, it'll return into the gadget pop eas, and return, and that will pop slash bin into eas. And where do we want to have that return to? Our memory write gadget, which writes the contents of ebs into that and is pointed by ebs. And after this rock payload runs, we will have the string slash bin written in to the data segment of the program. Usually, by the time you're doing this, you pop down the program to the point where it's no longer doing the original operation, right? And so it likely won't try to do those again. Now, sometimes you have to do an exploit specially so that the program can keep running after you're done, then you care. And sometimes if you have multiple shot exploits, you get some, probably from very complex stuff, you get some rock tables that you're a little privileged by, you need to send out something and let the program run for a while and then exploit it again later, then you do care, you don't want to flop over there. In that case, so this last data, and that last data, or the data segment, you have almost four kilobytes, right? It's unlikely that they're all used. There's a lot of padding, this new variable, often times, you simply have, you map an entire page of writeable memory that you can't map on your page if you only use a little bit of it. And so usually there's stuff that you can write that won't matter. In this case, just for the example, we're using that data. So, of course, it's not just like every one you want back then, flash not safe. Presumably, a couple of classes ago, you covered this whole thing where since you're using string copy to write over the stack, you need to avoid no bytes. Does it sound familiar? Cool. So yeah, you use slash slash SH. So now we're back to the same thing, but you do instead of this data, an address, you can get a plus four and you write slash SH into it, boom. And as we call the same, you'll trigger the same gadget for that. And then you do want to now terminate the path so that system would, or whatever, exactly will read it properly. And so we do the exact same thing again, data was saved this time. But here X or VAS, AX, right, a different gadget that doesn't take any data in point seven five on the stack, with zero data, yes. Okay, so now you have in memory the SH. And then so now you have the first argument to exactly, now the next thing you can build up the RV vector and the second argument. So you need to push a bunch of pointers to the stack. And it's the same sort of thing. You pick an address for this vector. And we use our same set of, our same memory, right, and write the dot data as well. So we can actually write this out to keep track. So yeah, our dot data memory here. So let's say here's dot data, what will this look like? Well, after this execute, when we have an expectation, after all these memory, right, gamut run, this will write into the data second, hold slash B, I, F, hold slash hold slash SH, and then four heroes. We want to write a bunch of pointers back here for exactly. So what we want to write is, so this is, okay, this is four bytes. This is four bytes. This is four bytes. Now we want to write a pointer that, right, so into data plus 12, this is data, data plus four, data plus eight, data plus 12. We want to write the address of data a pointer into slash bin, right, because if you remember, remember a stack B, you need to run exactly our command, a list, or an array, or a V array. Depending on the specific shell that you're running, you can leave this completely blank. So you can just give it a pointer to a null byte here. The buttons assume they're nicer than that. So for all we want to do, give it an army zero, an army one, or sorry, your army zero, and then a null byte. This is a null terminated array. And then we want to give it a null byte for the environment or a pointer to a null byte. The same thing for the purposes of that, either it's completely not in this environment or an empty environment. So here, we're building this, right, we're getting an address to the data, which is that point right here, and we're running it here, right. So this now points to that, to an advanced level stage. And so that's this pointer, the zero army one to the army B to exactly E. And then we add a null byte. And so here we want to write a null to here. So again, this is zero, zero, zero, zero. And so now when we call exactly the army one, give it our this guy. And then a pointer to this guy. And this has a pointer to this guy. And this has a pointer to the strength and our null. Okay. Cool. And then now we have all the data and metrics that we need. And in fact, I can make that call. So what do you do? You need to do this exactly that data, that first arrow data plus well, the second arrow, it looks like Adam wants to be queen. And instead of a non-existent environment, you'll blame the environment. Does everyone understand the difference here? So the environment is an array of strings, array pointers to strings, right. And the environment and our be array, they're both null terminated array. So they'll keep reading until it hits the null. Right. In this case, this is a null terminated array with one element. I could have a pointer and then null. If you have a pointer to a null, it's a null terminated array with zero elements, it's a blank environment. If you just have a null, it's just null environment, which the kernel G stays the same way as a blank environment. It's just kind of a distinction without much of a difference. Cool. Cool. So EDS, the first argument is that V is the path. So we have a pop EDS gadget that we found earlier. We use it with the data and metrics. Now we control EDS. The second argument is VCS. That is the pointer to this list, which is we want the pointer to be VX plus 12. So again, we kind of pop ECS object. We do this, we give it the address of data plus 12. And VVX is the third one, and that's the environment. So we have an EVX gadget as well. We're very wondering now if it was a Christmas, and then we give it this plus 8, which is actually so cool. And then EDS must be alive in order to trigger exactly the system call. And so if we are unsure that EDS is zero, we want to zero out EDS, of course. This is actually EDS. I understand the incrementing. Why did we not just set it to EDS? Why did we do pop EDS, right? I wonder if we could solve it. In our table here, which would have caused stirred pop EDS to terminate pop EDS and all those screwed up. All right. So then we trigger the system call, which is here. We have a gadget for it. We don't need it to return. It doesn't matter what it does that way because it doesn't have our shell. And then we just print the table out and type that into the program. So let's see what happens when we run it. And let's break at this 4867, which is, but you'll see in the slide. So we break at this 804867. We run the x-boy. Let's see what happens. So here is our red. After the overflow, trigger the bubble overflow and you will return. This is our state in our register file. That's the state of our staff. And let's see. So we hit return and we began our payload by popping at this 918. 918, that's where we returned to from main. And that's pop EDS. Here, you're really just been a saint. That's the address of that data. You pop it, now it's an EDS. Then we return to this pop EAS. And here, we've written out our gaskets concatenated as a return on the system. All of these rests, they just measure control to the next gaskets. These aren't continuous in memory, right? They're just continuous in terms of FDS. Right now, they're long. And so we got EDS into the register that we sent out at the prompt value of EDS. Now we're going to send the prompt value of EAS. Now we're going to do the write over here of EAS and EDS. And then we're going to return. So now we've written this part. This is a possibility we've written it. Check. EDS, right? To write the second part, SSH. Cool. You pop in EDS again. So now this is that data plus four. Return into the pop RAS. And so now our EAS. Do I keep saying RAS, R-E-S? Okay. So you guys know 64-bit X86? Yeah, a little bit. Cool. Yeah. So EAS in 32-bit is the equivalent of RAS in 64-bit X86. RAS. I've worked on 64-bit stuff. The most thing now in 64-bit is a center. Let's say. Anyway, you pop EAS and you pop EAS in return. So this is now slash, slash, SSH. And then you keep going. You just want to do this whole thing, what it's going to do, right? So now you set up an SSH. Now we're going to set up this null byte, this EAS plus eight, this guy. You do X or EAS, EAS. And now EAS is zero. And we return from there, which illustrates our memory. Right. Boom. Now we've written this. So now this gap, this gap, this gap. And we write two more things. Of course, we set EDS to 6C, which is 8 plus 12. Write, boom, set EAS to that data to make this pointer. Boom, write, happy, set EDS to here to write this null byte. EDS, we set to that, plus OAS-1L. X or EAS, EAS to write it zero. Boom, write it. Now this is done. So we're done with the memory part. What are you doing now? You're setting up the call frame on the call site on the system call. So you pop EDS, so EDS is going to do that data. E-CX, E-CX is pointing through our list. And you pop EDS. EDS is EDS is pointing through null byte, X or EAS, EAS is now zero. We've commended a bunch of times, whoops, until it's OXB. And then you trigger the system call and you click. So before we turn the system call, let's look at the state of memory. So we read out that data. We'll see that it says the NSA. We read out a bunch of words from here. You see that we have a pointer here to that data and a null byte or a null word. And then if you read out the word here, you'll see a null word. So it's all set up. I'll convince you, I'll show you text popping up on the slide, that we're about there. So in this thing, we hit continue and boom, it's happening and boom. We have a new program, Big Dash, which is the minimalistic shell nowadays in control of distributions. That's what we ran. And we have an ASLR group, failed kind of, as long as your binary is not dependent. And binary is now based on our condition. So how do we get around that? I'll give you guys a couple of ideas. One is sometimes you've got to leave specific, you can leave an address. Maybe you can't leave an address in libc, but you can leave an address in libmap for some reason. Or lib, we already brought that library, right? The way that ASLR works in Linux is that, oh, hey, we have a whole, how do you do it for this job? Okay, the way ASLR works in Linux is you have your amazing memory layout that's horizontal. Somewhere in here, you have your program, maybe you don't know where it is, position is the best. Somewhere you have a stack, somewhere you have your key, you don't know where this prep is, and then you have libc, you don't know where that is. Right, you've done that to each other before, that's not an accident. Linux will always map them next to each other. It's really stupid because if you leave any address anywhere here from any of them, you've broken library and SLR. You know where all the libraries are. So that's one way to do it. You don't have to leave necessarily leave that address the exact address you need. You'll need almost any address. You really, when you leave unadress from there, you don't have to create stuff. You can add it in the stack that you know about to mess up the local function range and a lot of other functions and so forth and try to, like I said, this sort of modification is always the battle of getting a little more control until you, I think, split the program. If you leave an address in some other library, then you're pretty much good to go with a follow-up, equitation and so on. Another way that SLR offers nowadays, and this is kind of unburging to me, is that I mentioned E&E relative action. So in modern 64-bit X86, you can do memory action and compiler does, based on instruction. And so somewhere you might have a thing that's a move, write a B plus EBS, other times a BBS, write a B plus ESI into DAX and then something DAX. If you control ESI, ESI, this memory access is an offset from ESI. So it doesn't matter that you don't know where the program is. If you control ESI and the program is here and you set ESI to 10, you will do a memory access into the program and do a valid application. That means essentially that it is not impossible, if you do not see this time yet, but it's not impossible that ESLR isn't necessarily powerless in the face of a complete position independent code, but it's less effective or it could still be done in some sort of position-dependent, or rock is a power, but it could still be done in some sort of position-independent rock, maybe that's an emerging sort of thought. Anyway, there's a lot of tooling for doing this automatically. Let's see about blowing the rest of the class on a demo showing you guys AIMROCK. It's a tool that came out of our research lab on my graduate study. AIMROCK, I would say AIMROCK. Look at that. It's not turkey. It's not easy to use. This might be a little easier to use, but it's less general. So AIMROCK is a tool that analyze a binary and will automatically synthesize, drop it on like this. And like that, it's not very easy to use. Cool, right. Thank you very much.