AtomBombing: Brand New Code Injection for Windows

TL;DR Here’s a new code injection technique, dubbed AtomBombing, which exploits Windows atom tables and Async Procedure Calls (APC). Currently, this technique goes undetected by common security solutions that focus on preventing infiltration.

Code injection has been a strong weapon in the hacker’s arsenal for many years. For background on code injection and its various uses in APT type attack scenarios please take a look at:

http://blog.ensilo.com/atombombing-a-code-injection-that-bypasses-current-security-solutions

Overview

I started poking around to see how hard it would be for a threat actor to find a new method that security vendors are unaware of and bypasses most security products. It also needed to work on different processes rather than being tailored to fit a specific process.

I would like to introduce you to AtomBombing – a brand new code injection technique for Windows.

AtomBombing works in three main stages:

  1. Write-What-Where – Writing arbitrary data to arbitrary locations in the target process’s address space.
  2. Execution – Hijacking a thread of the target process to execute the code written in stage 1.
  3. Restoration – Cleaning up and restoring the execution of the thread hijacked in stage 2.

AtomBombing Stage 1: Write-What-Where

I stumbled onto a couple of rather interesting API calls:

  • GlobalAddAtom – Adds a character string to the global atom table and returns a unique value (an atom) identifying the string.
  • GlobalGetAtomName – Retrieves a copy of the character string associated with the specified global atom.

By calling GlobalAddAtom one can store a null terminated buffer in the global atom table. This table is accessible from every other process on the system. The buffer can then be retrieved by calling GlobalGetAtomName. GlobalGetAtomName expects a pointer to an output buffer, so the caller chooses where the null terminated buffer will be stored.

In theory, if I could add a buffer containing shellcode to the global atom table by calling GlobalAddAtom, and then somehow get the target process to call GlobalGetAtomName I could copy code from my process to the target process, without calling WriteProcessMemory.

Calling GlobalAddAtom from my process is pretty straightforward, but how would I get the target process to call GlobalGetAtomName?

By using Async Procedure Calls (APC):

QueueUserApc – adds a user-mode asynchronous procedure call (APC) object to the APC queue of the specified thread.

DWORD WINAPI QueueUserAPC(
_In_ PAPCFUNC  pfnAPC, 
_In_ HANDLE    hThread, 
_In_ ULONG_PTR dwData
);

QueueUserApc receives a pointer to an APCProc which is defined as follows:

VOID CALLBACK APCProc(
  _In_ ULONG_PTR dwParam
);

GlobalGetAtomName’s prototype is:

UINT WINAPI GlobalGetAtomName(  
_In_  ATOM   nAtom,  
_Out_ LPTSTR lpBuffer,  
_In_  int    nSize
);

Since GlobalGetAtomName expects 3 parameters (while  APCProc is defined to expect only 1 parameter) we can’t use QueueUserApc to get the target process to call GlobalGetAtomName.

Let’s take a look at the internals of QueueUserApc:

Figure 1: QueueUserApc

Figure 1: QueueUserApc

As you can see QueueUserApc uses the undocumented NtQueueApcThread syscall in order to add the APC to the target thread’s APC queue.

Interestingly enough NtQueueApcThread receives a pointer to a function that is to be called asynchronously in the target thread, but the function being passed is not the original APCProc function the caller passed to QueueUserApc. Instead the function being passed is ntdll!RtlDispatchAPC, and the original APCProc function passed to QueueUserApc is passed as a parameter to ntdll!RtlDispatchAPC.

Let’s take a look at ntdll!RtlDispatchAPC:

Figure 2: ntdll!RtlDispatchAPC

Figure 2: ntdll!RtlDispatchAPC

It starts by checking if the 3rd parameter is valid, which means an ActivationContext needs to be activated before dispatching the APC.

If an ActivationContext needs to be activated:

Figure 3: ntdll!RtlDispatchAPC – RtlActivateActivationContextUnsafeFast

Figure 3: ntdll!RtlDispatchAPC – RtlActivateActivationContextUnsafeFast

