Insecure coding in C (and C++)
Maudal, Olve
Let's turn the table. Suppose your goal is to deliberately create buggy programs in C and C++ with serious security vulnerabilities that can be "easily" exploited. Then you need to know about things like stack smashing, shellcode, arc injection, return-oriented programming. You also need to know about annoying protection mechanisms such as address space layout randomization, stack canaries, data execution prevention, and more. This session will teach you the basics of how to deliberately write insecure programs in C and C++. Warning: there will be lots of assembler code in this talk.
 in 20 now. So welcome to this session about insecure coding in C and C++. First of all, I have to make a small disclaimer because it's not that much C++ here. Everything I'm talking about is also relevant for C++. But there are few or actually nothing that is specific for C++ per se. And that's quite typical when you walk down in the stack and close to the hardware. The other thing is that I kind of promised lots of assembler. But when I compare it to a few other talks that I've done, for example, test driven development in assembler. And another talk I did last year, where 90-minute talk where I think 60, 70% of the slides were in assembler. I have to admit it's not a lot of assembler, but it's enough. So some assembler in this talk. But perhaps more important in the program, it's impossible to see what kind of level talks are at because it's not written in the program. And when I sent in this proposal, I deliberately set it to introduction and a general kind of overview of how to do insecure coding in C and C++. So if there are any deep experts in hacking programs on machine code level, you might be disappointed. It's not an expert talk. It's not even advanced. It is a general introduction to a lot of concepts that are useful to know, both if you want to write insecure code, but also if you want to write secure code. So it's an introduction talk. But just checking, is there any kind of hackers in the room that really know this stuff? Okay. Just anyone that know about cold injection? Yeah. A few people. Anyone that have done it in the last 10 years, because everybody did it when they were kids, but in the last 10 years? Okay. Not so many. But that's good because then it's nice to have this introduction level. So being stupid is a privilege to some extent. But you can also do dumb things intentionally. And you have to admit that these guys, these guys, they do actually know a few things in order to do so many stupid things that they do. And I hope this talk will also focus on knowledge-based ways of doing stupid things in C++. So there is nothing special with my machine when I'm referring to it. Apart from it's just a 32-bit Linux kernel, fairly recent, with a fairly recent compiler, and a fairly recent Ubuntu distro. I wrote the main of this talk in March. So if I wrote the main of this talk now, I would have just upgraded it. But it's nothing special in there. So that's not where to look for faults, etc. This is something that you can do on all types of machines and operating systems and compilers that you find out there. So in this talk, I will briefly discuss the following topics, StackBuffer overflow, also called Stack Smashing. How the call stack and activation frame is working. I just have to go through that, even if most people have a reasonable understanding of how it's working. Well, most C programs have a reasonable understanding of how it's working. I need to go through it because I will refer to a few of those things later when I explain how to write exploits, how to do arc injection, code injection, how a few protection mechanisms are working. There is some feedback in the audio. I'm getting some feedback in the audio. Okay, it's probably good. And then some protection mechanisms like ASLR, StackCanaries, and a fancy mechanism called return-oriented programming. Who knows about return-oriented programming? Okay, three, four people who have not only heard about it, but actually read about it and studied it a bit. Nobody, good. Because I don't know very much about it. I wasn't sure if I was going to include it because while I think I understand it, I don't understand it well enough to explain it really well. So I've just done a very brief explanation of return-oriented programming. Then I'll show some things about how to write code with surprising behavior. Talk about layered security, information leakage, how to patch boundaries, and in the end I will do a summary where I summarize a few tricks for writing in secure code. All of this in 60 minutes are actually 55. So we better get started. But now we understand it's an overview. It's not going deep into anything really. But take a look at this code first. It's a small program. Of course, it's a contrived example. I'm using it just to illustrate a few other concepts. So I had to make some stupid stuff in there. And of course, the key thing here is the use of gets and the buffer, the response buffer. That is what we're going to have fun with. And I guess we all know that gets is a function that you should never use. And it has been removed from the language now. But it's still a nice function to have there when you want to kind of explain in a simple way how stack smashing can be done. There are so many other ways you can do it. So don't be confused by me using gets in this example because there are hundreds of other ways you can do exactly the same thing. Yeah. Of course, it doesn't use gets and that's good because it has been removed from the language. But for now, we are going to use it. Let's see what happens when you try to execute this code. So it was supposed to work like this. When you run the program, it's asking you for a secret. And if you type in your name, which name should I type in? Anyone remember the movie? Oh, you're close. But the hacker was named David. So you try with David first. And David is not the keyword. So access is denied. And the operation completes. Nothing has happened. Okay. So that was how it was supposed to work. If you type the wrong secret. But if you went into it and typed the right secret, Joshua, the name of the professor, then access was granted to the system and two missiles were launched. Operation complete. And now we are going to look at kind of the simplest way of exploiting this because if we type in a very long string, bad things will happen. And in this particular case, my machine, I got access granted. Even though through comp didn't work. And it was launching a few missiles. And operation was complete. Did anyone see something strange here? Yeah. We got both access granted and access denied at the same time. So not have we only kind of launched how many millions of missiles. But we have also seemed to create a program kind of messed up the program in such a way that it becomes unstable and seemed to both pick this path and this path at the same time. Now, for those of you who have seen some of my previous talk last year, you might remember why it is like that. I will come back to it and explain it. But first of all, I will look at this one. Why did we get so many missiles? And in order to understand, to kind of explain that phenomenon, we need to understand how the stack is working and what is happening when the program is executing. So due to an overflow, what has happened is that we have messed up, changed the value of allow access and we have changed the value of end missiles. And this is the strange thing that we will look at later. So what we just saw now is what is typically called Stack Buffer Overflow and sometimes Stack Smashing. There was a famous paper that came out in the 90s called Stack Smashing for Firm and Profit. That in some way changed the computer industry because suddenly a lot of attention came into this point that we need to kind of write bug free code and certainly not allow Stack Buffer Overflows because there are so many things you can do. And while it is common to hear C and C++ programmers discuss with each other and say, oh, this is a stack variable and this is on the stack and there is a call stack and activation frame, etc., it is important to know that the standard never says anything about the stack. So although it is very common for a C program and C++ program to actually use a call stack and activation frames when executing, this is not something that is mandated by the standard. So if the compiler or the optimizer can create a similar behavior without using a stack, it is allowed to do so. So this depends very much on the optimization level. But from a conceptual point of view, it is reasonable to think about an execution stack that works approximately like I am just going to describe now. And it is not. While I have been doing this on a Linux on an Intel CPU, this is approximately the same as all typical CPUs are working. So for what happens here when we start the program is the operating system is loading the program into memory and then it is passing control to usually something called start, which is often in a C runtime library. And inside of start, it is not doing very much. It is setting up the call stack, maybe initializing some variables, preparing for dynamic memory allocation, etc. But very soon it will jump into main. And once inside of main, it will start executing the assembly instructions that are represented. That is a representation of this code. So the call stack has been set up before we enter main. And it is useful to draw it like this. High address, low and low address on top, because nearly all call stacks, they grow from high address up to the low address. So if you try to draw it all the way around, it is difficult to reason about it, at least sometimes. So the first thing that happens when it is jumping into main is that the start, the runtime start library has pushed the return address, kind of the next instruction that is supposed to be executed when main is finished. And so when, so this is coming in here, the return address, the next instruction in start. And once inside of main, main will then set up its own activation frame by putting a pointer to the previous stack frame so that it can be restored. And now it has its own activation frame that it can use. So when it is supposed to execute puts, it will first put a pointer to the string onto the stack and then jump into and then the return address, the next instruction in main that should be executed, which is this one. And then it will make the jump into puts that can do whatever it wants. But it is usually just building another activation frame and behaving like others, but it doesn't have to do that. And when puts is finished, these things go away, kind of like garbage collection, not in use anymore. And before calling authenticate and launch, the same procedure happens again. We push the return address of the next instruction, which is here. And then it jumps into authenticate and launch. And then restore the pointer to the previous stack frame. And then allocate space for these local variables. And local variables or stack variables is not a very exact name. So if you are wondering how this is working and you use those inexact names, you typically end up in discussions between people that is not necessarily experts in the topic. So if you really want to go to the places where they discuss how this is really working, you should use variables or objects with automatic storage duration, because that is the word that is used in the standard. And it's in some way a much better word because it doesn't indicate that this is going on the stack. But now you see we have put stuff here, allow access and miss all response. Anyone see something that might be a bit strange there? The order? Yeah. So it's, I'm not trying to pick on you there, but thanks for playing. It's very common for programmers to believe that they have a correct idea about how things are laid out on the stack. But there is no reason why programmers should be able to reason about that because as soon as you increase the optimization level, for example, things will be rearranged. Some things will be stored on stacks. Something will never be, never get actually a physical memory or whatever. And these kind of rearranging, the order is very typical for all compilers. They do that all the time. So there is no correct order in this particular case. But this is what happened, exactly this happened on my machine when I was executing it. And then we go into print. We just follow the same thing, point it to the string, save the return address, save the previous stack frame, print it, and then we get into gets, which is the culpate here. Now, the reason why we get this problem is, of course, gets doesn't have any idea about how many characters it's allowed to write. So depending on how many you are writing, it's just going to continue poking stuff into memory. And any input eight characters or more will cause a problem. And this is exactly the stack data that I got when I executed this on my machine. And most of this stack is basically just padding to make sure that things are aligned properly in memory. So it doesn't really matter what kind of values are there. But we recognize with some training at least, you look at the stack frame and the stack data and you start recognizing that this is the return address. This is the pointer to the stack frame. This is allow access and missiles response and pointed to the response buffer. So by focusing on the stack variables, per se, this is what happened when I typed in global thermal nuclear war. Okay. And now we partly have an explanation for why we got, how much is it? One billion missiles because this number is 1.8 billion. And, but we are also close to see why this happened. Access granted and access denied. And it's because of this one. The 6C here. And the first time I saw this, I was kind of surprised. That's, I think it was two years ago when 6, when GCC 471 came out. It was the first time I saw this particular issue. But I studied the assembler code. It was blogged by Mark Schroyer first. And I continued in his direction and I studied the assembler code. And what I saw was that GCC and my compiler in this particular case basically said that a bool is always either zero or one and never anything else internally in memory. So if someone messes up so that it's neither zero or one, you get this behavior. This is sort of a sampler of the C code. Because when you read the assembler, you see that in order to decide whether you should do access granted or not, it basically says, is allow access not zero? Then I'm going to allow grant access. And the next thing in the sampler code is that if allow access is not one, then I'm going to deny access. And if for some reason allow access becomes anything but zero or one, you get this kind of quantum behavior in your code. And this is not limited to bool. This happens all the time when you mess up the internal data structures inside of your program. So by allowing in some way memory overrides, you can also get this very, very strange and surprising behavior like this. So going back to our understanding of how the stack is working on my particular machine, we also see that now we can write a small script printf unix command, where we basically just send in eight characters because we don't care anyway. And then we type in two a, put that into end missiles, and then we put in one to allow our self access. And that gives us launching 42 missiles and operation complete. And now we have a way of controlling the program. But using scripts like this is not a very effective way of exploiting. So it's perhaps more common to see exploits, for example, written in C or Python, for example, that are in this case, building up a structure that is exactly the same as the stack on that particular machine. And now we can programmatically say, I want to allow access to be true, I want end mass missiles to be 42. And then I'm just writing this into the place where I can kind of put the payload or this is not really a payload, but where I can put the data and really control how the program is working. Yeah. So now we see we have a programatical way to do it. But we perhaps we also see a new opportunity now. What about this one? This was the return address. This is the place where it's supposed to jump when it's finished with a function. Hmm. What would happen now if we write an exploit more like this? We still, we increase our struct because we're going to map a bigger part of the stack on the target. So we still allow access. We launched three missiles. But now we are poking also in the particular address for where this function is supposed to return. So it's, we are not, we are saying I don't want you to go necessarily to put operation complete when you're finished. I want you to do something else. And in this case, this particular address happened to be pointing to the beginning of authentic at the launch again. And now I have a way to, I've changed the path, the execution path of the program in such a way that it's basically launching more and more missiles and just for fun. I'm increasing the number of missiles every time. So four, five, six, seven, eight, nine missiles should be launched. And this is called arc injection. It's not very often used like this going back to your own function. What it's more used, typically more used for is to jump into one of the library routines. So, for example, first you push, you push the address to a string that you have poked into memory somewhere. And then you change the return address and jump into a libc function, for example, system. And suddenly you can invoke Unix commands inside of the program. And that's the reason why arc injection is often called return to libc because that's where it's mostly used to jump into libc. Any questions around that? Yeah? No? Feel free to stop me during the talk. So now we have looked at arc injection and return to libc, which is a very common way of exploiting a program. But we are not limited to that because we can also let the compiler generate another compiler, perhaps generate some values, a small program that we can put on the stack. And in this case, I've just written a small function and compiled it with gcc. I already get all kind of the hex values that I need to know so that now I can take this, create a string with these hex values, and I can write it on the stack, and I can jump to that location in memory and start executing code. So this is another way of doing arc injection. You inject some code first and then you jump to that code. Sometimes it's difficult to kind of calculate exactly where you should start. So it's very common to use a knob slide where you have thousands and thousands of no operation knobs first so that it doesn't really matter where you are hitting because you will hit somewhere and then the execution will just do no, no, no, no, no, no, and then suddenly execute your code. And that's what is called a knob slide. So can I demonstrate code injection? Well, it used to be very easy to do so back in the old days. And that's the reason why I said in the last 10 years because while it was easy to do it on the Commodore 64 and the early 8080 machines, etc., early PCs, for the last 10 years there has been this annoying data execution protection mechanism which is using a write or execute strategy, sometimes called an XPIT, where it basically says when a program or operating system is asking for a page of memory, it has to say, is this going to be data or is it going to be executable code? And it cannot be both. And this mechanism is very effective to prevent the possibility of executing a code that is stored in the data segment and not in a code segment or a code page. So, but it's not the only protection mechanism out there that is useful to know about. There are plenty of them, but they are often easy to turn off. And one of them is called address, space, layout randomization. And it also became common on major operating systems like, I'm not sure, five, six, seven years ago. So, now all the regular operating systems tend to implement it. And that basically says that before we had the situation where when you execute to the program, it tends to always go into the same place in memory. All the addresses were the same. So, the stack were at the same place, the global, the functions were approximately the same place and also the library routines were at the same place. But with ASLR enabled, then every time the operating system is loading a program into memory, it tends to put them in different places. So, it becomes slightly more difficult to guess where things are in memory. So, it's more difficult to kind of jump into a particular function, etc. Now, this is considered to be a very kind of minor obstacle because there are so many ways you can do information leakage. You can first get the information of where things are stored in memory and then you can calculate exactly where it needs to be. So, while it's slightly annoying, it's not considered to be a very, very strong mechanism. And also, in order for ASLR to work, you need to have compiled with position independent code and position independent executable. And this is not on by default in typical compilers. So, you have to explicitly say, I want position independent code for ASLR to work. And often, people are not willing to pay that 10% extra, well, 10-ish percent extra price of having position independent code. So, but there are many ways of disabling it. You can even poke stuff into your kernel where you basically say, no, I don't want ASLR anymore. You can boot up your machine without ASLR. And of course, you can make sure that your code is not position independent. Here is another mechanism, which is called Stack Protector, often. And that one is injecting a so-called Stack Canary. Stack Canary. Here is the Stack Canary. So, the body of the function is the same, but in the preamble, just before executing the body, it's poking, yeah, supposed to be random value into a memory location and XORing that one. And then when it's exiting the function, it's checking, has this canary died, has it changed? And if it's changed, then it's just going to, the program is going to terminate. So, at least it doesn't continue in an invalid state. And this is enabled by doing minus f Stack Protector, which is often default on modern compilers, because this is not a very costly operation, because the Stack Canary only comes into functions that actually do have a potential for doing buffer overflows. So, it's not something that, it's not the cost you have to pay for every function. But not only does it put in this magic value, but it also moves around, often it moves around the variables. So, in this case, the response buffer is at a higher address than it was before. And that is nice, because it means if you are overwriting it, you can't, it's difficult to change allow access and admissance. And this is a deliberate strategy that they are using, putting that kind of the vulnerable buffer at an high address. And some people have actually suggested that we can solve all the security issues if we start making our execution Stack grow up instead of down. I never understood that proposal, and it seems like there is a, it's not a very popular suggestion out there, but it's interesting thought of that you can the position of your Stack variables depends on how easy it is to exploit the program. But finally, when you have of the protection mechanisms, we have this data execution prevention, Stack protectors, SLR and similar techniques, they certainly make it difficult to hack into a system. But there is a very powerful exploit technique called return oriented programming that has become very popular in the last few years. I think the first paper around Rop came out in 2006, 2007, but it became common to use it only a few years ago. And according to someone that knows this much better than myself, Rop is used in nearly every single exploit that you hear about these days. And it's a very powerful technique and it's apparently impossible to stop it. And the reason is how a machine is working and how we are executing code. I take my binary now, which is called launch, and I just dump the data on that binary file. And by studying that data, I start recognizing a few things here that is very useful for Rop. Anyone know what these are? C6? Not loop? Oh, it's not no operation either. It can be used for jump, that's the point. It's actually the RET instruction. It's a RET instruction. And there are other useful instructions out there that you can use, but the nice thing about RET is that it's reading from stack and address. And moving it into the EIP, the instruction pointer. And in that way, you can build up a lot of addresses on the stack. And when you start unwinding the stack doing returns, it will just pick another return address and jump around. And I show you these things. You usually have programs, and this is called Rop Gadget. There are millions of those programs out there, which can look at the binary and then figure out, here are all the small bits and pieces of code that is unintentionally in your binary. For example, if I want to just to show you a very simple example, just before I return back to main, for some reason, I want to increment ECX. I just want to run this small kind of assembly instruction ECX and then return. Then I can put this address onto stack first, and then have the real return address afterwards. And then it will first jump there, run int ECX, then run return, and jump back to main. And it has increased ECX by one, as if nothing has happened. But you're not limited to do it one. You can actually build up a chain of these gadgets that are each doing a small little assembly instruction. And it has been shown on, I think it's on Intel, ARM, and Spark CPUs. It has been shown that there is often a Turing complete set of these gadgets on the programs that are running on them. So it is possible to imagine that by finding these gadgets and creating a long chain of small bits and pieces that is going to execute by just reading the stack and doing return, return, return, return, but just before the return doing a small thing, you can build up a whole program in there. And this is the technique that is often used. And it's very difficult to do by hand. So you typically always use programs, like in this case, ROP gadgets, which can also, it can find the gadgets and it can chain them together for you if you want something to do a particular command. And then you have the payload that you can just dump into your target program. Yeah? Yes, you want to get around the no execute program. So you basically, you create your program as just a long string of data. And then you let original program jump around in its own executable doing all these small pieces of instructions. So that's what return-oriented programming do. And just one of the more famous stories around return-oriented programming, and probably one of the stories that made it kind of famous and magazines and newspapers were writing about it. Some researchers into return-oriented programming that asked for access to the new vaulting machine that we're using in the States, which had, I don't know how many hundred security researchers employed to kind of create a really secure machine. And they used this technique and they showed that they could actually exploit the vaulting machine that was just designed to be unbreakable. And so far, there are very few suggestions on how to protect programs from exploit by return-oriented programming. So back to more, well, this is what I showed now, is very realistic, but now to something slightly different. Here is a case which I find very, very interesting. And now that I know more about this one and similar cases, I see this all over the place and code bases. Now, this function, which is of course contrived because it's small and I have to put it on the page. But there is a fairly common idiom here. And that is, in this function, we are given a pointer and an offset and an end of the buffer that the pointer is pointing at. And then a value to poke into it. So just to be kind of secure, first we check if pointer plus offset is bigger than end because then we have an auto-bond. That's not good. The next thing we do, now the offset is an unsigned value, but still we can have this kind of wrap going on. So if it's a very large value, you can imagine that pointer plus offset becomes less than pointer and that gives you, oh, it's a wrap. And that's not good. We don't want that. So we return and if everything is okay, we are confident that okay, we are within the buffer, then we poke the value in. And according to the researchers that the paper that I read about this, it was published, the one I read was published in November last year. This is a very common idiom also in what we would consider serious software. So they found a lot of, for example, Linux programs, even in kernel modules that use this as an idiom for checking for wraps. But the problem is, and this is the auto-bond guard and this is the wrap guard. So if we compile this without optimization, it works exactly as it is supposed to work. So we give it some large numbers. It's poking into the buffer. Then it detects, oh, we are out of buffer. And since we use very large initial values, we get this wrap now. And yeah, so this seems to work. But with optimization, this happens. Out of bounds, out of bounds. And now it's just poking into memory. So why is that? And this is something that you will see more and more of when you have code that has been working for a decade or two. And then suddenly a new optimization technique comes in. And it starts reasoning more, better and better around your code. And in this case, there was a new version of a few compilers that came out where they figured out that this can never happen. I mean, this is, first of all, pointer overflow is undefined behavior in C. So this is not going to happen anyway. So why should we generate code for something that will never happen? So if you look at the assembler here, it looks like this and without going into details on that one, what has basically happened is that it's a, well, this can never happen. So it just deleted it. This code is not present in the assembler. And this is something that you see over and over again that the optimizers that become smarter and smarter and suddenly they remove code that you thought, oh, that's useful code. The compiler is smarter than you and say, if that is going to be true or that is going to be false, then there must be undefined behavior. Of course, you're not doing undefined behavior. Are you? So I just remove it. You want fast code? That's the reason why you write in C and C++. And the research paper, they claims that there were like 200 modules or something like that in the Linux code that used this idiom or that idiom was used in 200 places. I can't remember exactly the numbers, but it's a common thing. And I see it in our code basis as well. It's something that people do. And you might say, oh, that's inconceivable. It should never happen. But as long as you're stepping outside of the rules for the language, then anything can happen. So I have some more stuff about security because security comes typically in layers, very much in layers. You put several layers of security on protection mechanisms on top. And in this case, we might go into the source code and we might start trying to fix and use F gets instead of gets, et cetera. But it's easy to forget that the easiest way to find the information you need is if you have the binary, you just search for the strings inside, of course. I mean, it's silly, but I still have to mention it here because you can have all these protectionism in place. And suddenly you realize you have actually leaked the password or you have leaked information. Similarly, if you have access to the binary, you can just disassemble the binary and you can read the authenticate and launch function and you can read how it works. And then we recognize, oh, that's two missiles, isn't it? And that is not allowing access. I can just use said and I can patch that binary file on those two places and then run it. And suddenly we have access granted whatever we do and we always launch 42 missiles. So that's also one way of doing it. If you're doing embedded applications, for example, sending out firmware to somewhere and you allow someone to change the firmware before they upload it into your router or switch or whatever. Well, that can happen. So yeah, so we recognize this thing. So that is a nice way of patching it. And you can also patch complete functions, of course. So here I write my own my authenticate and launch David rocks launch 1983 missiles. Here is the assembler code machine code. We just create a printf with that particular thing. And they poke it directly into the memory. And as long as the function is smaller than the previous function, it's typically a very easy thing to do. You don't have to move things around or anything. You just replace the function completely. Now we're doing our stuff here without any fancy way of hacking into the system. So I just wanted to mention those before we go into the summary finale, I'm not going to give 13 14 tricks about how to write insecure code in CNC plus plus. First of all, this one. It's very common for programmers to think that they know which one will be called first. Oh, it's going to call a and then be. And that is true for all languages except from CNC plus plus. In CNC plus plus, it can either call a first or be first. The only guarantee you have it's that they are not going to execute at the same time. And this is called unspecified behavior. Actually, co ball now for trying also has this feature, but all the other languages that you know about probably will have a left to right evaluation. So trick number one, make sure that you write code that this is bending on a particular evaluation order. This is trick for writing insecure code, of course. Now, unspecified evaluation order has some serious consequences, very serious consequences. And that is what is the value of n. Any suggestions? Yeah, it's undefined behavior. It can be 42, it can be zero, it can be seven, it can be whatever. And even if you have seen your own compiler generating exactly the same value over and over and over again, doesn't mean that it will do so in the future. And it certainly doesn't mean that it will do so if you change the compiler. So this is an example of a sequence point evaluation and you get undefined behavior. So trick number two, try to break the sequencing rules that will give you some cool effects. And I'm showing you that one in the next one. This one, for those who have been to a previous talk about, and I've probably seen this one before, so you don't need to answer. But I think we have time to very briefly look at this. What do you think will actually happen if you run this code, or compile, and run this code in your development environment without picking up your computer? Just try to guess. You have some experience with your own development environment. What do you think your compiler will do? I'm quite sure this will compile and this will run cleanly. So you don't need to look for semicons or whatever missing semicons. It's going to print the value. What do you think it will print? First one. Second one. Seven. I like that. Anything else? Eleven. I like that as well. Anyone higher? Yeah? 15? Oh, 21. That's even better. Anyone higher? Well, this is what happened on my computer. I have many compilers on my computer. So I just happened to pick three interesting ones. If I use the GCC that came with the operating system, not the one that I compile myself, which I do all the time, the one that came with the operating system, GCC gives me 12, Clang gives me 11, and Intel Compiler gives me 13. This is a consequence of the unspecified evaluation order, and therefore the expression that you see here doesn't make sense because we don't know whether I has been updated here or there or there, or when the side effect of plus plus i actually happens. Yes? You are ahead of me. Good. So trick number three, write insecure code where the result depends on the compiler. And if you want a detailed explanation with all the assembler involved, here is the link. So if you enable warnings for code like this, I don't know how many flags you want. So to write insecure code, it's important to know a lot about the weak spots, the blind spots of your compiler, because there is always one annoying colleague that wants to add another flag. Oh, I want minus f, whatever. So know your blind spots, and the compilers will typically not, well, they will try to warn you about things, but very often they can't see it, and sometimes they can see it, but they have decided that I'm not going to warn anyway to diagnose this. And remember when you have undefined behavior, and that's what we saw, we saw undefined behavior, and that's the reason why the compilers can just do whatever they want. Anything can happen. There is this saying on constancy that when a compiler encounters a kind of an illegal construct, it can try to make demons fly out of your nose. That's okay behavior. And this is what we see in this particular example. I'm not going to spend time on that one because we already discussed slightly this Boole problem earlier. But the point is that if you have code like this, and the problem is we don't initialize B, but we are still reading it. So that means B in theory can be whatever value, or in practice can be whatever value. So if you just put on a main and a bar here, just to poke, for example, the value two into this memory location, remember how the stack was working on my machine. Then we get the situation where it's trying to evaluate B that has an internal representation of something that is not zero or one. And the compilers that behave differently. The Intel compiler in this case will give through, clang will give false, and GCC have this quantum behavior and gives me both through and false at the same time. So maybe this is the first preparation for quantum computing. With optimization that just happened to all of them happened to do false. So this is also you see an example where the value changes completely with optimization as well. And it's different between the compilers. And once again, I described two concepts in this 90 minute talk that I did at Acura last year with all the assembler involved, and it was the previous one and it was this one. So if you want to see all the assembler code and explanation for why this is happening, then you can go there and have a look. So write insecure code by messing up the internal state of the program. Now this one, anyone see a problem with this function? Apart from being stupid and doing nothing serious? I mean, we're quite used to write the function that takes an integer and do something with that integer and then return something. So this is innocent looking code. But there is a problem. We can get integer overflow. Because if we send in a large value, in this case int max, then we get signed integer overflow and that is undefined behavior in c and c++. So and you remember when you have undefined behavior, anything can happen. So this might happen. Of course, you might say, well, unlikely. But remember, anything can happen. Even that thing, even though I would be surprised if it actually happened, it was a real phenomenon. But in theory, anything can happen. So make sure you write insecure code by only assuming input valid input values. Don't check for large integers before you're doing calculations with it because that will make your code more secure and less buggy. Number seven, trick number seven, now trick number eight, this one. Now I have a small loop that is basically looping through i. And I've already given you a small hint about what might happen here. But this one terminates after doing four calculations and printing out for values, which is fine. That is what you would expect maybe. But if you combine with optimization, this can happen. And this actually happens on my machine. So what looked like a valid terminating condition is not a valid terminating condition in this case. Because this thing can never be true. No, it can never be anything but true. We are doing additions and signed integer overflow is not allowed. So either it's crappy code or this can never be anything but true. So the compiler will change it to true and therefore eliminate the code. If you have a good compiler, though, lousy compilers, they don't see these kind of things. So write insecure code by letting the optimizer remove apparently critical code for you. And here is a big topic. And there are plenty of C++ examples as well I could have used. What is the big problem here? It's of course the use of this one. It looks like a kind of a secure way of copying things. And it has a very bad name, but it was invented like 220 years ago, so they didn't think that far. Just kidding about 220 years. But the point is that true and copy is not doing what you think it does. Because it's not null terminating the string. So if you write a large string, for example, if you write global term, in this case, you are filling up the buffer. And it's going to stop there. It's not going to do the buffer overwrite as, for example, true copy would have done or whatever. But it's going to truncate it without null terminating. So the effect is that when you print it out, it will continue after the string and into the next buffer and you get this information leakage. Whenever you see true and copy, you should expect to find this line afterwards. And if you don't find that afterwards, you are probably looking at a bug. So you can just scan through your source code, look for string and copy, and if you don't see that terminating thing afterwards, you're probably looking at the bug. So write insecure code by using library functions incorrectly. And of course, you should never allow the stack protector to kick in so you can disable it with minus ethanol stack protector. Disable it. You should also make sure that ASLR is not working. You can either turn it off or you can compile your code as not position independent. That's useful. And make sure you use an old hardware and old operating systems like five, six, seven years old machines and operating systems because if you're lucky, they don't have this data execution prevention. It's an X bit in place. So go back a few years. Use those kind of old stuff. And here is another one. The difference, I've just showed an example here where I compile my program with using shared libraries and one with static libraries. And that makes a huge difference in the size of the program. So you see, in this case, it's only 7K and this one, it's 780K. The cool thing about that is that the larger the file is, the more gadgets you can find. So if you want to do ROP, you want to have a huge program that has a lot of kind of random data in there so you can find a lot of gadgets that you can chain together and start exploiting the program. Make it easy to find ROP gadgets in your program. And you should not check the integrity of the code. So you should not do checksum. When you distribute the code, you should certainly not do a checksum when you load the program and install it on your machine and start running it because that would make it difficult to kind of do patching of the binaries. So skip the integrity checks. And finally, perhaps most important, you must never, ever let other programings review your code. So pair programming, forget about that. Never review code because your colleagues might see all the crap that you are creating. So that was the advice for writing insecure code. And here is the summary. And thank you very much. So we are out of time, but I will hang around here a bit and if you want to ask about something particular here.
 in 20 now. So welcome to this session about insecure coding in C and C++. First of all,  I have to make a small disclaimer because it's not that much C++ here. Everything I'm talking  about is also relevant for C++. But there are few or actually nothing that is specific  for C++ per se. And that's quite typical when you walk down in the stack and close to the hardware.  The other thing is that I kind of promised lots of assembler. But when I compare it to a few other  talks that I've done, for example, test driven development in assembler. And another talk I did  last year, where 90-minute talk where I think 60, 70% of the slides were in assembler. I have to  admit it's not a lot of assembler, but it's enough. So some assembler in this talk. But perhaps more  important in the program, it's impossible to see what kind of level talks are at because it's not  written in the program. And when I sent in this proposal, I deliberately set it to introduction  and a general kind of overview of how to do insecure coding in C and C++. So if there are  any deep experts in hacking programs on machine code level, you might be disappointed. It's not  an expert talk. It's not even advanced. It is a general introduction to a lot of concepts that  are useful to know, both if you want to write insecure code, but also if you want to write  secure code. So it's an introduction talk. But just checking, is there any kind of hackers in  the room that really know this stuff? Okay. Just anyone that know about cold injection? Yeah.  A few people. Anyone that have done it in the last 10 years, because everybody did it when they were  kids, but in the last 10 years? Okay. Not so many. But that's good because then it's nice to have  this introduction level. So being stupid is a privilege to some extent. But you can also do  dumb things intentionally. And you have to admit that these guys, these guys, they do actually  know a few things in order to do so many stupid things that they do. And I hope this talk will  also focus on knowledge-based ways of doing stupid things in C++. So there is nothing special  with my machine when I'm referring to it. Apart from it's just a 32-bit Linux kernel,  fairly recent, with a fairly recent compiler, and a fairly recent Ubuntu distro. I wrote the main  of this talk in March. So if I wrote the main of this talk now, I would have just upgraded it.  But it's nothing special in there. So that's not where to look for faults, etc. This is something  that you can do on all types of machines and operating systems and compilers that you find out  there. So in this talk, I will briefly discuss the following topics, StackBuffer overflow, also  called Stack Smashing. How the call stack and activation frame is working. I just have to go  through that, even if most people have a reasonable understanding of how it's working. Well, most C  programs have a reasonable understanding of how it's working. I need to go through it because I  will refer to a few of those things later when I explain how to write exploits, how to do arc  injection, code injection, how a few protection mechanisms are working. There is some feedback in  the audio. I'm getting some feedback in the audio. Okay, it's probably good. And then some protection  mechanisms like ASLR, StackCanaries, and a fancy mechanism called return-oriented programming.  Who knows about return-oriented programming? Okay, three, four people who have not only heard  about it, but actually read about it and studied it a bit. Nobody, good. Because I don't know very  much about it. I wasn't sure if I was going to include it because while I think I understand it,  I don't understand it well enough to explain it really well. So I've just done a very brief  explanation of return-oriented programming. Then I'll show some things about how to write code  with surprising behavior. Talk about layered security, information leakage, how to patch  boundaries, and in the end I will do a summary where I summarize a few tricks for writing in  secure code. All of this in 60 minutes are actually 55. So we better get started. But now we understand  it's an overview. It's not going deep into anything really. But take a look at this code first.  It's a small program. Of course, it's a contrived example. I'm using it just to  illustrate a few other concepts. So I had to make some stupid stuff in there. And of course,  the key thing here is the use of gets and the buffer, the response buffer.  That is what we're going to have fun with. And I guess we all know that gets is a function  that you should never use. And it has been removed from the language now. But it's still a nice  function to have there when you want to kind of explain in a simple way how stack smashing can  be done. There are so many other ways you can do it. So don't be confused by me using gets in this  example because there are hundreds of other ways you can do exactly the same thing.  Yeah. Of course, it doesn't use gets and that's good because it has been removed from the language.  But for now, we are going to use it. Let's see what happens when you try to execute this code.  So it was supposed to work like this. When you run the program, it's asking you for a secret.  And if you type in your name, which name should I type in? Anyone remember the movie?  Oh, you're close. But the hacker was named David. So you try with David first.  And David is not the keyword. So access is denied. And the operation completes. Nothing has happened.  Okay. So that was how it was supposed to work. If you type the wrong secret. But if you went into  it and typed the right secret, Joshua, the name of the professor, then access was granted to the  system and two missiles were launched. Operation complete. And now we are going to look at kind  of the simplest way of exploiting this because if we type in a very long string,  bad things will happen. And in this particular case, my machine, I got access granted.  Even though through comp didn't work.  And it was launching a few missiles.  And operation was complete. Did anyone see something strange here?  Yeah. We got both access granted and access denied at the same time.  So not have we only kind of launched how many millions of missiles. But we have also seemed to  create a program kind of messed up the program in such a way that it becomes unstable and seemed to  both pick this path and this path at the same time. Now, for those of you who have seen  some of my previous talk last year, you might remember why it is like that. I will come back to  it and explain it. But first of all, I will look at this one. Why did we get so many missiles?  And in order to understand, to kind of explain that phenomenon, we need to understand how the  stack is working and what is happening when the program is executing.  So due to an overflow, what has happened is that we have messed up, changed the value of  allow access and we have changed the value of end missiles.  And this is the strange thing that we will look at later.  So what we just saw now is what is typically called Stack Buffer Overflow and sometimes  Stack Smashing. There was a famous paper that came out in the 90s called Stack Smashing for  Firm and Profit. That in some way changed the computer industry because suddenly  a lot of attention came into this point that we need to kind of write bug free code and  certainly not allow Stack Buffer Overflows because there are so many things you can do.  And while it is common to hear C and C++ programmers discuss with each other and say,  oh, this is a stack variable and this is on the stack and there is a call stack and activation  frame, etc., it is important to know that the standard never says anything about the stack.  So although it is very common for a C program and C++ program to actually use a call stack  and activation frames when executing, this is not something that is mandated by the standard.  So if the compiler or the optimizer can create a similar behavior without using a stack,  it is allowed to do so. So this depends very much on the optimization level. But from a  conceptual point of view, it is reasonable to think about an execution stack that works  approximately like I am just going to describe now. And it is not. While I have been doing this  on a Linux on an Intel CPU, this is approximately the same as all typical CPUs are working. So  for what happens here when we start the program is the operating system is loading the program  into memory and then it is passing control to usually something called start, which is often  in a C runtime library. And inside of start, it is not doing very much. It is setting up the  call stack, maybe initializing some variables, preparing for dynamic memory allocation, etc.  But very soon it will jump into main. And once inside of main, it will start executing  the assembly instructions that are represented. That is a representation of this code.  So the call stack has been set up before we enter main. And it is useful to draw it like this.  High address, low and low address on top, because nearly all call stacks, they grow from high  address up to the low address. So if you try to draw it all the way around, it is difficult to  reason about it, at least sometimes. So the first thing that happens when it is jumping into main  is that the start, the runtime start library has pushed the return address, kind of the next  instruction that is supposed to be executed when main is finished. And so when, so this is coming  in here, the return address, the next instruction in start. And once inside of main, main will then  set up its own activation frame by putting a pointer to the previous stack frame so that it  can be restored. And now it has its own activation frame that it can use. So when it is supposed  to execute puts, it will first put a pointer to the string onto the stack and then jump into  and then the return address, the next instruction in main that should be executed,  which is this one. And then it will make the jump into puts that can do whatever it wants.  But it is usually just building another activation frame and behaving like others,  but it doesn't have to do that. And when puts is finished, these things go away,  kind of like garbage collection, not in use anymore. And before calling authenticate and  launch, the same procedure happens again. We push the return address of the next instruction,  which is here. And then it jumps into authenticate and launch.  And then restore the pointer to the previous stack frame. And then allocate space for these  local variables. And local variables or stack variables is not a very exact name. So if you  are wondering how this is working and you use those inexact names, you typically end up in  discussions between people that is not necessarily experts in the topic. So if you really want to  go to the places where they discuss how this is really working, you should use variables or objects  with automatic storage duration, because that is the word that is used in the standard. And it's  in some way a much better word because it doesn't indicate that this is going on the stack.  But now you see we have put stuff here, allow access and miss all response. Anyone see something  that might be a bit strange there? The order? Yeah. So it's, I'm not trying to pick on you there,  but thanks for playing. It's very common for programmers to believe that they have a correct  idea about how things are laid out on the stack. But there is no reason why programmers  should be able to reason about that because as soon as you increase the optimization level,  for example, things will be rearranged. Some things will be stored on stacks. Something will  never be, never get actually a physical memory or whatever. And these kind of rearranging,  the order is very typical for all compilers. They do that all the time.  So there is no correct order in this particular case. But this is what happened, exactly this  happened on my machine when I was executing it. And then we go into print. We just follow the same  thing, point it to the string, save the return address, save the previous stack frame, print  it, and then we get into gets, which is the culpate here. Now, the reason why we get this  problem is, of course, gets doesn't have any idea about how many characters it's allowed to write.  So depending on how many you are writing, it's just going to continue poking stuff into memory.  And any input eight characters or more will cause a problem. And this is exactly the stack  data that I got when I executed this on my machine. And most of this stack is basically just padding  to make sure that things are aligned properly in memory. So it doesn't really matter what kind  of values are there. But we recognize with some training at least, you look at the stack frame  and the stack data and you start recognizing that this is the return address. This is the  pointer to the stack frame. This is allow access and missiles response and pointed to the response  buffer. So by focusing on the stack variables, per se, this is what happened when I typed in  global thermal nuclear war. Okay. And now we partly have an explanation for why we got,  how much is it? One billion missiles because this number is 1.8 billion.  And, but we are also close to see why this happened. Access granted and access denied.  And it's because of this one. The 6C here. And the first time I saw this, I was kind of surprised.  That's, I think it was two years ago when 6, when GCC 471 came out. It was the first time I saw  this particular issue. But I studied the assembler code. It was blogged by Mark Schroyer first.  And I continued in his direction and I studied the assembler code. And what I saw was that GCC  and my compiler in this particular case basically said that a bool is always either zero or one  and never anything else internally in memory. So if someone messes up so that it's neither zero  or one, you get this behavior. This is sort of a sampler of the C code. Because when you read the  assembler, you see that in order to decide whether you should do access granted or not, it basically  says, is allow access not zero? Then I'm going to allow grant access. And the next thing in the  sampler code is that if allow access is not one, then I'm going to deny access. And if for some  reason allow access becomes anything but zero or one, you get this kind of quantum behavior in your  code. And this is not limited to bool. This happens all the time when you mess up the internal data  structures inside of your program. So by allowing in some way memory overrides, you can also get  this very, very strange and surprising behavior like this. So going back to our understanding  of how the stack is working on my particular machine, we also see that now we can write a  small script printf unix command, where we basically just send in eight characters because we don't  care anyway. And then we type in two a, put that into end missiles, and then we put in one to allow  our self access. And that gives us launching 42 missiles and operation complete. And now we have  a way of controlling the program. But using scripts like this is not a very effective way of  exploiting. So it's perhaps more common to see exploits, for example, written in C or Python,  for example, that are in this case, building up a structure that is exactly the same as the stack  on that particular machine. And now we can programmatically say, I want to allow access  to be true, I want end mass missiles to be 42. And then I'm just writing this into the place  where I can kind of put the payload or this is not really a payload, but where I can put the data  and really control how the program is working. Yeah. So now we see we have a programatical  way to do it. But we perhaps we also see a new opportunity now. What about this one?  This was the return address. This is the place where it's supposed to jump when it's finished  with a function. Hmm. What would happen now if we write an exploit more like this? We still,  we increase our struct because we're going to map a bigger part of the stack on the target.  So we still allow access. We launched three missiles. But now we are poking also in  the particular address for where this function is supposed to return. So it's, we are not,  we are saying I don't want you to go necessarily to put operation complete when you're finished.  I want you to do something else. And in this case, this particular address happened to be  pointing to the beginning of authentic at the launch again.  And now I have a way to, I've changed the path, the execution path of the program in such a way  that it's basically launching more and more missiles and just for fun. I'm increasing the  number of missiles every time. So four, five, six, seven, eight, nine missiles should be launched.  And this is called arc injection. It's not very often used like this going back to your own  function. What it's more used, typically more used for is to jump into one of the library routines.  So, for example, first you push, you push the address to a string that you have poked into  memory somewhere. And then you change the return address and jump into a libc function, for example,  system. And suddenly you can invoke Unix commands inside of the program. And that's the reason  why arc injection is often called return to libc because that's where it's mostly used  to jump into libc. Any questions around that?  Yeah? No? Feel free to stop me during the talk. So now we have looked at arc injection and return  to libc, which is a very common way of exploiting a program. But we are not limited to that because  we can also let the compiler generate another compiler, perhaps generate  some values, a small program that we can put on the stack. And in this case,  I've just written a small function and compiled it with gcc. I already get all  kind of the hex values that I need to know so that now I can take this, create a string with  these hex values, and I can write it on the stack, and I can jump to that location in memory  and start executing code. So this is another way of doing arc injection. You inject some code  first and then you jump to that code. Sometimes it's difficult to kind of calculate exactly where  you should start. So it's very common to use a knob slide where you have thousands and thousands of  no operation knobs first so that it doesn't really matter where you are hitting because you will hit  somewhere and then the execution will just do no, no, no, no, no, no, and then suddenly execute  your code. And that's what is called a knob slide. So can I demonstrate code injection? Well, it used  to be very easy to do so back in the old days. And that's the reason why I said in the last 10 years  because while it was easy to do it on the Commodore 64 and the early 8080 machines, etc.,  early PCs, for the last 10 years there has been this annoying data execution protection mechanism  which is using a write or execute strategy, sometimes called an XPIT, where it basically  says when a program or operating system is asking for a page of memory, it has to say,  is this going to be data or is it going to be executable code? And it cannot be both.  And this mechanism is very effective to prevent the possibility of executing  a code that is stored in the data segment and not in a code segment or a code page.  So, but it's not the only protection mechanism out there that is useful to know about.  There are plenty of them, but they are often easy to turn off. And one of them is called address,  space, layout randomization. And it also became common on major operating systems like,  I'm not sure, five, six, seven years ago. So, now all the regular operating systems  tend to implement it. And that basically says that before we had the situation where when you  execute to the program, it tends to always go into the same place in memory. All the addresses  were the same. So, the stack were at the same place, the global, the functions were approximately  the same place and also the library routines were at the same place. But with ASLR enabled,  then every time the operating system is loading a program into memory, it tends to put them in  different places. So, it becomes slightly more difficult to guess where things are in memory.  So, it's more difficult to kind of jump into a particular function, etc. Now, this is considered  to be a very kind of minor obstacle because there are so many ways you can do information leakage.  You can first get the information of where things are stored in memory and then you can  calculate exactly where it needs to be. So, while it's slightly annoying, it's not considered to  be a very, very strong mechanism. And also, in order for ASLR to work, you need to have  compiled with position independent code and position independent executable. And this is not  on by default in typical compilers. So, you have to explicitly say, I want position independent code  for ASLR to work. And often, people are not willing to pay that 10% extra, well, 10-ish  percent extra price of having position independent code. So, but there are many ways of disabling  it. You can even poke stuff into your kernel where you basically say, no, I don't want ASLR  anymore. You can boot up your machine without ASLR. And of course, you can make sure that your code  is not position independent. Here is another mechanism, which is called Stack Protector,  often. And that one is injecting a so-called Stack Canary. Stack Canary. Here is the Stack Canary.  So, the body of the function is the same, but in the preamble, just before executing the body,  it's poking, yeah, supposed to be random value into a memory location and XORing that one. And  then when it's exiting the function, it's checking, has this canary died, has it changed? And if it's  changed, then it's just going to, the program is going to terminate. So, at least it doesn't  continue in an invalid state. And this is enabled by doing minus f Stack Protector,  which is often default on modern compilers, because this is not a very costly operation,  because the Stack Canary only comes into functions that actually do have a potential for doing  buffer overflows. So, it's not something that, it's not the cost you have to pay for every function.  But not only does it put in this magic value, but it also moves around, often it moves around  the variables. So, in this case, the response buffer is at a higher address than it was before.  And that is nice, because it means if you are overwriting it, you can't,  it's difficult to change allow access and admissance. And this is a deliberate strategy that  they are using, putting that kind of the vulnerable buffer at an high address. And some people have  actually suggested that we can solve all the security issues if we start making our execution  Stack grow up instead of down. I never understood that proposal, and it seems like there is a,  it's not a very popular suggestion out there, but it's interesting thought of that you can  the position of your Stack variables depends on how easy it is to exploit the program.  But finally, when you have of the protection mechanisms, we have this  data execution prevention, Stack protectors, SLR and similar techniques, they certainly  make it difficult to hack into a system. But there is a very powerful exploit technique  called return oriented programming that has become very popular in the last few years. I think the  first paper around Rop came out in 2006, 2007, but it became common to use it only a few years ago.  And according to someone that knows this much better than myself, Rop is used in nearly every  single exploit that you hear about these days. And it's a very powerful technique and it's  apparently impossible to stop it. And the reason is how a machine is working and how we are  executing code. I take my binary now, which is called launch, and I just dump the data  on that binary file. And by studying that data, I start recognizing a few things here that is  very useful for Rop. Anyone know what these are? C6? Not loop? Oh, it's not no operation either.  It can be used for jump, that's the point. It's actually the RET instruction.  It's a RET instruction. And there are other useful instructions out there that you can  use, but the nice thing about RET is that it's reading from stack and address. And moving it  into the EIP, the instruction pointer. And in that way, you can build up a lot of addresses on the stack.  And when you start unwinding the stack doing returns, it will just pick another return address  and jump around. And I show you these things. You usually have programs, and this is called  Rop Gadget. There are millions of those programs out there, which can look at the binary and then  figure out, here are all the small bits and pieces of code that is unintentionally in your binary.  For example, if I want to just to show you a very simple example, just before I return back to main,  for some reason, I want to increment ECX. I just want to run this small kind of assembly  instruction ECX and then return. Then I can put this address onto stack first, and then have the  real return address afterwards. And then it will first jump there, run int ECX, then run return,  and jump back to main. And it has increased ECX by one, as if nothing has happened.  But you're not limited to do it one. You can actually build up a chain of these gadgets  that are each doing a small little assembly instruction. And it has been shown on,  I think it's on Intel, ARM, and Spark CPUs. It has been shown that there is often a Turing  complete set of these gadgets on the programs that are running on them.  So it is possible to imagine that by finding these gadgets and creating a long chain of small bits  and pieces that is going to execute by just reading the stack and doing return, return, return, return,  but just before the return doing a small thing, you can build up a whole program in there. And  this is the technique that is often used. And it's very difficult to do by hand. So you typically  always use programs, like in this case, ROP gadgets, which can also, it can find the gadgets and it  can chain them together for you if you want something to do a particular command. And then  you have the payload that you can just dump into your target program.  Yeah?  Yes, you want to get around the no execute program. So you basically, you create your program  as just a long string of data. And then you let original program jump around in its own  executable doing all these small pieces of instructions. So that's what return-oriented  programming do. And just one of the more famous stories around return-oriented programming,  and probably one of the stories that made it kind of famous and magazines and newspapers were writing  about it. Some researchers into return-oriented programming that asked for access to the new  vaulting machine that we're using in the States, which had, I don't know how many hundred security  researchers employed to kind of create a really secure machine. And they used this technique  and they showed that they could actually exploit the vaulting machine that was just designed to be  unbreakable. And so far, there are very few suggestions on how to protect  programs from exploit by return-oriented programming. So back to more, well, this is what I showed now,  is very realistic, but now to something slightly different. Here is a case which I find very,  very interesting. And now that I know more about this one and similar cases, I see this  all over the place and code bases. Now, this function, which is of course contrived because  it's small and I have to put it on the page. But there is a fairly common idiom here.  And that is, in this function, we are given a pointer and an offset and an end of the buffer  that the pointer is pointing at. And then a value to poke into it.  So just to be kind of secure, first we check if pointer plus offset is bigger than end  because then we have an auto-bond. That's not good. The next thing we do, now the offset is  an unsigned value, but still we can have this kind of wrap going on. So if it's a very large value,  you can imagine that pointer plus offset becomes less than pointer and that gives you, oh, it's a wrap.  And that's not good. We don't want that. So we return and if everything is okay, we are confident  that okay, we are within the buffer, then we poke the value in. And according to the researchers  that the paper that I read about this, it was published, the one I read was published in November  last year. This is a very common idiom also in what we would consider serious software. So they  found a lot of, for example, Linux programs, even in kernel modules that use this as an idiom for  checking for wraps. But the problem is, and this is the auto-bond guard and this is the wrap guard.  So if we compile this without optimization, it works exactly as it is supposed to work.  So we give it some large numbers. It's poking into the buffer. Then it detects, oh, we are out of  buffer. And since we use very large initial values, we get this wrap now. And yeah, so this seems to  work. But with optimization, this happens. Out of bounds, out of bounds. And now it's just poking  into memory. So why is that? And this is something that you will see more and more of when you have  code that has been working for a decade or two. And then suddenly a new optimization technique  comes in. And it starts reasoning more, better and better around your code. And in this case,  there was a new version of a few compilers that came out where they figured out that this can never  happen. I mean, this is, first of all, pointer overflow is undefined behavior in C. So this is  not going to happen anyway. So why should we generate code for something that will never happen?  So if you look at the assembler here, it looks like this and without going into details on that  one, what has basically happened is that it's a, well, this can never happen. So it just deleted  it. This code is not present in the assembler. And this is something that you see over and over  again that the optimizers that become smarter and smarter and suddenly they remove code that you  thought, oh, that's useful code. The compiler is smarter than you and say, if that is going to be  true or that is going to be false, then there must be undefined behavior. Of course, you're not  doing undefined behavior. Are you? So I just remove it. You want fast code? That's the reason why  you write in C and C++. And the research paper, they claims that there were like 200 modules or  something like that in the Linux code that used this idiom or that idiom was used in 200 places.  I can't remember exactly the numbers, but it's a common thing. And I see it in our code basis as  well. It's something that people do. And you might say, oh, that's inconceivable. It should  never happen. But as long as you're stepping outside of the rules for the language, then  anything can happen. So I have some more stuff about security because security comes typically in  layers, very much in layers. You put several layers of security on protection mechanisms on top. And  in this case, we might go into the source code and we might start trying to fix and use F gets  instead of gets, et cetera. But it's easy to forget that the easiest way to find the information you  need is if you have the binary, you just search for the strings inside, of course. I mean, it's  silly, but I still have to mention it here because you can have all these protectionism in place.  And suddenly you realize you have actually leaked the password or you have leaked information.  Similarly, if you have access to the binary, you can just disassemble the binary and you can read  the authenticate and launch function and you can read how it works. And then we recognize, oh,  that's two missiles, isn't it? And that is not allowing access. I can just use said and I can  patch that binary file on those two places and then run it. And suddenly we have access granted  whatever we do and we always launch 42 missiles. So that's also one way of doing it. If you're  doing embedded applications, for example, sending out firmware to somewhere and you allow someone  to change the firmware before they upload it into your router or switch or whatever. Well,  that can happen. So yeah, so we recognize this thing. So that is a nice way of patching it.  And you can also patch complete functions, of course. So here I write my own my authenticate  and launch David rocks launch 1983 missiles. Here is the assembler code machine code.  We just create a printf with that particular thing. And they poke it directly into the memory.  And as long as the function is smaller than the previous function, it's typically a very easy  thing to do. You don't have to move things around or anything. You just replace the function completely.  Now we're doing our stuff here without any fancy way of hacking into the system. So I just wanted  to mention those before we go into the summary finale, I'm not going to give 13 14 tricks about  how to write insecure code in CNC plus plus. First of all, this one. It's very common for  programmers to think that they know which one will be called first. Oh, it's going to call a and then  be. And that is true for all languages except from CNC plus plus. In CNC plus plus, it can either call  a first or be first. The only guarantee you have it's that they are not going to execute at the same  time. And this is called unspecified behavior. Actually, co ball now for trying also has this  feature, but all the other languages that you know about probably will have a left to right  evaluation. So trick number one, make sure that you write code that this is bending on a particular  evaluation order. This is trick for writing insecure code, of course. Now, unspecified  evaluation order has some serious consequences, very serious consequences. And that is what is the  value of n. Any suggestions? Yeah, it's undefined behavior. It can be 42, it can be zero, it can  be seven, it can be whatever. And even if you have seen your own compiler generating exactly  the same value over and over and over again, doesn't mean that it will do so in the future.  And it certainly doesn't mean that it will do so if you change the compiler. So this is an example  of a sequence point evaluation and you get undefined behavior. So trick number two,  try to break the sequencing rules that will give you some cool effects. And I'm showing you that  one in the next one. This one, for those who have been to a previous talk about, and I've probably  seen this one before, so you don't need to answer. But I think we have time to very briefly look at  this. What do you think will actually happen if you run this code, or compile, and run this code  in your development environment without picking up your computer? Just try to guess. You have some  experience with your own development environment. What do you think your compiler will do?  I'm quite sure this will compile and this will run cleanly. So you don't need to look for  semicons or whatever missing semicons. It's going to print the value. What do you think it will print?  First one.  Second one. Seven. I like that. Anything else?  Eleven. I like that as well. Anyone higher? Yeah? 15? Oh, 21. That's even better. Anyone higher?  Well, this is what happened on my computer. I have many compilers on my computer. So I just  happened to pick three interesting ones. If I use the GCC that came with the operating system,  not the one that I compile myself, which I do all the time, the one that came with the operating  system, GCC gives me 12, Clang gives me 11, and Intel Compiler gives me 13.  This is a consequence of the unspecified evaluation order, and therefore the expression that you see  here doesn't make sense because we don't know whether I has been updated here or there or there,  or when the side effect of plus plus i actually happens. Yes?  You are ahead of me. Good. So trick number three, write insecure code where the result  depends on the compiler. And if you want a detailed explanation with all the assembler involved,  here is the link. So if you enable warnings for code like this,  I don't know how many flags you want.  So to write insecure code, it's important to know a lot about the weak spots,  the blind spots of your compiler, because there is always one annoying colleague that wants to add  another flag. Oh, I want minus f, whatever. So know your blind spots, and the compilers will  typically not, well, they will try to warn you about things, but very often they can't see it,  and sometimes they can see it, but they have decided that I'm not going to warn anyway to  diagnose this. And remember when you have undefined behavior, and that's what we saw,  we saw undefined behavior, and that's the reason why the compilers can just do whatever they want.  Anything can happen. There is this saying on constancy that when a compiler encounters  a kind of an illegal construct, it can try to make demons fly out of your nose. That's  okay behavior. And this is what we see in this particular example. I'm not going to spend time  on that one because we already discussed slightly this Boole problem earlier.  But the point is that if you have code like this, and the problem is we don't initialize B,  but we are still reading it. So that means B in theory can be whatever value,  or in practice can be whatever value. So if you just put on a main and a bar here,  just to poke, for example, the value two into this memory location, remember how the stack  was working on my machine. Then we get the situation where it's trying to evaluate B  that has an internal representation of something that is not zero or one.  And the compilers that behave differently. The Intel compiler in this case will give through,  clang will give false, and GCC have this quantum behavior and gives me both through and false  at the same time. So maybe this is the first preparation for quantum computing. With optimization  that just happened to all of them happened to do false. So this is also you see an example where  the value changes completely with optimization as well. And it's different between the compilers.  And once again, I described two concepts in this 90 minute talk that I did at Acura last year  with all the assembler involved, and it was the previous one and it was this one.  So if you want to see all the assembler code and explanation for why this is happening, then  you can go there and have a look. So write insecure code by messing up the internal state of the  program. Now this one, anyone see a problem with this function? Apart from being stupid and doing  nothing serious? I mean, we're quite used to write the function that takes an integer  and do something with that integer and then return something. So this is innocent looking code.  But there is a problem. We can get integer overflow. Because if we send in a large value,  in this case int max, then we get signed integer overflow and that is undefined behavior in c  and c++. So and you remember when you have undefined behavior, anything can happen.  So this might happen.  Of course, you might say, well, unlikely. But remember, anything can happen.  Even that thing, even though I would be surprised if it actually happened,  it was a real phenomenon. But in theory, anything can happen.  So make sure you write insecure code by only assuming input valid input values.  Don't check for large integers before you're doing calculations with it because  that will make your code more secure and less buggy.  Number seven, trick number seven, now trick number eight, this one. Now I have a small loop  that is basically looping through i. And I've already given you a small hint about what might  happen here. But this one terminates after doing four calculations and printing out for values,  which is fine. That is what you would expect maybe. But if you combine with optimization,  this can happen. And this actually happens on my machine.  So what looked like a valid terminating condition is not a valid terminating condition in this case.  Because this thing can never be true. No, it can never be anything but true.  We are doing additions and signed integer overflow is not allowed. So either it's  crappy code or this can never be anything but true. So the compiler will change it to true  and therefore eliminate the code. If you have a good compiler, though,  lousy compilers, they don't see these kind of things. So write insecure code by letting the  optimizer remove apparently critical code for you. And here is a big topic. And there are  plenty of C++ examples as well I could have used. What is the big problem here?  It's of course the use of this one. It looks like a kind of a secure way of copying things.  And it has a very bad name, but it was invented like 220 years ago, so they didn't think that far.  Just kidding about 220 years. But the point is that true and copy is not doing what you think it does.  Because it's not null terminating the string. So if you write a large string,  for example, if you write global term, in this case, you are filling up the buffer.  And it's going to stop there. It's not going to do the buffer overwrite as, for example,  true copy would have done or whatever. But it's going to truncate it without null terminating.  So the effect is that when you print it out, it will continue after the string and into the next  buffer and you get this information leakage. Whenever you see true and copy, you should expect  to find this line afterwards. And if you don't find that afterwards, you are probably looking at a bug.  So you can just scan through your source code, look for string and copy, and if you don't see  that terminating thing afterwards, you're probably looking at the bug. So write insecure code by  using library functions incorrectly. And of course, you should never allow the stack protector to  kick in so you can disable it with minus ethanol stack protector. Disable it.  You should also make sure that ASLR is not working. You can either turn it off  or you can compile your code as not position independent. That's useful.  And make sure you use an old hardware and old operating systems like five, six, seven years old  machines and operating systems because if you're lucky, they don't have this  data execution prevention. It's an X bit in place. So go back a few years. Use those kind of old  stuff. And here is another one. The difference, I've just showed an example here where I compile my  program with using shared libraries and one with static libraries. And that makes a huge difference  in the size of the program. So you see, in this case, it's only 7K and this one, it's 780K.  The cool thing about that is that the larger the file is, the more gadgets you can find.  So if you want to do ROP, you want to have a huge program that has a lot of kind of random data  in there so you can find a lot of gadgets that you can chain together and start exploiting the  program. Make it easy to find ROP gadgets in your program. And you should not check the  integrity of the code. So you should not do checksum. When you distribute the code, you should  certainly not do a checksum when you load the program and install it on your machine and start  running it because that would make it difficult to kind of do patching of the binaries. So skip  the integrity checks. And finally, perhaps most important, you must never, ever let other  programings review your code. So pair programming, forget about that. Never review code because  your colleagues might see all the crap that you are creating. So that was the advice for  writing insecure code. And here is the summary. And thank you very much. So we are out of time,  but I will hang around here a bit and if you want to ask about something particular here.
