python / cpython

The Python programming language
https://www.python.org
Other
61.86k stars 29.75k forks source link

winapi audit events returning garbage #119690

Open zooba opened 2 months ago

zooba commented 2 months ago

The CreateFile and CreateNamedPipe audit events from the winapi module appear to be returning garbage instead of the names. There's potential for buffer overreads and/or information leakage.

Linked PRs

zooba commented 2 months ago

At a glance, it looks like _winapi is still using MBCS paths by default. We should switch it all to Unicode. (There may already be an issue for this.)

eryksun commented 2 months ago

In 3.11+, the audit call looks correct in _winapi_CreateFile_impl(). The wrapper was updated to link with CreateFileW() and make file_name a wide-character string (LPCWSTR). The other audited values are of the DWORD type (i.e. unsigned long). Strictly they should be "k" values, not "I" values (i.e. unsigned int), but in practice "k" and "I" are equivalent on Windows. However, prior to 3.11 the audit call is incorrect.

At a glance, it looks like _winapi is still using MBCS paths by default. We should switch it all to Unicode. (There may already be an issue for this.)

I think it's just the CreateNamedPipe() and WaitNamedPipe() calls that need to be fixed.

Here's a couple more that aren't pressing issues:

zooba commented 2 months ago

In 3.11+, the audit call looks correct in _winapi_CreateFile_impl().

Hmm, I've definitely got garbage in logs from 3.11, but it might be an earlier version. Worth going back and fixing, or else I'll be going back and fixing in my own builds.

I think it's just the CreateNamedPipe() and WaitNamedPipe() calls that need to be fixed.

Thanks for confirming. I would've gone crazy trying to figure out the problem with CreateFile otherwise!

  • More generally, there is no sufficient reason for this code to try to enable the restore privilege. It is not required to set a junction reparse point.

Is it not? That privilege was the cause of one of the weirdest bugs I've ever had to diagnose (it was causing an unrelated stat test to succeed when run as admin after the privilege was set but not cleared, because it allowed the backup privilege to be used on a file ACLd for no access 🤦‍♂️)

  • I rewrote _winapi_CreateJunction_impl() more correctly ...

I was excited, but I think you rewrote it more correctly for Windows, not for us! As long as there's a specific API for us to use, I'd rather use it, even if technically all the structs used are supported. If a user is not supposed to be creating junctions, they'll get a relevant security error (and if an admin is auditing junction creation, they'll get those audit events).

Either way, no plans to touch anything outside of winapi in this issue.

eryksun commented 2 months ago

I was excited, but I think you rewrote it more correctly for Windows, not for us! As long as there's a specific API for us to use, I'd rather use it, even if technically all the structs used are supported. If a user is not supposed to be creating junctions, they'll get a relevant security error (and if an admin is auditing junction creation, they'll get those audit events).

I don't know what you mean about a user not being allowed to be create junctions. There is no special privilege required to create a junction. You just need synchronize, read-attributes, and write-data access to set the reparse point. There is no API to create a junction per se. There's SetVolumeMountPointW(), but that sets a "\??\Volume{GUID}\" volume mountpoint and registers it with the system mountpoint manager. The latter requires Administrator access.

I rewrote the code for _winapi_CreateJunction_impl() to address multiple serious flaws in the existing code (only intended as is for internal testing) in order to bring it up to a level good enough that we could support adding a function in the os module to support creating junctions. Python's inability to create junctions is a notable gap compared to other scripting languages and shells.

zooba commented 2 months ago

Oh my bad, there isn't an API for creating a junction. I was probably thinking of the mount point API, yeah.

Python's inability to create junctions is a notable gap compared to other scripting languages and shells.

Perhaps, but I haven't heard any requests for it. The closest I've seen is people requesting posixpath.isjunction so they don't have to test for the function.