我们专注于一种这样的技术——像素化——并将向您展示为什么它是一种让您的敏感数据泄露的不好、坏、不安全、万无一失的方法。为了向您展示原因,我编写了一个名为Unredacter的工具,它采用经过编辑的像素化文本并将其反转回未编辑的形式。在野外有很多这样的真实例子来编辑敏感信息,但我不会在这里命名。
接受挑战
因此,有一个名为 Depix 的现有工具试图通过一个非常聪明的过程来做到这一点,即在给定 正确字体的De Bruijn 序列的情况下,查找哪些像素排列可能导致某些像素化块。我非常喜欢这个工具的理论,但Jumpsec 的一位研究人员指出,它在实践中可能并不如你所愿。在现实世界的示例中,您可能会得到微小的变化和噪音,这会将扳手扔进齿轮中。然后他们向任何人发出挑战,如果您可以取消编辑以下图像,则提供奖品:

像素化的工作原理
像素化看起来像这样:



值得注意的是,这个算法被广泛标准化,因为它非常简单。因此,无论您是在 GiMP、Photoshop 还是基本上任何其他工具中进行此编辑,编辑结果都是一样的。
对于我们的概念验证,让我们假设攻击者知道:
- 编辑文本的字体类型
- 编辑文本的字体大小
- 编辑首先是文本
我会断言,这些都是相当合理的假设,因为在现实场景中的攻击者可能会收到一份完整的报告,其中只有一个被删节。在我们的挑战文本中,您可以在像素化文本上方看到几个单词,这些单词为我们提供了这些信息。
击败编辑的许多问题
我们关注的关键是编辑过程本质上是本地的。在密码学术语中,我们会说它没有扩散。原始图像中某个像素的变化只会影响它所属的编辑块,这意味着我们可以(大部分)逐个字符地猜测图像。我们将对每个字符进行递归深度优先搜索,根据与编辑文本的边缘匹配程度对每个猜测进行评分。
基本上,我们猜测字母“a”,将该字母像素化,然后查看它与我们的编辑图像的匹配程度。然后我们猜测字母“b”,依此类推。听起来没那么难,对吧?好吧,还有一堆后勤问题需要克服,一开始可能并不那么明显!让我们进一步深入研究。
角色溢出问题
我们立即遇到的第一个问题是我们文本的字符没有与编辑块 1:1 对齐。这意味着给定的正确猜测实际上可能在最右边有一些错误的块。要了解我的意思,请查看以下示例:

正确的像素与猜测“t”与差异

我们尝试的第一件事是避免计算任何猜测的最右边的块。它是流血最多的列,并且可能有相当多的错误。这样做的问题是,在实践中,它大大减少了我们猜测的总规模,以至于你开始收到误报。你的信总是有可能会意外地排成一行,并且纯粹是偶然地产生匹配,而当需要考虑的块更少时,这个机会就会大大增加。
因此,我们所做的是在字母本身的边界处切断比较块。因此,我们的差异看起来像这样:


空白问题
字符溢出问题的一个特定子集是空格往往会破坏我们关于字符猜测如何工作的一些假设。整个问题的内在假设是,当我们猜测一个正确的字符时,我们期望得到的像素化版本与挑战图像最相似。
然而,当我们猜测的字符是空格时,这并不总是正确的。发生这种情况时,像素化块将被下一个字符完全取代。以这个例子为例,猜测“这是”(尾随空格):



相反,我们可以做的是对空白猜测做一个特殊的分割,让他们在被认为是“好的”猜测时更加宽容。在测试中,似乎溢出从未如此糟糕以至于超过了较低的阈值。这有点笨拙,我会同意你的,但它似乎有效。
可变宽度字体问题
人们书写的大多数字体都是可变宽度的。这意味着每个字母占用的水平空间量取决于字母本身。例如,“w”比“i”占用更多空间。这与等宽字体形成鲜明对比,等宽字体故意分隔字母,使每个字母占据相同数量的水平空间。
可变宽度:
iiiiii
万维网
等宽:
iiiiii
万维网
这对我们的攻击(假设是可变宽度字体)意味着每个猜测的字母在其右侧都有级联效应。如果你猜:
这是supww
那么所有未来的字母都将被关闭,即使这些字母在其他方面是“正确的”。
这听起来很重要,但实际上并没有那么糟糕。这只是意味着我们必须坚持递归深度优先搜索,而不是将字母视为单独和独立的工件。递归深度优先搜索在这里效果很好,因为它自然会考虑到这种排序。它的工作方式如下:
假设我们目前的猜测是:
这是苏
我们所做的是尝试下一个字母的每个字符,看看哪些字符与编辑后的图像匹配得相当好。我们将得到一些“好”猜测的子集,可能是“p”和“q”,因为 p 是正确的,而 q 与它非常相似。然后,我们将重新开始整个过程,在链上重新猜测“this is sup”的新字符串,直到我们遇到没有好的猜测的死胡同。此时,函数调用堆栈自然会备份到尝试我们的其他猜测 q。
以此类推,直到我们用尽所有“好的”猜测。
字体不一致问题
碰巧的是,即使对于应该是完全相同的字体,不同的渲染引擎也会产生略有不同的图像。看看这两个相同文本的捕获。顶部是 GiMP 在 Sans Serif 中的渲染,底部是 FireFox:

对于 Unredacter,我们使用 Electron 截取本地无头 HTML 窗口的屏幕截图。因此,渲染器本质上是 Chrome。大多数时候,这不是问题。但是,如果您的编辑文本是使用一些不符合标准的非常不稳定的程序呈现的,那么它可能最终会偏离轨道。记住这一点。
如果有人想为 Unredacter 编写一个包装器,该包装器使用 MS Word 通过一些包装器和宏的 Rube Goldberg 机器生成猜测,欢迎您试一试。
像素化偏移问题
在对图像进行像素化时,必须考虑两个自由度:x 和 y 偏移坐标。但这些到底是什么?
考虑我们猜测文本的图像被分成 8×8 块:

相同文本的不同偏移值

这里的好消息是抵消的可能性并不多。有块大小2排列。对于 8 的块大小,需要尝试 64 个偏移量。在我们的挑战文本中,块大小为 5,这意味着只有 25 个偏移量需要测试。

解决 Jumpsec 挑战文本
好的!有了这些知识和利用它的工具,让我们再次看看 Jumpsec 的挑战图像:

我实际上不是 100% 确定为什么会发生这种情况(有时不会),但它是文本渲染到屏幕时光栅化过程的产物。看看当你放大到在记事本中输入的文本时会发生什么:



挑战形象与猜测


顶部:原始挑战图像底部:Unredacter 的 Headless Chrome 渲染

Unredacter 很快就会在 [3, 1] 的偏移量上找到目标,所以让我们看看它是怎么做的!


顶部:原始挑战图像(灰度和底行固定)底部:Unredacter 的猜测