Olve_Maudal_-_Insecure_coding_in_C_and_0_3527.png Olve_Maudal_-_Insecure_coding_in_C_and_3528_3911.png Olve_Maudal_-_Insecure_coding_in_C_and_3912_4475.png Olve_Maudal_-_Insecure_coding_in_C_and_4476_5495.png Olve_Maudal_-_Insecure_coding_in_C_and_5496_8387.png Olve_Maudal_-_Insecure_coding_in_C_and_8388_10247.png Olve_Maudal_-_Insecure_coding_in_C_and_10248_10427.png Olve_Maudal_-_Insecure_coding_in_C_and_10428_15107.png Olve_Maudal_-_Insecure_coding_in_C_and_15108_17711.png Olve_Maudal_-_Insecure_coding_in_C_and_17712_17819.png Olve_Maudal_-_Insecure_coding_in_C_and_17820_19127.png Olve_Maudal_-_Insecure_coding_in_C_and_19128_20903.png Olve_Maudal_-_Insecure_coding_in_C_and_20904_21503.png Olve_Maudal_-_Insecure_coding_in_C_and_21504_21923.png Olve_Maudal_-_Insecure_coding_in_C_and_21924_25835.png Olve_Maudal_-_Insecure_coding_in_C_and_25836_25883.png Olve_Maudal_-_Insecure_coding_in_C_and_25884_26459.png Olve_Maudal_-_Insecure_coding_in_C_and_26460_27875.png Olve_Maudal_-_Insecure_coding_in_C_and_27876_31739.png Olve_Maudal_-_Insecure_coding_in_C_and_31740_33119.png Olve_Maudal_-_Insecure_coding_in_C_and_33120_34007.png Olve_Maudal_-_Insecure_coding_in_C_and_34008_34475.png Olve_Maudal_-_Insecure_coding_in_C_and_34476_34847.png Olve_Maudal_-_Insecure_coding_in_C_and_34848_35759.png Olve_Maudal_-_Insecure_coding_in_C_and_35760_38327.png Olve_Maudal_-_Insecure_coding_in_C_and_38328_40559.png Olve_Maudal_-_Insecure_coding_in_C_and_40560_40643.png Olve_Maudal_-_Insecure_coding_in_C_and_40644_40691.png Olve_Maudal_-_Insecure_coding_in_C_and_40692_42707.png Olve_Maudal_-_Insecure_coding_in_C_and_42708_43187.png Olve_Maudal_-_Insecure_coding_in_C_and_43188_43331.png Olve_Maudal_-_Insecure_coding_in_C_and_43332_46499.png Olve_Maudal_-_Insecure_coding_in_C_and_46500_46631.png Olve_Maudal_-_Insecure_coding_in_C_and_46632_50303.png Olve_Maudal_-_Insecure_coding_in_C_and_50304_51767.png Olve_Maudal_-_Insecure_coding_in_C_and_51768_53867.png Olve_Maudal_-_Insecure_coding_in_C_and_53868_57407.png Olve_Maudal_-_Insecure_coding_in_C_and_57408_57455.png Olve_Maudal_-_Insecure_coding_in_C_and_57456_59735.png Olve_Maudal_-_Insecure_coding_in_C_and_59736_60071.png Olve_Maudal_-_Insecure_coding_in_C_and_60072_63263.png Olve_Maudal_-_Insecure_coding_in_C_and_63264_63491.png Olve_Maudal_-_Insecure_coding_in_C_and_63492_64211.png Olve_Maudal_-_Insecure_coding_in_C_and_64212_65723.png Olve_Maudal_-_Insecure_coding_in_C_and_65724_65831.png Olve_Maudal_-_Insecure_coding_in_C_and_65832_67739.png Olve_Maudal_-_Insecure_coding_in_C_and_67740_67799.png Olve_Maudal_-_Insecure_coding_in_C_and_67800_68003.png Olve_Maudal_-_Insecure_coding_in_C_and_68004_68435.png Olve_Maudal_-_Insecure_coding_in_C_and_68436_68999.png Olve_Maudal_-_Insecure_coding_in_C_and_69000_69155.png Olve_Maudal_-_Insecure_coding_in_C_and_69156_70511.png Olve_Maudal_-_Insecure_coding_in_C_and_70512_70811.png Olve_Maudal_-_Insecure_coding_in_C_and_70812_70943.png Olve_Maudal_-_Insecure_coding_in_C_and_70944_71663.png Olve_Maudal_-_Insecure_coding_in_C_and_71664_71711.png Olve_Maudal_-_Insecure_coding_in_C_and_71712_71771.png Olve_Maudal_-_Insecure_coding_in_C_and_71772_71819.png Olve_Maudal_-_Insecure_coding_in_C_and_71820_71951.png Olve_Maudal_-_Insecure_coding_in_C_and_71952_71999.png Olve_Maudal_-_Insecure_coding_in_C_and_72000_72239.png Olve_Maudal_-_Insecure_coding_in_C_and_72240_73199.png Olve_Maudal_-_Insecure_coding_in_C_and_73200_73439.png Olve_Maudal_-_Insecure_coding_in_C_and_73440_74399.png Olve_Maudal_-_Insecure_coding_in_C_and_74400_74543.png Olve_Maudal_-_Insecure_coding_in_C_and_74544_74735.png Olve_Maudal_-_Insecure_coding_in_C_and_74736_77987.png Olve_Maudal_-_Insecure_coding_in_C_and_77988_78539.png Olve_Maudal_-_Insecure_coding_in_C_and_78540_79871.png Olve_Maudal_-_Insecure_coding_in_C_and_79872_80195.png Olve_Maudal_-_Insecure_coding_in_C_and_80196_80531.png Olve_Maudal_-_Insecure_coding_in_C_and_80532_83387.png Olve_Maudal_-_Insecure_coding_in_C_and_83388_84167.png Olve_Maudal_-_Insecure_coding_in_C_and_84168_84635.png Olve_Maudal_-_Insecure_coding_in_C_and_84636_85259.png Olve_Maudal_-_Insecure_coding_in_C_and_85260_85631.png Olve_Maudal_-_Insecure_coding_in_C_and_85632_87563.png Olve_Maudal_-_Insecure_coding_in_C_and_87564_87827.png Olve_Maudal_-_Insecure_coding_in_C_and_87828_90563.png Olve_Maudal_-_Insecure_coding_in_C_and_90564_90887.png Olve_Maudal_-_Insecure_coding_in_C_and_90888_91235.png Olve_Maudal_-_Insecure_coding_in_C_and_91236_91799.png Olve_Maudal_-_Insecure_coding_in_C_and_91800_92423.png Olve_Maudal_-_Insecure_coding_in_C_and_92424_92987.png Olve_Maudal_-_Insecure_coding_in_C_and_92988_93095.png Olve_Maudal_-_Insecure_coding_in_C_and_93096_93587.png Olve_Maudal_-_Insecure_coding_in_C_and_93588_93815.png Olve_Maudal_-_Insecure_coding_in_C_and_93816_93995.png Olve_Maudal_-_Insecure_coding_in_C_and_93996_94307.png Olve_Maudal_-_Insecure_coding_in_C_and_94308_94391.png Olve_Maudal_-_Insecure_coding_in_C_and_94392_94535.png Olve_Maudal_-_Insecure_coding_in_C_and_94536_94871.png Olve_Maudal_-_Insecure_coding_in_C_and_94872_94922.png
in 20 now. So welcome to this session about insecure coding in C and C++. First of all, I have to make a small disclaimer because it's not that much C++ here. Everything I'm talking about is also relevant for C++. But there are few or actually nothing that is specific for C++ per se. And that's quite typical when you walk down in the stack and close to the hardware. The other thing is that I kind of promised lots of assembler. But when I compare it to a few other talks that I've done, for example, test driven development in assembler. And another talk I did last year, where 90-minute talk where I think 60, 70% of the slides were in assembler. I have to admit it's not a lot of assembler, but it's enough. So some assembler in this talk. But perhaps more important in the program, it's impossible to see what kind of level talks are at because it's not written in the program. And when I sent in this proposal, I deliberately set it to introduction and a general kind of overview of how to do insecure coding in C and C++. So if there are any deep experts in hacking programs on machine code level, you might be disappointed. It's not an expert talk. It's not even advanced. It is a general introduction to a lot of concepts that are useful to know, both if you want to write insecure code, but also if you want to write secure code. So it's an introduction talk. But just checking, is there any kind of hackers in the room that really know this stuff? Okay. Just anyone that know about cold injection? Yeah. A few people. Anyone that have done it in the last 10 years, because everybody did it when they were kids, but in the last 10 years? Okay. Not so many. But that's good because then it's nice to have this introduction level. So being stupid is a privilege to some extent. But you can also do dumb things intentionally. And you have to admit that these guys, these guys, they do actually know a few things in order to do so many stupid things that they do. And I hope this talk will also focus on knowledge-based ways of doing stupid things in C++. So there is nothing special with my machine when I'm referring to it. Apart from it's just a 32-bit Linux kernel, fairly recent, with a fairly recent compiler, and a fairly recent Ubuntu distro. I wrote the main of this talk in March. So if I wrote the main of this talk now, I would have just upgraded it. But it's nothing special in there. So that's not where to look for faults, etc. This is something that you can do on all types of machines and operating systems and compilers that you find out there. So in this talk, I will briefly discuss the following topics, StackBuffer overflow, also called Stack Smashing. How the call stack and activation frame is working. I just have to go through that, even if most people have a reasonable understanding of how it's working. Well, most C programs have a reasonable understanding of how it's working. I need to go through it because I will refer to a few of those things later when I explain how to write exploits, how to do arc injection, code injection, how a few protection mechanisms are working. There is some feedback in the audio. I'm getting some feedback in the audio. Okay, it's probably good. And then some protection mechanisms like ASLR, StackCanaries, and a fancy mechanism called return-oriented programming. Who knows about return-oriented programming? Okay, three, four people who have not only heard about it, but actually read about it and studied it a bit. Nobody, good. Because I don't know very much about it. I wasn't sure if I was going to include it because while I think I understand it, I don't understand it well enough to explain it really well. So I've just done a very brief explanation of return-oriented programming. Then I'll show some things about how to write code with surprising behavior. Talk about layered security, information leakage, how to patch boundaries, and in the end I will do a summary where I summarize a few tricks for writing in secure code. All of this in 60 minutes are actually 55. So we better get started. But now we understand it's an overview. It's not going deep into anything really. But take a look at this code first. It's a small program. Of course, it's a contrived example. I'm using it just to illustrate a few other concepts. So I had to make some stupid stuff in there. And of course, the key thing here is the use of gets and the buffer, the response buffer. That is what we're going to have fun with. And I guess we all know that gets is a function that you should never use. And it has been removed from the language now. But it's still a nice function to have there when you want to kind of explain in a simple way how stack smashing can be done. There are so many other ways you can do it. So don't be confused by me using gets in this example because there are hundreds of other ways you can do exactly the same thing. Yeah. Of course, it doesn't use gets and that's good because it has been removed from the language. But for now, we are going to use it. Let's see what happens when you try to execute this code. So it was supposed to work like this. When you run the program, it's asking you for a secret. And if you type in your name, which name should I type in? Anyone remember the movie? Oh, you're close. But the hacker was named David. So you try with David first. And David is not the keyword. So access is denied. And the operation completes. Nothing has happened. Okay. So that was how it was supposed to work. If you type the wrong secret. But if you went into it and typed the right secret, Joshua, the name of the professor, then access was granted to the system and two missiles were launched. Operation complete. And now we are going to look at kind of the simplest way of exploiting this because if we type in a very long string, bad things will happen. And in this particular case, my machine, I got access granted. Even though through comp didn't work. And it was launching a few missiles. And operation was complete. Did anyone see something strange here? Yeah. We got both access granted and access denied at the same time. So not have we only kind of launched how many millions of missiles. But we have also seemed to create a program kind of messed up the program in such a way that it becomes unstable and seemed to both pick this path and this path at the same time. Now, for those of you who have seen some of my previous talk last year, you might remember why it is like that. I will come back to it and explain it. But first of all, I will look at this one. Why did we get so many missiles? And in order to understand, to kind of explain that phenomenon, we need to understand how the stack is working and what is happening when the program is executing. So due to an overflow, what has happened is that we have messed up, changed the value of allow access and we have changed the value of end missiles. And this is the strange thing that we will look at later. So what we just saw now is what is typically called Stack Buffer Overflow and sometimes Stack Smashing. There was a famous paper that came out in the 90s called Stack Smashing for Firm and Profit. That in some way changed the computer industry because suddenly a lot of attention came into this point that we need to kind of write bug free code and certainly not allow Stack Buffer Overflows because there are so many things you can do. And while it is common to hear C and C++ programmers discuss with each other and say, oh, this is a stack variable and this is on the stack and there is a call stack and activation frame, etc., it is important to know that the standard never says anything about the stack. So although it is very common for a C program and C++ program to actually use a call stack and activation frames when executing, this is not something that is mandated by the standard. So if the compiler or the optimizer can create a similar behavior without using a stack, it is allowed to do so. So this depends very much on the optimization level. But from a conceptual point of view, it is reasonable to think about an execution stack that works approximately like I am just going to describe now. And it is not. While I have been doing this on a Linux on an Intel CPU, this is approximately the same as all typical CPUs are working. So for what happens here when we start the program is the operating system is loading the program into memory and then it is passing control to usually something called start, which is often in a C runtime library. And inside of start, it is not doing very much. It is setting up the call stack, maybe initializing some variables, preparing for dynamic memory allocation, etc. But very soon it will jump into main. And once inside of main, it will start executing the assembly instructions that are represented. That is a representation of this code. So the call stack has been set up before we enter main. And it is useful to draw it like this. High address, low and low address on top, because nearly all call stacks, they grow from high address up to the low address. So if you try to draw it all the way around, it is difficult to reason about it, at least sometimes. So the first thing that happens when it is jumping into main is that the start, the runtime start library has pushed the return address, kind of the next instruction that is supposed to be executed when main is finished. And so when, so this is coming in here, the return address, the next instruction in start. And once inside of main, main will then set up its own activation frame by putting a pointer to the previous stack frame so that it can be restored. And now it has its own activation frame that it can use. So when it is supposed to execute puts, it will first put a pointer to the string onto the stack and then jump into and then the return address, the next instruction in main that should be executed, which is this one. And then it will make the jump into puts that can do whatever it wants. But it is usually just building another activation frame and behaving like others, but it doesn't have to do that. And when puts is finished, these things go away, kind of like garbage collection, not in use anymore. And before calling authenticate and launch, the same procedure happens again. We push the return address of the next instruction, which is here. And then it jumps into authenticate and launch. And then restore the pointer to the previous stack frame. And then allocate space for these local variables. And local variables or stack variables is not a very exact name. So if you are wondering how this is working and you use those inexact names, you typically end up in discussions between people that is not necessarily experts in the topic. So if you really want to go to the places where they discuss how this is really working, you should use variables or objects with automatic storage duration, because that is the word that is used in the standard. And it's in some way a much better word because it doesn't indicate that this is going on the stack. But now you see we have put stuff here, allow access and miss all response. Anyone see something that might be a bit strange there? The order? Yeah. So it's, I'm not trying to pick on you there, but thanks for playing. It's very common for programmers to believe that they have a correct idea about how things are laid out on the stack. But there is no reason why programmers should be able to reason about that because as soon as you increase the optimization level, for example, things will be rearranged. Some things will be stored on stacks. Something will never be, never get actually a physical memory or whatever. And these kind of rearranging, the order is very typical for all compilers. They do that all the time. So there is no correct order in this particular case. But this is what happened, exactly this happened on my machine when I was executing it. And then we go into print. We just follow the same thing, point it to the string, save the return address, save the previous stack frame, print it, and then we get into gets, which is the culpate here. Now, the reason why we get this problem is, of course, gets doesn't have any idea about how many characters it's allowed to write. So depending on how many you are writing, it's just going to continue poking stuff into memory. And any input eight characters or more will cause a problem. And this is exactly the stack data that I got when I executed this on my machine. And most of this stack is basically just padding to make sure that things are aligned properly in memory. So it doesn't really matter what kind of values are there. But we recognize with some training at least, you look at the stack frame and the stack data and you start recognizing that this is the return address. This is the pointer to the stack frame. This is allow access and missiles response and pointed to the response buffer. So by focusing on the stack variables, per se, this is what happened when I typed in global thermal nuclear war. Okay. And now we partly have an explanation for why we got, how much is it? One billion missiles because this number is 1.8 billion. And, but we are also close to see why this happened. Access granted and access denied. And it's because of this one. The 6C here. And the first time I saw this, I was kind of surprised. That's, I think it was two years ago when 6, when GCC 471 came out. It was the first time I saw this particular issue. But I studied the assembler code. It was blogged by Mark Schroyer first. And I continued in his direction and I studied the assembler code. And what I saw was that GCC and my compiler in this particular case basically said that a bool is always either zero or one and never anything else internally in memory. So if someone messes up so that it's neither zero or one, you get this behavior. This is sort of a sampler of the C code. Because when you read the assembler, you see that in order to decide whether you should do access granted or not, it basically says, is allow access not zero? Then I'm going to allow grant access. And the next thing in the sampler code is that if allow access is not one, then I'm going to deny access. And if for some reason allow access becomes anything but zero or one, you get this kind of quantum behavior in your code. And this is not limited to bool. This happens all the time when you mess up the internal data structures inside of your program. So by allowing in some way memory overrides, you can also get this very, very strange and surprising behavior like this. So going back to our understanding of how the stack is working on my particular machine, we also see that now we can write a small script printf unix command, where we basically just send in eight characters because we don't care anyway. And then we type in two a, put that into end missiles, and then we put in one to allow our self access. And that gives us launching 42 missiles and operation complete. And now we have a way of controlling the program. But using scripts like this is not a very effective way of exploiting. So it's perhaps more common to see exploits, for example, written in C or Python, for example, that are in this case, building up a structure that is exactly the same as the stack on that particular machine. And now we can programmatically say, I want to allow access to be true, I want end mass missiles to be 42. And then I'm just writing this into the place where I can kind of put the payload or this is not really a payload, but where I can put the data and really control how the program is working. Yeah. So now we see we have a programatical way to do it. But we perhaps we also see a new opportunity now. What about this one? This was the return address. This is the place where it's supposed to jump when it's finished with a function. Hmm. What would happen now if we write an exploit more like this? We still, we increase our struct because we're going to map a bigger part of the stack on the target. So we still allow access. We launched three missiles. But now we are poking also in the particular address for where this function is supposed to return. So it's, we are not, we are saying I don't want you to go necessarily to put operation complete when you're finished. I want you to do something else. And in this case, this particular address happened to be pointing to the beginning of authentic at the launch again. And now I have a way to, I've changed the path, the execution path of the program in such a way that it's basically launching more and more missiles and just for fun. I'm increasing the number of missiles every time. So four, five, six, seven, eight, nine missiles should be launched. And this is called arc injection. It's not very often used like this going back to your own function. What it's more used, typically more used for is to jump into one of the library routines. So, for example, first you push, you push the address to a string that you have poked into memory somewhere. And then you change the return address and jump into a libc function, for example, system. And suddenly you can invoke Unix commands inside of the program. And that's the reason why arc injection is often called return to libc because that's where it's mostly used to jump into libc. Any questions around that? Yeah? No? Feel free to stop me during the talk. So now we have looked at arc injection and return to libc, which is a very common way of exploiting a program. But we are not limited to that because we can also let the compiler generate another compiler, perhaps generate some values, a small program that we can put on the stack. And in this case, I've just written a small function and compiled it with gcc. I already get all kind of the hex values that I need to know so that now I can take this, create a string with these hex values, and I can write it on the stack, and I can jump to that location in memory and start executing code. So this is another way of doing arc injection. You inject some code first and then you jump to that code. Sometimes it's difficult to kind of calculate exactly where you should start. So it's very common to use a knob slide where you have thousands and thousands of no operation knobs first so that it doesn't really matter where you are hitting because you will hit somewhere and then the execution will just do no, no, no, no, no, no, and then suddenly execute your code. And that's what is called a knob slide. So can I demonstrate code injection? Well, it used to be very easy to do so back in the old days. And that's the reason why I said in the last 10 years because while it was easy to do it on the Commodore 64 and the early 8080 machines, etc., early PCs, for the last 10 years there has been this annoying data execution protection mechanism which is using a write or execute strategy, sometimes called an XPIT, where it basically says when a program or operating system is asking for a page of memory, it has to say, is this going to be data or is it going to be executable code? And it cannot be both. And this mechanism is very effective to prevent the possibility of executing a code that is stored in the data segment and not in a code segment or a code page. So, but it's not the only protection mechanism out there that is useful to know about. There are plenty of them, but they are often easy to turn off. And one of them is called address, space, layout randomization. And it also became common on major operating systems like, I'm not sure, five, six, seven years ago. So, now all the regular operating systems tend to implement it. And that basically says that before we had the situation where when you execute to the program, it tends to always go into the same place in memory. All the addresses were the same. So, the stack were at the same place, the global, the functions were approximately the same place and also the library routines were at the same place. But with ASLR enabled, then every time the operating system is loading a program into memory, it tends to put them in different places. So, it becomes slightly more difficult to guess where things are in memory. So, it's more difficult to kind of jump into a particular function, etc. Now, this is considered to be a very kind of minor obstacle because there are so many ways you can do information leakage. You can first get the information of where things are stored in memory and then you can calculate exactly where it needs to be. So, while it's slightly annoying, it's not considered to be a very, very strong mechanism. And also, in order for ASLR to work, you need to have compiled with position independent code and position independent executable. And this is not on by default in typical compilers. So, you have to explicitly say, I want position independent code for ASLR to work. And often, people are not willing to pay that 10% extra, well, 10-ish percent extra price of having position independent code. So, but there are many ways of disabling it. You can even poke stuff into your kernel where you basically say, no, I don't want ASLR anymore. You can boot up your machine without ASLR. And of course, you can make sure that your code is not position independent. Here is another mechanism, which is called Stack Protector, often. And that one is injecting a so-called Stack Canary. Stack Canary. Here is the Stack Canary. So, the body of the function is the same, but in the preamble, just before executing the body, it's poking, yeah, supposed to be random value into a memory location and XORing that one. And then when it's exiting the function, it's checking, has this canary died, has it changed? And if it's changed, then it's just going to, the program is going to terminate. So, at least it doesn't continue in an invalid state. And this is enabled by doing minus f Stack Protector, which is often default on modern compilers, because this is not a very costly operation, because the Stack Canary only comes into functions that actually do have a potential for doing buffer overflows. So, it's not something that, it's not the cost you have to pay for every function. But not only does it put in this magic value, but it also moves around, often it moves around the variables. So, in this case, the response buffer is at a higher address than it was before. And that is nice, because it means if you are overwriting it, you can't, it's difficult to change allow access and admissance. And this is a deliberate strategy that they are using, putting that kind of the vulnerable buffer at an high address. And some people have actually suggested that we can solve all the security issues if we start making our execution Stack grow up instead of down. I never understood that proposal, and it seems like there is a, it's not a very popular suggestion out there, but it's interesting thought of that you can the position of your Stack variables depends on how easy it is to exploit the program. But finally, when you have of the protection mechanisms, we have this data execution prevention, Stack protectors, SLR and similar techniques, they certainly make it difficult to hack into a system. But there is a very powerful exploit technique called return oriented programming that has become very popular in the last few years. I think the first paper around Rop came out in 2006, 2007, but it became common to use it only a few years ago. And according to someone that knows this much better than myself, Rop is used in nearly every single exploit that you hear about these days. And it's a very powerful technique and it's apparently impossible to stop it. And the reason is how a machine is working and how we are executing code. I take my binary now, which is called launch, and I just dump the data on that binary file. And by studying that data, I start recognizing a few things here that is very useful for Rop. Anyone know what these are? C6? Not loop? Oh, it's not no operation either. It can be used for jump, that's the point. It's actually the RET instruction. It's a RET instruction. And there are other useful instructions out there that you can use, but the nice thing about RET is that it's reading from stack and address. And moving it into the EIP, the instruction pointer. And in that way, you can build up a lot of addresses on the stack. And when you start unwinding the stack doing returns, it will just pick another return address and jump around. And I show you these things. You usually have programs, and this is called Rop Gadget. There are millions of those programs out there, which can look at the binary and then figure out, here are all the small bits and pieces of code that is unintentionally in your binary. For example, if I want to just to show you a very simple example, just before I return back to main, for some reason, I want to increment ECX. I just want to run this small kind of assembly instruction ECX and then return. Then I can put this address onto stack first, and then have the real return address afterwards. And then it will first jump there, run int ECX, then run return, and jump back to main. And it has increased ECX by one, as if nothing has happened. But you're not limited to do it one. You can actually build up a chain of these gadgets that are each doing a small little assembly instruction. And it has been shown on, I think it's on Intel, ARM, and Spark CPUs. It has been shown that there is often a Turing complete set of these gadgets on the programs that are running on them. So it is possible to imagine that by finding these gadgets and creating a long chain of small bits and pieces that is going to execute by just reading the stack and doing return, return, return, return, but just before the return doing a small thing, you can build up a whole program in there. And this is the technique that is often used. And it's very difficult to do by hand. So you typically always use programs, like in this case, ROP gadgets, which can also, it can find the gadgets and it can chain them together for you if you want something to do a particular command. And then you have the payload that you can just dump into your target program. Yeah? Yes, you want to get around the no execute program. So you basically, you create your program as just a long string of data. And then you let original program jump around in its own executable doing all these small pieces of instructions. So that's what return-oriented programming do. And just one of the more famous stories around return-oriented programming, and probably one of the stories that made it kind of famous and magazines and newspapers were writing about it. Some researchers into return-oriented programming that asked for access to the new vaulting machine that we're using in the States, which had, I don't know how many hundred security researchers employed to kind of create a really secure machine. And they used this technique and they showed that they could actually exploit the vaulting machine that was just designed to be unbreakable. And so far, there are very few suggestions on how to protect programs from exploit by return-oriented programming. So back to more, well, this is what I showed now, is very realistic, but now to something slightly different. Here is a case which I find very, very interesting. And now that I know more about this one and similar cases, I see this all over the place and code bases. Now, this function, which is of course contrived because it's small and I have to put it on the page. But there is a fairly common idiom here. And that is, in this function, we are given a pointer and an offset and an end of the buffer that the pointer is pointing at. And then a value to poke into it. So just to be kind of secure, first we check if pointer plus offset is bigger than end because then we have an auto-bond. That's not good. The next thing we do, now the offset is an unsigned value, but still we can have this kind of wrap going on. So if it's a very large value, you can imagine that pointer plus offset becomes less than pointer and that gives you, oh, it's a wrap. And that's not good. We don't want that. So we return and if everything is okay, we are confident that okay, we are within the buffer, then we poke the value in. And according to the researchers that the paper that I read about this, it was published, the one I read was published in November last year. This is a very common idiom also in what we would consider serious software. So they found a lot of, for example, Linux programs, even in kernel modules that use this as an idiom for checking for wraps. But the problem is, and this is the auto-bond guard and this is the wrap guard. So if we compile this without optimization, it works exactly as it is supposed to work. So we give it some large numbers. It's poking into the buffer. Then it detects, oh, we are out of buffer. And since we use very large initial values, we get this wrap now. And yeah, so this seems to work. But with optimization, this happens. Out of bounds, out of bounds. And now it's just poking into memory. So why is that? And this is something that you will see more and more of when you have code that has been working for a decade or two. And then suddenly a new optimization technique comes in. And it starts reasoning more, better and better around your code. And in this case, there was a new version of a few compilers that came out where they figured out that this can never happen. I mean, this is, first of all, pointer overflow is undefined behavior in C. So this is not going to happen anyway. So why should we generate code for something that will never happen? So if you look at the assembler here, it looks like this and without going into details on that one, what has basically happened is that it's a, well, this can never happen. So it just deleted it. This code is not present in the assembler. And this is something that you see over and over again that the optimizers that become smarter and smarter and suddenly they remove code that you thought, oh, that's useful code. The compiler is smarter than you and say, if that is going to be true or that is going to be false, then there must be undefined behavior. Of course, you're not doing undefined behavior. Are you? So I just remove it. You want fast code? That's the reason why you write in C and C++. And the research paper, they claims that there were like 200 modules or something like that in the Linux code that used this idiom or that idiom was used in 200 places. I can't remember exactly the numbers, but it's a common thing. And I see it in our code basis as well. It's something that people do. And you might say, oh, that's inconceivable. It should never happen. But as long as you're stepping outside of the rules for the language, then anything can happen. So I have some more stuff about security because security comes typically in layers, very much in layers. You put several layers of security on protection mechanisms on top. And in this case, we might go into the source code and we might start trying to fix and use F gets instead of gets, et cetera. But it's easy to forget that the easiest way to find the information you need is if you have the binary, you just search for the strings inside, of course. I mean, it's silly, but I still have to mention it here because you can have all these protectionism in place. And suddenly you realize you have actually leaked the password or you have leaked information. Similarly, if you have access to the binary, you can just disassemble the binary and you can read the authenticate and launch function and you can read how it works. And then we recognize, oh, that's two missiles, isn't it? And that is not allowing access. I can just use said and I can patch that binary file on those two places and then run it. And suddenly we have access granted whatever we do and we always launch 42 missiles. So that's also one way of doing it. If you're doing embedded applications, for example, sending out firmware to somewhere and you allow someone to change the firmware before they upload it into your router or switch or whatever. Well, that can happen. So yeah, so we recognize this thing. So that is a nice way of patching it. And you can also patch complete functions, of course. So here I write my own my authenticate and launch David rocks launch 1983 missiles. Here is the assembler code machine code. We just create a printf with that particular thing. And they poke it directly into the memory. And as long as the function is smaller than the previous function, it's typically a very easy thing to do. You don't have to move things around or anything. You just replace the function completely. Now we're doing our stuff here without any fancy way of hacking into the system. So I just wanted to mention those before we go into the summary finale, I'm not going to give 13 14 tricks about how to write insecure code in CNC plus plus. First of all, this one. It's very common for programmers to think that they know which one will be called first. Oh, it's going to call a and then be. And that is true for all languages except from CNC plus plus. In CNC plus plus, it can either call a first or be first. The only guarantee you have it's that they are not going to execute at the same time. And this is called unspecified behavior. Actually, co ball now for trying also has this feature, but all the other languages that you know about probably will have a left to right evaluation. So trick number one, make sure that you write code that this is bending on a particular evaluation order. This is trick for writing insecure code, of course. Now, unspecified evaluation order has some serious consequences, very serious consequences. And that is what is the value of n. Any suggestions? Yeah, it's undefined behavior. It can be 42, it can be zero, it can be seven, it can be whatever. And even if you have seen your own compiler generating exactly the same value over and over and over again, doesn't mean that it will do so in the future. And it certainly doesn't mean that it will do so if you change the compiler. So this is an example of a sequence point evaluation and you get undefined behavior. So trick number two, try to break the sequencing rules that will give you some cool effects. And I'm showing you that one in the next one. This one, for those who have been to a previous talk about, and I've probably seen this one before, so you don't need to answer. But I think we have time to very briefly look at this. What do you think will actually happen if you run this code, or compile, and run this code in your development environment without picking up your computer? Just try to guess. You have some experience with your own development environment. What do you think your compiler will do? I'm quite sure this will compile and this will run cleanly. So you don't need to look for semicons or whatever missing semicons. It's going to print the value. What do you think it will print? First one. Second one. Seven. I like that. Anything else? Eleven. I like that as well. Anyone higher? Yeah? 15? Oh, 21. That's even better. Anyone higher? Well, this is what happened on my computer. I have many compilers on my computer. So I just happened to pick three interesting ones. If I use the GCC that came with the operating system, not the one that I compile myself, which I do all the time, the one that came with the operating system, GCC gives me 12, Clang gives me 11, and Intel Compiler gives me 13. This is a consequence of the unspecified evaluation order, and therefore the expression that you see here doesn't make sense because we don't know whether I has been updated here or there or there, or when the side effect of plus plus i actually happens. Yes? You are ahead of me. Good. So trick number three, write insecure code where the result depends on the compiler. And if you want a detailed explanation with all the assembler involved, here is the link. So if you enable warnings for code like this, I don't know how many flags you want. So to write insecure code, it's important to know a lot about the weak spots, the blind spots of your compiler, because there is always one annoying colleague that wants to add another flag. Oh, I want minus f, whatever. So know your blind spots, and the compilers will typically not, well, they will try to warn you about things, but very often they can't see it, and sometimes they can see it, but they have decided that I'm not going to warn anyway to diagnose this. And remember when you have undefined behavior, and that's what we saw, we saw undefined behavior, and that's the reason why the compilers can just do whatever they want. Anything can happen. There is this saying on constancy that when a compiler encounters a kind of an illegal construct, it can try to make demons fly out of your nose. That's okay behavior. And this is what we see in this particular example. I'm not going to spend time on that one because we already discussed slightly this Boole problem earlier. But the point is that if you have code like this, and the problem is we don't initialize B, but we are still reading it. So that means B in theory can be whatever value, or in practice can be whatever value. So if you just put on a main and a bar here, just to poke, for example, the value two into this memory location, remember how the stack was working on my machine. Then we get the situation where it's trying to evaluate B that has an internal representation of something that is not zero or one. And the compilers that behave differently. The Intel compiler in this case will give through, clang will give false, and GCC have this quantum behavior and gives me both through and false at the same time. So maybe this is the first preparation for quantum computing. With optimization that just happened to all of them happened to do false. So this is also you see an example where the value changes completely with optimization as well. And it's different between the compilers. And once again, I described two concepts in this 90 minute talk that I did at Acura last year with all the assembler involved, and it was the previous one and it was this one. So if you want to see all the assembler code and explanation for why this is happening, then you can go there and have a look. So write insecure code by messing up the internal state of the program. Now this one, anyone see a problem with this function? Apart from being stupid and doing nothing serious? I mean, we're quite used to write the function that takes an integer and do something with that integer and then return something. So this is innocent looking code. But there is a problem. We can get integer overflow. Because if we send in a large value, in this case int max, then we get signed integer overflow and that is undefined behavior in c and c++. So and you remember when you have undefined behavior, anything can happen. So this might happen. Of course, you might say, well, unlikely. But remember, anything can happen. Even that thing, even though I would be surprised if it actually happened, it was a real phenomenon. But in theory, anything can happen. So make sure you write insecure code by only assuming input valid input values. Don't check for large integers before you're doing calculations with it because that will make your code more secure and less buggy. Number seven, trick number seven, now trick number eight, this one. Now I have a small loop that is basically looping through i. And I've already given you a small hint about what might happen here. But this one terminates after doing four calculations and printing out for values, which is fine. That is what you would expect maybe. But if you combine with optimization, this can happen. And this actually happens on my machine. So what looked like a valid terminating condition is not a valid terminating condition in this case. Because this thing can never be true. No, it can never be anything but true. We are doing additions and signed integer overflow is not allowed. So either it's crappy code or this can never be anything but true. So the compiler will change it to true and therefore eliminate the code. If you have a good compiler, though, lousy compilers, they don't see these kind of things. So write insecure code by letting the optimizer remove apparently critical code for you. And here is a big topic. And there are plenty of C++ examples as well I could have used. What is the big problem here? It's of course the use of this one. It looks like a kind of a secure way of copying things. And it has a very bad name, but it was invented like 220 years ago, so they didn't think that far. Just kidding about 220 years. But the point is that true and copy is not doing what you think it does. Because it's not null terminating the string. So if you write a large string, for example, if you write global term, in this case, you are filling up the buffer. And it's going to stop there. It's not going to do the buffer overwrite as, for example, true copy would have done or whatever. But it's going to truncate it without null terminating. So the effect is that when you print it out, it will continue after the string and into the next buffer and you get this information leakage. Whenever you see true and copy, you should expect to find this line afterwards. And if you don't find that afterwards, you are probably looking at a bug. So you can just scan through your source code, look for string and copy, and if you don't see that terminating thing afterwards, you're probably looking at the bug. So write insecure code by using library functions incorrectly. And of course, you should never allow the stack protector to kick in so you can disable it with minus ethanol stack protector. Disable it. You should also make sure that ASLR is not working. You can either turn it off or you can compile your code as not position independent. That's useful. And make sure you use an old hardware and old operating systems like five, six, seven years old machines and operating systems because if you're lucky, they don't have this data execution prevention. It's an X bit in place. So go back a few years. Use those kind of old stuff. And here is another one. The difference, I've just showed an example here where I compile my program with using shared libraries and one with static libraries. And that makes a huge difference in the size of the program. So you see, in this case, it's only 7K and this one, it's 780K. The cool thing about that is that the larger the file is, the more gadgets you can find. So if you want to do ROP, you want to have a huge program that has a lot of kind of random data in there so you can find a lot of gadgets that you can chain together and start exploiting the program. Make it easy to find ROP gadgets in your program. And you should not check the integrity of the code. So you should not do checksum. When you distribute the code, you should certainly not do a checksum when you load the program and install it on your machine and start running it because that would make it difficult to kind of do patching of the binaries. So skip the integrity checks. And finally, perhaps most important, you must never, ever let other programings review your code. So pair programming, forget about that. Never review code because your colleagues might see all the crap that you are creating. So that was the advice for writing insecure code. And here is the summary. And thank you very much. So we are out of time, but I will hang around here a bit and if you want to ask about something particular here.
how to do insecure coding in C and C++. So if write insecure code, but also if you want to there. So in this talk, I will briefly discuss exploits, how to do arc injection, code of return-oriented programming. Then I'll show some things about how to write code with that I need to know so that now I can take this, one of them is called address, space, layout data execution prevention, Stack protectors, SLR things. You usually have programs, and this is program. So you basically, you create your layers of security on protection mechanisms on So if you want to see all the assembler code and