 Cool, so to recap our discussion. There's gonna be no midterm review. The midterm will have questions on it You'll be expected to answer those questions Hopefully you can infer from the material. I like that you can find vulnerabilities So you should expect to be able to read code and talk about find vulnerabilities know the different kinds of vulnerabilities what they're Big capabilities they allowed why they're vulnerable all that kind of stuff, right? Those are the important things everything we've covered up until after today is fair game Any other questions? Let me Yeah, it's a weird button that only sometimes works Okay, so I'm actually going to skip a lot of content. So there's about We're gonna go over loop overflows which are really important And then we're gonna go over format strains and then we're gonna look at defenses against these binary Exploitations that we talked about so for those of you who are You know doing the levels there may be some of the levels have to relate to some of the things I'm skipping but only definitely after 10 that correct. Yeah, that's correct So don't worry, you know, you want to stop at 10 stop there the slides are still available They're still in the slides. They're just hidden so you can easily see that content and you can Go look and learn and all that fun stuff. So questions on All right, let's get into it. Okay So we saw on Wednesday, right? We saw loop overflow vulnerability. So we saw We saw index Overflow right or you can pull the index so you can overwrite any relative address from an array Right. So in loop overflows. So I do I mean that we're overflowing a Loop and a for loop or a while loop The code of the loop Right, so yeah, so not doesn't mean you're not overwriting the loop, right, but we're Controlling the loop iteration right how many times does that loop iterate and so if we can do that We can often have a security vulnerability And a very special case of this that happens often Is no didn't stop Can't stop won't stop. All right, but my clicker won't work Unplugging it and play this is actually hilarious. I don't want to go didn't do it. Okay. Wow. That's crazy There's only two difficult problem with your science Naming things fashion validation and off by one Right so Wow, that was got a terrible response You're not having a midterm today, so you can relax a little bit laugh Okay, so what's an off by one error in a loop? What does that mean? Yeah, so we're we're looping through something over the length of something and we should be doing less than length Right, but if we do less than or equal to the length that allows us to go one extra Right, so we're looping our loop iterator is going one more than we expect similar to array overflows right in the sense that We're going past the bounds of the array But the key thing is that oftentimes we're only one we can only go one element above that array right and so These are very tricky because oftentimes the program will not crash when you do this Right, it you may have to wrangle the computer to make sure that you can actually do what you want it to do So what's so if we think about there's a buffer on the stack, right? It's I don't know. It doesn't matter the size. What's it's the only variable on the stack What's right above that buffer of the local variables the save base pointer, right? Yeah, so an off by one error, right will allow us to go to the array and go one above that that saved One above this loop, right So we can maybe modify either depending on the size of the data We can modify you at least significant bite, which is usually the case because we're talking about character buffers or the whole thing So there's a really good paper You want to get more in depth into this frame pointer overwrite Reading this paper So let's look at an example to see exactly what happens So here we have some function. It's got a 256 white character array It's got an integer I It has a for loop. So this for loop is going from zero to two fifty six It's setting the I element of the SM Array that gets passed in copying that to buffer I and then it's quitting. So what essentially is this I mean Actually, I guess this is better. It's essentially a men copy, right? So we're moving memory 256 bytes Well, actually we want it to be 256 bytes, right from SM to buffer Right, that's what the developer wanted to do. So if we look at main we say hey, you know You got to make sure you pass those two arguments and then we call this function with argv one and then we return Equal to right in that in that loop iterator, so how many times is this loop going to execute? 257 times right Which is what makes this really really tricky to look at and just eyeball and see yeah, there's definitely a vulnerability, right because Less than or less than or equal is very slight plus. There's not the number 257 doesn't appear anywhere Right, we have to know that based on some man takes up the looping and our experience before loops and our experience of knowing that I'm showing you an example that's specifically about this type of vulnerability, right? So the question is Can we So Here at this point so at this point where it's gonna do this copy What's the stack looks like so let's assume that the variables are in this order as they appear So first there's buffer and then under so underneath the first variable on the stack, right local parameters It's gonna be I and then above that is 256 bytes. So 256 characters. So then what's above that? The saved base pointer and then what's above that above the save base pointer Instruction pointer. Yeah, the saved instruction pointer and then what's above that? SM. Yeah, exactly the argument SM Right, and then above that is mains locals and mains all that main stuff, right? So if we go buffer plus 257 are we gonna get to We'll get to the base pointer or can we overwrite that whole thing why not The size of the character, right exactly so characters only want a Eight bits wide right one bite. So by this final right where it's gonna be buffer bracket 256 is gonna go buffer plus 256 and Overwrite that bite and change that bite, which is gonna be the least significant bite of the saved E.V.P. So we can't change instruction pointer We can't we're not gonna get there I concur, okay, let's look so this really has to do with the function epilogue. So what's the normal function epilogue on x86? Leave and then read. So what does leave do? Yeah, so it actually does two things, right? so it first so We got to remember our base pointers Somewhere for our current function, right? So we know based on what we just saw There's gonna be I and then it's gonna be the buffer And then the save the base pointer is gonna be there right at where the save base pointer is and above that's gonna be EIP So the stack pointer is gonna be somewhere Down farther right because we allocated memory when we called this function Right, so it leave has to do it first has to essentially deallocate by moving the stack So it first does a move The base pointer into the stack pointer so make the base make the stack pointer point to wherever the base pointer is Then it does pop EVP. So then it does restores the base pointer that's saved on the stack So in these examples I'm gonna explicitly write out these two instructions. So these two instructions move EVP into ESP Moving the stack pointer up to where the base pointer is and then pop EVP pops that value into EVP So those two are exactly equivalent to the leave instruction But I'm writing it out here so we can see exactly what happens and then what does Rhett do Yeah, pop EIP essentially right or start So get that value on the stack and start jumping to it and also move this stack up one It should be the EIP that's saved when you call the call function or the call instruction right if the call instruction pushes a Pushes the next instruction that would have been executed onto the stack That's where the save EIP comes from. So there's pop EVP, right? Put store EVP in EVP Then that pop move the stack up. So Rhett So now with the stack of point two is the save instruction pointer and then Rhett jumps to that and moves the stack up Cool. Okay, so let's look at this. So we have a stack pointer So these are registers right the stack pointer the base pointer and the program counter or the instruction pointer Right, and so we're kind of doing this a little bit more symbolically So hopefully it should be a little easier to understand. So The program counter is now at this instruction, right? So we haven't actually executed this instruction yet so Question you should some of the things you should be able to do right look at this function and write the stack That the function should have at this point right so we saw that There'll be an integer I then there'll be buffer, right? So these Here even though these are look kind of wide. Well, these are actually each one bite. So this is not going to be the whole Objects are not drawn to scale, right? Exactly there would be four on one line, right? But it's a little harder to see that and then above that buffer, right? So the end of the buffer is buffer bracket 255 That's how to get to the final bite of the buffer and then right above that is going to be the saved EVP And then above that's going to be saved EIP and actually if we go up we can see that main doesn't Didn't have any local variables. So right above that is going to be Actually, this is wrong. There'll be Saved EVP of mains caller and saved EIP of mains caller and then the argument but also yeah, the parameter sm is also missing What are you gonna do? Yes close enough for me Okay, so we know so base pointer, right? So we know that the base pointer is gonna point here Right because we reference all local variables by negative offsets from the base pointer Which is gonna go down and we reference parameters by positive So it's gonna go up to reference the positive arguments and so from looking at this we can tell that okay This is mains function frame and this is Sorry, this is function Clunks, I gotta use a different name. This is funks function frame, right and above that is main And we also know that the stack Points to here. It really doesn't matter exactly where the stack is but we know that the stack is going to be below EVP so What's going to happen? How does this diagram going to change based on executing this instrument? Save EVP, right? They're going to both point to the same place, right and now Essentially all of this has been freed in some sense, right? So it's grayed out because it's Freed from the program's perspective, right? But those memory addresses are still there We didn't change what's in those addresses, right? Oh, did I go too far? Okay. So then what happens in the next instruction? But we haven't done the copy. We're at the end of the function right here Just normal stepping through this to understand exactly what happens. So then what happens here? What happens with this pop? So EVP is then going to point up Right, it's going to point somewhere up here to mains base pointer Whatever that value that was in save EVP is now going to be where our base pointer points to Cool. What happens to the stack pointer? Do they ring the same? Somebody argue one way or the other? Yeah, I thought you're raising a hit It's going to pop, right? That's it pushes and pops change Change the stack pointer, right? So at the end of this the stack pointer is going to move up one So it's going to point to the save vip All right to make sense because we've just gotten rid of the save base pointer We save this base pointer so that we could use it in funct Or we could that funct could use its own base pointer and then when we're done We want to go back to main so we want to get rid of that memory So now that we're in here EVP is going to point somewhere up here Not exactly there and then stack pointer is going to point to the instruction point And then so now what's going to happen when we call ret? Well, we return Yeah, pop eip, right? So it's going to take this saved instruction pointer value start executing there And then it's going to move the stack pointer up one, right? So it's going to go to main All right remain doing something and then it's going to call Return zero so the stack pointer is above the save vip and the base pointer is somewhere above that And so from our function, we know we call this funct and then we return immediately, right? Okay Yes Okay, so now so in this diagram, what can we Change with this off by one overflow save evp. So what can we control the whole thing? Just one byte exactly. So when our program accesses buffer 256 It's actually referencing this byte on evp Right, and so depending on the end in this x86 this is going to be the least significant byte So we can control the least significant byte of evp Okay, so let's think about What that gets us right because if we go back here Well, if we control the base pointer Then what let's say you can point this base pointer to anything, right? Did that change anything here? Right, so we control the save base pointer So now at this when we do pop evp now evp can point anywhere But does that get you anything here? Yeah, but right here right with function and functions epilogue Normally on a normal buffer overflow, right? You have at this return instruction you control the save evp so you can make it go wherever you want right And this ret instruction transfers control from the program to your shellcode, right? That's what you want But if you've just changed this base pointer ret still happens exactly how it would happen Right, and you're going to go back to main and start executing main Okay So our goal is we want to see what we can do by changing this right but just changing evp. What can we do? so Let's try to track it. Okay, so From the epilogue right so we're moving the base pointer into the stack pointer right so so this is Any epilogue function epilogue moves the base pointer Into the stack pointer. So this now changes the stack pointer right before it's going to do what? Pop evp and then what return right? How does it know where to return to? What register does return implicitly use? How does it know what this where the saved instruction pointer is? The stack pointer yes because where the stack pointer is pointing to at a return That's where it's going to go jump to What are we controlling in this instruction? What happens here? Where does what happens to the stack pointer? It goes to wherever the base pointer is pointing to right So now what if we control this base pointer? Now we control the stack pointer And now when we do pop evp Something about choosing is going to be popped into evp Right, so now the the stack pointer is where evp was our frame pointer plus four bytes to move up four bytes Now when we do a ret now what happens goes where the stack pointer is And is going to take the value that that stack pointer pointed to you put it in the ip start executing from it and move the stack up one so Right, so now the original program counter basically references the original frame pointer the evp right plus four bytes Do you see how so if we control this base pointer? We can arbitrarily control this base pointer We can influence what the stack pointer is And then where the program returns from but we can't do it in the function where the overflow occurs right But function is called by main And we can control mains essentially when function is called when f UNC is called We can control main's base pointer because when function leaves Calls the leave and return it's going to set up names base pointer And then when main does this right main has an epilogue. It's going to do this exact same thing It's going to move the base pointer into the stack pointer And at this point now we control the stack pointer because we control the base pointer And then it'll do pop evp and then a return so as long as we make sure that whatever value we put inside evp if Four bytes above that is the address we want to jump to then the program's going to jump to where we want it to go And so this is how we can use this so the idea is Is in a normal buffer overflow, right? We usually do our knobs plus our shell code plus the address of the buffer that we want to jump to So we still want to use knobs because they're usually always a good idea, right? If you can get away with using it you want to use some knobs so that you have a little bit of leeway Our shell code Then we're going to do the address of the shell code and then we want Then we're going to have that lowest byte of the frame point, right of the say So let's see how we can put this all together, right? So this is the lowest Byte of evp right here So what we're going to do is we want this buff we want this saved evp to point here Right into the shell code Well, we want to point here So that that way when main returns it's going to move the stack pointer down here. It's going to do pop E pop evp to pop whatever garbage is here into evp And then it's going to do ret to the address of the shell code which should hopefully go down here Does that make sense? so you can so another way to think about it is We essentially want to create a fake function frame for main Right, so if we consider whoops if we consider here right here if we consider this main's base pointer Let's say we're just We're given Godlike powers and we can just change main's base pointer to point to here right before it returns Right, then what main's going to do is it's going to move the stack pointer down here first move evp into esp Move the stack pointer down here pop evp So this shell code whatever it is is going to be put into evp the stack moves up to here And then it's going to return into the address of the shell code So our address of our shell code is down here and it's going to start executing In our original program. Can we control the whole base pointer? So let's look at the program. That's a good question So can we control all of evp save evp here? Sorry, it's a little small Right, so because of this the way this loop is written Right on the very last iteration i is going to be equal to 256 And we're going to say buffer bracket 256 is equal to whatever we pass in from sm Okay But we can't access buffer 250 Or no 256. Yeah, we can't access buffer bracket 257 which would be the next byte or 258 or 259 Yeah, if we could we could use exactly these same techniques Just You know think about like if we can do it with one byte we can do it with all the bytes Mm-hmm. Yeah. Yeah, I mean Well, it'd be a little bit. Yeah, it's a little bit. This is a mistake that you're like Very likely to see right it's not likely that somebody's going to say less than You know 258 or whatever no plus fours 260 Yeah, unless they're specifically doing it for back if I was gonna do it back door I do it like this right because this is like a one character bug here this equal sign Right Trying to think I think it's defined Either by the compiler based on the architecture you're compiling on I think there's a c header file that defines the size of all the built-ins Because you can yes you can run a c program You can compile a c program on different architectures that have different sizes of characters integers Whatever, right? That's the same thing with 64 bit is 64 bit integers And other data types. So you definitely can do it I don't know if you can do it on a I don't know how to do it so that it would work on a non System look like that. I'm sure you could do it But the code wouldn't be able to interact, right? You can't run the code that thinks characters are eight bits with code that was written thinking characters are four bits or four bytes What do you mean a standard? Well, these aren't I mean these are characters, but they're It's more about the size. I mean we call them chars, but the important thing is that they're one byte Well, that's the Aspies only Only seven bits. So you only actually need seven bits for Aspie and they probably use eight because of byte boundaries, right? Yeah, but this is historical stuff, right? So, you know, they called it a car, but really the only thing that matters is the size of it, right? so you can think of a system that had native utf 8 or Yeah, utf maybe a better example of 16 where every character is 16 Bits so two bytes so every character would then be two bytes But they think it's confusing with utf 8 because characters don't map exactly the bytes. So you want to talk about bytes instead of characters That's great So now we completely control The function frame of main Right, which also gets tricky if main accesses any of its arguments or local variables Right, it's going to use our new base pointer. So we better make sure that whatever those offsets are There's things in there that are not going to break things That's actually what can make this very tricky, but also very powerful Yeah, so the problem the key problem is we're influencing. We're able to arbitrarily change main space pointer Well, not arbitrarily in this case. We can only change one byte, but you can think we can arbitrarily control it Not relatively that's part of the tricky part. Yeah, so you can't um Well Okay, you can't control necessarily where your shellcode where this buffer is on this stack, right this buffer The relative offset between this buffer and save dvp is always going to be fixed right Where your shellcode is could be a different thing you could put your shellcode in an environment variable In which case it's going to be above you can put your shellcode in one of the other argv parameters um You can even put it elsewhere on the stack if there are other functions that got called um But you need to get that address of that shellcode onto this Onto someplace where you're going to overflow and make the base pointer point Yes, yes, that's true. I mean, how do you do it? You can do it while controlling eip, right? So the same instruction pointer You have access to the fold you can let's see You could possibly do it with one byte of eip depending It gets tricky It makes it easier, but this I'm going to show that because so off by one is going to be something that is Incredibly common and then we can see how easily this can become Incredibly simple mistake can become an exploitable vulnerability if you can control more your job as an attacker becomes a lot easier Then if you didn't have that we want Yes, we want eip to point actually four bytes below the address of the shellcode We want save evp to point here So that way when it does a pop evp It's going to move up here and then the ret is going to jump to whatever's above that Yeah, so could you make this easier for yourself by Do knops shellcode and then a bunch of addresses of shellcode so that your base pointer only needs to get somewhere in there Yes, we definitely do that But we need to first find this address this buffer, right? We need this address of the buffer Which makes sense, right? Just like when we do a stack overflow, we need the address of our shellcode We need to figure that out so we can jump to that code right So you can actually brute force this Just like with knops lids, I mean you can try a bunch of stuff and eventually it'll hopefully get it right You can also Try to find out use a debugger try to find out where the stack pointer is and try to find out values What do you have to keep in mind when you're doing this with the debugger? Yes, the debugger adds environment variables, so it's going to shift things right and you can still It gives you a pretty good target to hit for right and you can kind of adjust So you can look at the function you can see Uh, the function is here. We can set a breakpoint at this function and then we can Run it and then see in this case The stack pointer is at bfffc 60, right? So we can actually find the address of our buffer should be so the stack pointer right move down to make enough room for the variables So right at the stack pointer is i Right and then four above that is going to be should be the address of buffer Right, so we'll use uh bfffc 64 But now we want to know what's the address of the address of shellcode Why do we need to know this? Let's go back to our diagram Yeah, we need to know how to change evp to point here right So we So we need to actually determine what that last four bytes are Right and we're trying to be precise here, but how many tries are going to take you to try all possible values for one byte? 256 for those that brute force A sign of two how many tries do you have to try? A couple billion This 250 16 a lot more feasible Did we even do that by hand if you want to do so? But let's talk about how you would try to do this if you're trying to be very precise, right? So we're We need to determine those last Address of the shellcode right because we want to determine where we need to change Let's think about what we already know based on this example What do we know about ebp? from this example Is it going to be The ebp that we want it to be the address of the address of shellcode Do we know anything about it from this diagram? Yeah, so a it's right below it. So it's going to be what greater than less than? less than Less than greater than higher lower, right? So it's going to be less it's going to be Something that's going to be less than us, right? And it's just one of those things you can use the self-check. It's calculating this, right? Okay, so we want to first so we have the stack pointer, right? We have the address of buffer Then we want to we add 256 bytes To get to the very end of the buffer right That's pointing at the address of the address of shellcode But we want to subtract four bytes because we want to move down and get to this point here Right, we want to be four below where the shell address of the shellcode is because that's where we want to eventually execute But we first are always going to do a pop and then a wrap So we can actually just calculate this we can say, okay, it's probably going to be here So it's going to be this plus 256 up from the stack pointer Uh actually from 250 260 up right because it's the stack pointer plus this plus four minus four plus uh 256 So the nice thing is since we do know that we're going to be very close to evp to the saved evp Right, we know we can actually probably do this with just the one byte Right because we know save evp is going to point to somewhere up here Right somewhere above us on the stack No, hopefully it's not if it's too big then we maybe can't do it But in this case we know it'll probably be very close, right? So we probably know these first three bytes are going to be in the same ballpark. Yeah Yes, it would point it would point Uh essentially here. Yeah It'll be I guess on this example There'll be what four up for eip then four up for sm Which is what we said and then that should be where evp is so four and four eight. So it'll be eight bytes up Yeah, so this depends obviously right on the Size of main right because main is going to have local variables So what's the size of the local variables in main? Are they really large? Are they small? Okay Okay, so now we need to figure out where this is so we want Evp right that save evp to be the address of the after the shell code minus four Right you're going to take us down for Because the stack is going to be incremented when we do pop evp So from our example our calculation is 57 so we can calculate that to be 57 Right because we want to put the address of the shell code in there. So we need So this So right so this we just calculated what byte to overwrite So now we calculated exactly right here what this address is remember But we need to put something in for the address of shell code that we're going to jump to right So we're saying it's going to be you know 16 bytes down or whatever Whatever we calculate is going to be within that range right so is You know that's knowable right because we're passing in this All this value here, right So we know What we think the save evp is going to be and then so they address the shell code should be just 16 bytes below that And so in our case we'll use this example so Now so what we're going to do what the code is hopefully going to look like right needs to look like this Where we have knobs We have our shell code our shell code starts our shell code ends And then right above that we have the address of the shell code, right? This is so in a normal buffer overflow, right? This is what we would try to overflow evp with So that evp would start the save evp would start executing into our shell code Right, but we can't actually do that, but if we can change this Saved instruction save base pointer right So that bff fd 5c is here Now When main returns it's going to set the stack pointer here to be bff fd 5c It's going to pop evp and pop this last four bytes of the shell code into the base pointer And then it's going to do ret Bip Uh, sorry return, which is going to jump to this code which is going to jump down here and start executing this But you are having the assumption that nothing else is relating in this 5c I'm The assumption is that exactly at this address bff fd 5c or I guess the save evp Change the last byte to 5c is going to be this specific byte in my buffer If it's any other byte this whole thing is not going to work Right because we're going to put a different value in base pointer And then the base pointer of main is going to point somewhere completely different Cool so if we see this if we go back to our example now that we've overflowed the save base pointer Right now we move base pointer into stack pointer Right remember this is functions epilogue So now this instruction pointer just like the floor is going to point up to here We're going to pop evp Which is going to cause the stack pointer to move up one And the base pointer to hopefully point to right here, right? This this is our goal condition We want this to happen But no right here. We still have you know, this is the important thing right we have taking control of this function Right it's still when it calls return It's going to jump back into main by using the save instruct eip, which we haven't touched at all on the stack So it's going to do that. It's going to jump back into main now, right Function returns evp should point to the address of the address of shellcode minus four So that when main returns it's going to Set esp equal to where the base pointer is it's going to pop evp Which is going to increase the stack pointer up one and then when it does the ret it's then going to jump into our shellcode So this is the goal. So now we're in mains epilogue, right? So this is the key same steps different function So now we move the base pointer to the stack pointer. So usually when we do this right the stack pointer goes up Right because it's freeing memory But since we've corrupted and controlled the base pointer the stack pointer is actually going to move down Right the stack pointer is going to point right here And then we're going to do pop evp Which is then going to move this Shellcode into evp, which means evp is going to point to garbage. Does that crash our system? Why? Yeah, we haven't dereferenced it, right? We don't care about it. We haven't used it right now Exactly Now we do a ret and then where are we going to where's the program counter going to point to? The address of the shellcode, right? Which should be somewhere in here Well, put a little bit down, right and then it's going to start executing our shellcode And maybe it's hard to tell in this diagram, right? But we can see that we've actually So by doing this right when main returns now essentially you could see mains frame Main's frame is no longer up here as far as main is concerned, right? Main's frame is actually here Right because we've controlled the base pointer and we've essentially tricked main into thinking that its frame is farther down the stack Right at an arbitrary place. We can control and since we've saved the same instruction pointer is um Inside the frame, right? The frame defines where the save instruction pointer is If we control that frame is we can control where that saved where the code goes and executes So more sophisticated attack than standard buffer overflows, right? We have to be a bit more precise, but um I think it's really cool. Yeah, absolutely. Yes. Well, it needs to be somewhere in the processes memory. Yes Make it easier for ourselves You don't ever need a knob It's just to make things easier for yourself Because um, so you can think that with the knob that means this address of shellcode must be exactly byte precise right And the same thing The way we have it now, right by overriding this byte. We have got to Having the save base pointer point here. Otherwise everything fails right, but We could actually add a couple of address of shell codes here to then make it so that we only have to get anywhere in here Right, that would be helpful. Um So yeah, that would be one thing to do, especially in this example is put your shell code in the environment somewhere Right, which is where you know what you've been doing with the other Hopefully some other stuff, right? So you kind of know that it's going to be up here somewhere Then in the buffer have the buffer be the address of that shell code everywhere Right, then this should be very easy and you just need to guess the address of the shell code cool Okay, so how do we fix this? Use a different language. What language are you going to use that doesn't have c at the bottom? Ah c plus plus is it what c plus plus? It's just the same thing. You could have the same example and c plus plus A range base for loop. Does it work on arrays like like buffers like this? But how does it know the size of this? Uh for instance Yeah, how does it know the size of sm in this case, right? It's just a pointer Ah man, we covered a lot Yeah, right, so Okay, c plus plus was not a big example. I was looking for It's a java java, right would be an example, but still what's the java jvm written in? See right doing the same stuff under the hood Okay, where are we? Okay, what else? Is it going to cause a security problem though? Is are you going to allow you to control the x what happened if you access an element outside the bounds of the And you get an exception right in the program term where in this case the program doesn't terminate just overwrite the memory You can't Overwrite arbitrary memory in a java program because it's checking the right bounds you mean arbitrary Oh, yeah, yeah, that would be well that would give you a little bit that would help definitely off by one You could even just add some padding right between the local variables and the stack That way you're protected from off by ones maybe add a bit more so it's off by one that's Depending on the size of your off by one, but yeah, that's kind of only your Yeah, it's exactly. Okay. So you've got to thoroughly check loops Right, the problem is so you can control that loop iteration count right in this case It was hard coded it was hard coded incorrectly Right, but if we control that loop cap, we can get it to overwrite. So yeah as we saw we can do crashes We can cause the program to We can cause arbitrary code execution all kinds of bad stuff All right, so let's stop here I will not be here on monday sigh stand up raise your hand Sai is going to be proctoring and probably some other people as well since there's a lot of people in this class, so Uh, good luck