 Yeah, a good evening everyone now Sorry now Matthias Pio Who does now his PhD in the software security which Sorry, I must start over I'm a bit nervous today So I'm brought to present you Matthias Pio who currently works on his PhD in software security and In a sub theme office is a software defense and within this sub team he works on a topic called string oriented programming who Where he does analyze how format string attacks can be used to attack programs. So give him a round of applause Thank you very much for the warm introduction. It kind of brought back memories to last year where I stumbled over the first couple of sentences So let's just hope that this doesn't happen this time. Thanks So to get to the topic. What is it all about the motivation behind the work that I did here was that There are a lot of additional protection mechanisms out there and they are used more and more in the wild and the standard security configuration is changing for stock operating systems So and in addition to that additional hardware mechanisms are being developed that stop all our traditional exploits And we need to find new ways to exploit these running systems to get access to the to the code and to inject our own data So we have hardware mechanisms like data execution prevention that is out there that standard That's usually available Enabled right now and it's out there in use and this makes many of the traditional exploits impossible and Or a lot harder at least and we also see you don't actually have to read this this table But this is the comparison of the Ubuntu security features from the old versions For all the old versions and basically you see that they started off is only a few Little bits and pieces enabled and the current version has like a ton of additional Security features out there that protect from many of our standard and well-proven exploits so What what can we do about that? What? part of it has been overlooked well format strings had a big hype in around 2000 and something but Nowadays they are a bit overlooked On the other hand, there's a drawback that they are very hard to construct Especially with a couple of these new protect protection mechanisms. They're out there So we need to define a way how we can deterministically Exploit these format string bugs and get access to the machine in the end and that's what this talk is all about If we look at the attack model that We assume we see that an attacker with some restricted privileges on a machine Wants to escalate his privileges up to a higher level So for example, we have a local user that wants to escalate his or her privileges to a System user account or we have a remote user without any user capabilities that wants to force user capabilities on top of that So we also assume we live in an open-source world. This has many advantages, but one of the Other of the downsides is that the attacker knows the source code And if we are using a stock stock image like for example a Ubuntu server The attacker also knows the exact binary and can replay the exact same scenario that is used on the server at home in his little playground So We have to assume that the attacker knows all these these little things on the other hand we define a successful attack to be if an attacker is able to redirect a control flow at one point in time to an alternate location by Injected data or inject the code and we also Require the attacker to execute either inject the code that is now part of the runtime image or Alternate data that is used for existing code So the outline of the talk looks a bit Like like this first. I'm going to talk to you about the existing attack vectors that are out there the protection mechanisms That are used to combat these techniques Then I'm going to introduce string-oriented programming show you a little demo or two if time permits and in the end conclude and if the demo works as we've seen up with the Insile irons with the Telecom guys so The first of the attack vectors that we all got very used to and we all loved was code injection, which is One of the very nice and simple exploited inject additional code into the runtime image of an application through some Not through some attack factor. Maybe we can use a buffer overflow to inject code into the runtime image but the code is injected as data so the Processor will just execute that given data as new code and in the end The attacker will have control over the application So if you have this little example program We have a nice little buffer on the on the stack and we execute our little string copy function The buffer of course is limited and in the end We will be able to override some stack data with that for this example. We assume No protection mechanisms as have been around in the late 90s and early 2000s The stack looks a little bit like this We have our stack frame from the bottom then we have the first argument to our little function safe return address a base pointer and our little temporary Array on the stack so we start to copy our user input down from that From that pointer and we will end up with something that looks like this We have some nice little knob slide and exploit code that we injected through that Data buffer and we override the return address to point back to the beginning of the buffer and in the end we can get control over Over the application like that because we redirect the control flow We injected new code and in the end we execute arbitrary code that is controlled by the attacker well, but things have changed since then modern hardware and operating systems separate data and code so on a Page-level granularity the operating system can enforce that it's either data or code that is on that On that memory page and if it's data and the attacker writes his nice code into that data page And wants to execute it by overwriting the return instruction pointer The processor will raise an exception and stop the program because it is not allowed to execute Due to this additional hardware code injection is no longer feasible because the protection mechanisms ensure that a page is either writable or executable, but never both on The other hand there are some limitations if we have a chip program like a Java virtual machine or things like that They have a couple of pages around in memory where they place dynamically generate a code So we might still be able to get lucky with these old-school exploits once in a while if the circumstances are right so We already heard a little bit about the different protection mechanisms But let's just look at the three most dominant protection mechanisms that are out there that make our lives a little bit harder so the first protection mechanism is data execution prevention called DEP or exec shield on Linux systems this protection mechanism enforces the executable bit that the hardware provides on a page-level granularity and If a page is not executable then code on that page will not be Executed by the processor this limits all our code injection exploits if it is set up correctly So if this is enabled data execution prevention We can no longer use code injection techniques to get control of the application the next protection mechanism is address-based layout randomization address-based layout randomization is a probabilistic protection mechanism that is also enabled by default on current kernels and SLR enforces that all memory addresses on the heap on the stack and for for all libraries are Dynamically shuffled around and randomized this leads to the fact that if you think back to the code injection example or the code injection exploit that We can no longer redirect the return instruction pointer to the beginning of the buffer because we have no idea Where this buffer is located in memory But the current implementation in Linux uses static application Where some part of the application still is located at a fixed address due to some optimization issues And that's what we are going to use for that and the last That's nevertheless still important protection mechanism that I'm going to talk about is pro police which is used in more current versions of GCC and so on pro police adds additional canneries a cannery is A little bird that miners used in the old times to take down into the mine and if the bird died The miners knew that well the air is getting thin and we better should get out of here the same idea applies to canneries on the stack the compiler places Secret hidden values in specific locations on the stack and checks these in specific intervals If they are still the same if there has been a buffer overflow the cannery values will change the Program will detect that and terminate itself because of the buffer overflow that happens So well if we combine these mechanisms they make our life a lot harder So let's look at what other attack mechanisms are out there that can Help us in one way or another We already know that code injection is no longer possible So we have to move to a new attack form and the new attack form No longer injects code or new code into the process image But re-executes the already existing code with new data So we search for specific code sequences Stitch them together and just use a database approach To execute arbitrary commands The idea is that we go one level higher. We no longer inject code directly But we take a different approach. We see the program as a big interpreter that runs Specific commands on top of it. So we just exploit the existing code sequences reorder them and Due to the database approach that we have we can execute arbitrary instructions in the end and also inject code then return-oriented programming is one of these database attack forms that prepares a set of stack frames on top of each other with specific return instructions or return directions To code sequences in the program that are available So if we have the same sample program from before we once again have the stack frame We use our buffer overflow, but we assume that data execution prevention is enabled. So we cannot inject code into the Onto the stack and execute it there. So we have to take a different approach we once again copy the input and We now don't care about what is in the temporary area at all But we prepare a set of return addresses to point to a gadget catalog that we pre identified based on On existing on existing code Does it get away? Yes So we search the application for nice instruction sequences that help us that always end with a return instruction so we then Implement some kind of a stack machine on a stack with additional stack frames You can see of the return address to as an indirect control flow transfer to a new catalog and the data is then used by these These instructions in the catalog and if this gadget ends or completes we execute the next gadget So this sounds like a very nice idea, but what are the drawbacks? If we if we use such an exploit we can we still have to problem with address based layout randomization because we don't know Where to place the data and what we can do is that and we also have a problem with pro police with the stack canaries because We just overwrite them and we are not able to To execute the first indirect control flow transfer that gives us the control over the application So we have to escalate a little bit further We have to find Refine our idea a bit more and that's where jump-oriented programming comes in jump-oriented programming abstracts the idea from return oriented programming to use data as an additional pro attack form and Moves from return instructions to any indirect control flow instructions So any data region in the application that we control can be used as a scratch space to set up such an interpreter Let's look at it. We have a scratch space at some static address that we control with a set of gadget addresses and data that we consume in this in this interpreter so this gadget addresses point to the To the gadgets in our catalog. They are executed one after another and The indirect jump transfer control transfer at the end always redirects the control flow to the big dispatcher and The dispatcher moves from one Entry in the scratch space to the next entry and executes all our gadgets one after another Using these two abstract approaches. We can basically construct any code that is executed So we can chain a set of library commands. For example, we can mMap a memory page We can execute a string copy using the same approach that copies our Exploited data into the newly allocated Memory page and we can then add a control flow transfer to that memory page and in the end execute or re-inject the code again But we first use this data oriented approach to set up the scene for the following attack so well What's the problem of jumper in the programming once again? We have a SLR in there if we don't control the heap. We don't know the addresses on the heap We cannot get around these randomization Problems that we make some money. We also have the problem of propolis once again If we have some buffers on the stack and we we get into trouble with the canaries So we have to get around that as well. How can we do that? Well, maybe format strings will come to the rescue format string bug Basically Exploits the fact that a format string Well, let me let me tell you first what the format string is a Format string is a special string that is allowed to contain Specific tokens that are interpreted in a special way in a very general general form So you all I I assume that you all know the print dev command print of the print dev command has special string as a first argument and this string specifies how many arguments on the stack will be consumed by the the string that is printed if a user can control this first string he can basically place Arbitrary special tokens in that string that read from the stack and also write to the stack if you use the Percent and token so the percent and token is a very special feature that comes from very old uniques version versions that reverse the input And basically results in a random random memory right so We redirect we now redirect the input and we no longer consume values from the stack, but we write to To a specific location somewhere in memory and we can control that location so if the string is on the stack we can also use the same string to Store pointers and basically randomly write any data somewhere to memory if you construct a string carefully So we want to write coffee, babe to o x for one for one for one for one and Construct a format string like that with two half word writes the print dev command Consumes the the first format string the first eight bytes of this format string are the two half word addresses the first time the a A address and the second time the aac address these two half word pointers are then used in the in the exploit itself then We use the we just print a specific number of bytes to the to the terminal in this case we write O X coffee minus the eight bytes that we already wrote to the to the terminal and we then Use the sixth parameter. We assume that the string Buffer that we control is on us a six words up on the stack then use the first First pointer in there to write the number of already printed bytes to the given pointer because percent n can be used to write the number of written bytes to the terminal at that point in time to the to the given pointer so We just write the o x coffee parts the first two bytes to the given address in the old days these things were used to For pretty printers where you had a specific column this and maybe you printed a string from a database or something Like that and you didn't know how long that string was and you didn't want to call that expensive string land func function So you just stored a pointer you just add a pointer somewhere that the percent n then updated with the amount of already printed characters and this way It was very convenient to find these things or to use these things But they're also a huge security problem that can be used up until today so These random writes that we have can then be used to redirect the control flow or to prepare and inject malicious data Basically, if you want to know more about the basic format string Attacks, this is only a short overview that I can give here But if you want to know more about basic format string exploits, you should know the you should watch the black hat talk from this year where they talked about New format string attacks that use the the similar approaches with these with these parameters And they go into great detail about how to to construct these strings But still it's kind of very cumbersome to come up with these These strings and to start with it's very hard to get around ASLR data execution prevention and Propolis things if you overwrite the specific parts in memory so Let me now come to a generic form to exploit these format string exploit that relies on many of the attack vectors that I presented to you string-oriented programming is The approach to execute arbitrary data Arbitrary code through given data what we need to construct section exploit is a format string bug in an application and An attacker controlled buffer somewhere on the stack It doesn't matter where on the stack it is We only need to know the offset from the printf function to that buffer on the stack What we don't need to execute such an exploit is a buffer overflow executable memory regions or any other fancy things When we use string-oriented programming we build on the attacks of return-oriented programming and jump-oriented programming and We also use these some of these available gadgets in the application To to then execute nice code sequences With string-oriented programming we can also patch and resolve addresses For example, if you want to call a library function that is not imported in the current In the current application we can just resolve this This location Using some nice little gadgets. That's usually available in the application. I Told you before about the aslr address-based randomization implementation in linux and they use a weak form of aslr out of optimization issues To randomly place the application somewhere in memory You actually need to generate position independent code when you compile a program But the application is usually not so dynamic So you have to place it always at the same location and that's how we can Come to our gadgets. We use the fixed application search for our gadgets and then also use static region regions in the application to construct our data flow in there. So for example, if the application calls any library functions we have things like a Global offset table or a procedural link linkage table that is used by the linker When the application is loaded to resolve connections to auto-shared libraries and we can use these available offsets to To our or for our needs So if you want to resolve a hidden function, we just search for For a GOT slot that contains the pointer to that given function Sorry, if you want to resolve the pointer to To a hidden function the the location of hidden function somewhere in memory if you want to break aslr. We take the Function that is used from the same library in the application We read the pointer using a random read and then we just add the offset between the original imported function and the function that we want to execute to that GOT slot and therefore can resolve the given entry so We assumed that the attacker has access to the binary So the attacker can just disassemble the library and check the offsets between the locations If you have one pointer into the library We can resolve any other function in that same library and just add and adjust the offset in the end So we can call any hidden function for example a nice system function without any lot of support so I Now want to go through the steps of breaking all the different Protection mechanisms one after the other and therefore we have this little running example. We have a buffer on the stack the user or the Programmer added a length check that checks for the given lengths on the stack if the Input buffer is longer than we fail then we copy it to the local buffer and just print that buffer The attacker controls the string and can inject arbitrary data in there So how does it look like what can we do is that? First of all if we don't have any protection at all then all addresses are known We don't have any execution protection. No stack protection and nothing at all so What we do is here We have the three stack frames the main frame the full frame and from the full frame we call the the print that function If you look into that we have the buffer on the stack We have some unused bytes that are left out of for alignment reasons. We have our EBP and EIP in the end. So what we do is We just Inject string with a random write and some exploit code because we have no execution prevention So we can execute the data as code on the stack the random write at the beginning of the Of the format string will override the saved EIP in the end in the print dev data to redirect it to the to the format string and it will then execute our nice exploit in the In the in the buffer that we placed but unfortunately things are not that easy. So we add data execution prevention So data execution prevention prevents code injection So we have to rely on return or in the programming and jump or in the programming instead and go back to that so Fortunately for us any program as small as it is even if it's just a one-liner Does not only consist of the one line of code that you add But if you use the new C compiler, it will add a couple of Of functions that actually set up the application Call the lauder and do many different things and also initialize the lip see and things like that And as part of that setup code that's always available in the in any compiled application We have a nice Framelift gadgets that we we look at it in a bit more detail this frame lift gadget can be used to add o x1c bytes to the stack and Gives us control over the ebx exe edi and ebp registers So using this little gadgets that we have available at a static location in every single application We can control for registers and we can adjust the ESP With that little gadget we can do some nice things like once again, we have our Our frame our three frames and we look again at the foo frame in the middle and We place our random right and our stack in location frames in these in our buffer so We then Overwrite the return instruction point we're using the random right To the frame lift gadget the frame lift gadgets pops The 44 bytes from the stack ends up in our buffer that we control and we now can execute The stack invocation frames that are available in the buffer Well, this is pretty nice, but there are other protection mechanisms out there. So What happens if you use pro police? Pro police uses and enforces these stack canaries So we once again have our three stack invocation frames We look at them in a little bit more detail the GCC implementation of pro police uses the stack canary at the end of the buffer to check for a buffer overrun and copies the arguments on Specific locations in the stack to ensure that the following Following functions can always use the correct value of the the parameter but well If we reuse the same mechanism, we can actually keep the canaries intact intact and just reuse the same random right To redirect control to the frame lift gadget and we will end up in the stack again in our Stack buffer again Where we can then use arbitrary stack invocation frames the fun thing is once you get around The pro police protection you no longer have to worry about these protections because you control the control flow and all the following Control flow transfers so as soon as you are able to redirect the control flow to your locations You can execute arbitrary stuff and arbitrary stack frames and the game is lost for the defense guy So this is pretty nice and sweet but What changes if we add ASLR address based layout ramization to the picture? So if you combine address based layout randomization data execution prevention and pro polo pro police So if we combine all these defenses, we have to rely on the already existing code and on the static locations that we know about We also have a set of imported functions in the application in the procedural linkage table and Some symbols in a global offset table that we can reuse for our purposes So in the end we can just use random byte rights to adjust these global offset table entries and redirect the control flow in a specific specific way and then Rely on the different functions that we set up that will be called in at other places in the in the application and We can then combine stack invocation frames that we place somewhere plus the indirect call and jump gadgets So To make it a bit easier We just look at this little program here where we once again have a buffer of around one kilobyte on the stack Which is protected by pro polis So we cannot misuse the string copy function Because otherwise the program will fold we will then have a printf and some other function in the end We don't really care about it as long as it is imported through some external library. It could be any function basically for this example so if we zoom into the application at the point Where the printf is executed we see a picture that looks a little bit like this We have the static part of the application on the left hand side where we have a couple of pages that are mapped Readable and executable. That's the init section the plt section the text section and the finish section that is available in the In the application itself in the plt section we have the two link calls system at plt and put as at plt and in the text section at one point in time We have our little and nice lift ESP gadget At the point in time when we Execute our format string bug the Printf function the stack check file function from pro polis and the put as function all point somewhere into the Lipsy code that is somewhere in memory at some randomized Location the Lipsy all other libraries the heap and the stack are all at random locations And we want to get around that So let's just zoom into the stack frame. It looks pretty similar than before But now it's all at random location plus the canaries plus the data execution prevention So what do we do? We no longer need just one memory write, but we need for this simple example We need three random memory writes plus a set of stack in location frames So our three random writes Help us to get control over the application first of all We want to get around as LR and pro polis so we Place some data in the read writeable section that contains the global offset table the procedural linkage table and so on And we just overwrite these two functions Nobody told us that we actually have to rely or that these little things are pointers We can also reuse them as just some scratch pace space where we can add any data so we place the nice string slash bin SH into some Read writeable the section that we can control we now have So in system languages, you don't have a type checker. That's why we can just reuse any Memory regions for our own purposes So we now have our nice string in there. You also see that we have a null byte in there We can easily write null bytes with these Format string bugs because you can just control the null byte doesn't have to be part of The format string we can just write zero bytes and then write the zero somewhere to a given given location So the second these are the first two writes bin bin shell are eight bytes long the third byte redirects one of the imported functions We no longer can just easily redirect the stack the return instruction pointer on the stack, but we have to Overwrite a specific function that is called in the control flow of the application after our exploits takes place In our example that we just looked at the put s function is executed right after the return from the printf So we just override the put s The put s slot in the global offset table to point to the lift ESP gadget So when we now execute The put s or in the application executes the put s Put s function it gets redirected to the lift ESP gadget Which in turn will pop a specific amount of bytes from the stack Which will end up in our buffer that we control and in the end we can just execute our Our place our special Stack invocation frames and use return-oriented programming for that If we would like to use jump oriented program We could we could use a similar approach where we redirected through the return address to some jump oriented programming space so To make you believe that this actually works I have this little program here The format string bug with all your things we can add The parameter in the end this time it's ASDF it prints out some debug values Main is located here through is here RGV is here and We have other values in there and here we print ASDF and the put s function prints out that a nice redirect is possible and We return safely Let's execute it again You see here that oh these things are actually randomized. I'm not joking. You see all these things some of these things change but other things like foo all All all functions that are part of the actual application remain the same because they are static so let's just Execute our format string. We have the same program. We use our little format string construct Python script we write we place stack invocation frames on the stack in the buffer and we prepend our Generated format string with some Garbage data or with some additional data here we have a coffee vape. It's always good to have one of these coffee vapes around Then we add our stack invocation frame Where we have just one frame where we use the put s the the system function that we imported and we give the pointer to the Global offset table or the part of the global offset table where we placed our string in We then tell our format string constructor that well We have to order the buffer that we control is 12 words above the printf function so that we can adjust the parameter accordingly and We write three values to this value which is the same as this value here. We write the first part of Slash bin shell and to the other four bytes here at the later point We write the second part of bin bash and we also overwrite the put s function Which happens to be a dislocation in the global offset table Where's the nice value of our frame lift gadget? So if we execute this It runs it runs it runs and we end up in a shell and If you are an external user user we now have control over the application and We go back and we fault So these things can nicely be used as a chain of escalation to break all the different exploit mechanisms We got around ASLR. We got around data execution prevention and we got around pro-police all in one go with one simple simple little Little format string You can also look at the format string It's 127 bytes long Let's just look at it without that. So it's just 127 bytes long There are the pointers that we use in the beginning then we generate the random rights a couple of half words that we write and In the end we win So let's switch back to the presentation You all believe me that these things work The script is fairly easy It will be on the on the web page You can look at it and you can generate your own format string and it comes with some additional Playing material as well that you can use to get around it So What did we learn? first of all string oriented programming relies on a format string exploit and Extends data oriented programming like return oriented programming jump oriented programming We now see the application as an interpreter for our data that we add And this interpreter can be used to execute arbitrary code We can easily circumvent data execution prevention using one of these data oriented One of these data oriented techniques and we can get around properties by using the format string exploits to exactly just Overwrite the values that we want to change and we can reconstruct any pointer and circumvent ASLR using these global offset table and procedure linkage table tricks that I I've shown you a bit So the format string bug that or format string bugs that we see here can result in a complete compromise of the application and Full control of for the attacker So to protect against string oriented programming We would need to work or we would need to go one level higher and maybe use virtualization techniques or things like that and we also have to look at the complete tool chain Word use format string bugs actually come in So with this I would like to thank you for your attention, and I'm happy to take your questions Yes, I have actually two questions. First of all, well, it seems to heavily rely on the format string bugs and Well, if the format strings are implemented correctly, then this whole thing doesn't work Well, if your program doesn't have a buffer overflow, you have no exploit as well, right? Yeah, of course and the second question is You mentioned the gadgets that the GCC leaves in the program But wouldn't it be basically possible to kind of externalize these gadgets because they are needed at initialization of the program only and Maybe if one adds some codes to Linux program execution, then This gadgets wouldn't be visible to the program itself well in theory, yes But it's hard to do part of the gadgets also come from the area where you can have Constructors and deconstructors, and they're just in there by default Maybe if your program uses them, you actually have to add them to to the application You could just strip them if your program doesn't use it but GCC just uses a set a small set of these start files As they are called and adds them by default even if your program doesn't use it you could change the Linux kernel in one way or another But then you would basically just move the loader into the kernel and the loader is a huge mess of code that you don't really want to look at Okay Did that answer your question? Okay. Thanks Okay, I have one small inquiry from IRC and angstrom asks What blackhack talk you were referring to earlier regarding format string exploits the At what which blackhead probably would be in this 2011 this year's blackhead Okay, it's extended format string exploits by bletch. I think I would I would have to look it up I can put it on this on the slides when I put them on the back Yeah, apparently he looked at 2011 didn't find anything but okay if you say it's that's probably there and one That's begging for holy war Joey a one from IRC asks According to Microsoft the person sign n type has been disabled since 2005 and he wants to know why it's still available on the nox Because a lot of old software is still using it There are guards out there that are in play implemented in your versions, but basically lip see is a Huge mess in one way where you can just disable these guards at runtime with some In your format string exploits you can disable the guards that should check for the format string exploit So that's just an additional nice thing It's out there But I didn't add that to the slides because it would get too complicated But the percent n is still out there and you can still use it if you have a format string that you can control So if you have a printf where the attacker can control the format string even if these protections are enabled you can get around them pretty easily Are there any other questions So I don't see any other questions here in the room So thank you Matthias. It was a very interesting talk Yeah, thank you