检测和防止 PDF 文件中的“电话回家”行为

信息安全 pdf
2021-08-23 12:34:37

我通过电子邮件收到了一些我不信任的人发来的 PDF 文档。我需要阅读文件并做出回应。它们没有加密。

我想确保文件是完全安全的。

我用多种防病毒产品扫描了它们。未检测到问题。

我可以从我的网络邮件中查看它们,但我想下载它们并直接查看它们并将它们保存为我的记录。

我担心如果我在 PDF 阅读器/查看器/编辑器中打开文件,文档中可能会有一些东西会尝试连接到服务器以发送“ping”,表明我已经打开了文档。

PDF文档可以做到这一点吗?如果是这样,我如何确定这些文件中的任何一个是否设置为这样做?另外,除了断开与互联网的连接,我该如何防止呢?

4个回答

PDF 文档可以拨号回家吗?

是的,至少对于 Adob​​e 阅读器产品(请参见此处):

除了 PDF 文档中的可见链接之外,表单域还可以包含隐藏的 JavaScript 调用,这些调用在浏览器中打开页面或从 Internet 静默请求数据。

我如何判断一个特定的 pdf 是否这样做?

我确信有办法做到这一点,但我不知道它是什么。adobe pdf reader 可能会向您展示特定文档使用的功能,但我不使用它们,所以我真的不知道。我认为更重要的问题是......

如何保护自己免受 PDF 文件的影响?

首先,我应该说防病毒扫描不是这样做的方法。一方面,“拨号回家”不是 pdf 中的病毒,它只是使用“合法”功能。另一方面,病毒扫描是一种被破坏的安全模型:每次都有新病毒通过扫描程序。

幸运的是,可以使用 Reader 的首选项禁用许多选项,例如 Web 链接和 JavaScript(例如,请参见此处,请注意 Adob​​e 术语“到 Internet 的链接”并不是指像 Web 那样的常用超链接,而是实际连接)。您可能希望永久禁用 Internet 访问和 JavaScript:您很少需要这些功能,它们只会暴露潜在问题。

实际上,这是您真正需要做的所有事情来保证自己的安全。

然而...

多年来,在各种 pdf 查看器中也发现了漏洞,这使得特制的 pdf 可以执行诸如执行任意代码之类的令人讨厌的事情。也有一些方法可以缓解这种情况:现代版本的 adobe reader 有一个可以启用的内置沙箱,请参见此处

假设您在不断修补的系统上运行,这可能不是一个巨大的风险。如果您需要额外确定,请使用虚拟机(如VMWareVirtualBox)。我建议这个程序:

  • 创建一个虚拟机并在其上安装pdf阅读器软件
  • 在主机和虚拟机之间设置共享文件夹
  • 使用此共享文件夹将 pdf 文件复制到虚拟机。
  • 关闭虚拟机,禁用它的网络和共享文件夹
  • 拍摄虚拟机硬盘状态的快照
  • 重新启动虚拟机并查看pdf文件。由于网络和共享文件被禁用,因此 pdf 文件中的任何令人讨厌的东西都无法从虚拟机中删除。
  • 完成后,关闭虚拟机,并将其状态回滚到检查点。现在,pdf 可能对我们的虚拟机造成的任何不良影响都消失了。

然而...

话虽如此,理论上可能存在虚拟化软件中的缺陷,从而使 pdf 文件中的一些额外讨厌的东西得以逃脱。对于虚拟机,恕我直言,我们处于极度偏执的状态,我们现在已经处于边缘,但为了完整起见,气隙物理机将是一个更安全的选择。

(正如 Deer Hunter 的评论所暗示的,使用不连接到任何网络的物理硬件会更加安全,尽管我们每分钟都变得更加偏执)。

我没有足够的声誉发表评论,但我想补充一下 dotancohen 的回答。如果您想以纯文本格式阅读 PDF,pdftk是一个了不起的免费工具。

只需运行如下命令:

pdftk input.pdf output out.pdf uncompress

并且所有压缩的内容流都将被解压缩。结构(例如对象编号)可能会发生一些变化,但这将使您能够使用您喜欢的工具对已知字符串(如“/JavaScript”)进行简单的解析。