The function ntdll!RtlDispatchAPC executes the following:

  1. The passed ActivationContext (currently in ESI) will be activated by calling RtlActivateActivationContextUnsafeFast.
  2. The parameter to the original APCProc function (i.e. the third parameter passed to QueueUserApc) is pushed onto the stack. This is because we are about to call the original APCProc function.
  3. Right before dispatching the APC, a call to CFG (__guard_check_icall_fptr) is made to make sure the APC target is a CFG valid function.
  4. A call to the original APCProc is made, and that’s it – the APC has been dispatched.

Once APCProc returns, the activation context is deactivated:

Figure 4: ntdll!RtlDispatchAPC – RtlDeactivateActivationContextUnsafeFast

Figure 4: ntdll!RtlDispatchAPC – RtlDeactivateActivationContextUnsafeFast

If, on the other hand, no activation context needs to be activated:

Figure 5: ntdll!RtlDispatchAPC – no activation context

Figure 5: ntdll!RtlDispatchAPC – no activation context

The code skips all the activation context related stuff and simply dispatches the APC right away after calling CFG.

What does all this mean? When calling QueueUserApc we are forced to pass an APCProc which expects one parameter. However, under the hood QueueUserApc uses NtQueueApcThread to call ntdll!RtlDispatchAPC which expects 3 parameters.

What was our goal? To call GlobalGetAtomName. How many parameters does it expect? 3. Can we do this? Yes. How? NtQueueApcThread!

See main_ApcWriteProcessMemory in AtomBombing’s GitHub repository.

AtomBombing Stage 2: Execution

Obviously I could never hope to consistently find RWX code caves in my target processes. I needed a way to consistently allocate RWX memory in the target process without calling VirtualAllocEx within the context of the injecting process. Sadly, I could not find any such function that I could invoke via APC and would allow me to allocate executable memory or change the protection flags of already allocated memory.

What do we have so far? Write-what-where + a burning desire to get some executable memory. I thought long and hard how to get over this hurdle, and then it hit me. When DEP was invented, its creators thought, “that’s it, data is no longer executable, therefore no one will ever be able to exploit vulnerabilities again”. Unfortunately, that was not the case; a new exploitation technique was invented solely to bypass DEP: ROP – Return Oriented Programming.

How can we use ROP to our advantage in order to execute our shellcode in the target process?

We can copy our code to an RW code cave in the target process (using the method described in stage 1). Then use a meticulously crafted ROP chain to allocate RWX memory, copy the code from the RW code cave to the newly allocated RWX memory, and finally jump to the RWX memory and execute it.

Finding an RW code cave is not a big problem. For this proof of concept, I decided to use the unused space after the data section of kernelbase.

See main_GetCodeCaveAddress in AtomBombing’s GitHub repository.

The ROP Chain:

Our ROP chain needs to do 3 things:

  1. Allocate RWX memory
  2. Copy the shellcode from the RW code cave to the newly allocated RWX memory
  3. Execute the newly allocated RWX memory

ROP Chain Step 1: Allocating RWX Memory

We would like to allocate some RWX memory. The first function that comes to mind is VirtualAlloc – a very useful function that can be used to allocate RWX memory. The only problem is that the function returns the newly allocated RWX memory in EAX which would make our ROP chain complicated by having to find a way to pass the value VirtualAlloc stored in EAX to the next function in the chain.

A very neat trick can be employed in order to simplify our ROP chain and make it more sophisticated. Instead of using VirtualAlloc, we can use ZwAllocateVirtualMemory, which returns the newly allocated RWX memory as an output parameter. This way we can actually set up our stack so that ZwAllocateVirtualMemory stores the newly allocated memory further along the stack, effectively passing the address to the next function in the chain (see Table 1).

ROP Chain Step 2: Copying the Shellcode

