How the ELF ruined Christmas
CC Attribution 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Di Federico, Alessandro
Shoshitaishvili
The ELF format is ancient, and much mystery lurks in its dark depths. For 16 years, it has safely encompassed our software, providing support for binary loading, symbol resolution, and lots of very useful binary stuff. In that time, security has become a key concern, resulting in binary defenses like NX and ASLR, which have made exploiting vulnerabilities quite difficult. ASLR, for example, randomizes the location of the stack, the heap, libraries, and (optionally), the binary itself at every execution of an application. There is no easy way to say this: ELF has let us down. In this talk, we'll explore the dark side of ELF. Specifically, we'll show how ELF, by design, implicitly trusts data structures in the ELF headers. Even in the presence of ASLR, an attacker able to corrupt these headers can trick the ELF loader into calling any function in any linked-in library, providing nothing but the name of the binary. In essence, this technique allows an attacker to call arbitrary library functions (such as system()!) without leaking memory addresses. We call this technique Leakless. While developing Leakless, we checked many different implementations of the standard C library and found that Leakless can be adapted to attack the ELF loader implementations in all of the common ones (i.e., GNU libc, the libc of the major BSDs, and uClibc). In this talk, we'll describe the internals of the ELF format, show how Leakless works to subvert library function resolution, and demonstrate how it can be use to carry out attacks without information disclosures. And, of course, we'll open-source the tool that we developed to make carrying out this attack easier. Speaker Bios: Alessandro is a PhD student at Politecnico Di Milano, right under that leaning tower. In his spare time, he hacks with Tower of Hanoi. He likes exploitation and doing really crazy stuff, on and off the computer! Hacking since the age of eight, Yan Shoshitaishvili is fascinated by understanding and commandeering the computation and actions carried out by binary code. He is currently pursuing his PhD in the Seclab at UC Santa Barbara and is one of the hacking aces behind team Shellphish. In the little spare time he has left, he develops and releases computer security tools on the Internet.
 question. What's the question? Is this your first time speaking at DEF CON? It is. Oh, excellent. So actually I wanted to say that we were experimenting with something new this year at DEF CON. Could you set us up please? We were looking for a drone delivery system. What is this? What is this? What do you think? Will that deliver shots? That's cool. You all know how this works. You've been here long enough. Wait, slow down there, man. Whoa. All right. Cheers. Thank you. Cheers. Thank you. Thank you. Thank you. Thank you. Thank you. And now back to our readily scheduled talk. So I was a bit warmer. Okay. So I was saying let's see how the usual exploitation process takes place. So if you're an exploiter you're trying to exploit something, usually first of all you have to find a vulnerability. And this vulnerability has to be useful. And by useful means I mean that you have to be able to basically divert the control flow of the program to some address you want. And once you're able to do this, then you can perform your desired actions like invoking the system library function and exact VE or launching program, copying wallets, I mean doing your actual final aim. And our focus is on this last part. So we are assuming we are able to divert the control flow and then we'll see what can we do afterwards. And in particular we'll see how can we do this last part of the exploitation process in presence of certain countermeasures that I present. Because just being able to divert execution is not enough because okay, I can, you know, I have control of the program counter but the question now is where do I point it to? Where it's an important thing. And since it's 2015 we cannot upload shell code in our target and just jump there because open and insist on preventing this kind of stuff. So as you all know, hackers and exploiters came up with the concept of code reuse attack. So we cannot upload or inject new code and then what we do? We reuse existing code. So we came up with the famous returning to libc attack and then all the return oriented programming which I hope you are at least a bit familiar with. The problem is that okay, we are able still to perform our attack even if we are not able to inject a new shell code we're using code. But the problem is that operating system developers came up with countermeasure which is called ASLR which basically means that it's other space layout randomization. Which means that basically the code that you want to reuse, for instance, the system library functions and those kind of functions are not always in the same position. Their position is not deterministic. So the question again is okay, I can divert the control flow. The code I want to reuse is there but where it is. So the typical situation to get around ASLR is use the functions that are already imported. So the main executable uses some functions for instance the C standard library like the printf function which is very common. To be able to use this function it keeps in memory in the memory area which is dedicated to the main binary a reference to this function which basically holds the address of the printf function. So the typical way as I was saying to bypass ASLR is okay, let's try to read the address of this printf function which is actually imported by the main binary. Then if we have a copy of the C standard library, if you're targeting the C standard library, let's compute the distance between the printf function and another function we want to execute to perform our malicious operations, typically system or exact VE. We compute this distance and then if you're able to get from our target the others of printf we can add the distance to reach exact VE and then we know the address of exact VE and then we can call exact VE and perform our attack. This works but the problem is that first of all it requires you don't just have to be able to divert the control flow but you also have to be able to leak this piece of information, the others of printf so you need at least two vulnerabilities, you need a memory leak vulnerability typically and also you need the layout of the library you're targeting so you basically need the exact copy, not just the version you need like the exact copy, so the exact build of the library which is not always the case, I mean there are some situations where maybe you don't have access to it and finally there's another point which is a bit subtle is that you need to interact with the attacker, so it's not a single stage attack, it's not that you just launch your attack and it works, you do your exploitation, you need to communicate back to the attacker so basically you read the printf and then on the attacker side you compute the new address and use another stage of the exploit so it's two stage and this is a problem because maybe if your final target is a hair gap machine for instance you can freely communicate, maybe you have a JPG, you are storing your exploit in a JPG or in a pcap file or something which is open on a hair gap machine you can freely communicate so this is a problem. So how can we solve this problem? Let's try to zoom out a bit, actually our idea when we came up with these techniques is let's try to zoom out a bit, what are we trying to do? Basically what we're trying to do is put in the address of an arbitrary library function so I have a name and I want its address so I'm able to call it but if you think well there is already a part of the operating system doing this job and this is the dynamic loader. The dynamic loader basically the role of the dynamic loader is to take the main binary or even a library and see what are the important functions for instance printf and from the name from the string printf obtain its address where the printf function actually resides in memory considering A, S, R and everything. So let's try to get to know this guy, the dynamic loader. First of all I'm going to talk about dynamic loading and everything in the context of ELF based platforms so ELF for those who do not know that stands for executable and linking format and it's basically the most popular format for UNIX based platforms so Linux or BSD, like free BSD, open BSD they all use ELF which is a binary format as I said. So if we consider an ELF file like the ELF executable the first way we can see it is we can split it in sections so it's a file and it has several parts which are called sections. The most important sections that you usually deal with maybe if you've been doing a bit of reverse engineering are usually the dot text, all the sections start with a dot. So the dot text section which holds the executable code so the actual binary code of the application then we have dot data which holds all the writeable global data so let's say the global variables that are writeable they're not just read-only. The read-only one is the arrow data which stands for read-only data and then we have BSS which is section which holds global variable which are not initialized so for instance if you like in C write a global array that it's not initialized it will be zero initialized and will end up in BSS. So let's see what's the role of the dynamic loaders. Basically the compiler hides a bit of the complexity of the dynamic loader because when we see this piece of code like a very simple lower program we see just printf but what actually the compiler meets it's not a call to the printf in the C standard library because as I said the libraries are positioned in random position so you cannot know at compile time where the printf will end up. What actually the compiler does is calling the printf at PLT which is a trampoline so let's say a small piece of assembly code that we're going to see or explore outwards. This small trampoline is storing another section which is called dot PLT the so-called procedure linkage table which is a table composed by this small trampoline one for each imported function and basically let's see how it looks like. So this trampoline are used to support lazy loading. Lazy loading is a feature of the several dynamic loaders basically most of them which allows you when you start the program instead of resolving all the important functions getting the real address of the start up of the program you basically obtain the address the first time you call them so if there's a function you never call it's not going to be resolved and you're saving time. And also the start up of the program it's faster for the end user. So it works a bit like this. This is pseudo code it's not actually it's an assembly optimized code what the trampoline doesn't look like this but let this high level stuff to make you understand. If it's the first time that the trampoline is being called the main binary will pass the control flow to the dynamic loader calling this DL runtime resolve function which will explore in a bit otherwise it will just jump to the cache version of this function. For instance if this is the trampoline of printf there will be somewhere in memory we'll see where the place where the address of printf is cached. And DL runtime resolve will take care of finding where printf is storing the address of printf in a dead cache and printf address and then also call the function. So DL runtime resolve takes two parameters the first parameter is just a pointer to a data structure which describes the current L object we'll see more about that later. And the 1, 2, 3 parameter it's an index in a table it's an index representing a relocation. So what is a relocation? A relocation is basically a directive for the dynamic loader telling him so take this symbol with a symbol it's a concept that represents like a function for instance in a library or maybe a global variable in an external library so a symbol take this symbol for instance printf in this case and write its address at this specific address in particular our offset represents where the address of the symbol has to be written and our info represents the basically the identifier of the symbol. So relock index which is the second parameter of DL runtime resolve is an index in a table of this relocation. Basically there is a section called a relplt section which is basically an array of relocation data structure which is called L rel which is composed by our offset and the info. So it's an identifier but it's an index in another table which is called dynesim which is an array of symbols structures which are actually L sim which have a lot of details we're not interested in. The only thing we're really interested in is that there's a field called stname which is an offset in another table and this is the last one I promise which is called dynestrain which is basically just the concatenation of the name of all the symbols that are imported from a certain binary. So to recap basically the DL runtime resolve takes relock index which is an index in the real plt table which is a relocation. From the relocation which we pass to the symbol table and from the symbol table we pass to the name which is in this case printf. We'll get back on these things. So to recap again DL runtime resolve does three things. Finds the symbol and it's associated with location and finds its address. So if you from the relocation go to the symbol and you go to the name and from the name the dynamic loader is able to get its address. It writes that address at the error offset and the address specified in error offset in the relocation and then it also transfers the execution to that function. So it also calls it. As you might have understand at this point error offset in this case will point to the address of cache printf address. So error offset tells okay right there the address of this function. So next time I'll call the trampoline. I want to resolve and get to do all the trickery to get the to resolve the symbol again and just jump straight there. It's sort of an optimization. Okay. So okay where does this cache printf address actually state is? It's actually in another section which is called got plt which is the it's more mostly known as the just the global offset table which basically holds an entry which is a pointer for each important function. So it's where these cache addresses actually are. So just to recap we have plt which contains all the trampoline which enable lazy loading. We have got plt where the cache address of the important functions are stored where basically initially they are all uninitialized and they get initialized lazily from the first time you call that function. We have the table of relocation which is rel plt, table of symbols which is dynestream and then we have the symbol of the symbol name which is dynestream. Just now terminated strings concatenated. Okay. So let's try to come up with an attack to this system. So first some assumptions. Our assumption as I said is that we are already able to divert the control flow and we are also able to run a route chain and we also are able to write arbitrary memory location with this route chain. So let's say we have a small very small gadget which is able to say okay I have this address, I have this value, please write the value at that address. So very simple stuff. What can we do? So if we look at this setting the idea is okay what if I'm able to replace the printf string for instance with execv. If I'm able to do so to replace that string and I invoke the dial run time result function with the relocation index corresponding to printf what the loader will do it will go through relocation symbols but then in the end it will end in the dynamic string table and it won't find printf but it will find execv and so it will resolve the address of execv and also invoke that function. So we are basically in this way we will be able to invoke any function we want just by name if we are able to write this arbitrary memory location. This lies is called naive approach because this approach actually does not work because there's no reason why the dynamic string table should be writeable. So the dynamic string table it's not writeable because it's like static information that you just write once and you never change. So this attack will not work. Even if you have this gadget we will try to write in unknown writeable memory location and we just get a seg fold. So let's try to work around this. So we have been talking about a lot of different sections but the dynamic loader actually does not go through, does not consider sections by their name. It doesn't look up the PLT, GOT section by name. It uses another section which is called the dynamic section which holds basically key value pairs where the key represents one of the sections it needs and the value it's actual address. For instance DTE syntax keeps a pointer to the dynamic symbol table. DTE STR table and so on and so forth. We're not really interested in details here but the point is that the dynamic loader uses this, takes the information about the binary, about these sections from this table. So the nice thing is that the dynamic section is writeable. So what we can do is instead of trying to write directly in the dynamic string table we can tweak the loader into thinking that the dynamic string table is somewhere else. And where can we make it point? For instance we can build a fake string table in the BSS or in any other memory section which is writeable by us. BSS is typically writeable. It's always writeable. So basically we go to the dynamic section and we change the D value field of the structure, making it point instead of making it point to dynamic string we make it point to BSS. So what the dynamic loader will do is okay I'll go through relocations, symbols and then when I get to the dynamic string table instead of going to dot-dine string I'll go to BSS where I as the attacker I forge a fake string table which is instead of printf as exact V. And so basically we are able to perform the attack in the sense of being able to call any function call, any library function, sorry. Okay. But this approach is still quite naive because actually we were not the first person people thinking about this and so the developers of compilers and in particular of the linkers develop a protection called relocation reel only or more shortly like realm room which is a binary ardening technique which prevents exactly the attack we just described because why is the dynamic section writeable? It's simply because there are some entries that we did not describe yet which have to be initialized at one time. So it has to be writeable when you start your binary but after you initialize them you can mark that section as read only and that's exactly what the rail road protection tells the dynamic loader to do. And so basically our previous attack doesn't work anymore. But maybe we can do something else. So we came up with another idea. So far we played with the dynamic section but what can we do if we are able to play a bit with the relocation index, the second parameter of the runtime result. What happens if instead of making it point to an entry in the rail PLT section, making it point to an existing relocation, we put an index which is big enough to go after the end of rail PLT section. Maybe we can trick the loader into going somewhere more interesting. So let's take a look in the particular, can we make it the loader thing that he has to resolve a relocation which is in a memory area which is writeable by us. So not in the rail PLT section but maybe in BSS. So let's see what section do we have after rail PLT. So let's suppose that we have, usually the indexes start from the beginning of the rail PLT section and if we put an index big enough we can go through rail PLT, PLT, dot X, dot dynamic, dot PLT and then we can end up in dot data and dot BSS. And so if you are able to trick the loader in going there and we are able to forge a fake relocation there, we can basically build our own relocation and resolve any library function without touching the dynamic section which is not writeable. So this is an example of the thing. So we put a relocation which is big enough not to go to rail PLT but to get into BSS where we forge a fake relocation which points to a fake symbol with the same trick. So it's the same trick. So if we start from Dynesim we put an index which is big enough to end up in BSS again and then the same trick again with ST name we put an offset in the dynamic string table big enough to end up in BSS again. So basically we are building all the data structure which are needed by the dynamic loader to resolve a library function in the BSS and using always the same trick of overflowing the section which are supposed to be used, we end up in BSS and we are able again to call any arbitrary library function by passing the railroad protection. So here there are just some very simple formulas how to compute the addresses that we have to put there. For instance, you have a relocation index and an error info in the ST name field to be able to perform this attack. But this is not that simple. This will be quite true because actually the binary is round in particular like in Ubuntu and several other distributions and a feature which is called symbol version which basically allows you to depend not on any printf function but on a specific version of printf. For instance, I want printf function from the G-Lib C 2.22. This is just an elf feature which is actually a new extension but since it's popular we have to deal with it. And what's the problem? The problem is that if symbol version is enabled, the error info field is not used just as an index in the symbol table but it's used also as an index in another table which is called the new version table which we will not talk about. But the fact is that this symbol, this index is used for two different things. And so basically we have additional constraints. So what we have to do in this case is either we make both indexes go to the BSS section and so we can fake also the other data structures which are related to versioning which we will not look into. Or we can make it point, we can make the version thing point to a zero zero somewhere in a memory area where we cannot write like if you find like a zero zero in text it's fine. So we just basically, because this just basically disabled the versioning. So is it doable? Yes. And it can also be automated. The point is that there are silent situations when this is really, really hard. For instance in particular with 64-bit binaries using huge pages, huge pages means that you have like memory pages which can be large up to a megabyte. And so basically the read only part of the binary where we have text, relocation, the relocation table, the dynamic symbol table, the dynamic string table, all these things which is the read only part, it's very far away. It's like one megabyte away from the writeable page. And so this huge distance makes it really hard to satisfy the constraints we just saw. And so in this case it's not doable. The problem is that 64-bit binaries with huge pages and symbol versioning enabled are pretty popular. So we found another solution for this. The idea is in this case is not to play around with Relock index but with current object info. So let's look into current object info. What do we have there? It's basically a pointer to a link map structure and we have this pointer, it's always stored in a reserved entry in the GOT table which is the second one. GOT1 is the second entry of the GOT table. And the nice thing about this data structure is that it has a field called L-info which basically keeps a cache of pointers to the entries in the dot dynamic section. So the idea is if we can tamper with this internal data structure of the loader, we can basically go back to the first attack when we were tampering directly with the dot dynamic section. And this is actually what happens. So we go to the PLT GOT section, we go to the second entry which keeps a pointer to this link map structure. We go to the L-info field and to the entry corresponding to the DT STR tab which is a pointer to the dynamic entry keeping itself a pointer to the dynamic string table. We can change this value and make it point to BSS and we can build a fake dynamic entry which tricks again the dynamic loader into thinking that the dynamic string table is a memory area that we control. So we're basically falling back to the first attack we saw. So we are still tampering with the dot dynamic table but indirectly, like corrupting the internal data structure of the dynamic loader. And we can do this reliable and deterministically because the pointer to this data structure is always in the GOT one, in the GOT, in the first, second entry of the GOT. Okay, then, but still there's some additional protection to this because railroad, it was, it comes in two flavors. Partial railroad which is the one we just saw, but then there's full railroad. Full railroad basically it has all the features of partial railroad but in addition, it basically completely disables lazy loading. This means that when you start the binary, when you start your program, all the GOT entries are initialized and the GOT, it's marked as read only. So we cannot write in the GOT anymore. And also since they are not used any longer, the GOT one entry which was keeping the pointer to this link map structure is not initialized. So we lost the pointer to this critical data structure which helped us to bypass partial railroad. And not only this, we also lose the pointer to the L runtime result which is something I skip over but we were getting its address from the GOT2 address and the GOT2 entry. And also this entry is not initialized because simply lazy loading is disabled. So these three things, we don't have a pointer to link map, we don't have a pointer to the L runtime result and we cannot write in the GOT. It seems like we are pretty fine. But DT debug to the rescue. So there is this feature which is like a, the typical debug feature which is staying there and waiting for someone to abuse that. And here we are. So DT debug, it's an entry of the dot dynamic table which is used by GDB and other debuggers to be able to break on certain events related to dynamic loading. Like, okay, we have a new library being loaded. You want to break so you can explore this library and see what new symbols you have. So debugging stuff that we don't really care about. But the nice thing is that this dynamic entry doesn't point to a section but points to another data structure which is our debug structure. But this debug structure keeps a pointer to link map. So we basically are able just passing, going through this debugging feature to get back to the previous attack. But it's not that simple. Because as we said, we also, this is the last drawing I'm showing you. But this is really interesting because as we said, we don't have a pointer, we have, we have found a pointer to link map going through the DT debug dynamic entry. But still we have to be able to find a pointer to the DL runtime resolve. So let's do, let's see how can we make this. So let's start from this area of the drawing. So in the dot dynamic section, we go to DT debug, we follow its value and we get to the R debug. From R debug, we have this field which is R map which points to the link map structure that we saw before. So first thing we do, we corrupt the DT STR tab entry which is the one keeping a pointer to the dynamic entry for the dynamic string. Okay? And so we do the thing we just did before. We build a fake dynamic entry and we build a fake string table and this is, let's say, usual for now. But the point is that we, what will the dynamic loader do? Okay, it will go through all the stuff that we crafted and it will resolve exactly, exactly, nice. But then one of the features of the DL runtime resolve, it's also storing the address of exact VE in the GOT. But the GOT has been completely initialized and marked read only by the dynamic loader because of full error. And so we get a seg fault because we are trying to write in a memory area which is read only. So we have to also to fake another entry of the link map data structure which is JMP rail which is a pointer which was the one holding a pointer to relocation table. So we fake also the relocation table. We create a fake relocation which points to an existing symbol but as error offset instead of pointing to the GOT, it's pointing to, like in this case, a memory area just after it which is writeable. So we don't get the seg fault. And so we solve also this problem. Now we have one last problem which is the address of DL runtime resolve. So we don't have it in GOT2 and so we have to get it somehow. But how can we get it? The trick here is that usually, actually in our survey basically always, only the main binary is protected with full variable. The libraries are not protected with full variable. So if we are able to get the GOT of libraries, we can still get the address of DL runtime resolve. And the nice thing is that the link map structure, it's not just a data structure per se. It's actually part of a linked list of all the link map data structures representing all the loaded L-th objects. So basically what we can do is just we can dereference, like, the pointer to the next, to the next entry in the dynamic in the, in the linked list and get to the link map data structure of just any library. For instance, Libc or whatever library is being loaded, we go to the, we get the address of the PLT GOT, GOT, and then we go to the third entry and we get again the address of DL runtime resolve. And basically we are able to build, building up all these things together. We are able to bypass also full variable, which is a pretty cool thing. Okay. So, but, okay, this is very, very interesting, but how can we do that? So we implemented Leakless, which is the name of our tool, which implements all these techniques. Just giving the binary and it tells you which is the best, actually the approach that is most suitable for this particular binary based on the protection it has enabled and basically if it's 64 bit with huge pages and those kind of things, and it can produce two different kind of, of outputs. It can either tell you, okay, do these things. It outputs like a JSON, a JSON file, which basically instructs you, okay, if you are writing an exploit, write this thing there, write this thing there, and then you'll be able to, and then just call the runtime resolve and everything will work. Or if you provide Leakless with the gadgets it needs, and we'll see what kind of gadgets it needs, it will also, it can also produce the ROP chain for you directly. So it actually produces the exploit to resolve one or more functions one after the other and call them with the appropriate parameter. You can, you can see the code there, it's in GitHub, we just published it and just, you can play around. So the gadgets, we talked about gadgets. So basically we need at most four different gadgets, depending on what of the four attacks I presented, excluding the first one which was not working, it was just the first naive approach. Depending on which attack we are dealing with, we are different gadgets that we need. So the first one, the one which was basically just overwriting the dot dynamic section, that just needs a memory write gadget. So you give him, you need a gadget, you give him an address, a value to write there and it writes there. And so basically all the exploits, all the techniques that we saw need this kind of gadgets. So N stands for no railroad, P stands for partial railroad, H stands for when you have huge pages and all kind of stuff and F for full railroad. In the other case we have slightly more sophisticated gadgets, for instance this one is, if you look at it, it's the one we use to tamper with data structure. So you have a pointer which is usually a pointer to a data structure, you add an offset, you reference it and you write a value there. And this is used for the huge pages attack and for the full railroad. Full railroad requires two additional gadgets. This one is basically a gadget that we need to store somewhere, some data that we took from those, like what we were walking through, all those data structures, for instance the runtime resolve, basically you choose a memory area where you want to save this address and you take it from these data structures at these offsets. And in this case, so I initially skipped over this, but for the first three attacks to call the runtime resolve we were using a part of the PLT, which if you remember it's where the trampoline were. But in this case we cannot do that because the runtime resolve is not initialized and so we also need to be able to write the address of the runtime resolve directly on the stack. So we need a gadget which allows us to write at an offset on the stack. So we need these four gadgets. And this is also the reason why I'm here, you know, annoying you with four different techniques instead of just showing the last one, which is the most powerful one. Because depending on the protection that I enable, you have different requirements and you need different gadgets which might be easier or harder or maybe just take more time to find and implement. So okay, but after all these things, what loaders are actually vulnerable to this? So in our, we tested our leakless against the G-Lib C, so the new standard library, and against the free BSD standard library. But by manual inspection we think we deem it vulnerable, so diet lib C, UC lib C and new lib, which is, you know, embedded, there are C standard libraries for embedded systems. And also open BSD and net BSD. Because basically they all behave like the same. If you think about it, we're just relying on the standard health features. And except for minor modifications, maybe, you are, they all, for instance, they all cash pointers to the dynamic entries, somehow in their internal data structures, they are maybe a bit different, but there's not a real big deal. We say that it's not vulnerable by on it, which is the C standard library 400, because as far as I know it does support only PIE binaries. And new, which is an embedded C standard library, because simply it does not have lazy loading. So it's like if you have full error all over the place always. So basically our tech is worthless. It's a feature, not having a feature, it's a feature actually. And free BSD loader, I'd say it's kind of not vulnerable because the first and the second attack I presented you, basically the one which was overflowing the relocation table and symbol table and those kind of things, does not work. Because these are the only guys that are actually checking the boundaries, which is like, basically two things to do, but they are the only one. But still the other two attacks, they do work. So it's kind of vulnerable and not vulnerable. Okay, so let's recap. What are the advantages of leakless? So first of all it's single stage, so you don't need a memory leak vulnerability and you don't require interaction with the victim. We are not sending back to the attack anything. We just do a single way, single shot exploit, which might work in any situation like air gap machine and those kind of things. So like offline attacks, which maybe before were not feasible or no feasible. It's reliable and portable because it's deterministic, there's nothing left to randomness or it's very deterministic. And then you do not need a copy of the target library. So if you think about that in the beginning, I told you that you have to compute in the typical situation where you use a memory leak, you have to compute the distance between exactly the m print f. But to do this, you need a copy of the library, which is not always the case. In this case, we do not care about the layout of the library. We just abuse the dynamic loader, which does it in the proper way. And since it relies on just under L feature, in most cases it's very portable and it's easy to port for instance to net BSD, open BSD and so forth. Except it's link map layout of the data structure, but it's only a really minor fix to the exploit. It's short because if you want something with the same characteristic I just mentioned like reliability and deterministic, you will need to basically reimplement what the dynamic loader is doing. So implement like in puro, going through all the relocation symbols and those kind of things, which is very complex. And it's also, it gets very long because it's not just say, okay, dynamic loader, do this for me. You have to do it by yourself. And also the advantage of Leakless is that once you set up all the data structures, if you want to make multiple calls to different library functions, you just need to, after you did the first one, you just need to change the name of the function you want to call and just call again the runtime resolve. Instead, if you want to implement the dynamic loader, you have to do again all the process. And so it's, it's a cost that is not negligible. And you know, shorter, shorter rope chains mean higher feasibility. You know, sometimes buffer are small and you have limits. And if you don't want to interact again, you cannot read, you know, it's, if you want to do it single stage, being short is important. We also say that it's stealthy because basically we are not, the typical criticism one could make to such an attack is that, okay, but why don't you just do this with sys calls? Okay. Because first of all, sys call might not be available. You might not have them in the binary, like even in misaligned. But it's also more invasive. Because for instance, you can always do, if you can do sys call, you can basically do everything you want. But it might, you might have intrusion detection system and also spowing a new process, for instance, if you want to do exactly, it's kind of an invasive. And here is an example of a thing we came up with. It's a sys code for using PgN functions. PgN is a client. And so what we're doing here is we're taking the pointer to the proxy object of PgN and we are setting, so the attack we want to carry on is like, okay, set a proxy for, so I can intercept the instant messaging traffic for this user. So what we do is we take the global object for proxy, we send the proxy which is our server, the port, the type, and then we connect and disconnect the user. Sure, you can do this also with sys call somehow, but reusing a program functionality, it's much easier and less intrusion. And it's also easier. And also it's automated. And by this means that our tool basically does almost everything except finding the gadgets. But maybe in the future we can integrate it with some automated gadget finding tool. So counter measures, well, the most obvious counter measure is enabling PIE. So randomizing goes to the position of the main binary. Okay? This is an actual solution, but actually in our survey there are like very, very, very few, PIE is not being deployed a lot. The distribution basically uses it on the binaries, they deem critical. I don't know why they don't deploy it on all the binaries. It doesn't make sense to me, but this is a possible solution. Also, DT debug, why should it be there? Just remove it or maybe enable it only if there is like an exported variable, if you want, like an environment variable, if you want to do debug, then you can enable it. Or you can try to make the dynamic loader data structure and read all of this. So if you try to tamper with them, you get a crash. Or just validate the input is also very good counter measure. But the key point is that this kind of core components of the operating system should be retold with security in mind. Because basically all the libraries we expect that we're just trusting user input. And since they are all over the place, it's very dangerous because if you're able to attack them, you are able to obtain something that is very portable and it's all over the place. So also ELF maybe should be redesigned a bit with security in mind from the beginning. And this last thing I want to thank all the other people who work with me in this, like Amat, which is here, and Jan, which is not here, and Giovanni and Christopher at UCSB, which allow me to be here. And that's basically all. Maybe I have a second to do a very short, so just to show you some code. So this is, I'm just going, we tried to implement, to attack a real binary because we have a small test suite in Leakless, but we also want to do something real. So we took a CVE in Wireshark, just a very basic stack overflow, I mean a stack buffer overflow. And we tried to generate and exploit with Leakless, just providing it with the gadgets. Just a small demo. We launched it, this is just an error because I'm running Wireshark as root, don't do that. That's a very bad idea. We launched it passing a pick up, which I generated and I got a shell. It's pretty easy. Shell always good. Yeah, and then we have the same with Partial Rev, but it's the same experience for you, so just trust me. So the last thing, this is the part, Leakless has been implemented in Python, and this is the code that you need to write if you want to provide gadgets to them, to Leakless. And it's 200 lines of code, but most of them it's just boiler plate that could be factorized out. And it's basically just take the gadgets and mix them together so they can be reused by the, let's say, the part of Leakless which is agnostic from the binary. And the last thing is, yeah, I just wanted to show you the JSON output. Let me see. So this is dot exploit dot pie, it's basically the Leakless script. We pass it the Wireshark binary and we ask him to produce the JSON format using the LD corrupt method which is the second one I presented. And what it does, it basically gives out some instructions like, okay, write these things, this address, and so if you don't want the Rob chain to be generated automatically for it because maybe you have some complicated setting, it can just give you the instruction to perform the YATTA. With this I'm done and thank you for your attention. Thank you.
 question. What's the question? Is this your first time speaking at DEF CON? It is. Oh,  excellent. So actually I wanted to say that we were experimenting with something new this  year at DEF CON. Could you set us up please? We were looking for a drone delivery system.  What is this? What is this? What do you think? Will that deliver shots? That's cool. You  all know how this works. You've been here long enough. Wait, slow down there, man. Whoa.  All right. Cheers. Thank you. Cheers. Thank you. Thank you. Thank you. Thank you. Thank  you. And now back to our readily scheduled talk. So I was a bit warmer. Okay. So I was  saying let's see how the usual exploitation process takes place. So if you're an exploiter  you're trying to exploit something, usually first of all you have to find a vulnerability.  And this vulnerability has to be useful. And by useful means I mean that you have to be  able to basically divert the control flow of the program to some address you want. And  once you're able to do this, then you can perform your desired actions like invoking the system  library function and exact VE or launching program, copying wallets, I mean doing your  actual final aim. And our focus is on this last part. So we are assuming we are able to  divert the control flow and then we'll see what can we do afterwards. And in particular  we'll see how can we do this last part of the exploitation process in presence of certain  countermeasures that I present. Because just being able to divert execution is not enough  because okay, I can, you know, I have control of the program counter but the question now  is where do I point it to? Where it's an important thing. And since it's 2015 we cannot  upload shell code in our target and just jump there because open and insist on preventing  this kind of stuff. So as you all know, hackers and exploiters came up with the concept of  code reuse attack. So we cannot upload or inject new code and then what we do? We reuse existing  code. So we came up with the famous returning to libc attack and then all the return  oriented programming which I hope you are at least a bit familiar with. The problem is  that okay, we are able still to perform our attack even if we are not able to inject a  new shell code we're using code. But the problem is that operating system developers came up  with countermeasure which is called ASLR which basically means that it's other space layout  randomization. Which means that basically the code that you want to reuse, for instance,  the system library functions and those kind of functions are not always in the same position.  Their position is not deterministic. So the question again is okay, I can divert the control  flow. The code I want to reuse is there but where it is. So the typical situation to get  around ASLR is use the functions that are already imported. So the main executable uses  some functions for instance the C standard library like the printf function which is very  common. To be able to use this function it keeps in memory in the memory area which is  dedicated to the main binary a reference to this function which basically holds the address of  the printf function. So the typical way as I was saying to bypass ASLR is okay, let's try to  read the address of this printf function which is actually imported by the main binary. Then if we  have a copy of the C standard library, if you're targeting the C standard library, let's compute  the distance between the printf function and another function we want to execute to perform our  malicious operations, typically system or exact VE. We compute this distance and then if you're  able to get from our target the others of printf we can add the distance to reach exact VE and then  we know the address of exact VE and then we can call exact VE and perform our attack. This works  but the problem is that first of all it requires you don't just have to be able to divert the  control flow but you also have to be able to leak this piece of information, the others of  printf so you need at least two vulnerabilities, you need a memory leak vulnerability  typically and also you need the layout of the library you're targeting so you basically need the  exact copy, not just the version you need like the exact copy, so the exact build of the library  which is not always the case, I mean there are some situations where maybe you don't have access  to it and finally there's another point which is a bit subtle is that you need to interact with  the attacker, so it's not a single stage attack, it's not that you just launch your attack and it  works, you do your exploitation, you need to communicate back to the attacker so basically you  read the printf and then on the attacker side you compute the new address and use another  stage of the exploit so it's two stage and this is a problem because maybe if your final target  is a hair gap machine for instance you can freely communicate, maybe you have a JPG, you are  storing your exploit in a JPG or in a pcap file or something which is open on a hair gap  machine you can freely communicate so this is a problem. So how can we solve this problem?  Let's try to zoom out a bit, actually our idea when we came up with these techniques is let's  try to zoom out a bit, what are we trying to do? Basically what we're trying to do is put  in the address of an arbitrary library function so I have a name and I want its address so I'm  able to call it but if you think well there is already a part of the operating system doing  this job and this is the dynamic loader. The dynamic loader basically the role of the dynamic  loader is to take the main binary or even a library and see what are the important functions  for instance printf and from the name from the string printf obtain its address where the  printf function actually resides in memory considering A, S, R and everything. So let's  try to get to know this guy, the dynamic loader. First of all I'm going to talk about dynamic  loading and everything in the context of ELF based platforms so ELF for those who do not  know that stands for executable and linking format and it's basically the most popular  format for UNIX based platforms so Linux or BSD, like free BSD, open BSD they all use  ELF which is a binary format as I said. So if we consider an ELF file like the ELF executable  the first way we can see it is we can split it in sections so it's a file and it has several  parts which are called sections. The most important sections that you usually deal with  maybe if you've been doing a bit of reverse engineering are usually the dot text, all  the sections start with a dot. So the dot text section which holds the executable code so  the actual binary code of the application then we have dot data which holds all the  writeable global data so let's say the global variables that are writeable they're not just  read-only. The read-only one is the arrow data which stands for read-only data and then we  have BSS which is section which holds global variable which are not initialized so for  instance if you like in C write a global array that it's not initialized it will be zero  initialized and will end up in BSS. So let's see what's the role of the dynamic loaders.  Basically the compiler hides a bit of the complexity of the dynamic loader because when we see  this piece of code like a very simple lower program we see just printf but what actually  the compiler meets it's not a call to the printf in the C standard library because as I said  the libraries are positioned in random position so you cannot know at compile time where the  printf will end up. What actually the compiler does is calling the printf at PLT which is  a trampoline so let's say a small piece of assembly code that we're going to see or  explore outwards. This small trampoline is storing another section which is called dot  PLT the so-called procedure linkage table which is a table composed by this small trampoline  one for each imported function and basically let's see how it looks like. So this trampoline  are used to support lazy loading. Lazy loading is a feature of the several dynamic loaders  basically most of them which allows you when you start the program instead of resolving  all the important functions getting the real address of the start up of the program you  basically obtain the address the first time you call them so if there's a function you  never call it's not going to be resolved and you're saving time. And also the start up  of the program it's faster for the end user. So it works a bit like this. This is pseudo  code it's not actually it's an assembly optimized code what the trampoline doesn't look like  this but let this high level stuff to make you understand. If it's the first time that  the trampoline is being called the main binary will pass the control flow to the dynamic  loader calling this DL runtime resolve function which will explore in a bit otherwise it will  just jump to the cache version of this function. For instance if this is the trampoline of  printf there will be somewhere in memory we'll see where the place where the address of printf  is cached. And DL runtime resolve will take care of finding where printf is storing the  address of printf in a dead cache and printf address and then also call the function. So  DL runtime resolve takes two parameters the first parameter is just a pointer to a data  structure which describes the current L object we'll see more about that later. And the 1,  2, 3 parameter it's an index in a table it's an index representing a relocation. So what  is a relocation? A relocation is basically a directive for the dynamic loader telling  him so take this symbol with a symbol it's a concept that represents like a function for  instance in a library or maybe a global variable in an external library so a symbol take this  symbol for instance printf in this case and write its address at this specific address in  particular our offset represents where the address of the symbol has to be written and our  info represents the basically the identifier of the symbol. So relock index which is the second  parameter of DL runtime resolve is an index in a table of this relocation. Basically there is  a section called a relplt section which is basically an array of relocation data structure  which is called L rel which is composed by our offset and the info. So it's an identifier but  it's an index in another table which is called dynesim which is an array of symbols structures  which are actually L sim which have a lot of details we're not interested in. The only thing  we're really interested in is that there's a field called stname which is an offset in another  table and this is the last one I promise which is called dynestrain which is basically just the  concatenation of the name of all the symbols that are imported from a certain binary. So to  recap basically the DL runtime resolve takes relock index which is an index in the real  plt table which is a relocation. From the relocation which we pass to the symbol table and from  the symbol table we pass to the name which is in this case printf. We'll get back on these  things. So to recap again DL runtime resolve does three things. Finds the symbol and it's  associated with location and finds its address. So if you from the relocation go to the symbol  and you go to the name and from the name the dynamic loader is able to get its address. It  writes that address at the error offset and the address specified in error offset in the  relocation and then it also transfers the execution to that function. So it also calls it. As  you might have understand at this point error offset in this case will point to the address  of cache printf address. So error offset tells okay right there the address of this function.  So next time I'll call the trampoline. I want to resolve and get to do all the trickery to  get the to resolve the symbol again and just jump straight there. It's sort of an optimization.  Okay. So okay where does this cache printf address actually state is? It's actually in  another section which is called got plt which is the it's more mostly known as the just  the global offset table which basically holds an entry which is a pointer for each important  function. So it's where these cache addresses actually are. So just to recap we have plt which  contains all the trampoline which enable lazy loading. We have got plt where the cache address  of the important functions are stored where basically initially they are all uninitialized  and they get initialized lazily from the first time you call that function. We have the table  of relocation which is rel plt, table of symbols which is dynestream and then we have the  symbol of the symbol name which is dynestream. Just now terminated strings concatenated. Okay.  So let's try to come up with an attack to this system. So first some assumptions. Our assumption  as I said is that we are already able to divert the control flow and we are also able to run a  route chain and we also are able to write arbitrary memory location with this route chain. So  let's say we have a small very small gadget which is able to say okay I have this address, I have  this value, please write the value at that address. So very simple stuff. What can we do? So if we  look at this setting the idea is okay what if I'm able to replace the printf string for  instance with execv. If I'm able to do so to replace that string and I invoke the dial run time  result function with the relocation index corresponding to printf what the loader will do  it will go through relocation symbols but then in the end it will end in the dynamic string  table and it won't find printf but it will find execv and so it will resolve the address of  execv and also invoke that function. So we are basically in this way we will be able to invoke  any function we want just by name if we are able to write this arbitrary memory location. This  lies is called naive approach because this approach actually does not work because there's no  reason why the dynamic string table should be writeable. So the dynamic string table it's not  writeable because it's like static information that you just write once and you never change. So  this attack will not work. Even if you have this gadget we will try to write in unknown  writeable memory location and we just get a seg fold. So let's try to work around this. So we  have been talking about a lot of different sections but the dynamic loader actually does not go  through, does not consider sections by their name. It doesn't look up the PLT, GOT section by  name. It uses another section which is called the dynamic section which holds basically key  value pairs where the key represents one of the sections it needs and the value it's actual  address. For instance DTE syntax keeps a pointer to the dynamic symbol table. DTE STR table  and so on and so forth. We're not really interested in details here but the point is that the  dynamic loader uses this, takes the information about the binary, about these sections from  this table. So the nice thing is that the dynamic section is writeable. So what we can do is  instead of trying to write directly in the dynamic string table we can tweak the loader  into thinking that the dynamic string table is somewhere else. And where can we make it  point? For instance we can build a fake string table in the BSS or in any other memory section  which is writeable by us. BSS is typically writeable. It's always writeable. So basically we go to  the dynamic section and we change the D value field of the structure, making it point instead of  making it point to dynamic string we make it point to BSS. So what the dynamic loader will do is  okay I'll go through relocations, symbols and then when I get to the dynamic string table  instead of going to dot-dine string I'll go to BSS where I as the attacker I forge a fake  string table which is instead of printf as exact V. And so basically we are able to perform the  attack in the sense of being able to call any function call, any library function, sorry.  Okay. But this approach is still quite naive because actually we were not the first person  people thinking about this and so the developers of compilers and in particular of the linkers  develop a protection called relocation reel only or more shortly like realm room which is a  binary ardening technique which prevents exactly the attack we just described because why is the  dynamic section writeable? It's simply because there are some entries that we did not describe  yet which have to be initialized at one time. So it has to be writeable when you start your  binary but after you initialize them you can mark that section as read only and that's exactly  what the rail road protection tells the dynamic loader to do. And so basically our previous  attack doesn't work anymore. But maybe we can do something else. So we came up with another  idea. So far we played with the dynamic section but what can we do if we are able to play a bit  with the relocation index, the second parameter of the runtime result. What happens if instead of  making it point to an entry in the rail PLT section, making it point to an existing relocation, we  put an index which is big enough to go after the end of rail PLT section. Maybe we can trick the  loader into going somewhere more interesting. So let's take a look in the particular, can we make  it the loader thing that he has to resolve a relocation which is in a memory area which is  writeable by us. So not in the rail PLT section but maybe in BSS. So let's see what section do we  have after rail PLT. So let's suppose that we have, usually the indexes start from the beginning of  the rail PLT section and if we put an index big enough we can go through rail PLT, PLT, dot  X, dot dynamic, dot PLT and then we can end up in dot data and dot BSS. And so if you are able to  trick the loader in going there and we are able to forge a fake relocation there, we can basically  build our own relocation and resolve any library function without touching the dynamic section  which is not writeable. So this is an example of the thing. So we put a relocation which is big  enough not to go to rail PLT but to get into BSS where we forge a fake relocation which points to a  fake symbol with the same trick. So it's the same trick. So if we start from Dynesim we put an  index which is big enough to end up in BSS again and then the same trick again with ST name we put  an offset in the dynamic string table big enough to end up in BSS again. So basically we are  building all the data structure which are needed by the dynamic loader to resolve a library function  in the BSS and using always the same trick of overflowing the section which are supposed to be  used, we end up in BSS and we are able again to call any arbitrary library function by passing the  railroad protection. So here there are just some very simple formulas how to compute the  addresses that we have to put there. For instance, you have a relocation index and an  error info in the ST name field to be able to perform this attack. But this is not that simple.  This will be quite true because actually the binary is round in particular like in Ubuntu and  several other distributions and a feature which is called symbol version which basically  allows you to depend not on any printf function but on a specific version of printf. For  instance, I want printf function from the G-Lib C 2.22. This is just an elf feature which is  actually a new extension but since it's popular we have to deal with it. And what's the problem?  The problem is that if symbol version is enabled, the error info field is not used just as an  index in the symbol table but it's used also as an index in another table which is called the  new version table which we will not talk about. But the fact is that this symbol, this index is  used for two different things. And so basically we have additional constraints. So what we have  to do in this case is either we make both indexes go to the BSS section and so we can fake also  the other data structures which are related to versioning which we will not look into. Or we  can make it point, we can make the version thing point to a zero zero somewhere in a memory area  where we cannot write like if you find like a zero zero in text it's fine. So we just basically,  because this just basically disabled the versioning. So is it doable? Yes. And it can also be  automated. The point is that there are silent situations when this is really, really hard. For  instance in particular with 64-bit binaries using huge pages, huge pages means that you have like  memory pages which can be large up to a megabyte. And so basically the read only part of the  binary where we have text, relocation, the relocation table, the dynamic symbol table, the  dynamic string table, all these things which is the read only part, it's very far away. It's like  one megabyte away from the writeable page. And so this huge distance makes it really hard to  satisfy the constraints we just saw. And so in this case it's not doable. The problem is that 64-bit  binaries with huge pages and symbol versioning enabled are pretty popular. So we found another  solution for this. The idea is in this case is not to play around with Relock index but with  current object info. So let's look into current object info. What do we have there? It's basically  a pointer to a link map structure and we have this pointer, it's always stored in a reserved  entry in the GOT table which is the second one. GOT1 is the second entry of the GOT table. And the  nice thing about this data structure is that it has a field called L-info which basically keeps a  cache of pointers to the entries in the dot dynamic section. So the idea is if we can tamper  with this internal data structure of the loader, we can basically go back to the first attack  when we were tampering directly with the dot dynamic section. And this is actually what  happens. So we go to the PLT GOT section, we go to the second entry which keeps a pointer to this  link map structure. We go to the L-info field and to the entry corresponding to the DT STR  tab which is a pointer to the dynamic entry keeping itself a pointer to the dynamic string  table. We can change this value and make it point to BSS and we can build a fake dynamic  entry which tricks again the dynamic loader into thinking that the dynamic string table is a  memory area that we control. So we're basically falling back to the first attack we saw. So we  are still tampering with the dot dynamic table but indirectly, like corrupting the internal  data structure of the dynamic loader. And we can do this reliable and deterministically because  the pointer to this data structure is always in the GOT one, in the GOT, in the first, second  entry of the GOT. Okay, then, but still there's some additional protection to this because  railroad, it was, it comes in two flavors. Partial railroad which is the one we just saw, but  then there's full railroad. Full railroad basically it has all the features of partial  railroad but in addition, it basically completely disables lazy loading. This means that when  you start the binary, when you start your program, all the GOT entries are initialized and the  GOT, it's marked as read only. So we cannot write in the GOT anymore. And also since they are not  used any longer, the GOT one entry which was keeping the pointer to this link map structure is not  initialized. So we lost the pointer to this critical data structure which helped us to bypass  partial railroad. And not only this, we also lose the pointer to the L runtime result which is  something I skip over but we were getting its address from the GOT2 address and the GOT2 entry.  And also this entry is not initialized because simply lazy loading is disabled. So these three  things, we don't have a pointer to link map, we don't have a pointer to the L runtime result and  we cannot write in the GOT. It seems like we are pretty fine. But DT debug to the rescue. So there  is this feature which is like a, the typical debug feature which is staying there and waiting for  someone to abuse that. And here we are. So DT debug, it's an entry of the dot dynamic table which is  used by GDB and other debuggers to be able to break on certain events related to dynamic loading.  Like, okay, we have a new library being loaded. You want to break so you can explore this library and  see what new symbols you have. So debugging stuff that we don't really care about. But the nice  thing is that this dynamic entry doesn't point to a section but points to another data structure  which is our debug structure. But this debug structure keeps a pointer to link map. So we  basically are able just passing, going through this debugging feature to get back to the  previous attack. But it's not that simple. Because as we said, we also, this is the last  drawing I'm showing you. But this is really interesting because as we said, we don't have a  pointer, we have, we have found a pointer to link map going through the DT debug dynamic entry.  But still we have to be able to find a pointer to the DL runtime resolve. So let's do, let's see  how can we make this. So let's start from this area of the drawing. So in the dot dynamic  section, we go to DT debug, we follow its value and we get to the R debug. From R debug, we have  this field which is R map which points to the link map structure that we saw before. So first  thing we do, we corrupt the DT STR tab entry which is the one keeping a pointer to the dynamic  entry for the dynamic string. Okay? And so we do the thing we just did before. We build a  fake dynamic entry and we build a fake string table and this is, let's say, usual for now. But  the point is that we, what will the dynamic loader do? Okay, it will go through all the stuff  that we crafted and it will resolve exactly, exactly, nice. But then one of the features of  the DL runtime resolve, it's also storing the address of exact VE in the GOT. But the GOT has  been completely initialized and marked read only by the dynamic loader because of full  error. And so we get a seg fault because we are trying to write in a memory area which is  read only. So we have to also to fake another entry of the link map data structure which is  JMP rail which is a pointer which was the one holding a pointer to relocation table. So we  fake also the relocation table. We create a fake relocation which points to an existing  symbol but as error offset instead of pointing to the GOT, it's pointing to, like in this case,  a memory area just after it which is writeable. So we don't get the seg fault. And so we solve  also this problem. Now we have one last problem which is the address of DL runtime resolve.  So we don't have it in GOT2 and so we have to get it somehow. But how can we get it? The  trick here is that usually, actually in our survey basically always, only the main binary  is protected with full variable. The libraries are not protected with full variable. So if  we are able to get the GOT of libraries, we can still get the address of DL runtime resolve.  And the nice thing is that the link map structure, it's not just a data structure per se. It's  actually part of a linked list of all the link map data structures representing all the  loaded L-th objects. So basically what we can do is just we can dereference, like, the  pointer to the next, to the next entry in the dynamic in the, in the linked list and  get to the link map data structure of just any library. For instance, Libc or whatever  library is being loaded, we go to the, we get the address of the PLT GOT, GOT, and then we  go to the third entry and we get again the address of DL runtime resolve. And basically  we are able to build, building up all these things together. We are able to bypass also  full variable, which is a pretty cool thing. Okay. So, but, okay, this is very, very interesting,  but how can we do that? So we implemented Leakless, which is the name of our tool, which  implements all these techniques. Just giving the binary and it tells you which is the best,  actually the approach that is most suitable for this particular binary based on the protection  it has enabled and basically if it's 64 bit with huge pages and those kind of things,  and it can produce two different kind of, of outputs. It can either tell you, okay, do  these things. It outputs like a JSON, a JSON file, which basically instructs you, okay,  if you are writing an exploit, write this thing there, write this thing there, and then you'll  be able to, and then just call the runtime resolve and everything will work. Or if you  provide Leakless with the gadgets it needs, and we'll see what kind of gadgets it needs,  it will also, it can also produce the ROP chain for you directly. So it actually produces  the exploit to resolve one or more functions one after the other and call them with the  appropriate parameter. You can, you can see the code there, it's in GitHub, we just published  it and just, you can play around. So the gadgets, we talked about gadgets. So basically we  need at most four different gadgets, depending on what of the four attacks I presented,  excluding the first one which was not working, it was just the first naive approach. Depending  on which attack we are dealing with, we are different gadgets that we need. So the first  one, the one which was basically just overwriting the dot dynamic section, that just needs a  memory write gadget. So you give him, you need a gadget, you give him an address, a value to  write there and it writes there. And so basically all the exploits, all the techniques that we  saw need this kind of gadgets. So N stands for no railroad, P stands for partial railroad, H  stands for when you have huge pages and all kind of stuff and F for full railroad. In the  other case we have slightly more sophisticated gadgets, for instance this one is, if you look  at it, it's the one we use to tamper with data structure. So you have a pointer which is  usually a pointer to a data structure, you add an offset, you reference it and you write a  value there. And this is used for the huge pages attack and for the full railroad. Full  railroad requires two additional gadgets. This one is basically a gadget that we need to  store somewhere, some data that we took from those, like what we were walking through, all  those data structures, for instance the runtime resolve, basically you choose a memory area  where you want to save this address and you take it from these data structures at these  offsets. And in this case, so I initially skipped over this, but for the first three attacks to  call the runtime resolve we were using a part of the PLT, which if you remember it's where the  trampoline were. But in this case we cannot do that because the runtime resolve is not  initialized and so we also need to be able to write the address of the runtime resolve  directly on the stack. So we need a gadget which allows us to write at an offset on the  stack. So we need these four gadgets. And this is also the reason why I'm here, you know,  annoying you with four different techniques instead of just showing the last one, which is  the most powerful one. Because depending on the protection that I enable, you have different  requirements and you need different gadgets which might be easier or harder or maybe just  take more time to find and implement. So okay, but after all these things, what loaders are  actually vulnerable to this? So in our, we tested our leakless against the G-Lib C, so  the new standard library, and against the free BSD standard library. But by manual inspection  we think we deem it vulnerable, so diet lib C, UC lib C and new lib, which is, you know,  embedded, there are C standard libraries for embedded systems. And also open BSD and net  BSD. Because basically they all behave like the same. If you think about it, we're just  relying on the standard health features. And except for minor modifications, maybe, you  are, they all, for instance, they all cash pointers to the dynamic entries, somehow in  their internal data structures, they are maybe a bit different, but there's not a real big  deal. We say that it's not vulnerable by on it, which is the C standard library 400, because  as far as I know it does support only PIE binaries. And new, which is an embedded C standard  library, because simply it does not have lazy loading. So it's like if you have full error  all over the place always. So basically our tech is worthless. It's a feature, not having  a feature, it's a feature actually. And free BSD loader, I'd say it's kind of not vulnerable  because the first and the second attack I presented you, basically the one which was  overflowing the relocation table and symbol table and those kind of things, does not work.  Because these are the only guys that are actually checking the boundaries, which is like, basically  two things to do, but they are the only one. But still the other two attacks, they do work.  So it's kind of vulnerable and not vulnerable. Okay, so let's recap. What are the advantages  of leakless? So first of all it's single stage, so you don't need a memory leak vulnerability  and you don't require interaction with the victim. We are not sending back to the attack  anything. We just do a single way, single shot exploit, which might work in any situation  like air gap machine and those kind of things. So like offline attacks, which maybe before  were not feasible or no feasible. It's reliable and portable because it's deterministic, there's  nothing left to randomness or it's very deterministic. And then you do not need a copy of the target  library. So if you think about that in the beginning, I told you that you have to compute  in the typical situation where you use a memory leak, you have to compute the distance between  exactly the m print f. But to do this, you need a copy of the library, which is not always  the case. In this case, we do not care about the layout of the library. We just abuse the  dynamic loader, which does it in the proper way. And since it relies on just under L feature,  in most cases it's very portable and it's easy to port for instance to net BSD, open BSD and so  forth. Except it's link map layout of the data structure, but it's only a really minor fix to  the exploit. It's short because if you want something with the same characteristic I just  mentioned like reliability and deterministic, you will need to basically reimplement what the  dynamic loader is doing. So implement like in puro, going through all the relocation symbols and  those kind of things, which is very complex. And it's also, it gets very long because it's not  just say, okay, dynamic loader, do this for me. You have to do it by yourself. And also the  advantage of Leakless is that once you set up all the data structures, if you want to make  multiple calls to different library functions, you just need to, after you did the first one,  you just need to change the name of the function you want to call and just call again the  runtime resolve. Instead, if you want to implement the dynamic loader, you have to do again all the  process. And so it's, it's a cost that is not negligible. And you know, shorter, shorter  rope chains mean higher feasibility. You know, sometimes buffer are small and you have limits.  And if you don't want to interact again, you cannot read, you know, it's, if you want to do it  single stage, being short is important. We also say that it's stealthy because basically we are  not, the typical criticism one could make to such an attack is that, okay, but why don't you just  do this with sys calls? Okay. Because first of all, sys call might not be available. You might not  have them in the binary, like even in misaligned. But it's also more invasive. Because for  instance, you can always do, if you can do sys call, you can basically do everything you want.  But it might, you might have intrusion detection system and also spowing a new process, for  instance, if you want to do exactly, it's kind of an invasive. And here is an example of a thing  we came up with. It's a sys code for using PgN functions. PgN is a client. And so what we're  doing here is we're taking the pointer to the proxy object of PgN and we are setting, so the  attack we want to carry on is like, okay, set a proxy for, so I can intercept the instant  messaging traffic for this user. So what we do is we take the global object for proxy, we send  the proxy which is our server, the port, the type, and then we connect and disconnect the  user. Sure, you can do this also with sys call somehow, but reusing a program functionality,  it's much easier and less intrusion. And it's also easier. And also it's automated. And by this  means that our tool basically does almost everything except finding the gadgets. But maybe in the  future we can integrate it with some automated gadget finding tool. So counter measures, well,  the most obvious counter measure is enabling PIE. So randomizing goes to the position of the main  binary. Okay? This is an actual solution, but actually in our survey there are like very, very,  very few, PIE is not being deployed a lot. The distribution basically uses it on the  binaries, they deem critical. I don't know why they don't deploy it on all the binaries. It  doesn't make sense to me, but this is a possible solution. Also, DT debug, why should it be there?  Just remove it or maybe enable it only if there is like an exported variable, if you want, like an  environment variable, if you want to do debug, then you can enable it. Or you can try to make the  dynamic loader data structure and read all of this. So if you try to tamper with them, you get a  crash. Or just validate the input is also very good counter measure. But the key point is that  this kind of core components of the operating system should be retold with security in mind.  Because basically all the libraries we expect that we're just trusting user input. And since they  are all over the place, it's very dangerous because if you're able to attack them, you are able to  obtain something that is very portable and it's all over the place. So also ELF maybe should be  redesigned a bit with security in mind from the beginning. And this last thing I want to thank  all the other people who work with me in this, like Amat, which is here, and Jan, which is not  here, and Giovanni and Christopher at UCSB, which allow me to be here. And that's basically all.  Maybe I have a second to do a very short, so just to show you some code. So this is, I'm just going,  we tried to implement, to attack a real binary because we have a small test suite in  Leakless, but we also want to do something real. So we took a CVE in Wireshark, just a very basic  stack overflow, I mean a stack buffer overflow. And we tried to generate and exploit with Leakless,  just providing it with the gadgets. Just a small demo. We launched it, this is just an error  because I'm running Wireshark as root, don't do that. That's a very bad idea. We launched it  passing a pick up, which I generated and I got a shell. It's pretty easy.  Shell always good. Yeah, and then we have the same with Partial Rev, but it's the same  experience for you, so just trust me. So the last thing, this is the part, Leakless has been  implemented in Python, and this is the code that you need to write if you want to provide  gadgets to them, to Leakless. And it's 200 lines of code, but most of them it's just boiler  plate that could be factorized out. And it's basically just take the gadgets and mix them  together so they can be reused by the, let's say, the part of Leakless which is agnostic  from the binary. And the last thing is, yeah, I just wanted to show you the JSON output.  Let me see. So this is dot exploit dot pie, it's basically the Leakless script. We pass  it the Wireshark binary and we ask him to produce the JSON format using the LD corrupt  method which is the second one I presented. And what it does, it basically gives out some  instructions like, okay, write these things, this address, and so if you don't want the  Rob chain to be generated automatically for it because maybe you have some complicated  setting, it can just give you the instruction to perform the YATTA. With this I'm done and  thank you for your attention.  Thank you.
