BugTraq Defense in depth -- the Microsoft way (part 29): contradicting, ambiguous, incomplete documentation Feb 21 2015 02:43PM Stefan Kanthak (stefan kanthak nexgo de) Hi @ll, the MSDN documents the BRAINDEAD behaviour of the functions CreateProcess() , CreateProcessAsUser() CreateProcessWithLogonW() CreateProcessWithTokenW() for an unquoted "long" pathname of the executable in command lines: | [...] the module name must be the first white space-delimited token in | the lpCommandLine string. If you are using a long file name that contains | a space, use quoted strings to indicate where the file name ends and the | arguments begin; otherwise, the file name is ambiguous. | For example, consider the string "c:\program files\sub dir\program name". | This string can be interpreted in a number of ways. The system tries | to interpret the possibilities in the following order: ~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | c:\program.exe files\sub dir\program name | c:\program files\sub.exe dir\program name | c:\program files\sub dir\program.exe name | c:\program files\sub dir\program name.exe ... | [...] the first white space-delimited token of the command line | specifies the module name. If you are using a long file name that | contains a space, use quoted strings to indicate where the file name | ends and the arguments begin [...] If the file name does not contain | an extension, .exe is appended. [...] if the file name contains a path, | .exe is not appended. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ 1. self-contradictory/ambiguous: If the second underlined clause of the documentation were correct, and the usual definition of path(name) ['] is assumed (so "c:\", "c:\program files\sub" and "c:\program files\sub dir\program" qualify as pathnames), the interpretation of the string "c:\program files\sub dir\program name" given above would be wrong. The interpretation given above but matches the observed behaviour of the CreateProcess*() functions, therefore the underlined clause of the documentation is WRONG and should be removed! 2. incomplete/ambiguous: the documentation does not specify what "tries to interpret the possibilities" exacly means: using the example given above, is CreateProcess*() expected to skip "c:\program.exe", "c:\program files\sub.exe" and/or "c:\program files\sub dir\program.exe" if they exist but are not executable a) due to invalid file contents? Observed behaviour: CreateProcess*() tries to execute c:\program.exe etc. and returns ERROR_BAD_EXE_FORMAT, ERROR_EXE_MARKED_INVALID, ERROR_INVALID_EXE_SIGNATURE, etc. b) due to insufficient permissions? Observed behaviour: CreateProcess*() tries to execute c:\program.exe etc. and returns ERROR_ACCESS_DENIED! c) because they are an unsupported or unknown [²] reparse point? Observed behaviour: CreateProcess*() tries to execute c:\program.exe etc. and returns ERROR_CANT_ACCESS_FILE, ERROR_ACCESS_DENIED, ERROR_FILE_NOT_FOUND, etc. d) because they are a directory (including directories overlaid with a reparse point), a mount point, a junction to a directory or a symlink to a directory? Observed behaviour: in contradiction to MSKB 812486 [³] CreateProcess*() does not try to execute a directory c:\program.exe etc. and skips it. Skipping over directories or reparse points targetting directories is but surprising behaviour, since CreateProcess*("", NULL, ...) and CreateProcess*(NULL, "", ...) return (as expected) ERROR_ACCESS_DENIED! 3. incomplete/surprising: The observed behaviour for CreateProcess(NULL, "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe", ...) is: CreateProcess*() tries to execute "C:\Program.exe" and "C:\Program Files (x86)\Internet.exe", but NOT "C:\Program Files.exe" WTF? Why is "C:\Program Files.exe" NOT a "possibility to try"? 4. incomplete: when CreateProcess*() is called (for example) with the command line "c:\program files\sub dir\program name" and plays try&error, the executed application does NOT receive the original command line, but a MODIFIED command line: - "c:\program files\sub.exe" dir\program name - "c:\program files\sub dir\program.exe" name - "c:\program files\sub dir\program.exe name.exe" i.e. the pathname of the found executable gets quoted if it contains a space. The documentation of the function GetCommandLine() but misses this completely! Stay tuned! regards Stefan Kanthak ['] as soon as a name contains a single '\' or ':' it is a pathname! Cf. [²] : | When the file system opens a file or directory (obvious omission added) | with a reparse point, it attempts to find the file system filter | associated with the data format identified by the reparse tag. | If a file system filter is found, the filter processes the file or directory (obvious omission added) | as directed by the reparse data. If a file system filter is not | found, the file open operation fails. [³] : | * There is a file or folder on your computer's hard disk that | has the same name as a file or folder in the path to the | service's executable file. | | For example, if the path of the executable file for a service | is C:\Program Files\MyProgram\MyService.exe, and if a folder | that is named C:\Program also exists on your hard disk, Windows | locates the C:\Program folder on your hard disk before the | C:\Program Files\MyProgram\My Service.exe file, and then tries | to run it.[ reply ]