The next function we need is a function that will copy memory from one buffer to another. Two options come to mind: memcpy and RtlMoveMemory. When creating this kind of ROP chain one might be initially inclined to go with RtlMoveMemory because it uses the stdcall calling convention, meaning it will clean up the stack after itself. This is a special case though. We need to copy memory to an address (placed on the stack by ZwAllocateVirtualMemory) and then somehow this address needs to be called. If we used RtlMoveMemory, it will pop the address of the RWX shellcode right off the stack upon its return. On the other hand, if we use memcpy, the first entry on the stack would be the return address of memcpy, followed by the destination parameter of memcpy (i.e. the RWX shellcode).

ROP Chain Step 3: Executing the newly allocated RWX memory

We have allocated RWX memory and copied our shellcode to it. We are about to return from memcpy but the address of the RWX shellcode on the stack is 4 bytes away from the return address. Therefore, all we have to do is add an extremely simple gadget to our ROP chain. This simple gadget will execute the opcode “ret”. memcpy will return to this simple gadget which will “ret” right into our RWX shellcode.

See main_FindRetGadget in AtomBombing’s GitHub repository.

 

For those who have to see it to believe it:

Set EIP to point to ZwAllocateVirtualMemory, and ESP to point to this ROP chain:

Address Value Comment
0x30000000 ntdll!memcpy // Return address from ZwAllocateVirtualMemory
0x30000004 0xffffffff // Pseudo handle to the current process
0x30000008 0x30000020 // Where to store the allocated memory
0x3000000C NULL // Irrelevant
0x30000010 0x30000028 // Pointer to the size of the needed memory
0x30000014 MEM_COMMIT // Commit and not reserve
0x30000018 PAGE_EXECUTE_READWRITE

 

// RWX
0x3000001C POINTER_TO_SOME_RET_INSTRUCTION // Return Address from memcpy, our extremely simple ret gadget.
0x30000020 NULL // Where the allocated memory will be saved and the destination parameter of memcpy. This will store the address of the RWX shellcode.
0x30000024 CODE_CAVE_ADDRESS // The RW code cave containing the shellcode to be copied
0x30000028 SHELLCODE_SIZE // The size of the shellcode to be allocated

 

Table 1: The whole ROP chain.

See main_BuildROPChain in AtomBombing’s GitHub repository.

Invoking the ROP Chain

But wait, APCs allow me to send 3 parameters. Obviously I need to store 11 parameters on the stack. Our best bet is to pivot the stack to some RW memory which will contain our ROP chain (e.g. the RW code cave in kernelbase).

How could we pivot the stack?

NTSYSAPI NTSTATUS NTAPI NtSetContextThread(
_In_       HANDLE  hThread,  
_In_ const CONTEXT *lpContext
);

This syscall will set the context (register values) of hThread to the values contained in lpContext. If we can get the target process to call this syscall with an lpContext that will set ESP to point to our ROP chain and set EIP to point to ZwAllocateVirtualMemory, then our ROP chain will execute. The execution of the ROP chain will eventually lead to the execution of our shellcode.

How do we get the target process to make this call? APC has been good to us so far, but this syscall expects 2 parameters and not 3, so when it returns the stack will be corrupt, and the behavior will be undefined. That said, if we pass a handle to the current thread as hThread, then the function will never return. The reason is that once execution gets passed on to the kernel, the context of the thread will be set to the context specified by lpContext, and there will be no trace that NtSetContextThread was ever called. If everything works out as we hope, we will have successfully hijacked a thread and got it to execute our malicious shellcode.

See main_ApcSetThreadContext in AtomBombing’s GitHub repository.

AtomBombing Stage 3: Restoration

We do have one problem, though. The thread that we hijacked had a purpose before we had hijacked it. If we don’t restore its execution, there is no telling what kind of effect we could have on the target process.

How do we restore execution? I’d like to remind you that we are now in the context of an APC. When the APC function completes, somehow execution is restored safely. Let’s look at the dispatching of APCs from the target process’s point of view.

It looks like the function in charge of dispatching APCs (WaitForSingleObjectEx in this example) is ntdll!KiUserApcDispatcher.

Figure 6: KiUserApcDispatcher

