0

假设我在内存中有可执行文件(或 bat 脚本,没关系)的内容,并希望将其作为新进程运行。这很容易。

File.WriteAllBytes(filePath, contents);
// gap
Process.Start(filePath)

但我想确保执行的文件没有被任何其他进程篡改。文件创建和执行之间存在差距。它提供了使用正确工具篡改文件的机会。

因此,File.WriteAllBytes我没有打开FileStream FileShare.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是保存文件,关闭它,用and打开一个新的 FileStream FileAccess.Read,确保在执行之前内容仍然相同。但这并不漂亮。

4

1 回答 1

1

您所描述的是检查时间到使用时间漏洞的经典案例。

任何涉及检查然后执行它的解决方案,并且这两个操作不是原子的,仍然会让你容易受到攻击。例如:

在执行之前确保内容仍然相同。但这并不漂亮

“确保内容仍然相同”和“执行它”之间仍然存在(较小的)差距(时间窗口)。

2004 年,发布了一个不可能的结果,表明没有可移植的、确定性的技术来避免 TOCT-TOU 竞争条件

- https://web.cecs.pdx.edu/~markem/CS333/handouts/tocttou.pdf

你可以做几件事来减轻它:

  • 不要使用文件!你说你在内存中有一些代码需要执行:你能在同一个进程中自己执行吗?

  • 缩短时间窗口。

  • 使文件名随机且难以预测其他进程。

  • 在攻击者(或恶意程序)运行的可能性较小的情况下,以单独的用户身份运行您的程序,并将文件读/写限制为仅限新用户。

于 2021-01-12T21:08:57.097 回答