
this is jaden rivers attacking the t cash in glib c 2.32 so let's please welcome jaden to the stage [Applause] i'm jayden rivers i'm studying computer computer science while working at infosect and in general i'm interested in binary exploitation and software engineering in this talk we're going to cover allocating memory dynamic memory management in particular we'll look at the attacker's perspective on exploiting the memory allocator malloc and within malek we'll look at exploiting the tcash and lastly we'll look at bypassing safe linking which is a new mitigation in glibc 2.32 with the technique known as tcash list head poisoning so firstly what's allocating memory about there are three main ways of managing program memory first is automatically and these are
managed for a kind of a stack like data structure basically because a stack is lost in first out so it's good for nested function calls the duration of a stack region or frame or the local variables they're in is dependent on the lifetime of the function which manages it we also have dynamically allocated memory and the duration of a dynamically allocated region is basically constrained by the programmers choices as well as how the memory allocator is actually designed and implemented these regions can exist beyond the lifetime of any single function and it's the responsibility of the client to allocate and de-allocate correctly so as opposed to automatically managed memory these are manually managed memory we lastly have statically allocated
region and these are basically they're defined in the global context so they exist for the duration of the process the distinction i think between autonomic automatic dynamic and static is the duration and scope for which a region is well defined but we might also be able to access regions outside of there intended to duration scope or their linear boundary in the virtual address space and i think this is kind of the basis for memory use errors so automatic memory management i think is pretty easy you call a function from another function your arguments will get passed enough room for local variables is prepared and a reference to the next instruction for the cpu to carry out
when we exit that function context will be kept either on the stack frame or in a register depending on what architecture you're using so let's look at dynamic memory management in particular dynamic memory management is more difficult i think and we'll look at pt malloc which is part of canoe lib c malloc is what they call a heap style memory allocator and there are other types of allocation mechanisms such as slab and buddy interestingly the freebsd user space allocator i think j.e mallock employs both of these styles but we're only going to focus on malloc as it appears and used in linux systems so a heap style memory allocator has a range of possible sizes of memory
which the user can request from malloc and these regions will all be stored together in a larger region of memory called the heap and you can see here the um the virtual address mapping of the heap each new allocation will sit at a higher address in the heap however as we will see not every region returned by malloc is necessarily new as deallocated regions might be recycled basically for the sake of efficiency so the idea is that we don't want to keep cutting up the virtual address space when we can just reuse already cut out chunks this reduces fragmentation in the heap and speeds things up a bit the memory regions which the client can request from malek
are called chunks and they're kind of the fundamental unit or atom of malloc there are two perspectives and two states which relate to each chunk to the client a chunk will appear as a region of memory which can be read from and written to to malloc who's a server i guess a chunk appears as management data plus the user data portion so a chunk can be in an allocated state as you can see above or a free state as you can see below and these two states define the metadata associated with each chunk or basically how mal will interpret that metadata just like in stack memory there's both metadata and data but with the with the stack we we have
metadata which is directly related to control flow for example like storing a return address here it's a little bit further removed so let's just go back to basics and request two chunks of size 10 which get rounded up to hex 20 32 you can see that in memory but where's that metadata actually stored so if we look at the memory which just precedes each chunk we can see a size field so that's that hex 20 with a one bit flag which we don't really need to get into here i just use jeff jeb which is awesome to view some other metadata which is related to the chunk which a points to and as you'll notice those two
perspectives so we can see the chunk size which is what malloc thinks the chunk is and the usable size which is what us the user will actually interact with so let's go to the second state now from that allocated state to the freight state three a and b and as you can see there's a pointer to a at the first bytes of b first d word of b and the reason for these pointers is that when chunks are freed they're going to be linked into lists among other freight chunks at least in the malloc implementation these chunks can then be recycled in future requests made by the client in turn the lists are grouped together
in larger sets of lists called bins these bins are the small bin the large bin the fast spin and the unsorted bin and they basically correspond to different size ranges of chunks the unsorted bin also performs a special staging roll which we don't need to worry about then there's the per thread cache for each thread of execution and the tcash has its own set of free lists so it's kind of like a per thread bin in a way the tcash has these dimensions so they're configurable by the way chunks have to be in the range of hex 20 to hex 408 the number of lists is 64 where there's a maximum of seven chunks linked into
any single list at a time and also the chunks are singly linked so they only have forward pointers really the tcash exists because it wants to solve an additional problem compared to the other three lists the other bins to understand what this problem is i'm now going to mention the other units of malloc so we've already seen chunks but what else is there so in some order of generality or containment we have thread management with which obviously extends beyond malloc itself but within malek we have arenas below that we have heaps and then chunks at the most fundamental so a chunk will belong to a heap a heap to an arena and an arena to a
thread but only if said threat has locked the arena for itself and this basically implies that threads can access multiple arenas over the duration of the process but then an arena can only be accessed by one thread at any time so here's a kind of gross representation of thread one gaining exclusive access to the arena and all its chunks and you can kind of see the problem here that if thread two has to wait long then it might kind of counteract or negate the power of uh malek's free list optimization like in the end what's the point if we can't access those freight chunks arenas serve as a structure for storing the lists of freight chunks
they also have pointers to other arenas and other metadata such as where the top chunk is in memory basically where allocations will be serviced from in the future so some of the fields present in an arena as you can see here and most interestingly for us is that top field there and also the fast bin and bins the problem relates to the contention between threads for control over a single region of memory and the data they're in it's a general problem and in heavily multi-threaded applications it can become pretty inefficient to lock and wait at certain scales for malloc the solution is the established means of thread local storage and basically this is data which belongs
to each thread and transcends the regions of memory over which multiple threads contend so thread one doesn't need to worry about some thread two trying to access its thread local storage there's a lot more in malc which is not really relevant for our discussion today but hopefully we have a general grasp on the notions of data and metadata as they're used in chunks the units of malloc and also the justification or the reason behind the t cash and the problem that it aims to solve so what about the attacker's perspective on malloc exploitation of malik does have a quite a long history like 20 25 years i think but a lot of the techniques are no
longer really possible in the latest versions of malloc the first notable technique i think in heap exploitation was created by solar designer and this was the unlinking style attack essentially what we do here is we will overwrite the value at some location in memory by having malt consolidate already freight chunks the consolidation mechanism is uh what they call unlinking and one aspect of it can allow an attacker to gain a right or wear primitive and basically this is done by targeting the pointers of free chunks in one of those linked lists so before explaining this further it's good to just see a kind of abstract representation of a doubly linked list so you know just
basics like node one points no two no two to no three and they also have backward or previous pointers as well so consolidation in order to consolidate node 1 and node 2 we would update the size of node 1 to consume node 2 so the node 1 plus node 2 would basically be treated as one block and then to get rid of node 2 from the doubly linked list we would unlink node 2 and then we'd leave the list looking kind of like this so the macro to achieve this list unlinking mechanism in previous versions of glibc was what we can see here and to explain it a bit let's just say that p is a chunk which we want to
have consume the chunk ahead of it so we'll set back from p to the address of some shellcode or the first link in our rop chain and then forward from p to the address of a function point or a hook and we also have to minus for a 12 bytes struct offset and then after that back from fd is going to be set from back from back from p which is the address of our shell code so essentially it's that rightward ware thing where we're going to be out of rights the address of our shell code to a function pointer in a stack overflow contrasted with this we often want to overwrite the instruction pointer which is saved
on our stack frame but here we are further removed from code execution all we're really doing is linking and unlinking a specially crafted piece of data into a linked list data structure our machines need to refer to both the code and the data to run but often data is used to direct code for example storing function pointers these pointers that they're data but they can also be dereferenced in order to invoke the function that they're pointing you know like function pointers overriding this data we can alter execution unlinking has been followed by the house of star series so these also target metadata it might be in the house of force which targets the available size of male
chunks allowing an attacker to allocate a chunk which overlaps a function hook or the address of a function pointer in the global offset table or it might be in the house of spirit which frees a fake chunk targeting the list links so that malk returns a pointer into sensitive data what about exploiting the t cash in particular so for a bit of history the tcash was introduced in uh glib c 2.26 and at that time it had basically no security checks many of the older freeless based attacks were reintroduced in the t cash and though it operates differently the kind of general idea is that if we're given the misuse of a deallocation mechanism such as through a use after free or a
double free condition then the attacker might be able to get malloc to return a pointer to an arbitrary address it's also important to note that t cash lists are singly linked so we saw the representation of a doubly linked list before but the nodes in a tcash or the entries in a tcash will only have forward pointers so let's look at the abstract rep of a double free recall that a free chunk is going to be linked into one of those malloc management kind of lists bring it twice we'll link the same chunk twice and so we'll produce this kind of cyclic linked list if we then request a chunks so we can get back a
then the list is still going to look like this now we'll be able to write to the same chunk while it's in the t cache and essentially what we can do here is write the address of a target in memory to the foremost bytes of the a chunk such that the linked list will now look like this so we've kind of implicated the target address within one of malloc's own free lists and use after free is extremely similar basically we'll have this and then we write to the forward field of a and we have this and you know where this is a right after free kind of thing so more concretely so that we don't have
to keep looking at those diagrams um starting in glib c 2.27 a double free of the region of memory pointed at by a so as you can see here once we free a or double free a it's going to have a forward pointer back to itself and that's the same thing as the linked list cycle which we saw previously but it's not really that interesting just like this but if we take this we have a variable called overwrite me and this is obviously just a contrived example but imagine that it's a kind of arbitrary address in memory which relates to control flow somehow then we'll be at a double free a get back one of those a's write to the
forward pointer of it and then get back the remaining reference to a and then lastly we'll be able to write through d to the target address so as you can see here we'll just overwrite that so use after free condition as contrasted with double free can allow us to overwrite the forward pointer more directly and it's not really that interesting to just do this where we've written a bunch of uh a's to the forward field but if we have a look here we freed a and then at one we've done a use after free and then we've been able to get back our target address through the c pointer and so we have kind of an arbitrary
right so what are some mitigations for this kind of thing firstly is tcash count checking basically the idea is that we can't have malloc return more chunks than were legitimately linked into the free lists so that the add or remove operations have to be balanced but what we can do is we'll maintain the t cash account between calls so here we freed an extra chunk um to set the count at the tc index to one and then we freed another chunk and we launched our use after free attack again and another mitigation is to mark three chunks with a key field and this is even harder to bypass but basically there are a few ways
one way is to override the key field as detailed by silvio in this particular article the mitigation marks chunks which are freed into the t cash basically by setting a key field of a t cash note so you can see key from e will be equal to that t cash thing and we don't know what that is yet but it will come back later when we attempt to free one of those already free chunks into a t cash list malloc will check the key field and it will stop us so we'll enter that block up there and then we'll do a list traversal and eventually it's kind of guaranteed if we've done a double free that temp
will be equal to e and then we'll abort out so how can we kind of get around this essentially we can free a chunk and then overwrite the key field to ensure that the previous check fails and here's a demonstration of the technique from the article that i mentioned earlier so we'll free p and then we can overwrite key from e and we'll be able to free p again another way to bypass the key check is to confuse malk as to which list to actually check for a double free condition and we can achieve this by toggling the size of an adjacent chunk so the idea is that if we can change an adjacent chunk size metadata
then we can get the same chunk placed on different lists so while we do fail the first check and we enter this block here we can ensure that mel can't find our already free chunks because it'll be traversing or searching along the wrong list right so this so temp will never be e even though the key from a is equal to the t cash and in this example we just repeatedly toggle the size of an adjacent chunk which we know is going to be freed in the future and then we created cycles in the linked list and we retrieved our target address from a bin whose count is greater than zero so safe linking this is really hard to
bypass in my opinion the constraints are harsh and generally you need an information link in order to de-mangle pointers but if we're given the right circumstances we can bypass it by attacking the t-cash list heads directly so safe linking safe looking for a bit of background was introduced by checkpoint research in particular by their researcher ayalikum the idea as detail as detailed in cpr's article is basically to make use of aslr to sign or mangle the list's pointers el refers to the glibc unsafe on linking mitigation as inspiration for this mitigation and basically um this is because the doubly linked lists have already been protected from unlinking from the unlinking style attack that i mentioned earlier the one
that was designed by solar designer but mitigations over unsafe linking or unlinking in the singly linked lists such as those in the t cache have generally remained bypassable as we've seen safe linking is able to mask and unmask forward pointers with unlinking operations over the lists the forward pointers become mangled and then de-mangled from the original blog post we can see this kind of representation of the bitwise ops which mangle our pointers and we'll see that as code in a sec so the idea is that if they are legit forward pointers and they've gone through the legitimate process of linking by you know we've passed them to free and they've been put on the tcash in a legit way
then the process of de-mangling the pointers is going to be reversed and we'll get out the original pointer but if the pointer has not gone through the legit process it's going to become mangled and bad for us it will not be de-referenceable probably resulting in a seg fault or maybe in a board so the per the first piece of relevant code we're going to look at is in malik's tcash get function so here we just get the current head of the list and then we set a new head as kind of a simple list remove operation but if you notice the macro there reveal pointer there's a slight difference so compare that with malloc of glibc
2.31 and that was the version just prior to this mitigation so as you can see there's no reveal pointer applied to the next node from the head of the list and this this is actually kind of stock standard removal from the singly linked lists and to visualize the difference let's just say that we've got into here with our exploit so the target address will now be part of our linked list eventually we'll be able to get it back but the pointer from the t cash root node to a while it's legitimate the pointer from a into our target address is illegitimate right so we've actually we've freed a properly but we've the target address is only
kind of referenced by a it hasn't been properly freed and added to the t cash list in a legit way so now we get malloc to return a to us and what will happen ideally the target address is now going to be at the head of the list and so on the next call to malc would be able to get our arbitrary pointer to somewhere nice in memory but looking at the code we see that first e is set to the current head which is a and then the pointer in the t cache root note is not actually set to the next node from e which would be our target address right instead it's going to be set to the
results of reveal pointer given the next node from a and this is kind of where it all goes wrong so instead of what we had before we have the t cash root note um pointing into the result of reveal pointer which expands to protect pointer and that takes the position of the pointer in memory so kind of using aslr in order to mangle it and the pointer itself and then it performs the shift and zor operations if the pointer was not previously mangled then de-mangling is not going to produce the original pointer instead we will just get a mangled version of the pointer we wrote to the fd field the forward field of our target chunk
so with our view into memory we start with writing our target address so that's as you can see in blue that's a and then the target address is that yellow address there and then we'll get back our first chunk so notice the mangled pointer there that's not the same that's not our target address anymore and then when we try to get this pointer returned because it's not 16 byte aligned um there's going to be an abort raised and we won't be able to get further than this so this basically happens because when the tcash get function is called again it's going to attempt to access next from a and this can either result in a bought
which is the result of some alignment validation on the chunks in the t cash or it will just be a plain segbolt since e might not even be a valid address it might have been mangled so intensely the way to have a pointer demangled rather than mangled in this process is basically to perform a protect pointer before a reveal pointer and this kind of abstracts into like a t cash put before a t cash get so from the perspective of a user that would mean having a pointer legitimately linked by a free rather than through being overridden with a use after free or a double free bug in the tcash put function we can see
the list add operation performing some pointer signing so that's a protect pointer before reveal pointer and here what we do is we'll set a new head in a legit way so that a subsequent t cash get will be able to reverse this process and we'll get back our original pointer safe linking in my opinion is ingeniously simple and it only has a minor performance impact so in cpr's threat model an attacker has to have the ability to leak heap addresses and these can then be used to properly de-mangle the forward pointers hopefully resulting in the original primitive however something that i noticed here was that the tcash port mangling occurs only when a new head is set in
the t cash list and this kind of got me thinking that if we can control the list head more directly then no de-mangling would be performed on the target address as our target address would never actually be at next from a so to visualize it instead of this we're just going to start with this and we don't need that that um third-party kind of a but how could this work the t-cash root node is not meant to be part of our own free chunk metadata and we shouldn't be able to just access it or write to the head of the list which it refers to to give a bit more context the list head sits in an index
in an array of pointers and this array is part of an internal malloc management structure called the t cash per thread struct luckily for us malloc also inlines this t cash per thread struct in the heap so as evidenced this in the t cash init function a hex 290 sized heap allocation is made and this is the memory for the t cash management structure so here it is um and that's overlaid as the first chunk in our heap so we can see the array of pointers entries we can also see those counts there so what can we actually do with this information in order to attack uh safe linking we can do t cash list
head poisoning but before we get started in this section i think it's worth mentioning that with the write what where primitive which is what we're kind of aiming for we need to target data which has some effect on control flow we might want to target application specific function pointers or as is in the case in this section we can target the memory allocator hooks in particular the free hook so a hook in this context just to give a bit of a definition is just an address which is checked prior to the execution of one of malloc's internal functions and if the address holds a non-null value then malik is going to assume the value to be the address of another
function to be executed in place of this default function so here we can see the code in malek.c and this basically reads from the free hook to see if malek should call a custom free implementation so you can see the atomic's forced read and then the function pointer is checked to make sure it's not null and then it will be dev referenced and called so the idea is that if we can get malik to return a pointer to a hook and we subsequently write to it then the next time the corresponding function is called our own code will be executed in place of it and we won't focus on this but usually you'd want the address of the
first link in your rob chain to be the new hook or maybe the address of system or something so now that we have a target in mind for the remainder of this section i'm going to detail a few variants of the t cash list head poisoning attack with some hypothetical bugs so attacking the t cash list heads could be achieved with a negative offset right which might be caused by a user controlled index or assigned into overflow or decrementing an index or like a cursor pointer below zero and it could also be caused by a use after free given some constraints so with a user controlled index let's just say that we have a function which
performs a set operation on an array if it only checks the requested index against the upper boundary of the buffer then it might be possible to write at a negative offset and here that would mean that where is a negative integer so here we wrote directly to the t cache listed with a negative offset from the beginning of a heat buffer and then we overwrote a hook and we got code execution so essentially when free b is called it'll be calling hook override instead so where exactly we riding to with this negative offset we can see the hex 290 tcash management struct in our hate memory what we have done essentially is we've written the address of our target
freehold to the list head corresponding to the free chunks of size hex 3a0 and to show it with some really nice colors we have our previous representation and also the memory view so the free hook is at that list head so the code which doesn't perform lower bound checks on signed integer indices does exist in the real world but looking at previous cbes it seems pretty rare and i think this is mainly because the accepted practice is to use unsigned data types for variables which might end up being users indices and also generally to attempt to limit user controllable indices so an index overflow what about overflowing a signed integer which is subsequently used as an array
index so let's just take a like a custom stack implementation and say that we store the top of the stack as a signed integer and we begin repeatedly pushing values if we increment the index beyond its data types range then it will wrap around to become negative so here's just a quick refresher on what assigned integer overflow is if we keep incrementing assigned variable and i just did it use the chart just so it fit on the screen then at the limit of its data types range it's going to become negative and below is the result of incrementing a char type which has the smallest range in c application logic permitting this could allow us to write to a
negative offset from the beginning of the buffer and so we'll be able to write our target address to a t cash listed so let's look at the potentially buggy situation so here a check will be performed to ensure that the stack has an overflow beyond its upper boundary and this check kind of allows an off by one already but more importantly if top from stack if the top from stack variable wraps around to become negative then we will be able to write below the lower boundary of the buffer hopefully up into t cache list head so in the sei cert c coding standard we find this related quote that the sanitization of signed integers with respect to an array index operation
must restrict the range of that integer two numbers between zero and the size of the array minus one i've seen a few examples of signed integers uses both iterative variables in for loops as well as array indices within those so what if we decremented our index or maybe like our cursor pointer below the lower boundary sometimes it's useful to pass input data in reverse starting at the upper boundary of the buffer and working our way back down so for example say that we read a binary file in reverse and we miscalculate the last index of the buffer which we are reading into we'll just continue to decrement buff pointer below the address of index zero
and this could allow us to write into the tcash management struct again and i'm just kind of showing different uh potentially buggy situations just cases to show the problem with putting the t cash management struct in the same heap so some questions which we have to consider with these already seen variations are how far away will the tcash management struct be from the chunk that we control and what other amalgamated data will we corrupt when riding below our chunk in memory so looking back to the threat model of safe linking they say that the mitigation is aimed at stopping attackers who have a controlled linear buffer underflow or overflow over a hay buffer or a relative arbitrary right over heat
buffer so we can say that this does already constitute an attack vector which safe linking is muddled on even if the conditions are harsh and semi-unrealistic but what are the variants of list head poisoning are there so if we look back to the malloc.c source we can see the key field from the mitigation that i mentioned before and notice how it's a pointer the key field actually holds the address of that t cache management object so in the tcash init and tcash put functions we can see where that happens so the t cache will be that global pointer and then key from e will be set to it and essentially that key field mitigation which we saw
earlier actually initializes a pointer to the tcash management structure in every chunk linked into the t cash lists and the fact that it's a pointer rather than just some random hash or an xord pointer or even a protected pointer within safelinking's own logic that means that we can de-reference it directly so if we can pass this pointer to free um then we might be able to place the t cash management struct on a t cash list as if it was um afraid as part of those some those take cash list freight chunks and this ensures that it's actually it's legitimately pointer protected so that we can request it from malloc in the future additionally the tcash management struct
is already a legit chunk so freeing it won't actually be a problem in terms of the metadata validation routines that malek will run so in this example we freed a point of field after we freed its encapsulating object and this is just a kind of really silly binary tree but the idea is that um that key from e will be at uh right from roots after we free the encapsulating object so here we can see that the tcash management struct was linked into one of its own lists specifically the hex 290 list as you can see there and i'll just point out that the 5010 that's our tcash management struct so from there we can get it returned by
malc and this would allow us to write to the list heads in the future the technique does have three stages before it can be used to the same effect as the historical tcash attacks and there is a size constraint on getting the tcas struct returned so let's now look at writing with a use after free to a struct field in this example we wrote to the right child of the root node and this incidentally uh wrote to our target address wrote our target address to um the t cash list head at that sum that hex 80 offset from the beginning of the t cash per thread struct and with our view into memory we confirmed that the right was successful
so freehook will now be the head of the hex 20 t cash list and of course i just put this in for completeness but the attack is also possible and applications written in c plus plus because as before the second pointer is set to the t cache key but this is kind of obvious so here's uh here are a few examples of dynamically allocated structs with pointers which would be in the correct position and of the right size the reason why i included the last slide is not to pretend that having a point at a particular offset in the struct is necessarily a bug but i wanted to emphasize that it does seem very common for people to store pointers
at the same place and the worry i think with this almost default way of approaching dynamic data structures is that malloc has no facilities to autonomously distinguish between what metadata and data is they're essentially the same thing and given this fact i think programmers might want to organize their dynamic data in a way which makes the boundary between malloc's metadata and our own data better defined i think this is kind of comparable to how we don't want code and data to get mixed up hence non-executable mappings in the same way we want to limit the potential for metadata to be interpreted as data and vice versa but you know this is just my opinion regardless there's still something kind
of unsatisfying about this pointer position constraint so can we loosen it a bit using a house of spirit style attack we can construct a chunk contained within the larger chunk and we do this to override a pointer at whatever 16 byte aligned offset we want so we've reduced the constraint from necessarily an eight byte offset from the beginning of the t cash per thread struct to a 16 byte aligned offset from wherever in the t cash per thread struct so here we used uh the house of spirit which is kind of an established technique to control a pointer which is passed to free and with some influence over the data inside the chunk we um were able to pass malloc security
checks so you can imagine doing a kind of like partial override of a pointer in order to achieve this so with our view into memory again uh we can see that we overwrote the pass pointer with the address of the tcash management structure note how the pass pointer is not at that eight byte offset anymore after that we freed it and we achieved the same thing as before so we've kind of loosened the constraints a little bit with heap exploitation today you usually need to leak an address from lib c in order to defeat aslr by calculating offsets from the libsy base address for example how do we know which address to actually write to the free hook
one answer is to write the address of the system function arm to the hook or maybe like a rop gadget or something we can extend the technique shown here to get a libsary link or maybe some other primitive on our way to code execution so recall the cash count checking mitigation that i mentioned earlier there's a configurable limit on the number of chunks which are allowed in any one list at a time by default this number is seven so what happens when we try to link up the eighth chunk then the below check will fail so if this chunk doesn't go into one of those t cash lists it's going to go into a list from one of
those bins that i mentioned earlier for this example we target the unsorted bin
the unsorted bin oh hang on sorry the unsorted bin has a circular doubly length list so if a chunk is linked into the unsorted bin then it's going to be initialized with two pointers rather than just one one to the previous chunk and another to the next chunk so then say that we are dealing with the earliest adder chunk or the least recently added chunk while the bk field points to our second chunk the ft field will always point to an address which we can kind of guess is the unsorted bin root node so what happens if instead of only linking the tcash management struct onto one of its own free lists we also linked it into the unsorted bin so with
some heat grooming to ensure that the chunk validation passes we can write the address of the unsorted bin root node to uh those t cache list heads and this means that we can get it returned in a subsequent malloc request this helps us because the unsorted bin unlike the t cash management struct is not inlined in our heap like like the tcash management struct but instead it's part of the main arena or part of the arena which is stored in jlib c's own virtual address space and assuming that this is the main arena at this point we can make an allocation corresponding to the list ted where we wrote that libc address and so here we requested a chunk of
memory whose address was stored in our variable lib c pointer and as you'll notice the lipstick pointer is a pointer into the main arena so once we have this arena pointer we could do a few things we could read from the pointers surrounding this chunk and then we could use them to work out the offset to the rock gadget we could launch a house of four style attack by overriding the least significant byte of the lib c pointer to overlap the main arena field which points to where the top of the heap is overriding this we would ensure that a future allocation is serviced at a controlled address so the heap will grow beyond its
ordinary boundary to overlap other parts of memory so here we set the top of the heap just to a stack address and on a subsequent request to malloc we might be able to get our chunk to overlap the current stack frame and from there we'd be able to uh overwrite the return address without mangling the stack canary so here's our memory view and as you can see here uh top was overwritten we could probably have just written our stack address to the tcash list head directly but setting a new top ensures that every future allocation will be made relative to that address so we have a bit of wiggle room and trial and error i also included this just to emphasize
the level of complexity that goes into dynamic memory management and how it exposes different entries of attack as for a libsy leak itself we could achieve this by targeting the input output management structures which was used in c4e's house of rus blog post and this is where we get a chunk allocated from the appropriate t cash bin with a bit of trial and error we can get it to overlap the standard out geolib c i o management structure and then after that we'll overwrite the flags field with this hex value and then we'll null out those following fields and from there uh we'd hopefully get a huge dump from memory once our process uses the standard out file
stream then we'll just work out the libsy base address and then the relative address of our rop gadget and this should hopefully allow us to gain code execution in the end i've spoken with a yalikin who created safe linking and we wrote a blog post together about the technique before glibc 2.32 was officially released ayala was really helpful in putting the details of the attack in clear terms and i appreciate the interest and openness additionally ayala states at the bypass that it will be a knowing gap in safelinking's protection and will be a bypass that might be exploited by attackers so there are a few corner cases which need to be fulfilled and in this way i wouldn't say that safe
linking is broken it manages to mitigate against many examples of list poisoning attacks the main purpose of presenting this technique today was to add something to the arsenal and also to point out some of the design decisions in malloc safely in my opinion is a great mitigation and props to cpr for its simplicity i also recommend reading the house of ross blog post by c4e because it's awesome and presents another way to attack attack the list heads by using the t cash stashing mechanism matching different constraints so here's some open problems as well the technique presented here it aims at bypassing safe linking within the constraints set by cpr's threat model and to this end it does succeed
but there are also additional application specific constraints which also need to be satisfied for this to work i haven't had much time to explore it further so i just want to give some additional problems whose solution might further ease the restrictions on t cash list head poisoning so one the question is can we use the t cash key as a prev pointer in one of those doubly linked lists and two can we take advantage of the consolidation mechanism to consolidate with the tcash management structure so in summary um today we kind of covered the basics of memory allocation so that was autonomic automatic dynamic and static then we looked at exploiting malloc and then some historical attacks of the
unlinking and then the house of star and then um also double freeze and use after freeze as well as their mitigations then how to bypass these mitigations and lastly bypassing safe linking in geolib c 2.32 so my final shout outs are to kylie silvio and others such as like paul and peter for organizing b-sides uh faith and josh for proofreading the slides and everyone here for listening thanks [Applause] thank you jayden for that talk um some questions if you want to ask a question please go on to the slack and ask some questions i suppose i'll start off just by asking are there any distros at the moment that are using glibc 2.32 because i don't think
most of the main distros have actually started to use gmc 2.32 i have like a vagrant fedora box which uses glibc 2.32 but i think that that just might just be like a custom distro rather than like an official release but i'm not sure so when do you think uh distros will start to use you know when do you think ubuntu might start to use philips c2.32 i i honestly i have no idea but um maybe maybe next year i don't know well that's good that's great um that's i'll check this like we have any more questions but thanks once again for a great talk
you