Figure 6: KiUserApcDispatcher

We can see 3 “calls” in this block of code. The first call is to CFG, the next call is to ECX (which is the address of the APC function), and finally a call to the undocumented ZwContinue.

ZwContinue expects to receive a pointer to a CONTEXT structure and resumes the execution. Actually the kernel will check if there are any more APCs in the thread’s APC queue, and dispatch them before finally resuming the thread’s original execution, but we can ignore that.

The CONTEXT structure being passed to ZwContinue is stored in EDI before calling the APC function (stored in ECX). We can save EDI’s value at the beginning of our shellcode, and call ZwContinue with EDI’s original value at the end of the shellcode, thereby restoring execution safely.

See AtomBombingShellcode in AtomBombing’s GitHub repository.

We have to make sure that the value of EDI will not be overridden during the call to NtSetContextThread, since it modifies the values of the registers. This can easily be accomplished by setting ContextFlags (member of the CONTEXT structure passed to NtSetContextThread) to CONTEXT_CONTROL which means that only EBP, EIP, SEGCS, EFLAGS, ESP, and SEGSS will be affected. As long as (CONTEXT.ContextFlags|CONTEXT_INTEGER == 0) we should be ok.

Figure 7: AtomBombing chrome.exe

Figure 7: AtomBombing chrome.exe

And there you have it, we have injected code into chrome.exe. Our injected code spawned the classic calc.exe proving that it works.

Let’s try to inject code into vlc.exe:

Figure 8: AtomBombing vlc.exe

Figure 8: AtomBombing vlc.exe

The complete implementation can be found on GitHub. It has been tested against Windows 10 x64 Build 1511 (WOW) and Windows 10 x86 Build 10240. Compile for “release”.

Let’s do the same with mspaint.exe:

Figure 9: AtomBombing mspaint.exe

Figure 9: AtomBombing mspaint.exe

Oh no, it crashed.

Final Steps

