假设我在内存中有一个可执行文件(或bat脚本,无关紧要(的内容,并希望将其作为一个新进程运行。这很容易。
File.WriteAllBytes(filePath, contents);
// gap
Process.Start(filePath)
但我想确保执行的文件不会被任何其他进程篡改。文件的创建和执行之间存在差距。它提供了一个用正确的工具篡改文件的机会。
因此,我不再使用File.WriteAllBytes
,而是打开FileStreamFileShare.Read
,并将其保持打开状态,直到执行完成。
using(var fileStream = new FileStream(filePath, FileMode.CreateNew, FileAccess.Write, FileShare.Read))
{
Process.Start(filePath)
}
但这行不通。Process.Start
失败:
System.ComponentModel.Win32Exception(32(:进程无法访问该文件,因为另一个进程正在使用该文件。
这个问题及其答案解释了我为什么这么想。简而言之,Process.Start
将尝试用FileShare.Read
打开文件,但由于打开的FileStream已经具有写访问权限,因此失败了进程的FileShare.Read
尝试。
有没有干净的方法?
我能想到的一个解决办法是保存文件,关闭它,用FileShare.Read
和FileAccess.Read
打开一个新的FileStream,确保内容在执行之前保持不变。但这并不好看。
您所描述的是检查时间到使用时间漏洞的典型案例。
任何涉及检查某个内容然后执行它的解决方案,如果这两个操作不是原子操作,仍然会使您处于易受攻击的状态。例如:
在执行之前确保内容仍然相同。但这不是很好的
;确保内容仍然相同";以及";执行它";。
2004年,公布了一个不可能的结果,表明没有可移植的、确定性的技术来避免TOCT-TOU竞赛条件
-https://web.cecs.pdx.edu/~markm/CS333/讲义/tocttou.pdf
你可以做几件事来缓解它:
-
不要使用文件!你说你的内存中有一些代码需要执行:你能在同一个过程中自己执行吗?
-
缩短时间窗口。
-
使文件名随机且难以预测其他进程。
-
在不太可能有攻击者(或恶意程序(运行的地方,以独立用户身份运行程序,并将文件读/写限制为仅限新用户。