In MSDN we trust? - CreateRemoteThread Shenanigans

Thanks for @Intel80x86 and @whtaguy for reviewing!

 Disclaimer

The following by no means presents any security issue or highly complex stuff. It’s merely a story of a short journey stretching from a driver debugging session to discovering just how wrong MSDN’s documentation can be.


Motivation

 

As part of exercising writing different drivers, I wanted to see how removing the PROCESS_CREATE_THREAD access right from handles would affect the system, along with seeing just how effective this “aggressive” approach is when trying to block thread injections.

No Access Rights Required

 

Why would it affect thread injection? 

Well, apart from the self describing name of the access right, MSDN claims you need to pass a handle that has this access right when using CreateRemoteThread.

 

 

Figure 1: MSDN CreateRemoteThread handle parameter

 


Yet, my stupid simple thread injection PoC still worked after my driver removed that access right. Weird. 

Maybe my driver has a bug? 

Registering a post creation callback confirmed that PROCESS_CREATE_THREAD was indeed removed by my driver from the handle passed to CreateRemoteThread. So, still weird.

Next, I checked if CreateRemoteThread still works without PROCESS_CREATE_THREAD and with some other access right, such as PROCESS_QUERY_INFORMATION (error handling omitted for readability):

 

Figure 2: Thread Injection Using Only PROCESS_QUERY_INFORMATION  

 

I was surprised to see it worked just fine!

 

Clearly, something is funky with the documentation. Also, checking the injection PoC on a couple of Win10 versions, I saw it worked on 1903, but didn’t work on 1607 (we’ll discover the exact reason later on).

Let's take a look inside CreateRemoteThread!

CreateRemoteThread  

Looking inside CreateRemoteThreadEx (the function doing the heavy-lifting behind CreateRemoteThread), we can see that it calls NtDuplicateObject, requesting the PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD access rights.

 

Figure 3: CreateRemoteThreadEx on 1903

 

Tracing the handle, we can also see it’s the one later passed to the NtCreateThreadEx call. 


That seems like a valid explanation to why the thread injection experiment worked, but it brings up the following two questions:

  1. Why didn’t it work on earlier builds?

  2. What access rights can we get for a handle through NtDuplicateObject


To answer the first question, lets pop up the implementation of 1607:

 

Figure 4: CreateRemoteThreadEx on 1607

 

NtQueryInformationProcess requires the PROCESS_QUERY_INFORMATION access right. 

The first code block shows us that if we don't get STATUS_ACCESS_DENIED, we won’t reach the duplication call. 

Since our thread injection experiment used PROCESS_QUERY_INFORMATION, it didn’t get STATUS_ACCESS_DENIED and didn’t duplicate the handle. 

 

If we quickly change the injection experiment to open the process with SYNCHRONIZE - it’ll work similarly on all versions. 

 

Absurdly, that change just made the CreateRemoteThread documentation more wrong, since now we don’t even need PROCESS_QUERY_INFORMATION.

 

To answer the second question, we’ll perform a very short experiment with NtDuplicateObject.

 NtDuplicateObject

The documentation contains the following shady clue about the behavior we witnessed:

 

Figure 3: NtDuplicateObject’s shady documentation

 

To test its limits, we can request PROCESS_ALL_ACCESS access rights, providing our SYNCHRONIZE only handle. This works just fine.

 

Moreover, it doesn’t even seem like there’s any limitation when requesting different access rights once you have an opened handle.

 

As we can see in the final test below, we can go from some, to none, to all access rights in our handles! 

 

 

Figure 5: Testing NtDuplicateObject’s limits

 

Conclusions

  

Our adventure testing, debugging, and reversing brings up a couple of conclusions:

  • As long as you can open a handle to a process (thus this whole thing is not really a security issue) with any access right, you can duplicate the handle to have any other access right you want.

    • As @diversenok_zero stated, NtDuplicateObject still has to go through an access check which relies on the security descriptor.

  • Detection mechanisms integrated in endpoint protection software shouldn’t solely rely on kernel callbacks for handle creation events, and instead also register for handle duplication events. 

  • MSDN’s documentation can be very far from the truth. Staying suspicious and curious is a must (:  

    • You can find another very similar use case here


Follow me @B_H101 for my latest research

 

Comments

  1. Thanks for sharing your blog with us I am very inspired by your article kindly share some knowledge about security services calgary want to know about it

    ReplyDelete

  2. Security guards play a vital role in keeping businesses in Calgary safe and secure. Their presence brings a sense of reassurance to employees, customers, and valuable assets, creating a welcoming and protected environment. These dedicated professionals act as a deterrent to potential criminals, preventing theft, vandalism, and other security threats. Security Guard Calgary understand the unique needs of businesses and provide well-trained and licensed security guards who bring a human touch to their work. With their friendly and approachable demeanor, they not only provide a physical presence but also establish positive connections with employees and customers. By partnering with these security companies, businesses in Calgary can rely on the expertise and professionalism of these compassionate security guards, ensuring a safe and protected space for everyone and maintaining the reputation and well-being of their business.

    ReplyDelete
  3. Looking for the best security services in Edmonton? Our trusted security guard company offers top-notch protection services. Get a quote today!

    ReplyDelete
  4. World Guardian truly stands out as a top-notchCalgary security company
    ! Their highly trained personnel and comprehensive security solutions have given me peace of mind. Whether you need residential, commercial, or construction site security, they've got you covered. Highly recommend their services for anyone in need of reliable security in Calgary and beyond!

    ReplyDelete
  5. I recently hired World Guardian Security Services for my business in Yellowhead County, and their professionalism and dedication are outstanding. The security guards are well-trained and vigilant, providing excellent protection. I highly recommend their services to anyone needing reliable security solutions. They're truly the best!

    yellowhead county security company

    ReplyDelete
  6. Ponoka Healthcare Security Services provides top-notch security solutions for healthcare facilities in Ponoka. They offer 24/7 on-site security, advanced surveillance systems, and customized security plans. Their highly trained officers ensure patient and staff safety, protect sensitive data, and respond swiftly to emergencies. Numerous client testimonials highlight their effectiveness and dedication. Highly recommended for any healthcare provider in Ponoka!

    Learn more: Ponoka Healthcare Security Services

    ReplyDelete
  7. World Guardian Security is the best choice for earning your Security license in Alberta. Their training is trusted, and they offer live support 7 days a week. Highly recommend!

    ReplyDelete

Post a Comment

Popular posts from this blog

Revising Vulnerabilities - FTPShell 6.7 Client (Buffer Overflow)

Resources list for malware hunters