 All right folks, let's get started. Let's see your questions. That's not good. Maybe you found something good. The same shoes. Make sure that everybody walk out of here on Monday with only socks. The lecturer was not good at removing some of these shoes off. Was that painful? That painful? That's also good. I'll also accept that. If you're skinny, you're all right out of your shoes. There you are. Okay, so we're talking about a lot to cover. I think we'll be able to get through most of the stuff in this section. Probably today, maybe Monday. So I want to keep going where we were at. So we were talking about format string vulnerability. So what is the essence of a format string vulnerability? Sailor. Basically like overloading the perimeter of the ocean. More specifically. When do you know a print pad vulnerability can occur or exist in a user code? Format string is supposed to be specified by the user. Whenever a user input can influence or control any of the value of the inside of the format string, fundamentally at that point you can then overload the printout function by changing that format string to make the function think that more arguments are popped up the stack than actually are. So to refresh our memories, we are looking at a simple vulnerable program which has an int main. It opens a file called temp log. It then passes that to a function called add log, which has a buffer of a line of 65, I believe, thousand bytes, which then has local variables int, int, ion, result, and there's a while one, and basically read one byte from the file or from zero. So what's zero? Standard input. So read one byte from standard input into this line buffer. Then if the result is zero, is zero exit, which means that we're end of file, otherwise increment i. If we've reached the end of the buffer, then exit, and if the last thing we read was a new line, then exit this loop as well. So this will read in until the end of the file or against the new line character will keep just reading in bytes. So custom input routine, we went through this, and if you step through this, you can guarantee that there's no possible overflow. The most number of bytes that will be read is 65536, which is the size of the buffer, which means there's no overflow and no off-by-one errors, we hope. But then we get to this point where we make sure F print F, and we're passing in F, the file which was open in main of temp log, and we're passing in line, which we just read in from the input. This is a standard thing that we would write, but just write out that input we got into the log file, because we want to store the logs for later analysis. But here, the problem is that where does the bytes in line come from? Standard input, where does standard input come from? User, so the user can put whatever bytes they want, including percent end, percent exit, percent whatever. So, we demonstrated this with an input where we passed into the program four As, four Bs, four Cs, four Ds, followed by eight percent Ps, and we saw that it actually, well, an output four As, four Bs, four Cs, four Ds, which is exactly what a print F does when it's going through a format string, and it sees A, A, A, B, B, C, C, C. But then when it got to the first percent D, it printed out OX1. What is this OX1? The value of I, yeah, we drew the stack, and we looked and saw that now those percent Ps are essentially reading values off the stack starting, what was that, I believe, at EBP plus 12, because it's the F, they have the F parameter in the line, so it's at EBP plus 8, 12, 16, at EBP plus 18, 16, sorry, from the perspective of the F print F function. So it's when this F print F is a whole, so it's passed to it as F in line. So basically all of those stack values above where line is pushed onto the stack are being read out. So we saw the X1, which we saw is the int i on the stack. So what's this next thing? What's this? X? 41, 41, 41, 41, 41. That's four capital A's. But what is that? That's the start of the line buffer on the stack, because we know we just copied four A's onto there. And then above that we copied four B's and then four C's. And so when print F is printing up the stack, the second percent P gives us 41, 41, 41, 41, 41, 41. The second one gives 42, 42, 42, which is capital B, four capital B's. The next one is four C's, then four D's. And then we get to 70, 25, 70, 25, which, if we need to do that, would be percent P. So we're actually reading from our string here. And so you can test this to look at that. So this means that we essentially control the bytes at which, how many percent P's? How many bytes of, how many percent P's of the stack do we start controlling those bytes that is printed by the format string? So do we control that first percent P output? Our name is I, which is the number of lines, I believe. But, you know, whatever. But that's hard to control another. What about the next percent P? So we can completely control it. If we change those four A's to whatever we want, we could put whatever value we want there on the stack. What values can't we put on the stack? So, yeah, we can't, we may actually, if we go back. I believe we could, I think Reed will read in null bytes. So we could put null bytes in there. What can't we put? New line. New line. The new line character is going to break. So we can't have new line characters in there. Are there any other restrictions? So we're going to change, we can completely control those four bytes. So what would happen if I change the second percent P to a percent N? What would happen? Write to whatever the address would be. Yeah, so in this example, if I just change the second, if I did, instead of this percent P times A, I did percent P and then percent N, what's going to happen? Yeah, how many is it going to write? So it's going to write, there's 16, four A's, four B's, four C's, four D's, plus zero X1, so an additional three. And then it's going to write out to memory address 41, 41, 41, 41, which is probably going to do what? Seq fault. Seq fault, because that memory location is not allocated to our program. So would we give up, go home? No. What would we do? Find the letters we want to write. Yeah, let's put an address on there, right? We can change those four A's to be whatever bytes we want. The question is, okay, so now we can, we can put whatever address we want, but the question is, then what do we want to overwrite? So what are we used to overriding on a buffer at your flow? The save VIP. Right? The save VIP, do you know exactly the address of the save VIP you're overriding? Do you need to know that or to overwrite it? No, why not? You mean the location of the EAP? Yes. I mean, what is the exact memory location? So for instance, if you want to overwrite the save VIP, what's the do log function that we had, what would you change these four A's to to overwrite that value? And do you have to think about that when doing buffer overflows? Buffer overflows are relative, right? They start at a fixed memory location of the buffer and they go up, so it's a relative offset. You need to know what value to overwrite to go to your shellcode, but fundamentally it's a relative offset. Like here, is this a relative right? Well, it's absolutely just going to act right to whatever memory location we put in for those four A's. It will see whatever rights we want to choose. So what do we want to overwrite? We want to go back here and try to guess what the save VIP is on the stack of add log. How correct do we have to be? Like 100% correct. We're going to overwrite exactly those four bytes as they exist on the stack and stack to that memory location that they are. As we know, we're not dealing with ASLR on our thing, so we could do that, but if anything changes, right? Whereas when we're doing our shellcode, we do have to write the address on our shellcode with an op sled, we have more of a leeway, right? We can give ourselves additional space with an op sled so we don't have to be quite precise in what we overwrite. Sorry, the value that we overwrite on EIP. So then the question is, what then can we overwrite? Well, we talked about several things, and one thing that we can do is we know that the global offset table in the program contains the addresses of all the locations of all the functions used in libc or any other libraries from that code. So we can use read-elf, the read-elf program with dash-reloads, I think object-down, because that's something similar to use dash-slur, sorry, I don't remember. So we can look at the relocation table that will print us out the global offset table. So this will say, if you do that, you will have, and you can actually get really in deep of exactly what everything on this table means. I don't still quite remember everything, but essentially the way to read this is it says the read function. So actually, let's look at this. Actually, I want to, I wish I had this example. I can't have this example. All right, we are going to, I'm going to do a live demo, which is definitely going to work. Let's see. All right, so this is the disassembly of that compiled program, the format symbol. What does G mean to you? It's because I'm running on the map, and I believe the original object of it has this four mock binaries or something. You have installed GNU object down, so that's what the G stands for. So I think it's the home-grew thing that I'm using. That is a trick too. No, no tricks. There's everything that you can do on the server, I promise. Okay, so if we look, so we can go to the C code, and we can see that, let's say there's this call to F printf. So if we look at this assembly, and we see where is this call printf, we can see that inside the add log function, right, you're getting very good at looking at disassembly code now. It's almost becoming to be a second language to you. I understand and sympathize. So we're calling this function, but when we look, the call is call80483BC. We've just really jived with what I just told you when I said that the library is dynamically loaded, so does the loader know to put the printf function, F printf function at 80483BC? That would be a little bit brittle if printf changed, but if there's not space for that, that's something that's already allocated there. So what is actually there? If we look, there's actually, so there's a section of the Elf header. If you look at the PLT, I believe it's the process linking table. Essentially what it does, so what's the very first instruction here? So what's this instruction? The instruction at 80483BC says jump star hex 80497E0. What is that? So jump to that address. De-reference that memory location. So take those four bytes that are at 80497E0 and jump to them and start executing. So that's a G. Ah, this is a G, we don't forget. Good. What did I say if that magic command was a reload? Yeah. So I believe this is the exact same code. This is the binary that I took this from. If we look at the relocation table, we can see that F print F, so these are the global offset table at F print F at 080497E0, which was exactly where we saw that it's jumping to. That's in the global offset table, which means essentially, so at run time, what's going to happen here is at first there'll be a dummy address in there that actually calls into the dynamic linker and says link me into the C of the F print F function and put the result at 80497E0. And then the next time it calls at 80497E0 will be the memory address, the F print F function, which is awesome. And we can see it's exactly, so this when we talked about ways to divert control flow, we talked about a return function implicitly returns control to whatever the stack pointer is currently pointing to. Every time you call one of these dynamically linked functions, it's fetching whatever is acting global offset table at that memory location and jumping to that. So if you can change the value that's inside memory location 80497E0, that will be jumped to when there's a call to F print F. That make sense? The question is, so looking back at this, so looking back in the C code, what function would you like to overwrite? Let's say you could overwrite any function, any libc function, because you can't overwrite ad log or main. What would you overwrite? F close. Why F close? Because it's after ad log. Yeah, why not? F's open. It's when the exploit happens after it. Exactly, the overwrite happens after. So if you think about, is it ever possible for F open to be called after this F print F in this program? Is there any possible execution path where that can happen? No, it's fundamentally impossible. So that would be, even if we could completely change the value in F opens global offset table, it gets us literally nothing. But if we change F close, that gets executed immediately after ad log. So inside ad log, we have this while loop, we have an F print F, printing out F in the line, and then ad log returns, the only other function that gets executed is this F close function. So that's the function we want to target. And so how do we go about doing this? Well, we can look exactly what I showed you here. So the code again for F close and the PLT in the process linking table, it's at 0804978, so that's our target. We can change those four bytes in 0804978, then we will be able to redirect the control flow to whatever we want, and so if we can put the address of our shellcode there, we've got everything we need. And it's really that simple, except for all the pieces to do that. So we can first, so we have a percent P times 8, we know the second argument gets us to our first AAAA, so we can replace that with this is why we looked at all those esoteric print F things and how to do exactly a positional argument. So here if we do percent 2 dollar sign P, and why did I have to put a slash before this percent, before this dollar sign P? Yeah, staking it in bash, so protecting it from bash. So to Python it gets a percent 2 dollar sign P, and that's what we want to pass into the program. So if we out, so what should this input that we're passing through the program do? It should print, so this is really important, this is part of the scientific process of how you go about explaining these things. You think, okay, I want to get some input based on my knowledge of the program, what should be output B? You want to do that before you write it up, just like throwing great stuff to see what happens. And then you get a result, and you update your mental model to see whether that's correct or not. So what's the output going to be? What is it going to be? What is it going to be? It'll be the A, it'll give our A, B, C, C, and then it'll give us the O, X, 41, 41, 41, 41. It should, yes. Right, so it's always going to do the first 16 bytes of our input string. So it's going to do the four A's, the four B's, the four C's, and the four D's. And because we changed it to the second positional argument, and we know based on our previous experiment that the second positional argument is where our A's are, it's going to be X, 41, 41, 41, 41. So let's say we wanted to, so now that we've verified this, so now, what, and now we know if we change that P to an N program. Right, because we're trying to write to 41, 41, 41. Now what if we, so one thing, so what we want to do, and anytime you're doing this that thing, you want to build it up in this set. Right, so right now, now we want to be able to, eventually we want to overwrite that value that we just looked at, the 080497D8. This is the thing that we want to overwrite. So now we want to change all those A's to 0804 97D8. So how do we change these four A's to do that? Yes, hexadecimal in reverse order, right? This is why you guys have to do actual buffer overflows and stuff. So it's D8, 97, 0408. So it's going to be, so we do that and we change the, we'll change the P to an X to print it out in hex. So why are we doing this set? Make sure that we put the address in correctly because the X is going to interpret that value as hex. And it's going to print this out. And it should print this out again. It won't print out four A's this time. It's going to print out D8, 97, 0408. And then four B's, four C's, four D's. And then it should print out 0804 97D8. So that's what we're thinking is going to happen. And we do this. We see that's exactly what happened. So this is the garbage values that it's printing out of the address. And then 0804 97D8. So then, what do we think we change that P in the format matrix to an N? What's going to happen? Write 16 bytes to the address. It's going to write, yeah, it'll write it'll change the value of the global offset table to 16. So what should happen? So should we get a second fault in printf? No. Why not? Because it's still within the required character recovery, right? Exactly. And if we looked at the ELF header section we could see that this memory address is writable in this program. So we can write to that memory address and change that value. So there's an important distinction. It will crash but it should not crash in fprintf because it try to access that memory. It should crash when it calls fprintf. Why didn't this crash? Good. Oh, it does crash. Okay, good. Why does that say that? Alright. But now we can test it. So you can, this is trying to help you get used to doing this. So we can put our output to a file, use gv, run it with the input test. We can see that we get a set fault and we can see that the error here, the EIP is hex 10, hex 7 is hex 16. Which is the value that we wrote with the percent n into the GOT table, which when fprintf was called became EIP. So here, now we have our goal of we're changing EIP to what we want but we don't want it to be 16. What do we want to be? Address of our shellcode, right? So, but what are some of the addresses roughly of some shellcode that you're using? f, f, f, f d, I don't know, 0, 0 or something, right? So, is that a large value or a small value? It's a large, it's a very large value. It's so large it's negative probably, right? If it's outside the integer. And so, how do we get this 16? Yeah, so this is the amount of bytes that were written out. So why don't we write out f, f, f, f, f, f, f, f, d, e, d, 0, 0 bytes? Field width. Field width, we can say. Field width. I can't hear. Field width. Field width? Yeah, we're not there yet. But why can't, why can't, can we do that? I mean we, we saw the field width, yeah, so there's a way that we can control the output. So why don't we say hey, print out a field width here before the percent again, of hex, f, f, f, f, f, f, d, 0, whatever the address threshold code is, minus 16, because we already wrote out 16 bytes for those first, the a's, the b's, the c's, and the d's. I'm using the percent h, and I think I can read the card speed. Well, I'm asking, well, what happened if you did that? Can you do that? I thought you were having a property of 60. I do, but who's doing the writing? So let's say, so we saw there's a way to zero pad or to space pad a number, and you can actually put an arbitrary number there. So why not say, hey, output me a number that has f, f, f, f, f, e, 0, 1 trailing spaces or leading spaces. So it's not, so if we go here, it's not going to overflow our buffer because there's nothing to do. Our format string still exists. It's in that same buffer. It's only going to add some characters to do this. How big is the temp log going to be if we do that? Where are those bytes going that we're printing out? We're calling fprint depth, not print depth, so where are they going? Into the file, exactly. So this would mean that we would need to print out f, f, f, f, let's just let's get the calculator so we can see let's say something like this f, f, f, f, f, f, d, 0, 1. So that is let's see. Yes, a very big number. What is it? 4.2? Is it billion or trillion? It's a very large number. If you think about this many bytes, so you can, somebody can google this, how many bytes is this in gigabytes? It's going to be a lot. Just for one attempt. So you actually, if there's enough storage space, you can do that. But it's not advisable because of all the problems that we just talked about, right? It's really hard to test something that takes multiple 4 gigabytes of data for every test you want to take. But we saw, so the thing is when we do the percent to dollar sign n, how many bytes are we overwriting? What was the value in the ID of the box at the table? Address, right? It's a four byte address. We've got to be four bytes in there. It's 0, 0, 0, 0, 16. So we changed four bytes because the percent n, when you use it in a printf, we saw it takes in a parameter at the instar. So it's going to write out an integer which is four bytes. But that's a lot of bytes to control, right? Four bytes. But we saw that there are a nice lot of buyers we can use hh to write out as the number of characters to a character pointer to just change a single byte. So the field width, so with this one, percent 200x will pad whatever that value is with 200 space characters. So that's already what we talked about of the percent, the field width that we talked about. So you can put, you know, whatever, you can put 4, 49 billion or whatever, and we'll actually do it. I've kind of done that before and it's super weird, but it kind of works. Yeah, so if our, okay, good, I already had this in here. See, look at this, what you do. Math in advance, not in front of the class. So if our shell code is that let's say ff, ffcaf5 that's 4.2 gigabytes of data, you could actually do this and this would work, but we don't want to do that. So what we want to do, since we know we can use hhn percent hhn to write out a single byte of the values that we've written so far, we can just write each byte of fprintf changing in between there the number of characters we've written so far and we'll see for that it's very nice about it overflows, so it keeps track of the number of integers and we'll only write the number of hhn, it's only the least significant bytes of characters that we've written so far. So, we can easily do this, so we can so now we need to do math and this is where everything is very precise because we need to write the exact number of bytes but we control how many bytes are written it doesn't change based on the program of execution so we already know that 16 bytes were written so far so how many so we need some kind of percent something x of number of characters to output to get us to something that ends in ff because that's the first byte we want to write out so then what do we how many what's that percent something x wait, is that again? 255 minus 16 ff minus 16 so we only need one byte so we only need so we've already had 16 bytes so if you think about put yourself in printf shoes you're keeping track of how many bytes have been output right 100% n we know 16 bytes of an output but we really want that value to be ff so we need to go from 16 to ff we take that difference which is ef we convert that into decimal and we get 239 so if we do a percent 239x or whatever I don't think in this case it doesn't matter too much and then the percent two dollar sign hhn the small character n we will change a single byte to be ff so let's look at this so we have 0804978 b's, c's, d's percent 239 so now when printf is going through you have to put yourself in the mind of the printf function when you get to the percent two dollar sign hhn there should be 255 bytes inside of that output at that point yes and you will write that to the second positional argument which is the memory address 804978 that's right but the least significant byte right you tell me so what do we expect to have happen all of the zeros are ff in the end yeah so we're going to change well this is part of the problem is we're going to change one of the bytes the byte that is to ff so we will probably cause a crash here if we're changing a byte because it used to jump to f close but now it's going to jump to some random thing so we can gdb run it we'll get a signal illegal instruction so we'll see that it's actually received an illegal instruction at 80483 ff so we see that we actually overwrote the least significant byte so which one's then the most significant byte what's the memory address in the most significant byte 8b 8b d8 plus 3 I don't know, hex math is weird yeah is it db okay I believe it so if we change that to db then we should change we should be able to run this exact same thing and see that the error is the illegal instruction or actually I won't say a legal instruction it'll be a seg fault because it tried to fetch ff0483 ff or whatever this least significant byte was so yeah so now we can you can see that we've changed ff048382 and so now and basically we can just build up this process and we want to eventually write out ff ffcaf5 so if we actually have something very nice we can write out ff and do we need to output any more characters no because we're already at ff and if we output any more we'll roll over so the next one can be but which positional argument do we want to do 3 which is going to be the 4b's that we have so this is why we started with doing 4a's, 4b's, 4c's, 4d's because we're going to change 4 bytes in the program and we're going to need 4 memory locations 4 memory addresses on the stack in order to do that so if you're super clever or feeling very crazy, you can order these writes in a way that you never have to overflow you can only increase that's weird I mean you can totally do that but you'll just have to be like ok this one is this byte and this byte we're writing over bytes anyways I just do it byte by byte don't worry about it too much so we can do that here so now we can change the second so all of the b's we can change to 080497dA which is going to be the second most significant byte because it's one less than the most significant byte that we've just calculated at db so this is at dA and we have now a percent h, h, n sorry percent 3 dollar sign h, h, n your positional argument we know is all of the b's and write out to that to that byte and if we do that we see that we change the address to ff, ffba, 4b and then we change the c's so we need to output from ff to ca for the next byte so how many how many characters do we now need to output with another percent something x xc plus 1 when we use a 1 to bring us back to 0 then we need to so we need so it's going to wrap around so we need one more to wrap us around to essentially you can think of the internal counter will be 0100 so if we wrote that out of the character as the number of bytes it will just tell you 00 so from there we need to increment that to ca so we'll need c1 plus ca which is 203 so then we can change this to after our percent 3 dollar sign hhn percent 203 x and then a percent now we're getting the fourth positional argument because this is going to be the all of the c's 080497d9 and actually when I read this it worked, why? yes because I have a big knot sled so the value that was already in there we actually know from this page the value of 4b just happened to be inside my knot sled so ff ff what was my target? yeah, instead of f5 whatever that happened to be pointed to my shellcode and it just worked the shellcode no so sum it's there you're already knowing how there was a check after that I had to check shellcode and find out the addresses of the shellcode so using this technique this is what I mentioned with the scalpel you're changing 4 bytes in the program and are completely changing the execution here diverting the control flow you won't have to do this here but in many cases you may have to use a printf or ability that you mentioned to leak data because you may not know the memory layout may be random but if you can leak a pointer through printf because you can print values off the sack then you can use that to calculate the offset or whatever you want and then you can know what values to write but anyways very cool and this vulnerability actually comes up in a lot of real world software a lot of the time so there was a this is great this locale program you could pass in a value that it would do the similar thing or write into a log or whatever to equally pass through it with fprintf and it would trigger a buffer overflow or a format strength vulnerability so what how do we correct this we're writing software we want to use printf do I scare you away from using printf maybe how do you realize the true complexity of this beast that you're using it's much more complicated than you thought but it is nice to print out numbers and stuff so you want to still use it how do you do that never let the user specify the format strength because this game you can never have user input that's output from a printf yes user percent s you can pass in as a parameter the character pointer of the user's input although you will need to be careful that you no terminated their input because it is possible printf will keep printing out bytes until it hits a percent zero sorry got a percent zero but no bytes so it's actually possible sometimes to leak data from the program to the password or something if you can create a buffer that's not no terminated so you do need to be careful but fundamentally you will completely prevent printf vulnerabilities if you never always constant assurance think about it printf if you look at it, it's got to have a constant assurance no user input to a printf ever yeah so printf buff bad printf percent s buff good even if you're passing parameters this is another trick right this is what we saw even if you're passing parameters as part of the format strength if they can control the buffer and the format strength they can clearly keep getting values on there cool so now we start to level up the protection mechanism so we looked at various types of memory correction and ways that an adversary can arbitrarily change memory in our program so prevention is easy just write a better code and I think in the early history of security I think people honestly believe that they could do this that you just you teach people, you train them about all these vulnerabilities, all these problems and magically everything goes away and gets fixed and is fixed why do I believe this is impossible I think sometimes you write a program or a tool that writes it think about the code think about any piece of code that you've written in the last five or ten years did you write every single line of code that was executed as part of that does anyone think that they did yeah so even if you wrote every single line of code in your C code or your C++ or whatever or your java code you didn't write the JVM that's interpreting your java byte code you didn't write the C code you didn't write all of the function calls in the kernel that the application is calling into you're using neverthing you can write in the that code even if you wrote it in assembler you didn't even rely on a compiler to compile it you still have a lot of abstraction layers and then once you write stuff from scratch you're much more likely to implement a vulnerability yourself when you're writing a library than if you use a well-tested library but that still doesn't preclude some kind of vulnerability in that library so it's pretty much impossible to do this I will say you can prevent some memory corruptions by you know, using a language like Python do you ever worry about popular downloads in Python or in Java no, even if the language takes care of that it does take care of that but like I mentioned your interpreter is written in C and so you can still have memory corruption vulnerabilities so for instance javascript can you have a buffer overflow in javascript people who've programmed javascript no, it's fundamentally impossible the language does not allow you to do that however, it's still possible for you to have a browser visit a website and download javascript that takes advantage of a vulnerability in the javascript nj which is written in C to leak values and to it's probably more a key style vulnerabilities and other kinds of stuff but anyways, you can get arbitrary code execution in the browser from javascript that you downloaded and run and this happens all the time just check any CDEs related to related to browsers you can try performing static analysis you can try analyzing these things to try to see develop a program that will tell you if something has a vulnerability or not so actually I will so the key problem though is you've heard of the halting problem hopefully if you're trying to students okay, quickly do a look on your phone later halting problem means that it's impossible wow, I mean there's very much of this I mean it's possible to write a program that can tell if another program halts or terminates a lot of given input but it turns out that statically analyzing a piece of code for all memory correction vulnerabilities is a quick one to the halting problem in that if you can write that checker, you can use that to solve the halting problem which means you cannot write a perfect static analysis tool that can find all vulnerabilities in your program and never make any mistakes ugh so depressing you can make exploitation harder and that's really the I mean it's kind of a security kind of defense in depth strategy where you just make so one of the things we talked about is we've been saying that you know the address, why do you know the address of your shell node? you can debug it and do what? and look at the memory addresses, it has simple table loaded and it has and then you run it again so why is that information valid? it's it doesn't change it doesn't have XMR it doesn't change each time it's static and fundamentally your stack well it cuts it right so your stack location is more or less fixed we talked about it actually gets moved based on data and your environment it gets copied into the program and the rp parameters that also get copied into your program but does a program like do you have the right code that does fixed absolute values on the stack? what are all of your stack operations and the code that gets generated? well A you never really be able to stack yourself but in the x86 code that's generated does it need to know that the first location of main will be in memory address but C A because fundamentally a stack is froze down, shrinks up and everything's all relevant we set function pointers dynamic data runtime, first it's not function pointers but base pointers we do offsets of base pointers for parameters, positive offsets for parameters, negative parameters for local variables so the idea that came up with pretty early on is what if you shift the stack around every time the program is going to execute set the stack at a different location which makes your job harder because that needs to know where you go to get that code we can try detecting when these things happen so this is more the intrusion detection approach we can try finding out if our program is under attack turns out there's a lot of research on this it's very difficult very very difficult but in the exploitation harder this was the approach and it became essentially a cat-and-mouse game between attackers and defenders where attackers developed remote buffer overflows that rung shell thrown on the stack and started executing it and so defenders knew new techniques about what if we change the address of the stack every time the program executes another one is why does the stack need to be executable at all are there any programs that need to execute of things on this map library library calls library calls are loaded into a code segment in memory so they'll get their own executable code segment just like the program does but they don't have it on their own stack they share it with you interpreters, why would they need to do that so interpreters like the JVM interpreters on a bytecode when it detects a hotspot it compiles that to native code x86 code and executes it where does it do that it has to dynamically create code where does that code come from it has to be in memory somewhere either on the stack or on the heap and it needs to be executable so actually there are programs that need executable stacks but 9 times out of 10 most programs do not so this was kind of an easy technique of just hey let's probably do the stack executable if you need that you can change the compiler flag to allow that so this is called NX where it's also called unwriteable or XOR executable so a page in memory can be either writeable or executable but it can never be both at the same time and this actually is so the NX bit marks memory areas as non executable so this way you can say that hey the stack retain is not executable this way if you try to jump to show code on a stack what happens yeah it says sorry it's just like a send fault trying to access memory that is not allocated if you try to write to memory that's not writeable like the text segment you get a send fault so all different kinds of names for this because people you know this what happens when you develop technologies DEP is Microsoft's name NX there's WX or X writeable or executable so the idea is you never have a memory at the same time but like we just talked about applications may either need this stack to be executable or they may allocate a page of memory they get writeable write x86 code to it and then change it to executable and start executing it which is exactly what a JIT interpreter does and this is exactly how exploits against JVMs and browsers work as they take advantage of this functionality so it still doesn't prevent, protect anything even here and so I don't know I should probably it's like I think somebody needs to do like to look at like how long these timelines take when you develop this defensive feature and you think like this is also a lot of work you have to change the kernel, you have to change hardware features you have to all support this functionality probably they say it's slower if you're doing extra work that you weren't doing before and so you're a bad guy right you still want to break things and hack things you can, does this prevent you from overflowing buffer in a stack what's the memory protections now in the stack? navigation read values on the stack can they execute on the stack can they write? yeah so EIP, EDP are both the same still on the stack you can you can run it off or overflow it overflow those values the question is what are you going to redirect control it to any ideas? yes we're going to look at the future we're taking a step forward into the future the stack is now not executable we still have a problem with those do we do the libc functions? why? because if you pass a parameter it executes on its own stack right yeah so the general idea is well hey so think about it what were we doing with shellcode what was the point of our shellcode right so we wanted to call exec with the proper parameters of NSH well why do we have to why do we have to inject it into the process? so then it directs execute as it is and so you can think of it like we're trying to put our own instructions into the program our own x86 instructions into the program's memory and we want it to start executing there we can still divert control flow because we can control EIPs and EVPs on the stack we just can't directly inject instructions but have you looked at how many programs are? there's a heck of a lot of code that is executable in a program right all of their text segment is executable and the libraries that get loaded into the program are also executable and libraries contain great functions such as system right, if we can call systems.nsh that gets us exactly what we want or we can call popen or we can maybe we can use system.caf the file out or something we don't even need that so the first kind of iteration of this idea was this returning to libc so the idea that we can when our function returns rather than so remember when we control the stack we control the save EIP which controls where this function returns to and so fundamentally there's a lot of fun functions in libc so why not return to those functions and have them do what we want them to do so let's diagram this actually let's get to code first and then we'll diagram so we can basically call so if we think about it jumping we can actually call we can put the address and we saw that the text segment of the program doesn't change right the memory locations are more or less fixed so we can actually jump to any function that the program has itself so if there's an admin functionality or a function that says give us a flag we can just jump to that right otherwise we can maybe jump into any of the libc functions so we can jump into the system we can even do complicated things so there's libc calls to change the memory protections of various pages we can actually jump to a function to make the shell code our stack executable and then jump to that or maybe not the stack maybe some other data section now the difficulty is so now we just need to know the address of system where is system loaded by the loader our program is not already so we can look so let's look at a program so we have include string.h we have main a character buffer of size 50 string copy of rv1 onto foo and then return 10 so main we have a standard pushevp move the stack pointer into evp subtract 3c from est move evp plus c into eax add 4 to eax dereference eax move that into eax move eax onto esp plus 4 load effective address ebp minus 32 eax load effective address ebp minus 32 eax here yeah so this is our buffer foo right because it's moving that from eax onto the stack so it's setting up all the parameters to call string copy and then it's going to call string copy what is this actually calling so it's calling 80482p0 is this where string copy is going to be loaded what is it that's our flt i expect to use the word trampoline that's the other way they use to call it it's just a little bit of code that grabs the values and will loss that table and jumps to it so it's going to jump to the flt trampoline for string copy we tend to eax leave return pretty simple we can do this if you look very closely at these options we got rid of the dash executable stack option which is good we're getting rid of more and more of these protection mechanisms it's the dash of no stack we'll get to there later so if we think of what we want and it all comes back to drawing the stack so this is again why i keep harping on that so we can draw the stack pointer so main is executing so ebp points to here what is ebp currently point to on the stack for main what is ebp point to when main is executing let's say like right before this call the string copy save dvp right save dvp above that save eip above that argc above that argv pointer pointer above that yeah envp the environment pointer even though we don't use it it always is passed to main anyways alright then we're at this call instruction of call string copy so how far down from the ebp is the stack pointer right here this right before this call 80482d0 50 i mean you can say in hex when you all whisper it's really difficult to even hear if you're close to being correct which is probably your plan there what was it minus 32 no hex 3c yes it's this option so you have to go through all of them to see that we're not actually changing the stack pointer except for that location right there right so we're subtracting 3c from esp after we move the stack pointer into the base pointer so the distance between ebp and esp should be hex 3c which just for fun is 60 okay cool so 60 bytes between those two and then what is directly at esp on the stack of esp address of the buffer address of the buffer so where's the buffer at where on the stack 50 bytes 50 bytes so 32 hex below ebp which is 10 bytes which is 10 bytes above esp but we know so we can point to what's called foo so we know that between ebp and foo there's 50 bytes and i mean we can continue drawing the stack this is the address of foo and this is rv1 which is a character pointer so that's going to point somewhere up here and so we do that so then once we call string copy when now rv1 is now copied onto the buffer how many bytes from the starting buffer to the same base pointer so how many bytes do you need to reach the same ebp same ebp 50 we'll say 50 51 is you will overwrite the first byte of ebp but fundamentally you need let's say 50 a's to fill up all of the 50 bytes between foo and ebp on the stack and we know this specifically because it's load effective address ebp-32 into eax and pushing that on the stack so it's that is what tells us not the c code the c code is actually this option of n preferred stack number equals 2 means that it doesn't add a lot of padding to the stack so it's going to be almost precisely what we have so 50 bytes will get us right to ebp the next 4 bytes will overwrite saved ebp all good this is all normal stuff repeat that one more time yes so we know from looking at the assembly code that foo compile into load effective address ebp-32 hex so which is 50 so we know there's 50 bytes between where foo is to the start of the saved ebp on the stack so we need so we wanted to let's say control eip we first need 50 a's to get fill up the stack foo right before the save ebp we need let's say 4 b's to overflow and change save ebp and then the next 4 bytes of our rv1 will overflow save eip this is the first part so but our goal now is so now before we used to put the address of our shell code and overrode save eip can we do that anymore no we can't do that anymore because we can't execute on the stack we will get a overflow but what we really want to do is try to call what system system we really want to call system so let's say so we overflow with 50 a's 4 b's and then we'll say we'll see how to find the address of system are we done we need to actually put on the stack the arguments of system so now we need to so this is what gets kind of tricky because you need to think about the stack in two different ways there's what we're overflowing and what was currently there and then now we need to think about this so now after this call the string copy right we've overflowed back we've clobbered 50 bytes we've clobbered save eip we've placed the address of system on save eip now we move 10 into eax we do a leave and then a return so a leave is going to move the stack back up to esp we'll point here eip whatever value we clobbered onto the stack let's say 4 b's and then a return what about this and then the return will then pop 4 more bytes off the stack and now the eip will be the address of system so from and we've done this many times so this is nothing so from systems perspective right if you are the system function you just get called with the stack pointer here what is so write the very first byte of system what does it think is currently at the stack pointer yes the save eip of whoever called it and then what's the first thing that the prolog of every function does push ebp which moves the stack pointer down esp then sets up the new base pointer to point there ebp will point to here and then it will subtract whatever space now when it tries to access so system takes how many arguments one one how is it going to address where is it going to try to find that first argument ebp plus ebp plus what 8 ebp plus 8 always 8 right that's any function it doesn't matter so ebp plus 8 will be here so this is what is what's it called command so if we want to properly set up so if we want to properly set up a overflow to properly return to libc we need to construct this state function frame specifically for system or whatever function we're calling so we need to first get to with our overflow to the saved eip we overflow saved eip with the address of system and then what are the next four bytes the saved eip of wherever we want system to go to whenever it's done executing so if we don't care where system goes if we want to call system binsh and just get a shell and we can put junk there we'll actually see by actually chaining function calls so when system returns it goes to another function that we choose and that goes to another function all with parameters that we choose so we can basically create a whole series of fake system not system but fake function calls to do whatever we want but that has to be done very precisely which clearly we'll get to on Monday but so we overwrite the address of system we overwrite four bytes with the saved eip of system and then what are the next four bytes yeah so then we have to do four bytes that point to the string binsh so we need to then because that's the character pointer of command because so when we think about it so you have to kind of overlay these two stacks you're trying to make the stack on the right of saved eip and then command but because that's what system thinks should be in its function frame and then if we go back to the slides so we can the second four bytes so the address of system then the next four bytes are the saved eip of wherever system returns to so that's when system calls ret that's where it's going to go execute next so the four bytes of that we want to point to the string binsh so we can look at this example we can do read-elf to look at the stack and we can see that the stack is readable writeable so there's no executable stack so this is if you run this command on the programs on the server you'll see that the stacks are executable because that's how we're learning how to do those we can gdb this we can breakpoint we can run it and we can print out the address of system so that when we run this we can see that systems at b7 e6 6310 we can then do we can cat out the proc memory so we can use the proc memory maps to see this is actually what we looked at before but we can do that to look at this process that's being debugged and figure out where c-2.19.so is the libc binary where that is and we can see that the executable memory so there's one memory page in here that's readable and executable so the address of system is in size there and super cool thing so when you call system we actually did this for your very first project for doing the web service one of the semantics of system it's execute your command exactly how I can speak message with bnsh-c and then your command which means that inside of the libc library there must be the string bnsh so you don't even need to bring your own bnsh because it already exists inside of system because it must I mean not inside of system inside of libc because it must exist so we can actually reuse that so we can so this is gdb as a super cool find command we can look through memory to find values so this is looking at and we'll know that it's not going to be in the executable memory segment it'll be in the read-only memory segment because that is a constant string that should never change so we can look inside b726 e26000 which just so that I'm not super full of it should be within this range and we'll find that bnsh is at b7f8 684c so now we can actually have everything we need in order to write our command we know we can do 50 a's to overflow that buffer to say bdb 4b's to overflow say bdb with the address of system which we now have here we can then put 4 more junk bytes which are going to be where system goes when it returns and then right above that we have the address of bnsh we can put b7f8 684c and if we run that so 50 a's bcde to say bdbp the address of system this is clearly an example that is to show you that that doesn't work so why doesn't this work very quickly before we leave what are we missing yeah we're missing the 4 bytes of the saved eip that system thinks is there in between the address of system and the argument to system we need 4 bytes there so when you do this you'll see that this actually will work but when we get to system and it does push ebp and it tries to access it it's going to try to access the string bnsh from whatever was on the stack which is garbage which is not bnsh so if you do this you'll get a super weird error that's why you need to look at it and really understand how system is expecting the stack to look but when you figure that out and you do it correctly and you add some 4 junk bytes of where the saved eip of systems where system will go and it's not executing if you do that you will then get your awesome shell so you'll have called bnsh with slash bnsh and so the other thing is the only memory regions we use are the memory reasons of where bnsh is loaded so we're not using the stack at all we're reusing code that already exists in bnsh yes are we guaranteed that the system is going to be no because that's of course the next thing that they do is then they say well of course then let's not load the library so when we get to ASLR on Monday and we'll talk about that they'll say hey let's move it around so there's tricks around that so usually you need to read so you can read something with the GOT and then calculate all your offsets exactly so long as you know where it's loaded oh