DEF_CON_23_-_Di_Federico_and_Shoshitaishvili_-_Dark_Side_of_the_ELF_aGoDYa7Kbec_0_4031.png DEF_CON_23_-_Di_Federico_and_Shoshitaishvili_-_Dark_Side_of_the_ELF_aGoDYa7Kbec_4032_14411.png DEF_CON_23_-_Di_Federico_and_Shoshitaishvili_-_Dark_Side_of_the_ELF_aGoDYa7Kbec_14412_17231.png DEF_CON_23_-_Di_Federico_and_Shoshitaishvili_-_Dark_Side_of_the_ELF_aGoDYa7Kbec_17232_21011.png DEF_CON_23_-_Di_Federico_and_Shoshitaishvili_-_Dark_Side_of_the_ELF_aGoDYa7Kbec_21012_21467.png DEF_CON_23_-_Di_Federico_and_Shoshitaishvili_-_Dark_Side_of_the_ELF_aGoDYa7Kbec_21468_31211.png DEF_CON_23_-_Di_Federico_and_Shoshitaishvili_-_Dark_Side_of_the_ELF_aGoDYa7Kbec_31212_32687.png DEF_CON_23_-_Di_Federico_and_Shoshitaishvili_-_Dark_Side_of_the_ELF_aGoDYa7Kbec_32688_39035.png DEF_CON_23_-_Di_Federico_and_Shoshitaishvili_-_Dark_Side_of_the_ELF_aGoDYa7Kbec_39036_40571.png DEF_CON_23_-_Di_Federico_and_Shoshitaishvili_-_Dark_Side_of_the_ELF_aGoDYa7Kbec_40572_65963.png DEF_CON_23_-_Di_Federico_and_Shoshitaishvili_-_Dark_Side_of_the_ELF_aGoDYa7Kbec_65964_67847.png DEF_CON_23_-_Di_Federico_and_Shoshitaishvili_-_Dark_Side_of_the_ELF_aGoDYa7Kbec_67848_68831.png DEF_CON_23_-_Di_Federico_and_Shoshitaishvili_-_Dark_Side_of_the_ELF_aGoDYa7Kbec_68832_69535.png