不要使用文本像素来编辑敏感信息

2022-02-17 13:19:43

我们在Bishop Fox写了很多报道(这是当你破解所有东西时发生的事情)。这经常导致需要对某些文本进行编辑。我们有一个长期的政策,当你编辑文本时,唯一安全的方法就是使用黑条。有时,人们喜欢变得聪明,尝试其他一些编辑技术,比如模糊、旋转或像素化。但这是一个错误。

今天,我们将重点介绍一种这样的技术——像素化,并将向您展示为什么这是一种不好、不好、不安全、肯定会泄露敏感数据的方法。为了说明原因,我编写了一个名为Unredacter的工具,它将经过编辑的像素化文本还原为未经编辑的形式。在现实世界中,有很多这样的例子可以用来编辑敏感信息,但我不想在这里指名道姓。观看我的视频,快速回顾从不使用像素编辑文本的重要性,以及我如何取消Jumpseclabs';这是一个实时的挑战。

因此,有一个名为Depix的现有工具,它试图通过一个非常聪明的过程来实现这一点,即在给定正确字体的De Bruijn序列的情况下,查找像素排列可能会导致某些像素化块。我非常喜欢这个工具的理论,但Jumpsec的一位研究人员指出,也许它在实践中没有你想要的那么好。在现实世界中的例子中,你很可能会得到一些微小的变化和噪音,这会让你的齿轮扭动。然后,他们向任何人发出了挑战,如果你能取消对以下图片的编辑,他们将提供奖励:

算法非常简单;将图像分割为给定块大小的网格(上面的示例是8x8)。然后,对于每个块,将经过编辑的图像的颜色设置为相同区域原始图像的平均颜色。就是这样——每个块的滚动像素平均值。

这种效果有点“涂抹”了每个块的图像信息。但是,尽管在这个过程中有些信息丢失了,但它绝对会大量泄露出去。我们将利用这些泄露的信息为自己谋利。

值得注意的是,由于该算法非常简单,因此被广泛标准化。所以,不管你是在GiMP、Photoshop还是其他工具中进行编辑,编辑结果都是一样的。

我认为,这些都是相当合理的假设,因为在现实场景中,攻击者可能会收到一份完整的报告,其中只有一份经过编辑。在我们的挑战文本中,你可以在像素文本的正上方看到一些单词,它们为我们提供了这些信息。

我们关注的关键是编校过程本质上是局部的。在密码学方面,我们可以说它没有扩散。在原始图像的某个地方改变一个像素只会影响它所属的编辑块,这意味着我们可以(大部分)逐个字符地猜测图像。我们将对每个字符进行递归深度优先搜索,根据其与编辑文本的匹配程度对每个猜测进行评分。

基本上,我们猜测字母“a”,对该字母进行像素化,然后查看它与我们编辑的图像的匹配程度。然后我们猜字母“b”,以此类推。听起来没那么难吧?嗯,还有一大堆后勤问题需要克服,这在一开始可能并不那么明显!让我们进一步深入研究这些问题。

我们立即遇到的第一个问题是,文本中的字符与编辑块的比例不是1:1。这意味着一个给定的正确猜测可能在最右边有一些错误的块。要了解我的意思,请查看以下示例:

可以看到字母“t”和“h”共享一列块。所以,如果我们试着猜测字母“t”,最左边的一列结果是正确的,但最右边的一列有点错误。

第二栏是错误的,因为字母“h”把事情搞砸了。如果我们只看这一点,你可能会得出结论,字母“t”是一个不正确的第一个字母,因为它得到了几乎一半的区块完全错误。

我们尝试的第一件事是避免计算任何猜测中最右边的区块。这是最容易出错的专栏。问题是,在实践中,它减少了我们猜测的总大小,以至于你开始收到误报。总是有机会,你的信会意外排队,并产生一个纯粹的机会比赛,这个机会走上去,当有更少的块考虑。

因此,我们所做的是在字母本身的边界处切掉比较块。因此,我们的差异如下所示:

你可以看到我们比赛的质量有了很大的提高,因为我们在右边的错误区域减少了。这是因为我们在“t”结束的边缘处切掉比较:

这样做的好处是,我们的猜测字符越多地延伸到块中,块就越有可能是一个好的猜测,因此我们保留了更多的块。因此,当猜测错误时,它会自动切掉大部分块,当猜测正确时,它会保留大部分块。

角色溢出问题的一个具体子集是,空白往往会打破我们对角色猜测工作原理的一些假设。这个问题的本质是这样一种假设:当我们猜到一个正确的角色时,我们期望得到的像素化版本的角色与挑战图像基本相似。

然而,当我们猜测的字符是空白时,这并不总是正确的。当这种情况发生时,像素块将被下一个角色完全取代。举个例子,猜测“this is”(后面有空格):

然后将其像素化,如下图所示,后面有一个空白列:

问题是,在解决方案图像中,空格后面还有另一个字符。它流了这么多血,以至于我们正确的猜测看起来是完全错误的!

解决这个问题的方法不止一种。最明显的是永远不要自己猜测空格,而是将其与其他非空格字符配对。这样我们就可以控制流血的角色。虽然这种方法“有效”,但它有效地将可用字符集增加了一倍。这会让整个过程变得缓慢。

相反,我们可以做的是为空白猜测做一个特殊的划分,让他们在被认为是“好”猜测的情况下更加宽容。在测试中,似乎溢出从未如此严重,以至于超过了一个较低的阈值。我承认这有点笨拙,但似乎管用。

人们书写的大多数字体都是可变宽度的。这意味着每个字母占用的水平空间量取决于字母本身。例如,“w”比“i”占用更多空间。这与单空格字体形成对比,单空格字体故意将字母隔开,使每个字母占据相同的水平空间。

这对我们的攻击(假定为可变宽度字体)意味着,每个猜测的字母在其右侧都有级联效应。如果你猜:

然后,所有未来的字母都将关闭,即使这些字母在其他方面是“正确的”。

这听起来很重要,但实际上并不是那么糟糕。这只是意味着我们必须坚持递归深度优先搜索,而不是将字母视为独立的工件。递归深度优先搜索在这里效果很好,因为它自然会考虑这种排序。它的工作原理如下:

我们要做的是尝试下一个字母的每个字符,看看哪些字符与经过编辑的图像匹配得相当好。我们将得到一些“好”猜测的子集,可能是“p”和“q”,因为p是正确的,q与它非常相似。然后,我们将再次开始猜测新字符串“this is sup”的整个过程,直到我们遇到一个没有好猜测的死胡同。在这一点上,函数调用堆栈将自然备份,以尝试我们的另一个猜测q。

等等,直到我们用尽所有的“好”猜测。

碰巧的是,不同的渲染引擎生成的图像略有不同,即使是应该完全相同的字体。看看这两个相同文本的截图。顶部是GiMP的无衬线渲染,底部是FireFox:

它们几乎一模一样,但并不完全相同。有两件事很突出;一是长度。你可以看到上面的图片只是稍微长一点。对于足够长的字符串,这可能会产生一种级联效应,将整个事情抛诸脑后。另一个区别是文本如何光栅化;底线只是比最上面的要大胆一点。我们可以通过调整亮度来处理这个问题,但这是一个非常痛苦的问题。

对于Undeacter,我们使用Electron拍摄本地无头HTML窗口的屏幕截图。因此,渲染器基本上是Chrome。大多数时候,这不是问题。但是,如果你的编辑文本是使用一些不符合标准的非常不可靠的程序来呈现的,那么它可能会偏离正常的方向。记住这一点。

如果有人想通过Rube Goldberg的包装器和宏机器为Unredacter编写一个包装器,使用MS Word生成猜测,欢迎您试一试。

对图像进行像素化时,必须考虑两个自由度:x和y偏移坐标。但这些到底是什么?

如果你认为这是一个静态网格,那么有64个不同的位置供你放置文本在该网格上。我们称之为x和y“偏移”。根据您选择的偏移量,它可以生成截然不同的图像:

