January 2nd, 2024

It rather involved being on the other side of this airtight hatchway: Attacking another program by modifying its memory

A security vulnerability report arrived that took the following form:

There is a security vulnerability in XYZ.DLL. This DLL contains a function pointer stored in memory. An attacker can modify this function pointer and gain arbitrary code execution.

The proof of concept went like this:

auto processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, victimProcessId);
void* value = new_value_for_function_pointer;
void* victimAddress = address_of_variable_in_victim_address_space;
WriteProcessMemory(processHandle, victimAddress, &value, sizeof(value), &actual);

It is evident from this proof of concept that we are already on the other side of this airtight hatchway: PROCESS_ALL_ACCESS gives you total control over the victim process. If you wanted to gain control over it, just inject a thread and go to town! No need to hunt around for a function pointer you can overwrite to point to some other function, and the presumably arrange for that other function to do something unexpected when it is called.

The finder explained that the Write­Process­Memory was just a way to simulate a write-what-where vulnerability. The real attack would be to find a write-what-where vulnerability somewhere in the victim process, and then leverage that to overwrite the function pointer in XYZ.DLL.

That still assumes that you’re on the other side of the airtight hatchway. If you have gained write-what-where control over the process, then you can overwrite a return address onto the stack or overwrite an object’s vtable pointer to point to a constructed fake vtable. There’s nothing specific about XYZ.DLL. Any component that uses function pointers will do.¹

The real vulnerability is the component that has a write-what-where vulnerability. That’s the guy that let you into the airtight hatchway. But once you get there, you’ve already won.

Bonus chatter: Address Space Layout Randomization (ASLR) and Control Flow Guard (CFG) make these types of attacks harder to carry out remotely. In particular, this finder quietly disabled Call Flow Guard protection as part of their proof of concept so that their overwritten function pointer would be used without validation.

¹ Unless your point is that all function pointers are a security vulnerability?

Topics
Other

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

7 comments

Discussion is closed. Login to edit/delete existing comments.

  • Neil Rashbrook

    I searched for Call Flow Guard and got articles on Control Flow Guard. Did it get renamed?

    • Raymond ChenMicrosoft employee Author

      No, I just misremembered what CFG stood for.

  • Josiah Bills

    It doesn’t seem relevant in this case, but a term I have heard from security people a lot is defense-in-depth. The idea, as I understand it, is to put defenses in on the other side of the airtight hatchway to make it harder for attackers who have gotten their to do their thing. Have you ever run into an “other-side-of-the-airtight-hatchway” vulnerability that was patched on the basis of this principle?

    • Simon Farnsworth

      In this context, it's worth fully understanding what makes an "other-side-of-the-airtight-hatchway” vulnerability an "other-side-of-the-airtight-hatchway” vulnerability, and not a different sort of vulnerability.

      "Other-side-of-the-airtight-hatchway” vulnerabilities all take the following form:

      1. Attacker has permission to do foo.
      2. There exists a component bar which cannot do foo unless modified by someone with permission to do foo.
      3. The attacker modifies bar to do foo.
      4. Claim a vulnerability in bar, since it's not supposed to be able to...

      Read more
      • Falcon

        Sometimes it’s not even really obfuscated – I remember one about a scripting object that could supposedly be tricked into overwriting some files on a web server.

        The first step of the “attack” was to find a web server with a world-writable directory that executes scripts as SYSTEM!

    • Jamie Anderson

      Defense in depth basically means having multiple layers of protection, so that if someone gets through one layer there's another to hinder them. Think of it as adding more walls and locked doors around a secure room.

      In this case, `PROCESS_ALL_ACCESS` basically means that you don't have to break through those doors; you have a skeleton key and can just walk right through any door that's thrown at you.

      As the Bonus Chatter notes, CFG (making sure...

      Read more
    • Raymond ChenMicrosoft employee Author

      There is a lot of defense in depth: Stack canaries, ASLR, CFG, pointer authentication… They are secondary defenses that mitigate the impact of a vulnerability, but the underlying vulnerability still is addressed (assuming it is a valid vulnerability).