zwass
etw_process_events
table!) and we could use some code review from folks with Windows experience. Any chance you have some time to do a bit of review as he pushes PRs starting in the next couple of weeks?Mike Myers
10/06/2022, 11:32 PMthor
defensivedepth
10/07/2022, 3:00 PMsecedit
table work!!seph
defensivedepth
10/10/2022, 1:13 PMseph
zwass
SYSTEM
user that can lead to exploitable vulnerabilities, but we were not able to identify a way that this could be exploited.Marcos Oviedo
10/10/2022, 5:02 PM%windir%\temp
. There is a good doc that describes this exploitation technique here. I've also included examples of public exploits that abused these techniques when a privileged process wrote into temp directory here. Having said that, I have not created a PoC to exploit this specific scenario, so the general recommendation was around avoiding user-controlled directories from privileged processes as much as possible (here)seph
os.TempDir()
, which as you identify would create a known path and a potential racey exploit.
Instead, it uses ioutil.TempDir
, which is os.MkdirTemp
. This is notably different, in that it’s creating a random directory in whatever the system considers the temp directory. Mostly I trust the go authors to have gotten this use case correct, But…
1. It’s creating a random path. Yes, I suppose, one could create 2^32 directories. I’m not sure if the underlying library is checking
2. Testing, it is created with reasonable permissions
3. It seems to use a per-user directory. As myself, this creates stuff in ~/AppData\Local\Temp
, no idea what it does for services running as admin.
4. Ultimately this is read by <http://github.com/go-ini/ini|github.com/go-ini/ini>
. I don’t think there should be execution there.
Maybe there’s a route to getting secedit to overwrite some file. Or just feeding launcher bad data. But (1) and (2) are generally considered sufficient for those cases.Marcos Oviedo
10/11/2022, 4:58 PMioutil.TempDir()
🙌🙌🙌
I remember quickly trying ioutil.TempDir
back then to found that it also uses %windir%\temp
when called from a process running as SYSTEM. Down below are the details on why this happens. This affects #3 as a temporary base directory that can be user-controlled might introduce risks. I ended up suggesting to use os.UserCacheDir
across Orbit codebase as this helper always returns the path to the %localappdata%
directory, which is a directory associated with the running user (location with ownership and permissions safe to use, as you mentioned in #2)
Your point on #1 is very valid and mitigates exploitation attempts as it would make exploitation harder. I updated the original issue to reflect this and do some justice to the original comment, see here. Avoiding user-controlled tmp directory should be done if possible. Exploiting a bug like this will be complex, and AFAIK the only options an attacker will have are: A) hijack the privileged directory creation to create a directory on a privileged location (abuse examples around controlled privileged directory creation here). B) hijack the privileged .ini file creation/write to redirect the operations to an arbitrary file on a privileged location (abuse examples here). Doing #A is difficult as the attack will have to predict the directory name in advance, brute-forcing the directory name address space to place directory symlinks. This is not very practical and will produce an unreliable exploit (here is an example of people doing something similar for files). On the other hand, doing #B will require the exploit to continuously monitor the %windir%\temp
folder to look for newly created directories with the expected pattern which I think should be %windir%\temp\prefix{random}
, and then use this location to place file symlink with the expected ini filename. Winning this race condition will redirect that file operation somewhere else. Again, this is not very practical and will produce an unreliable exploit.
Now regarding ioutil.TempDir returning %windir%\temp
, I found that after os.MkdirTemp
is called, a call to TempDir() will be made because of the first parameter being empty. The implementation of this function in windows ends up calling syscall.GetTempPath, which in turn ends up calling kernel32!GetTempPathW to obtain the temporary directory. According to MSDN, the GetTempPathW export returns the content of the %TMP%
environment variable for the running user, which in the case of SYSTEM is %windir%\temp
. The default value for this environment variable on windows for the SYSTEM user is at the following registry location HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
. In the case of standard users, the content of the TMP environment variable corresponds to the value you observed, and it is stored at HKEY_CURRENT_USER\Environment
registry location.seph
os.UserCacheDir
sounds really valuable. I’ll have to dig in when I’m not jumping into office hours 😉Marcos Oviedo
10/11/2022, 5:00 PMjumping into office hourdoing the same 😄
defensivedepth
10/11/2022, 6:38 PMMarcos Oviedo
10/11/2022, 6:50 PMseph
Marcos Oviedo
10/11/2022, 6:52 PMthor
Marcos Oviedo
10/13/2022, 9:47 PMthor
Marcos Oviedo
10/17/2022, 6:40 PMzwass
thor
zwass
thor
Marcos Oviedo
10/29/2022, 9:05 PMthor
Marcos Oviedo
12/02/2022, 9:35 PM