此外,攻击者无法知道这些偏移量是什么。(与字体和字号不同)。在大多数编辑器(如GiMP)中,偏移量是由用户在创建边界框时碰巧单击的位置的随机过程确定的。如果他们向上或向下点击一个像素,像素化会产生一个完全不同的图像!

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

所以,Unredacter的第一步是发现使用了什么偏移量。我们通过在循环中尝试每个偏移量来实现这一点,并查看是否有任何字母给出了一个好的首字母猜测。我们将所有第一个字母猜测正确的偏移量添加到列表中,然后尝试正确的猜测。

可以有了这些知识和利用这些知识的工具,我们再来看看Jumpsec的挑战图:

你可能会注意到的第一件事是它有一点奇怪的颜色。有什么好处?既然文本是黑色的,就不应该是黑白的吗?他们在用彩色字母拖拽我们吗?

实际上,我并不完全确定为什么会发生这种情况(有时不会),但当文本呈现到屏幕上时,这是光栅化过程的产物。只需看看放大记事本中键入的文本时会发生什么:

当Undercater将字母渲染到无头Chrome窗口时,不会出现彩色瑕疵,因此我们需要将图像转换为灰度。这会丢失一些信息,但没关系。Unredacter不需要精确匹配,只需要猜测“基本正确”。一旦向下转换,我们的挑战图像如下所示:

我必须做最后一个调整,它在最底层:

太小了!其余的块是5x5,但最下面一行是5x3。经过几个小时的反复试验,我还注意到这些积木太暗了。查看字母“g”的猜测与挑战图:

看到最下面一排怎么太暗了吗?这是因为当图像被像素化时,他们一定选择了一个大小不是5倍的边界框。因此,当算法确定平均值时,它是一个较小区域的平均值。(因此更暗)没关系,我们可以通过点亮最后一排来修复它。这给了我们最后一个挑战的形象:

下一步是找出正确的字体和字号。幸运的是,这并不难,这张图片是在MS Notepad中拍摄的,默认字体为Consoleas。经过一点尝试和错误,我发现字体大小是24px。(我只是反复尝试字体大小,直到大写字母M的高度匹配。)唯一棘手的是,记事本的默认字母间距为-0.2px。如果你试着在控制台中用Chrome渲染文本,那就太长了。但是-0.2px的字母间距正好匹配。

如果仔细观察,“s”、“e”和“c”在记事本的渲染中有更多的曲线。但没关系。再说一遍,我们不需要100%准确。很接近!

Unredacter很快就以[3,1]的偏移量进驻,所以让我们看看它是如何做到的!

所以我联系了Jumpsec的Caleb Herbert,他们确认了我的猜测是正确的!

Caleb还要求我不要透露解决方案,所以你可以自己尝试一下。(上面的文字模糊了,你根本看不懂模糊的文字,对吧?)向Jumpsec发出了巨大的欢呼声,这是一个很大的挑战。也是测试新工具的好方法!

如果你想查看Unredacter的概念验证源代码,可以在我们的GitHub上找到。

底线是,当你需要编辑文本时,用黑条覆盖整个文本。别用别的东西。没有像素化,没有模糊,没有模糊,没有漩涡。哦,一定要把文本编辑成图像。不要错误地更改Word文档,使其具有黑色背景和黑色文本。(你仍然可以通过这样突出显示来阅读。)

在制作一份优秀的技术文档之后,你最不需要做的事情就是由于不安全的编辑技术而意外地泄露敏感信息。

Dan Petro是Bishop Fox的首席研究员,专注于应用程序渗透测试(静态和动态)、产品安全审查、网络渗透测试(外部和内部)以及密码分析。Dan曾在多个黑帽子和DEF CONs上展示过黑客智能保险箱、劫持谷歌Chromecast和人工智能武器化等主题。他开发了几个开源工具,包括Untwister,它可以分解伪随机数生成器。此外,《连线》、《卫报》、《商业内幕》和《Mashable》都引用了丹的话。Dan拥有亚利桑那州立大学计算机科学学士和硕士学位。

丹的更多