您可能需要仔细阅读 PDF 规范,看看这是否足够,但它应该可以帮助您入门。如果您没有时间或对此感兴趣,现成的工具或防火墙 VM 会更安全。

对于这一页,可以下载带有示例脚本的 PDF 文件。我下载了这个

作为一个实验,我运行了该文件strings并用于grep搜索 JavaScript:

$ strings JSPopupCalendar.pdf | grep -i java
<</JavaScript 251 0 R/EmbeddedFiles 243 0 R>>
<</S/JavaScript/JS 253 0 R>>
<</S/JavaScript/JS(\n\r\n       /* Set day 18 */\r\n    FormRouter_SetCurrentDate\("18"\);\r)>>
<</S/JavaScript/JS(\nFormRouter_PlaceCalendar\(this.getField\("FormDateField"\), false, "mmmm dd, yy"\);\r\n\r\n\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 17 */\r\n    FormRouter_SetCurrentDate\("17"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 26 */\r\n    FormRouter_SetCurrentDate\("26"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 16 */\r\n    FormRouter_SetCurrentDate\("16"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 31 */\r\n    FormRouter_SetCurrentDate\("31"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 15 */\r\n    FormRouter_SetCurrentDate\("15"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 25 */\r\n    FormRouter_SetCurrentDate\("25"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 14 */\r\n    FormRouter_SetCurrentDate\("14"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /*  Set day 13 */\r\n   FormRouter_SetCurrentDate\("13"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 24 */\r\n    FormRouter_SetCurrentDate\("24"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 12 */\r\n    FormRouter_SetCurrentDate\("12"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 30 */\r\n    FormRouter_SetCurrentDate\("30"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 21 */\r\n    FormRouter_SetCurrentDate\("21"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 23 */\r\n    FormRouter_SetCurrentDate\("23"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 10 */\r\n    FormRouter_SetCurrentDate\("10"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 9 */\r\n     FormRouter_SetCurrentDate\("9"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 22 */\r\n    FormRouter_SetCurrentDate\("22"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 8 */\r\n     FormRouter_SetCurrentDate\("8"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 29 */\r\n    FormRouter_SetCurrentDate\("29"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 7 */\r\n     FormRouter_SetCurrentDate\("7"\);\r)>>
<</S/JavaScript/JS(\n/* Set day 1 */\r\nFormRouter_SetCurrentDate\("1"\);\r\n\r\n\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 6 */\r\n     FormRouter_SetCurrentDate\("6"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 28 */\r\n    FormRouter_SetCurrentDate\("28"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 5 */\r\n     FormRouter_SetCurrentDate\("5"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 20 */\r\n    FormRouter_SetCurrentDate\("20"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 4 */\r\n     FormRouter_SetCurrentDate\("4"\);\r)>>
<</S/JavaScript/JS(\n\r\n\r\n   /* Set day 3 */\r\n     FormRouter_SetCurrentDate\("3"\);\r\n\r\n\r)>>
<</S/JavaScript/JS(\n\r\n\r\n   /* Set day 19 */\r\n    FormRouter_SetCurrentDate\("19"\);\r\n\r\n\r)>>
<</S/JavaScript/JS(\n/* Set day 2 */\r\nFormRouter_SetCurrentDate\("2"\);\r\n\r\n\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 27 */\r\n    FormRouter_SetCurrentDate\("27"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 11 */\r\n    FormRouter_SetCurrentDate\("11"\);\r)>>
<</S/JavaScript/JS(\nFormRouter_PlaceCalendar\(this.getField\("DateTest2"\), true, "ddd mmm d, yyyy"\);\r\n\r\n\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 23 */\r\n    FormRouter_SetCurrentDate\("23"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 24 */\r\n    FormRouter_SetCurrentDate\("24"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 25 */\r\n    FormRouter_SetCurrentDate\("25"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 26 */\r\n    FormRouter_SetCurrentDate\("26"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 27 */\r\n    FormRouter_SetCurrentDate\("27"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 28 */\r\n    FormRouter_SetCurrentDate\("28"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 29 */\r\n    FormRouter_SetCurrentDate\("29"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 30 */\r\n    FormRouter_SetCurrentDate\("30"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 31 */\r\n    FormRouter_SetCurrentDate\("31"\);\r)>>
<</S/JavaScript/JS(\n/* Set day 1 */\r\nFormRouter_SetCurrentDate\("1"\);\r\n\r\n\r)>>
<</S/JavaScript/JS(\nFormRouter_PlaceCalendar\(this.getField\("FormDateField.1"\), false, "mmm d, yyyy"\);\r\n\r\n\r\n\r)>>
<</S/JavaScript/JS(\n\r\nFormRouter_PlaceCalendar\(this.getField\("DateTest1"\), false, "mm/dd/yyyy"\);\r\n\r\n\r\n\r\n\r)>>
<</S/JavaScript/JS(\n/* Set day 2 */\r\nFormRouter_SetCurrentDate\("2"\);\r\n\r\n\r)>>
<</S/JavaScript/JS(\n\r\n\r\n   /* Set day 3 */\r\n     FormRouter_SetCurrentDate\("3"\);\r\n\r\n\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 4 */\r\n     FormRouter_SetCurrentDate\("4"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 5 */\r\n     FormRouter_SetCurrentDate\("5"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 6 */\r\n     FormRouter_SetCurrentDate\("6"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 7 */\r\n     FormRouter_SetCurrentDate\("7"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 8 */\r\n     FormRouter_SetCurrentDate\("8"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 9 */\r\n     FormRouter_SetCurrentDate\("9"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 10 */\r\n    FormRouter_SetCurrentDate\("10"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 11 */\r\n    FormRouter_SetCurrentDate\("11"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 12 */\r\n    FormRouter_SetCurrentDate\("12"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /*  Set day 13 */\r\n   FormRouter_SetCurrentDate\("13"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 14 */\r\n    FormRouter_SetCurrentDate\("14"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 15 */\r\n    FormRouter_SetCurrentDate\("15"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 16 */\r\n    FormRouter_SetCurrentDate\("16"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 17 */\r\n    FormRouter_SetCurrentDate\("17"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 18 */\r\n    FormRouter_SetCurrentDate\("18"\);\r)>>
<</S/JavaScript/JS(\n\r\n\r\n   /* Set day 19 */\r\n    FormRouter_SetCurrentDate\("19"\);\r\n\r\n\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 20 */\r\n    FormRouter_SetCurrentDate\("20"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 21 */\r\n    FormRouter_SetCurrentDate\("21"\);\r)>>
<</S/JavaScript/JS(\n\r\n       /* Set day 22 */\r\n    FormRouter_SetCurrentDate\("22"\);\r)>>
<</S/JavaScript/JS(\n\r\n\r)>>
<</S/JavaScript/JS 233 0 R>>
<</S/JavaScript/JS(\n\r\nif\(!event.willCommit\)\r\n{\r\n  FormRouter_SetDays\(parseInt\(event.changeEx\), parseInt\(getField\("FR_00000_Calendar.CalendarYear"\).value\)\);\r\n}\r\n\r\n\r\n\r\n\r\n\r)>>
               <rdf:li>JavaScript</rdf:li>

我不能确保所有带有 Javascript 的 PDF 文件都可以看到带有 Javascript 的 Javascript strings但是,以这种方式检查将是一个很好的第一步。

如前所述,可以将 PDF 文档称为主页。

这通常通过启动 URL 来完成,主要是在文档打开时。

可能最简单、最实用的方法是使用一个非常愚蠢的 PDF 查看器(它不知道操作等),并在启动查看器之前断开机器与网络的连接(并在退出后重新连接)。

但是,您希望保留 PDF 以供记录。在这种情况下,您必须“清理”它,为此您需要比愚蠢的 PDF 查看器更好的东西。

一种可能性是使用 Acrobat(当机器与网络断开连接时),找到 PDFOptimizer(在 Acrobat XI 中,您可以通过菜单文件 --> 另存为... --> 优化 PDF 来获得它)。在该对话框中,您有很多选项可以删除活动元素等。据说这足够可靠,应该这样做。

如果你有更多的文件要处理,你可以看看 Appligent 的一些产品;如果我没记错的话,有一个实用程序可以正确地从任何活动元素中删除 PDF(并且,由于它不是 PDF 查看器,因此文档没有机会调用 home)。