 I have a 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 that? What is that? Will that deliver shots? That's cool. You all know how this works. You've been here long enough. Okay. Wait, slow down there, man. 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, I don't know, invoking the system, the system library function and exact VE and launching program, copying wallets, I mean, doing the actual, your actual final A. And our, this talk, 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'll present. Because just being able to divert execution, it's not enough because, okay, I can, you know, I have my, I have control of the program counter, but the question now is where do I point it to? Where it's the important thing. And since it's 2015, we cannot, you know, upload a shell code in our target and just jump there because opening the system and preventing this kind of stuff. So as you all know, hackers and, you know, exploiters came up with the concept of code reuse attacks. So we cannot upload or, you know, inject new code. And then what we do, we reuse existing code. So we came up with the famous, you know, returning to libc attack and then all the return programming, 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 you're not able to inject a new shell code, we're using code. But the problem is that, you know, operating system developers came up with a 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. And 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 are able to get from our target the address 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 address of printf, so you need at least two vulnerabilities, you need a memory leak vulnerability, typically. And also you need the knowledge about 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, okay? 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 an air 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 it's 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 it is a lot 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. And so if we consider an ELF file like an ELF executable, the first way we can see it, 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 code, the binary code of the application. Then we have dot data which holds all the writable global data, so let's say the global variables that are writable, they're not just rid only, the rid only one staying arrow data, which stands for rid only data. And then we have BSS, which is a section which holds global variables 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 loader. 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 out with words. This small trampoline is storing another section which is called dot PLT, the so-called Procedure Linkage Table, which is a table composed by these small trampoline, one for each imported function. And basically let's see how it looks like. So these trampolines are used to support lazy loading. Lazy loading is a feature of 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 at 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 of what the trampoline doesn't look like this. But let this high level stuff to make you understand. So if it's the first time that the trampoline is being called, the main banner will pass the control flow to the dynamic loader calling this DL Runtime Resolve function, which we'll explore in a bit, otherwise it will just jump to the cached 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 the printf in a dead cached 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 described the current elf object. We'll see more about that later. And the one, two, three 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, a symbol is 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 the 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, it's basically the identifier of the symbol. So relock index, which is the second parameter of DL Runtime Resolve, it's 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 are called elf rel, which are composed exactly by our offset and our info. So our info, I said it's an identifier, but it's actually an index in another table, which is called dynesim, which is an array of symbols, structures, which are actually elf sim, which have a lot of details we are 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 DL Runtime Resolve takes relock index, which is an index in the real plt table, which is a relocation. From the relocation, 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 its associated relocation, 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 and printf address. So error offset tells, okay, right there, the address of this function. So next time, I'll call the trampoline, I won't have to resolve and get, do all the trickery to get the, to resolve the symbol again, and just jump right there. It's sort of an optimization. Okay. So, okay, where does this cache and printf address actually is? It's actually in another section which is called gotplt, which is the, it's mostly known as just a global offset table, which basically holds an entry, which is a pointer for each important function. So it's where these cache and addresses actually are. So just to recap, we have plt, which contains all the trampoline which enable lazy loading. We have gotplt, where the cache and 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 relplt, table of symbols, which is dinosim, and then we have the symbol of the symbol names, which is dinostring. Just null terminated strings, concatenated. Okay. So let's try to come up to, with an attack to this, 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 rope chain, and we also are able to write arbitrary memory location with this rope chain. So let's say we have very small gadgets, 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 the exact VE? If I'm able to do so, to replace that string, and I invoke the dl runtime 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 exact VE, and so it will resolve the address of exact VE, 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 out this arbitrary memory location. These lines 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'll try to write in a known writeable memory location, and we just get a segful. So let's try to work around this. So we've 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, I don't know, 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 evaluates its actual address. For instance, DTSimTab keeps a pointer to the dynamic symbol table. DTSTRTab, a pointer to the dynamic string table, and so on and so forth. We're not really interested in details here, but the point is that the dynamic loader uses these, takes the information about the binary, about the sections, from this table. So the nice thing is that the dynamic section is writable. 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, it's actually 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, any other section which is writable by us. BSS is typically writable, actually. It's always writable. So basically we go to the dynamic section, and we change the devalue 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'll get to the dynamic string table, instead of going to .dyn 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 read only, or shortly like railroad, which is a binary argument technique which prevents exactly the attack we just described. Because why is the dynamic section writable? 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 writable when you start your binary, but after you initialize them, you can mark that section as read only. And that's exactly what the railroad 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 like to play a bit with the relock index, the second parameter of the yield runtime resolve? 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 the loader think that he has to resolve a relocation which is in a memory area which is writable by us? So not in every 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 text, dot dynamic, dot PLT and then we can end up in dot data and in 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 writable. 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 DynSIM, we put an index which is big enough to end up in BSS again and then the same trick again with STNAME, 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 bypassing 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 RFON in STNAME field to be able to perform this attack. But this is not that simple. This will be quite too good to be true because actually the binary is around, in particular like in Ubuntu and several other distribution, and a feature which is called symbol versioning which basically allow you to depend not on any printf function but on a specific version of printf. For instance, I want printf function from the, I don't know, Glibc 2.22. Okay. This is just an elf feature which is actually a GNU extension but we don't really care. But since it's popular, we have to deal with it. And what's the problem? The problem is that if symbol versioning is enabled, the RFON 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 GNU 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 versioning thing point to a zero zero somewhere in a memory area where we cannot write like if we find like a zero zero in text it's fine. So we just basically, because this just basically disable the versioning. So is it doable? Yes. And it's also, 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 it means that you have like memory pages which can be a 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 and 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 constraint 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. GOT one 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 it 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 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 STR tab which is a pointer which is the 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. And so we're basically falling back to the first attack we saw. So we are still tampering with the dynamic table but indirectly like corrupting the internal data structure of the dynamic loader. And we can do this reliably 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 is an 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 GOTs mark 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 are, 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 resolve which is something I skip over, but we were getting its address from the GOT two address and the GOT two entry. And also this find, this entry is not initialized because simply lazy loading is disabled. So with these three things, we don't have a pointer to link map, we don't have a pointer to the L runtime resolve 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, you know, debug feature which is staying there and waiting for someone to abuse them. And here we are. So DT debug is 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 RDB structure. But this RDB 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 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 DL run time result. 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 RDB bug. From RDB bug we have this field which is air 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. 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 result exactly, exactly nice. But then one of the feature of the L run time result, 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 railroad. And so we get a seg fold 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 L info 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 air 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 fold. And so we solve also this problem. Now we have one last problem, which is the address of the L run time result. So we don't have it in GOT 2. 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 variant is protected with full railroad. The libraries are not protected with full railroad. So if we are able to get to the GOT of libraries, we can get, we can still get the others of the L run time result. 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 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, Lib C 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 the L run time result. And basically we are able to building up all these things together. We're able to bypass also full railroad, 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 all the, the, 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 publish 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, 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 memory write gadgets. 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 used 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, 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 why we were walking to all those data structures, for instance, the L runtime resolve. Basically you choose a memory area where you want to save this address and you take it from these data structure at these offset. And in this case, so I initially skipped over this, but for the first three attacks, to call the L 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 L runtime resolve it's not initialized. And so we also need to be able to write the address of the L 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 GNU standard library, and against the FreeBSD standard library. But by manual inspection we think we deem it vulnerable. So diet Lib C, UC Lib C and UC Lib, which are embedded, they are C standard libraries for embedded systems. And also OpenBSD and NetBSD. Because basically they all behave like the same. If you think about it, we're just relying on standard health features. And except for minor modifications, maybe they all, for instance, they all cache pointers to the dynamic entries, somehow in their internal data structures, they're maybe a bit different, but there's not a real big deal. We say that it's not vulnerable by Onig, which is the C standard library for Android, because as far as I know it does support only PIE binaries. And Newslet, 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 FreeBSD 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 attacker 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 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 an FBSD, open BSD and so forth. Except it's link map layout of the data structure, but it's always a really minor fixes to the exploit. It's short because if you want something with the same characteristic I just mentioned like reliability and deterministic and being 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 cause that is not negligible. And you know, shorter rope chains mean higher, 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 calls 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, 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 call for using PGIN functions. PGIN, it's I am client. And so what we're doing here is we're taking the pointer to the proxy object of PGIN. 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 a 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 calls somehow. But reusing a program functionality, it's much easier and less intrusing. And it's also easier. And also it's automated. And by this, meaning 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, PIE is not being deployed a lot. The distribution basically uses it on 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 use it, 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 redolny. So if you try to tamper with them, you get a crash or just validate the input, it's also a 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 inspected were just trusting user input. And since they are all over the place, it's very dangerous because if you are 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 worked with me in this, like Amat, which is here, and Yan, which is now 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 CV in Wireshark, just a very basic stack overflow, I mean a stack buffer overflow. And we tried to generate an 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. It'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 is always good. Yeah, and then we have the same with partial reverb, 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 boilerplate that could be factorized out. And it's basically just take the gadgets and mix them together so they can be reused by, 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 .exploit.py, it's basically the Leakless script. We pass it the Wireshark binary and we ask him to produce the exploit in 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 and 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 yate. With this I'm Daniel and thank you for your attention.