How do we proceed from here? I have worked it out and at this point, I’d rather leave this as an exercise to the reader. As an initial hint, I suggest you take a look at my previous blog post (https://breakingmalware.com/documentation/documenting-undocumented-adding-control-flow-guard-exceptions/). I’m sure you’ll also find creative ideas, that I myself haven’t found, to handle this problem and I’d be happy to start this discussion.

You can use the comments below or catch me @tal_liberman. Through Twitter, I’ll also release some tidbits throughout the week. At any rate, I will publish my solution next week.


 

APPENDIX: Finding Alertable Threads

One thing we have not yet mentioned is that QueueUserApc only works on threads that are in an alertable state. How does a thread enter an alertable state?

According to Microsoft:

“””

A thread can only do this by calling one of the following functions with the appropriate flags:

  • SleepEx
  • WaitForSingleObjectEx
  • WaitForMultipleObjectsEx
  • SignalObjectAndWait
  • MsgWaitForMultipleObjectsEx

When the thread enters an alertable state, the following events occur:

  1. The kernel checks the thread’s APC queue. If the queue contains callback function pointers, the kernel removes the pointer from the queue and sends it to the thread.
  2. The thread executes the callback function.
  3. Steps 1 and 2 are repeated for each pointer remaining in the queue.
  4. When the queue is empty, the thread returns from the function that placed it in an alertable state.

https://msdn.microsoft.com/en-us/library/windows/desktop/aa363772(v=vs.85).aspx

“””

For our technique to be effective the target process must have at least one thread that is in an alertable state, or will enter an alertable state at some point, otherwise our APCs will never actually execute.

I’ve checked various software, and I’ve noticed that most of the programs I’ve checked have at least one alertable thread. Examples: Chrome.exe, Iexplore.exe, Skype.exe, VLC.exe, MsPaint.exe, WmiPrvSE.exe, etc.

So now we have to find an alertable thread in the target process. There are many ways of doing this. I chose to use a method that is trivial, works in most cases, and is easy to implement and explain.

We’ll create an event for each thread in the target process, then ask each thread to set its corresponding event. We’ll wait on the event handles, until one is triggered. The thread whose corresponding event was triggered is an alertable thread.

How can an event be set? By calling SetEvent(HANDLE hEvent).

How will we get the threads in the target process to call SetEvent? APC of course. Since SetEvent receives exactly one parameter we can use QueueUserApc to call it. The actual details of the implementation can be found in main_FindAlertableThread in AtomBombing’s GitHub repository.

 

  • Eli Gadot

    Great article and Very interesting !!!

    • Tal_Liberman

      Thanks Eli, glad you enjoyed it!

  • Nira lavi

    Really enjoyed reading this article interesting and innovative

  • Theho

    Interesting reading! Found a small error in AtomBombingShellcode/main.c, line 56
    if (0 == hKernel32)
    should be
    if (0 == hNtDll)

    • Tal_Liberman

      Thank you, Theho. Fixed.

  • Joao Ferreira

    Amazing work … Respect

  • Would a mitigation be possible using EMET? There is some ROP chain mitigation there already, have you tested against EMET?

    • Jaewoong Roh

      I am also very curious about the EMET or any other similar security product such as PaloAlto Trap could detect the ROP chains of this.

  • It’s all very spooky, but after reading it again, I am shrugging… so what. I have to run something, that injects into something else, it can’t inject into ANYTHING it wants, just some things it appears, and I don’t see it operating with elevated priv’s or escalating privs. What did I miss? This is just another APT vector is all I’m getting, while scary, I’m not seeing new worries.

  • Neal Davis

    Really nice article and something we as software developers need to watch out for and understand to improve our applications. One thing that should be pointed out in the article especially to those less technical press stories about AtomBombing is that someone still has to find a way to get this AtomBombing code onto the end users computer – it’s important to point out to have really secure passwords and do not open attachments sent in email unless you absolutely know what they are and also don’t allow code to run to affect anything other than the browser HTML on your computer from visited websites. Main point is AtomBombing is undetectable currently at least for a few more months / years but someone still has to find a way to get it on your computer initially.

  • Nikolas Bourne

    What is the deal with “..ReleaseAtomBombingShellcode.h” ? It is missing for me……

    • Tal_Liberman

      It is generated during compilation by AtomBombingShellcode/Scripts/Post_Link.py.
      Open the solution in VS, then press Ctrl+Shift+B.

      This will compile the project AtomBombingShellcode, run Post_Link.py which will create AtomBombingShellcode.h, and then compile the project AtomBombing.

      • Nikolas Bourne

        Thanks a lot! 🙂
        (Minor problems with VS 2015)

        • Nikolas Bourne

          Fixed. works fine. Thanks !

      • Mr.JC

        Sorry… I am getting this error when I attempt to run the Post_Link.py, do you know what might be causing this?

        Traceback (most recent call last):
        File “C:…ScriptsPost_Link.py”, line 31, in
        main()
        File “C:…atom-bombing-masterAtomBombingShellcodeScriptsPost_Link.py”, line 8, in main
        exe_path = sys.argv[1]
        IndexError: list index out of range

        • Tal_Liberman

          Hi Mr. JC,

          You are not supposed to run Post_Link.py on your own. It runs as part of the compilation process. It is already defined in the VS project file*. All you have to do is clone the repository to your computer, open the solution file (AtomBombing.sln) with Microsoft Visual Studio 2013 and press Ctrl+Shift+B.

          Pressing Ctrl+Shift+B will compile the project AtomBombingShellcode, run Post_Link.py which will create AtomBombingShellcode.h, and then compile the project AtomBombing which will create AtomBombing.exe.

          Regardless, this PoC will only work on Windows 10.

          *https://github.com/BreakingMalwareResearch/atom-bombing/blob/629ff1d79bd032cf4c3fc173751a979cb4821d7f/AtomBombingShellcode/AtomBombingShellcode.vcxproj#L52

          • Michael

            First of all, great work and a very nice explanation!.

            I’m getting this error when compiling? Any idea what to do?

            The command “c:python27python.exe “C:Usersmichaelatom-bombing\AtomBombingShellcodeScriptsPost_Link.py” “C:Usersmichaelatom-bombingReleaseAtomBombingShellcode.exe” :VCEnd” exited with code 1.

            &

            Cannot open include file: ‘..ReleaseAtomBombingShellcode.h’:

            Thanks,
            Michael

          • Tal_Liberman

            Perhaps you don’t have Python installed in C:Python27?

          • Michael

            Thanks for responding!

            Python is installed in C:Python27, I also tried to do the same thing on my laptop and the same thing happens. I can’t figure out what the heck I’m doing wrong.

            The command “c:python27python.exe “C:UsersMichaelatom-bombing\AtomBombingShellcodeScriptsPost_Link.py” “C:UsersMichaelatom-bombingReleaseAtomBombingShellcode.exe”
            :VCEnd” exited with code 1.

            Resulting in:
            Cannot open include file: ‘..ReleaseAtomBombingShellcode.h’: No such file or directory

            Any idea what it could be? I’ve tried VS 2013 & 2015.

            Thanks,
            Michael

          • Tal_Liberman

            You are welcome to contact me on Twitter: @Tal_Liberman.

          • Maxim Chomyšyn

            Python fails to include ‘pefile’ module. You need to install it with pip -> ‘c:python27Scriptspip.exe install pefile’. Make sure you have Python version 2.7.12, that has pip already included.

  • YH Mark

    Thank you for a very innovative find on atom tables. I wonder won’t the ROP chain be detected by security products like emet that hooked the zwvirtualallocate function ?

  • Null Refrence

    what are differences between a runpe coded in .net and this? both of theme inject pe to a process or an other pe! and i have other question. what version of python should we use to compile Post_link without any error?

  • Orangeator

    Could this by any chance effect the security of KeePass on my PC?

  • Daniel B. S. S.

    Congratulations for this very well written explanation of this great technique.

  • David

    Result: AVs will move their existing hooks from QueueUserApc to NtQueuApcThread and add GlobalGetAtomName to the list of usual suspects like LoadLibrary. Since this was published a week ago your “unfixable” exploit has probably already been fixed by most AVs.

  • Pranjul Ahuja

    hi Tal_Liberman

    Why this code only works for calc.exe ??
    I have tried changing the executables in AtomBombingShellCode but it is not working.
    Any idea ?

    • Tal_Liberman

      This code was only tested with calc.exe as a PoC.

      What process are you trying to run instead of calc.exe?

      • Pranjul Ahuja

        I just tried with mspaint.exe and cmd.exe but nothing really happened. I just changed the exe name in the file where you gave calc.exe.
        I was wondering what else has to be changed in order to correctly build the shellcode binary ?

        • Tal_Liberman

          If you simply replaced;
          char pszCalcExe[] = { ‘c’, ‘a’, ‘l’, ‘c’, ‘.’, ‘e’, ‘x’, ‘e’, ” };
          with:
          char pszCalcExe[] = { ‘c’, ‘m’, ‘d’, ‘.’, ‘e’, ‘x’, ‘e’, ” };

          It should work.

          Note that the shellcode calls WinExec* with the second parameter set to 0 which is SW_HIDE**, and therefore cmd.exe opens up hidden. It works with calc.exe because calc will always present itself regardless of the creation flags specified. If you check the list of running processes you will see that cmd.exe was created, you just simply can’t see its window.

          If you want to see the window, replace:
          pfnWinExec(pszCalcExe, 0);
          with
          pfnWinExec(pszCalcExe, 3);

          Because 3 is SW_MAXIMIZE**.

          *https://msdn.microsoft.com/en-us/library/windows/desktop/ms687393(v=vs.85).aspx
          **https://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx

  • DankVader

    So whenever I try and run it against any program it always fails at NtQueueApcthread.
    It returns “ret: 0xC0000008 (-1073741816)”
    Then “suspendthread failed GLE: 6”
    Anyone have thoughts as to why this happens?

    • Tal_Liberman

      0xC0000008 is STATUS_INVALID_HANDLE. My guess is that there was some kind of problem getting a handle to an alertable thread. What is your target process?

      • Maxim Chomyšyn

        Getting the same problem. Targeting chrome.exe. After executing chrome just freezes and I need to terminate it manually.

        Tried it on sublime_text.exe with the same result.

      • DankVader

        I’ve been trying chrome, but I’ve also tried just about every process running. And all return the same error. Side note, I compile it on a Windows 10 machine and run it on a Windows 7 VM.

    • Mark Davis

      I have the same problem, did you find out how to fix this?

  • Mark Davis

    Every time im trying to run it, It returns “ret: 0xC0000008 (-1073741816)”
    Then “suspendthread failed GLE: 6”
    I’ve already tried on windows 10, and 7 on my virtual machine.
    I also tried to compile it with both visual studio 2015 and 2013, and everytime I get the same error at NtQueueApcThread.

    • Tal_Liberman

      You are welcome to contact me on Twitter: @Tal_Liberman:disqus .

  • Tal_Liberman

    No one claimed this was a privilege escalation vulnerability. This is a code injection technique. The claim that one can already inject code into any process is true if there is no security software on that computer. Using the classic VirtualAllocEx + WriteProcessMemory + CreateRemoteThread method will be flagged immediately by even the most basic AV.

    As for the second claim, sysmon shows opening a handle to chrome.exe, which if any security product flagged as malicious would cause a tremendous amount of false positives. Since there is no WriteProcessMemory or VirtualAllocEx, no security software will flag “asking the OS for a handle to a user-mode process” as malicious activity. Please note that his examples do not show any writing to the target process’s memory, nor do they show the thread hijacking being performed.

    As for the second sysmon event, well duh, the PoC gets chrome.exe to run calc.exe as it was designed to do. Of course monitoring software will be able to see the creation of calc.exe, that is the whole point. For a fully weaponized injection, one would not create calc.exe. Instead the shellcode would probably be designed to stealthily connect to the internet and exfiltrate data. That connection will also be seen by sysmon, but you cannot flag “chrome.exe connecting to the internet” as malicious activity. At the time of publishing AtomBombing could inject code into any qualified process without being detected by most security products.

    To the best of my understanding the fact that the author even thought this could be a priv-esc vulnerability tells us that he did not understand the technical blog of how this technique works and is not very familiar with Windows and its security model. His examples, that are supposed to prove that this technique is detectable by anti-malware programs, simply show that he doesn’t know how security software works, and that he does not understand what AtomBombing could be used for, had it stayed a “secret”.

  • Daniel

    i build the solution, but don’t get any executable from AtomBombing (no AtomBombingShellcode) project in output.
    what’s problem?

    • Tal_Liberman

      What do you mean you don’t get any executable? Do you have compilation errors?

      • Daniel

        no
        when i rebuild the solution, i see error like “error: AtomBombingShellcode.h not found/could not open…” in output. so i have to first build AtomBombingShellcode subproject, then AtomBombingShellcode.h and AtomBombingShellcode.exe create in release folder. second restart the solution (by close and open). third build AtomBombing subproject, but don’t create any exe related to it in release folder.

  • edgecrush3r

    For those who cant build the AtomBombingShellcode.h file..
    you will need to install the pefile support for python 27..
    install python en then
    >> c:python27Scriptspip.exe install pefile

    • Maxim Chomyšyn

      That’s right. Some will need to install Python 2.7.12 first. Just like me 😀

  • Create a file with your code to execute called chrome_child.dll in C:Program Files (x86)GoogleChromeApplication and put the code you want to inject in every chrome tab there. You only need write access to that folder, but undetected by any AV!!!

  • Daniel

    how can i convert AtomBombing.exe code injection to shellcode?

  • pwn Mactep

    Hi

    i like to test different Exe files with the same “atombomb.exe”

    How can i add a startup argument like in the pictures .
    Example : atombomb.exe TARGET.exe