
it's behalf now this is this is usually used by by attackers to bypass security solutions by injecting code into legitimate apps or whitelisted applications and to access context specific data such as taking screenshots or accessing encrypted passwords such as passwords encrypted encrypted by google chrome now so what is atom bombing atom bombing is it's a new type of injection technique that leverages the global atom table and APCs which are a sync procedure calls and basically this technique is undetected by common security solutions or at least it was until we were released in in October and then after that I'm sure most antivirus vendors kind of rolled out patches to make sure they get this stuff and also
what's interesting about atom bombing is that it doesn't rely on a flaw and Windows or a bug or some kind of security hole but really it just uses just normal features of the OS in order to get the code injection so there's no patch that's gonna happen or gonna be rolled out by Microsoft anytime soon so it's gonna keep working basically for the foreseeable future now in order to understand how atom bombing works we first have to understand what an atom table is and an atom table is simply a mapping of 16-bit integers called atoms into strings and so basically as an app developer what I can do is I can call the OS pass the string to it and get it
get a atom back a 16-bit integer and then whenever I want I can ask the OS to give me the string back by giving it the atom that I got so we have two two kinds of different atom tables we have the local atom tables and the global atom tables now local atom tables are less interesting to us because they're accessible to a single process and are completely managed in user mode and the global atom table is actually very interesting to us because it's accessible across processes and is managed by the kernel now the functions that we can use to to manipulate the global atom table our global ad atom and global get atom name
now the first one receive is a pointer to a string and returns an atom the 16-bit little token that we can use to identify the string and the second function is the function that retrieves the string and basically receives an atom and a pointer to a buffer and a size and the sizes are there just so we don't have any buffer overruns and then this is pretty neat because what we can do is once we're able to control the pointer to LP buffer that we can see over here we're able to choose where whatever string we stored is going to be written to so in theory if I could somehow call global add atom and store
some code in the global atom table and then somehow force the the target process to call global get atom name and I could somehow control the parameters being passed to this API call this would be enable me to achieve my right wetware because i could choose what to write because i can store whatever i want in the atom table and i choose where the string is going to be written to so what we'd like to do is to leverage a mechanism called APC which is a sync procedure called now this has been used by malware in the past just not in this way that we're about to use it and basically how a pcs work is that this
enables me to pass a handle to a thread a pointer to a function and a parameter to that function and then that thread will execute that function and receive that parameter that in theory I control now the only problem is that the function is of type APC proc that's its prototype and so an APC proc expects to receive just one single parameter and we'd like to call global get Adam name which receives three different parameters so we have a parameter mismatch and so we can't really control the values of these 2 parameters over here which really doesn't help us very much but if we take a look at the underlying implementation of queues or APC we can
see that it actually uses the undocumented system call ntq APC thread and what it does is instead of passing our pfn APC the APC proc it passes a pointer to our TL dispatch APC and this function is actually a function that's found in all in all windows processes and this function will actually dispatch our APC call so what's interesting about our Cal dispatch APC is that its prototype is exactly the same as the prototype of global get Adam name and this prototype is just three parameters being passed normally on the stack so what we could do is we could just cut the middleman and not call Q's or ABC and not work with our kill dispatch ABC
but simply to to call the system call directly and then pass a pointer to global get Adam name which will allow me to will allow me to pass the three parameters that I would like you can see the three pushes over here that are the three parameters and then basically I can control the parameters that are going to be passed to global get Adam name within the context of the target process now this basically just gives us our right what where or completes our step one because now I can store whatever I want in the global Adam table by calling global at Adam and then get the target process to call global get Adam name by using the underlying system
call ntq EPC thread so once we have our write what where we'd like to be able to write some code into the address space of the target process and then execute it now for code to execute it needs to be executable and we can't assume to find read write execute memory within the target process it's just not gonna happen but we can't assume we can find readwrite memory that we can write our shell code to and then use some return oriented programming to allocate some executable memory copy the executed memory from the readwrite memory to the newly allocated executable memory and then finally jump to our shellcode and then this is actually the the ROP chained in detail
and you guys will have a slide deck so you can check it out later but we're about to see like a little demo that'll really demonstrate how this how this works so now we know what we want to do with the return-oriented programming but we also need to get to return oriented programming to work so what we'd like to do is we'd like to leverage a another system call called anti set context thread which receives a handle to a thread and a pointer to a context structure and the context structure is just a holds the values of all the different registers so what I would like to do is just set the value of the
instruction pointer and the stack pointer to point to my ROP chain and then divert the execution to execute it however we don't want to call an tea set context to thread directly because this this system call is quite suspicious and well if we have a process that is our under our control that's trying to change the context of a thread that's within the the address space of another process then that's very suspicious in many anti-malware solutions we'll flag that so what we'd like to do is we'd kind of like the thread to change its own context and we can try to leverage a PC thread accuser a PC thread again to execute ng set context thread or have
the thread call aunty set context thread on itself by passing the we handle to the current thread and then the context structure that we wrote using our right but we're from step one now the only problem here is that generally speaking a parameter mismatch causes a crash on return and NT set context thread expects two parameters and not three and so in theory this should lead to a crash however in this specific scenario the once the execution gets passed on to the kernel the return will never takes place because the execution is diverted from the normal execution flow to our new context that we passed in this pointer right here so there will never be a
return and so there will never be a crash and so we we don't really have a problem here so let's let's take a look at the ROP chain in action I've set up my debugger to to break just after the execution flow has been has been diverted and so we can we can take a look at the instruction pointer that currently points to NT allocate virtual memory and now this this function is the functions can allocate some virtual executable memory for us now the return address is mem copy which is the function that's going to copy the code from the readwrite memory to the executable memory and this is the 40 right here represents executable
readwrite and the memory is gonna be stored here where we have zeros right now so let's let that execute until the return and see see it happen so now if we take a look at the stack again we can see that where we once had zeros we now have newly allocated memory and if we take a look at the protection of this memory we can see that this is this is page execute readwrite which is 40 as we specified now we can take one more step and see that we land in mem copy no mem copy is the function that's gonna copy the memory from the readwrite to the read/write/execute memory and so if we
take a look at the stack again we can see that we have this is the executable memory that was just allocated and currently contains zeros and this is where we stored our shellcode before you can see this is the actual code that's going to be run but the only problem is that this memory is is a page read right so it can't execute and that's why we need the mem copy and so we'll let the mem copy execute until the return and then take a look at where we once had zeros now we have some code and what's left to do is just let the code execute a bit more until we land into our shell code now we can see that
our shell code is executing if we take a look at the value of the IEP we can see that that's our shell code and so what we're gonna do is gonna let this shell code execute for a bit until it does something interesting and that's to call the windows API when exit which will spawn a new process and so let's let this happen and see how what it looks like so one more step and we can see the calculator pop up and this basically proves that we were able to inject code into the target process and the calculator pops up so back to the slides what we did is we hijacked a thread to execute code on our behalf and this
thread had a purpose before we had hijacked it so if we don't restore its execution safely to where it once was there's no telling what kind of affect we could have on the target app but what I can assure you what will happen is that it's not gonna be stealth so I'd like to remind you that we're within the context of a of an APC APC dispatching and so somehow the operating system has to return the execution safely because that's just how APC is work and so if we take a look at ki user APC dispatcher which is the function that dispatches the APCs we can see that it actually stores the original context in register
named EDI and then dispatches the APC and when the APC returns it'll call ZW continue to with EDI passed as its parameter to restore the execution safely in our case calling the APC causes the diversion of execution to our shellcode and so this code will never actually execute because there will never be a return to this code and so what we would like to do is we would like to just back up EDI at the beginning of our shellcode store it in a temporary variable and then do our malicious code or whatever we want to do and then finally call ZW continue ourselves and pass a pointer to the to the contact structure that we
backed up from EDI and then this actually is all that we need to do and we can go back to our demo and we can see live we can see this happen so we'll take a few more steps and we can see that the next thing that's gonna be done is we're gonna place the backed up value of EDI into EAX which is another register push this onto the stack and then finally call ante continue which should restore execution safely and so let's let this this execute and we can see it says the debug E is running if we take a look at Google Chrome which is the injected process we can see that it
works just fine I don't have internet here so I can't show you that I can use the web but trust me it works so this works for all normal processes basically now as for processes that are protected by control flow guard which mspaint is an example of those if we try to inject code into mspaint we can see that mspaint crashes and if we take a look at the call stack we can see that actually what causes the crash is a call to our TLP handle invalid user call target which is a function that belongs to control flow guard and basically how control flow guard works it's a new mitigation technique introduced in Windows 8.1 and
Windows 10 and it it checks it validates every indirect call and makes sure that the indirect call is made to a to an end error into a valid indirect call target and basically so there's the list or a bitmap of valid indirect call targets and what we'd like to do is have our indirect call target added to that list and we can do this using anti set information virtual memory and we have a whole blog about this on our website you guys are more than welcome to check it out which explains how to do this and has code examples but for our purposes you can imagine that this system call expects a handle to to the process a
call target and a flag that says mark this call target is valid and then once we do this you would expect this to just magically work but there's actually one more hurdle we need to get over and that that not many people know that actually see if G does more than advertised and when you enable CFG for a process that actually enables some stack pivot protection in calls to system calls such as NT set context thread and and to continue now this functionality is implemented by calling verify context record which in turn calls RTL guard is valid stack pointer so what we'd like to do is we'd like to take a look at these functions and see how this is
implemented and see how we can bypass this and so verify context record simply calls RTL gardez valid stack pointer and passes a pointer to the new value of ESP we're trying to set and then whatever this function returns will either determine will determine whether we'll return status invalid parameter or status success so we take a look at at RTL guard is valid stack pointer we can see that what it does is it it loads it loads the TB from the e thread then from the e thread from the TV it loads the TI b then the TI b it references the stack limit in stack base of the of the process of the thread sorry
and and then depend then checks whether the the new value for ESP is between the stack limit and stack base and if it's below the stack limit or over above the stack base it'll return false otherwise it will return true and so what we'd like to do here is we just like to make it seem like there is no stack pivot and we can do that by querying the stack base and the stack limit of the target thread and we can do that because they're stored in user mode and so once we do that we can just copy our ROP chain to the actual stack of the target thread and this will make it seem to see
if gee like there is no stack pivoting going on now some vendors actually demonstrated the prevention of atom bombing by flagging this stack pivot and this is just an implementation detail something I'd like to note it's just an implementation detail and it can be easily overcome and we show here some code that actually overcomes this stack pivot problem and we're gonna post this on github within the next few hours actually so you can go on and browse it on our repository and so this actually this is all we need to inject code into CFG protected processes and so let's let's see this again live so you can see we have paint open here and we have the command line
ready you also have the process monitor open in the background and so what we're gonna do is just gonna inject the code we'll see the calculator pop up just as before and if we take a look at the process monitor we can see that that mspaint created a new process and this process is calculator which is pretty cool now if we take a look at mspaint again we can see that it's completely functioning all of its threads are intact nothing is nothing is wrong with it and if the user was using amis paint while we were doing this the user couldn't couldn't tell the difference so to sum up what we did is we took we took
atom bombing and we split it in two into three different steps then the first step was to write whatever we wanted to the address space of the target process and we achieved this by calling global add atom to store code in the global atom table and then we called ntq a pc thread to queue and a PC to the target thread and that a PC actually executed global get atom name and that retrieved the code that we stored within the global atom table then step number two is execution we were used a little return-oriented programming to allocate some executable memory then copy the shell code that we wrote to readwrite memory to the newly executable memory and
finally we executed our shellcode in order to execute the wrap chain or to invoke it we used Q a PC thread again this time passing it a pointer to nt set context thread which diverts the execution to execute the little returning programming and then which eventually leads to the execution of the shellcode and then finally to restore execution and to leave no footprints behind we we copy the the value stored in EDI which is the original context we store that in a temporary variable and at the end of our shellcode we call ZW continue passive the backed up value and this restores the executioner just lets the OS do what it was meant to do now in
order to add CFG exceptions we did is we used empty set information virtual memory and the last step we had to take is to bypass see if G's stack pivot protection and to do that all we had to do is just copy the ROP chain to the stack and then this basically just solves the problem and there is no issue so as for Microsoft's response to this basically there the response is that they're not really interested in post exploitation techniques and well we all know that compromise is inevitable and we do have to deal with with post exploitation techniques and so the best course of action would be for for third party security vendors would be to hook
ki user a PC dispatcher and just block calls to global get atom name and to NT set context thread which nobody should be calling in the first place so this will never generate any false positives and this should should block any any implementation of atom bombing because this is the core of it and there's really no way around this and that's basically it guys if you have any questions I'd love to address them
thank you any questions all right
no one has questions at all that means this talk was either flawless or you didn't yes thank you yes sir yeah that's that's their take on it and I think that's yeah so the question was the question was what's my take on Microsoft's response I mean they basically said that post exploitation techniques are not interesting but I think that Microsoft do kind of contradict themselves because for example they they say that UAC is actually not a security mechanism but in fact they do patch windows to block any we see bypasses just like one of our you is he bypasses you guys can see on our blog and so I think they're just not interested in handing out cv ease and to
make a problem where there shouldn't be one but I think we all know that we do need to deal with post exploitation techniques because it's interesting and because this does happen out there in the wild all the time any more questions yeah
no so they can be used legitimately they shouldn't be yeah sorry yeah you're right so the three the three functions that I said that we should just block why not why not just block them entirely and why do they even exist if nobody can use them legitimately so what I meant to say was these functions can be used legitimate lis just not within the context of an APC so during normal programming you could use these these functions and the first the first two which are the globe will get atom named function so these functions they they're used within the Windows user interface a lot actually and the the other system call is it's known to be malicious but it does have
some some some quite legitimate uses but there's no way that an APC should call any of these functions that's just a coincidence that it's possible and something that Microsoft didn't think was possible when they were designing this mechanism anything else it's hard to see if there's anyone up there raising their hand but I think not yeah couldn't Microsoft block those from the context of an APC yeah they could in theory I think they're just not interested in doing it but yeah that's they leave that kind of stuff to the to the antivirus or next-gen antivirus solutions but we might see Microsoft making changes to this kind of stuff you know in the future because they are trying to come
up with new a lot of new mitigation techniques and for example they're actually they they're coming up with this new mitigation technique now that's gonna be gonna block the ability of one process from changing the context of another process the privilege itself will not exist for it and that's something you can set you will be able to set once this new feature gets rolled out and so this kind of shows that maybe they are interested in doing something like this someday in the future but I don't think they're just there yet yeah can you speak louder I can't hear you
so a hacker would just need to be able to run code on your on your machine there's no need for any high privileges the limit is that you will only be able to inject code into processes that are within your privilege of accessing so this basically does not give you an elevation and privilege this lets you jump from one process to another okay anyone else all right thank you thank [Applause] you very much tall on behalf of Fitbit and besides SF we would like to present you with a Fitbit Alta and to remind you that motivation is your best accessory thank you it took three times we got last that time thank you um there is also a happy
hour after all of this after other talks right here hosted by Salesforce there are still a lot of cookies over there and there is a spymaster challenge going on all day in the lockpick village which is right up that away thank you so thank you all for coming and I'm here to answer any questions you may have and once again you can connect with tall on peer list