【翻译】PDF格式详解

PDF 专栏收录该内容
1 篇文章 0 订阅

1.简介

我们都知道,攻击者将一些shellcode包含在PDF文档中有许多攻击,这些攻击使用某种漏洞来分析PDF文档并将其呈现给用户以在目标系统上执行恶意代码。

下图显示了流行的PDF Reader Adobe Acrobat Reader中发现的漏洞数量。多年来漏洞的数量正在增加,但今年发现的漏洞数量略少(但今年尚未结束)。最重要的漏洞是代码执行漏洞,攻击者可以使用这些漏洞在目标系统上执行任意代码(如果尚未修补Acrobat Reader)。

这是一个重要的指标,我们应该定期更新我们的PDF阅读器,因为最近发现的漏洞数量非常艰巨。

2. PDF文件结构

每当我们想要发现软件中的新漏洞时,我们首先应该了解我们试图发现新漏洞的协议或文件格式。在我们的例子中,我们应该首先详细了解PDF文件格式。在本文中,我们将了解PDF文件格式及其内部结构。

PDF是一种可移植的文档格式,可用于呈现包含文本,图像,多媒体元素,网页链接等的文档。它具有广泛的功能。我们必须首先理解的是,PDF文件格式规范在这里是公开的,任何对PDF文件格式感兴趣的人都可以使用。PDF文件格式的文档几乎有800页,因此阅读并不是为期一天的快速阅读,但需要花费大量时间。

PDF具有比文本更多的功能; 它可以包含图像和其他多媒体元素,可以受密码保护,可以执行JavaScript等。图像文件的基本结构如下图所示:

每个PDF文档都包含以下元素:

- 标题:这是PDF文件的第一行,指定文档使用的PDF规范的版本号。如果我们想要找到它,我们可以使用十六进制编辑器或只需使用xxd命令,如下所示:

<span style="color:#474747"># xxd temp.pdf | head -n 1
0000000: 2550 4446 2d31 2e33 0a25 c4e5 f2e5 eba7  %PDF-1.3.%......
</span>

temp.pdf PDF文档使用PDF规范1.3。'%'字符是PDF中的注释,因此上面的示例实际上显示第一行和第二行是注释,对于所有PDF文档都是如此。以下字节取自以下输出:2550 4446 2d31 2e33 0a25 c4e5,对应ASCII文本“%PDF-1.3。%”。以下是一些使用不可打印字符的ASCII字符(请注意'。'点),这些字符通常告诉某些软件产品该文件包含二进制数据,不应被视为7位ASCII文本。目前版本号的格式为1.N,其中N的范围为0-7。

-正文在PDF文档的正文中,有些对象通常包括文本流,图像,其他多媒体元素等。“正文”部分用于保存向用户显示的所有文档数据。

- xref表:这是交叉引用表,其中包含对文档中所有对象的引用。交叉引用表的目的是允许随机访问文件中的对象,因此我们不需要读取整个PDF文档来定位特定对象。每个对象由交叉​​引用表中的一个条目表示,该条目总是20个字节长。让我们举个例子:

<span style="color:#474747">xref
0 1
0000000023 65535 f
3 1
0000025324 00000 n
21 4
0000025518 00002 n
0000025632 00000 n
0000000024 00001 f
0000000000 00001 f
36 1
0000026900 00000 n
</span>

 

我们可以通过简单地用文本编辑器打开PDF并滚动到文档的底部来显示PDF文档的交叉引用表。在上面的例子中,我们可以看到我们有四个子部分(注意四行只包含两个数字)。这些行中的第一个数字对应于对象编号,而第二行表示当前子部分中的对象数。每个对象由一个条目表示,该条目长度为20个字节(包括CRLF)。前10个字节是对象从PDF文档开头到该对象开头的偏移量。接下来是一个空格分隔符,其中另一个数字指定了对象的世代号。之后还有另一个空格分隔符,后跟一个字母'f'或'n',表示该对象是空闲还是正在使用。

第一个对象的ID为0,并且始终包含一个生成号为65535的条目,该条目位于自由对象列表的开头(注意字母“f”表示空闲)。交叉引用表中的最后一个对象使用世代号0。

第二个子部分有一个对象ID 3并包含1个元素,对象3从文档开头的25324个字节开始。第三个子部分有四个对象,第一个子对象的ID为21,并从文件开头的偏移量25518开始。其他对象具有后续数字22,23和24.所有对象都标记有标记“f”或“n”。标记'f'表示对象可能仍然存在于文件中,但标记为空闲,因此不应使用它。这些对象包含对下一个自由对象的引用,以及在对象再次生效时要使用的世代号。标志'n'用于表示有效和已使用的对象,这些对象包含从文件开头到对象的世代号的偏移量。

注意,对象零点指向表中的下一个自由对象,即对象23.但由于对象23也是空闲的,它本身指向表中的下一个自由对象,对象24.但是对象24是文件上的最后一个自由对象,因此它指向对象零。如果我们用每个对象编号表示上面的交叉引用表,它将如下所示:

<span style="color:#474747">xref
0 1
0000000023 65535 f
3 1
0000025324 00000 n
21 1
0000025518 00002 n
22 1
0000025632 00000 n
23 1
0000000024 00001 f
24 1
0000000000 00001 f
36 1
0000026900 00000 n
</span>

 

当对象被释放时,对象的世代号递增,因此如果对象再次变为有效(将标志从“f”更改为“n”),则世代号仍然有效而不必增加它。对象23的世代号是1,所以如果它再次变为有效,则世代号仍将是1,但如果它再次被删除,则世代号将增加到2。

多个子部分通常存在于已逐步更新的PDF文档中,否则只应出现一个以数字零开头的子部分。 

- 预告片: PDF预告片指定阅读PDF文档的应用程序应如何找到交叉引用表和其他特殊对象。所有PDF阅读器都应该从文件末尾开始阅读PDF。下面是一个示例预告片:

<span style="color:#474747">trailer
&lt;&lt;
/Size 22
/Root 2 0 R
/Info 1 0 R
&gt;&gt;
startxref
24212
%%EOF
</span>

 

PDF文档的最后一行包含文件字符串'%% EOF'的结尾。在文件标记结束之前,有一行带有字符串startxref,用于指定从文件开头到交叉引用表的偏移量。在我们的例子中,交叉引用表从偏移24212字节开始。在此之前是一个字符串预告片,它指定了预告片部分的开头。预告片部分的内容嵌入在<<和>>字符中(这是一个接受键值对的字典)。我们可以看到预告片部分定义了几个键,每个键用于特定动作。预告片部分可以指定以下键:

/ Size [integer]:指定交叉引用表中的条目数(也计算更新部分中的对象)。使用的数字不应是间接参考。

- / Prev [integer]:指定从文件开头到上一个交叉引用部分的偏移量,如果有多个交叉引用部分,则使用该偏移量。该数字应该是交叉引用。

/ Root [字典]:指定文档目录对象的引用对象,它是一个特殊对象,包含指向不同类型的其他特殊对象的各种指针(稍后将详细介绍)。

- / Encrypt [dictionary]:指定文档的加密字典。

- / Info [字典]:指定文档信息字典的引用对象。

- / ID [array]:指定形成文件标识符的两个字节未加密字符串的数组。

- / XrefStm [integer]:指定从解码流中的文件开头到交叉引用流的偏移量。这仅存在于混合引用文件中,如果我们还想要打开文档,即使应用程序不支持压缩引用流,也会指定它。

我们必须记住,如果我们稍后更新PDF文档,可以修改初始结构。更新通常会在文件末尾附加其他元素。

道德黑客培训 - 资源

3.增量更新

PDF的设计考虑了增量更新,因为我们可以将一些对象附加到PDF文件的末尾,而无需重写整个文件。因此,可以快速保存对PDF文档的更改。PDF文档的新结构如下图所示:

我们可以看到PDF文档仍然包含原始标题,正文,交叉引用表和预告片。此外,还有其他Body,Cross-reference和Trailer部分已添加到PDF文档中。其他交叉引用部分将仅包含已更改,替换或删除的对象的条目。删除的对象将保留在文件中,但将标记为标记“f”。每个trailed需要由'%% EOF'标记终止,并且应包含指向上一个交叉引用部分的/ Prev条目。

在PDF版本1.4及更高版本中,我们可以在文档的目录字典中指定Version条目,以覆盖PDF标题中的默认版本。

4.例子

让我们提供一个简单的PDF示例并进行分析。让我们从这里下载一个示例PDF文档并进行分析。打开此PDF文档后,它看起来如下所示:

交叉参考和预告片部分如下图所示:

为清楚起见,交叉参考部分已经减少。交叉引用部分包含一个本身包含223个对象的子部分。预告片部分从字节偏移50291开始,包括223个对象,其中根元素指向对象221并且Info元素指向对象222。

在下一节中,我们将了解PDF结构的基本数据类型。

5. PDF数据类型

PDF文档包含下面描述的八种基本类型的对象。即这些类型的对象是:布尔值,数字,字符串,名称,数组,字典,流和空对象。可以标记对象,以便其他对象可以引用它们。带标签的对象也称为间接对象。

5.1。布尔

有两个关键字:truefalse表示布尔值。

5.2。数字

PDF文档中有两种类型的数字:整数和实数。整数由一个或多个数字组成,可选地前面带有符号加(字符'+')或减号(字符' - ')。整数对象的示例如下所示:

<span style="color:#474747">123 +123 -123
</span>

实数值可以用一个或多个带有可选符号和前导,尾随或嵌入小数点(句点 - 字符'。')的数字表示。下面是一个实数的例子:

<span style="color:#474747">123.0 -123.0 +123.0 123. -.123
</span>

5.3。名称

PDF文档中的名称由0x21 - 0x7E范围内的ASCII字符序列表示。例外是:%,(,),<,>,[,],{,},/和#,必须以斜杠开头。字符的替代表示是十六进制等效,前面是字符'#'。name元素的长度有一个限制,可能只有127个字节长。

在写名字时,必须使用斜线来引入名称; 斜杠不是名称的一部分,而是一个前缀,表示后面是表示名称的字符序列。如果我们想使用空格或任何其他特殊字符作为名称的一部分,则必须使用2位十六进制表示法进行编码。

名称的例子可以在下表中看到,它取自[1]:

5.4。字符串

PDF文档中的字符串表示为由括号或尖括号括起的一系列字节,但最长可达65535个字节。任何字符都可以用ASCII表示来表示,也可以用八进制或十六进制表示来表示。八进制表示要求字符以\ ddd格式写入,其中ddd是八进制数。十六进制表示要求字符以<dd>的形式写入,其中dd是十六进制数。

表示嵌入括号中的字符串的示例如下所示:

<span style="color:#474747">(mystring)
</span>

表示嵌入尖括号中的字符串的示例如下所示(下面的十六进制表示与上面的相同,它读作'mystring'):

<span style="color:#474747">&lt;6d79737472696e67&gt;
</span>

我们还可以在表示字符串时使用特殊的已知字符:它们是:\ n表示新行,\ r表示回车符,\ t表示水平制表符,\ b表示退格键,\ f表示换页符\,(左括号) ,\)表示右括号,\\表示反斜杠。

5.5。数组

PDF文档中的数组表示为一系列PDF对象,可以是不同类型的,并用方括号括起来。这就是PDF文档中的数组可以包含任何对象类型(如数字,字符串,字典甚至其他数组)的原因。数组也可以具有零元素。阵列呈现方括号。下面给出了一个数组示例:

<span style="color:#474747">123 123.0 true (mystring) /myname]
</span>

5.6。字典

PDF文档中的字典表示为键/值对的表。键必须是Name对象,而值可以是任何对象,包括另一个字典。字典中的最大条目数为4096个条目。可以使用双尖括号<<和>>括起来显示字典。字典的一个例子如下:

<span style="color:#474747">&lt;&lt; /mykey1 123
     /mykey2 0.123
     /mykey3 &lt;&lt; /mykey4 true
                         /mykey5 (mystring)
                    &gt;&gt;
&gt;&gt;
 </span>

5.7。流

流对象由字节序列表示,并且长度可以是无限的,这就是图像和其他大数据块通常表示为流的原因。流对象由字典对象表示,后跟关键字stream,后跟换行符和endstream

下面是一个流对象的示例:

<span style="color:#474747">&lt;&lt;
/Type /Page
     /Length 23 0 R
     /Filter /LZWDecode
&gt;&gt;
stream
…
endstream
</span>

所有流对象都应是间接对象,流字典应是直接对象。流字典指定流的确切字节数。在数据之后应该有换行符和endstream关键字。

所有流字典中使用的常用关键字如下(请注意,长度条目是必需的):

- 长度:PDF文件的字节数用于流的数据。如果流包含Filter条目,则Length应指定编码数据的字节数。

- 类型:字典描述的PDF对象的类型。

- 过滤器:将在处理流数据时应用的过滤器的名称。可以按照应用顺序指定多个过滤器。

- DecodeParms:Filter指定的过滤器使用的字典或字典数组。此值指定在应用过滤器时需要传递给过滤器的参数。如果过滤器使用默认值,则不需要这样做。

- F:指定包含流数据的文件。

- FFilter:在处理流的外部文件中找到的数据时应用的过滤器的名称。

- FDecodeParms:由FFilter指定的过滤器使用的字典或字典数组

- DL:指定解码流中的字节数。如果有足够的磁盘空间可用于将流写入文件,则可以使用此方法。

- N:存储在流中的间接对象的数量。

- 第一:第一个压缩对象的解码流中的偏移量。

- Extends:指定对其他对象流的引用,形成继承树。

对象流中的流数据将包含N对整数,其中第一个整数表示对象编号,第二个整数表示该对象的解码流中的偏移。对象流中的对象是连续的,不需要以相对于对象编号的递增顺序存储。在首先在字典条目识别对象流的第一对象。

我们不应将以下信息存储在对象流中:

- 流对象

- 世代号不等于零的对象

- 文档的加密字典

- 对象流字典中的Length条目的间接对象

- 文档目录,线性化字典,页面对象

在PDF 1.5中,交叉引用信息可以存储在交叉引用流中,而不是存储在交叉引用表中。每个交叉引用流包含与交叉引用表和尾部等效的信息。

5.8。空对象

null对象由关键字null表示。

5.9。间接对象

首先,我们必须知道PDF文档中的任何对象都可以标记为间接对象,它为对象提供唯一的对象标识符,其他对象可以使用它来引用间接对象。间接对象​​是用关键字objendobj表示的编号对象。endobj必须存在于它自己的行中,但是obj必须出现在对象ID行的末尾,这是间接对象的第一行。对象ID行由对象编号,世代号和关键字“obj”组成。间接对象​​的示例如下:

<span style="color:#474747">2 1 obj
12345
endobj
</span>

在上面的示例中,我们创建了一个新的间接对象,它保存了12345对象。通过将对象声明为间接对象,我们可以在PDF文档交叉引用表中使用它,并在文档中的任何页面,字典等中重用它。由于每个间接对象在交叉引用表中都有自己的条目,因此可以非常快速地访问间接对象。

间接对象​​的对象标识符由两部分组成; 第一部分是当前间接对象的对象编号。间接对象​​不需要在PDF文档中按顺序编号。第二部分是世代号,对于新创建的文件中的所有对象,该编号设置为零。稍后在更新对象时递增此数字。

我们可以引用间接引用的间接对象,它由对象编号,世代号和关键字R组成。要引用上面的间接对象,我们必须写下面的内容:

<span style="color:#474747">2 1 R
</span>

如果我们试图引用一个未定义的对象,我们实际上是指一个null对象。

6.文件结构

PDF文档由PDF文件正文部分中包含的对象组成。PDF文档中的大多数对象都是字典。文档的每个页面由页面对象表示,页面对象是包含对页面内容的引用的字典。页面对象连接在一起并形成一个页面树,在文档目录中使用间接引用声明。

PDF文档的整个结构可以用下面的图片表示[1]:

在上图中,我们可以看到文档目录包含对页面树,大纲层次结构,文章线程,命名目标和交互式表单的引用。我们不会详细介绍每个部分的内容,但我们只介绍最重要的部分,即Page Tree。

6.1。文件目录

从上图中,我们可以看到文档目录
是PDF文档中对象的根。我们已经说过,Trailer PDF部分中的/ Root元素指定了文档目录。文档目录包含对定义文档内容的其他对象的引用。它还包含声明文档在屏幕上显示方式的信息。文档目录中的条目如下:

- / Type:目录描述的PDF对象的类型(在我们的例子中,这是Catalog,因为这是文档目录对象)。

- / Version:构建文档的PDF规范的版本。

- / Extensions:本文档中有关开发人员扩展的信息。

- / Pages:对作为文档页面树根的对象的间接引用。

- / Dests:对作为命名目标对象的根的对象的间接引用。

- /大纲:对大纲目录对象的间接引用,该对象是文档大纲层次结构的根。

- / Threads:对表示文档文章线程的线程字典数组的间接引用。

- /元数据:对包含文档元数据的元数据流的间接引用。

我们可以看到许多其他条目是文档目录的一部分,但这里不会对它们进行描述。读者可以查看[1]了解详情。文档目录的示例如下所示:

<span style="color:#474747">1 0 obj
&lt;&lt; /Type /Catalog
/Pages 2 0 R
/PageMode /UseOutlines
/Outlines 3 0 R
&gt;&gt;
endobj
</span>

6.2。页面树

通过页面树访问文档的页面,页面树定义PDF文档中的所有页面。树包含表示PDF文档页面的节点,可以是两种类型:中间节点和叶节点。中间节点也称为页面树节点,而叶节点称为页面对象。最简单的页面树结构可以由单个页面树节点组成,该节点直接引用所有页面对象(因此所有页面对象都是叶子)。

页面树中的每个节点都必须具有以下条目:

- / Type:此对象描述的PDF对象的类型(在我们的例子中是Pages,因为我们讨论的是页面树节点)。

- / Parent:应存在于除root之外的所有页树节点中,此条目不得出现。此条目指定其父级。

- / Kids:应该出现在除叶子之外的所有页面树节点中,并指定可从当前节点直接访问的所有子元素。

- / Count:指定后续页面树中此节点后代的叶节点数。

我们必须记住,页面树与PDF文档中的任何内容都没有关系,例如页面或章节。

页面树的基本示例如下所示[1]:

<span style="color:#474747">2 0 obj
&lt;&lt; /Type /Pages
/Kids [ 4 0 R
10 0 R
24 0 R
]
/Count 3
&gt;&gt;
endobj

4 0 obj
&lt;&lt; /Type /Page
...
&gt;&gt;
endobj

10 0 obj
&lt;&lt; /Type /Page
...
&gt;&gt;
endobj

24 0 obj
&lt;&lt; /Type /Page
...
&gt;&gt;
endobj
</span>

上面的页面树定义了ID为2 的Root对象,它有三个子节点,对象4,10和20.我们还可以看到页面树的叶子是指定文档单个页面属性的字典。在为每个文档页面定义它们时,我们可以使用多个属性; 所有这些都在[1]中指定。

我们已经看到了PDF文档的基本结构及其数据类型。如果我们想要开始在PDF阅读器中查找漏洞,我们需要更改PDF文档,使PDF阅读器无法处理它并崩溃。通常,如果我们可以让PDF阅读器崩溃,我们就会发现一个安全漏洞,我们可以使用它来在目标机器上执行任意代码。

7.一个例子

在本文中,我们将看一个PDF文档的一个非常简单的示例。首先,我们需要创建PDF文档,然后我们将尝试分析它。要创建PDF文档,我们首先创建一个非常简单的latex .tex文档,其中包含的内容如下图所示:

我们可以看到.tex文档实际上并不多。首先,我们将文档定义为文章,然后在开始结束文档中包含文章的内容。我们将包含一个标题为“ 简介”的新部分,其中包含一个静态文本“Hello World!”。我们可以使用pdflatex命令将.tex文档编译为PDF文档,并将.tex文件的名称指定为参数。生成的PDF看起来如下图所示:

我们可以看到PDF文档确实不包含很多,只包含我们实际包含的文本,没有图片,JavaScript或其他元素。

8.例1

我们来看看PDF文档结构,它在下面的输出中显示:

<span style="color:#474747">%PDF-1.5
%ÐÔÅØ
3 0 obj &lt;&lt;
/Length 138
/Filter /FlateDecode
&gt;&gt;
stream
...
endstream
endobj
10 0 obj &lt;&lt;
/Length1 1526
/Length2 7193
/Length3 0
/Length 8194
/Filter /FlateDecode
&gt;&gt;
stream
...
endstream
endobj
12 0 obj &lt;&lt;
/Length1 1509
/Length2 9410
/Length3 0
/Length 10422
/Filter /FlateDecode
&gt;&gt;
stream
...
endstream
endobj
15 0 obj &lt;&lt;
/Producer (pdfTeX-1.40.12)
/Creator (TeX)
/CreationDate (D:20121012175007+02'00')
/ModDate (D:20121012175007+02'00')
/Trapped /False
/PTEX.Fullbanner (This is pdfTeX, Version 3.1415926-2.3-1.40.12 (TeX Live 2011) kpathsea version 6.0.1)
&gt;&gt; endobj
6 0 obj &lt;&lt;
/Type /ObjStm
/N 10
/First 65
/Length 761
/Filter /FlateDecode
&gt;&gt;
stream
...
endstream
endobj
16 0 obj &lt;&lt;
/Type /XRef
/Index [0 17]
/Size 17
/W [1 2 1]
/Root 14 0 R
/Info 15 0 R
/ID [&lt;1DC2E3E09458C9B4BEC8B67F56B57B63&gt; &lt;1DC2E3E09458C9B4BEC8B67F56B57B63&gt;]
/Length 60
/Filter /FlateDecode
&gt;&gt;
stream
...
endstream
endobj
startxref
20215
%%EOF
</span>

创建这样一个简单的PDF文档有很多必要的元素,所以我们可以想象一个非常复杂的PDF文档看起来如何。我们还需要记住,为了清楚和简洁,所有编码数据流都被删除并替换为三个点(如下所示:'...')。

让我们介绍每个PDF部分。的报头中可以看到下面的图片:

机身可以看到下面的图片:

所述外部参照部分可以看出,在下面的图片:

最后,预告片部分如下所示:

我们提供了PDF文档的所有部分,但我们仍需要进一步分析它们。PDF文档的标题是标准的,我们真的不需要谈论它,让我们离开正文部分以供日后使用。这就是为什么我们必须首先看一下外部参照部分。我们可以看到从文件开头到Xref表的偏移量是20215字节,十六进制格式为0x4ef7。如果我们看一下xxd工具可以得到的文件的十六进制表示,我们可以看到下图中显示的内容:

突出显示的字节恰好位于距文件开头20125字节的开头。前面的0x0a字节是新行,当前的0x31字节表示数字1,它恰好是Xref表的开头。这就是为什么Xref表用一个ID为16且生成号为0的间接对象表示的原因(这应该是所有对象的情况,因为我们刚刚创建了PDF文档而且所有对象都没有被更改;如果我们看的话在整个PDF文档中,我们可以看到这显然是正确的;所有对象的世代号为零)。

间接对象的/ Type将其分类为外部参照表。的/索引数组包含于本节中的每个子部分的一对整数。第一个整数指定子节中的第一个对象编号,第二个整数指定子节中的条目数。在我们的示例中,对象编号为零,此子节中有17个条目。这也是由/ Size指令指定的。请注意,此数字大于子部分中任何对象编号的最大数字。的/ W属性指定表示交叉引用项中的字段的大小整数数组。[1 2 1]表示字段是一个字节,两个字节和一个字节。

之后有/ Root元素,它指定PDF文档的目录目录为对象编号14. / Info是对象编号15中包含的PDF文档的信息目录。/ ID数组是必需的,因为加密条目存在并包含两个构成文件标识符的字符串。这两个字符串用作加密算法的输入。的/长度指定比特加密密钥的长度; 该值应为40 t o128范围内的8的倍数(默认值为40)。在我们的例子中,加密密钥的长度是60位。该/过滤器指定此文档的安全性处理程序的名称; 这也是用于加密文档的安全处理程序。在我们的例子中,这是FlateDecode,它使用zlib / deflate压缩方法对数据进行编码。

我们可以看到Xref表的其他部分是压缩的,所以我们无法真正阅读它。我们当然可以在压缩数据上应用一些zlib解压缩算法,但是有更好的选择。如果工具已经存在,我们为什么要为此编写程序?使用pdftk,我们可以使用以下命令修复PDF损坏的外部参照表:

<span style="color:#474747"># pdftk in.pdf output out.pdf
</span>

之后,out.pdf文件包含以下外部参照和预告片部分:

显然,/ Root和/ Info对象编号也已更改,其他内容也已更改,但我们获得了定义Xref表的预告片外部参照关键字。我们可以看到Xref表中有14个对象。

我们可以继续尝试解码其他部分,但我想这不属于本文的范围。接下来,我们宁愿检查未编码的文档。

9.例2

我们来看一下可在此处访问的示例PDF文档:www.stluciadance.com/prospectus_file/sample.pdf。某些流对象已加密,但现在不是那么重要。既然我们已经知道如何处理PDF文档,我们就不会在简单的东西上丢失太多的话。让我们在文本编辑器中打开PDF,比如gvim,然后查看Trailer部分。我们现在必须知道所有PDF文档都应该从头到尾阅读。预告片如下图所示:

让我们也只用几个对象呈现外部参照(其余部分为了清晰起见而被丢弃):

我们可以看到PDF文档的/ Root包含在ID为221的对象中,对象222中有附加信息。对象221是整个文档中最重要的对象,所以让我们呈现它; 它可以在下图中看到:

我们可以看到该对象确实是文档目录。该页面树对象是212,轮廓对象213,对象是220和OpenAction对象是58.我们还没有谈到任何其它类型的页比树对象,因此我们将继续与页面树只谈。

具有ID 212的页面树对象如下图所示:

因此212对象包含PDF文档的实际页面。它包含10页,这是完全正确的(如果我们用任何PDF阅读器打开PDF文件并检查页数,我们可以检查这一点)。我们知道Kids属性指定了可以从当前节点直接访问的所有子元素。在我们的例子中,有两个直接子节点,对象id为66和135.对象66如下所示:

对象66包含具有ID 57,69,75,97,108和120的其他子元素。

对象135还定义了对象129,138,133和158。

如果我们计算所有元素,我们可以看到正好有10个元素,这意味着10个页面中有10个页面。这进一步意味着所有呈现的对象实际上是PDF文档的实际页面,并且不包含任何其他子节点。所有呈现的对象都是相似的声明,因此我们不会依次查看每个对象。相反,我们只看一个对象,即对象57.对象57包含声明如下:

我们可以看到对象的类型是/ Page,这直接暗示这是一个叶节点,它呈现PDF文档的一个页面。该PDF页面的内容可以在对象62中找到; 该对象如下图所示:

我们可以看到PDF页面的实际内容是用FlateDecode编码的,这只是一个简单的zlib编码算法。

10.结论

我们已经看到了两个如何构建PDF文档的例子。凭借我们获得的知识,我们可以开始生成错误的PDF文档并将其提供给各种PDF阅读器。如果某个PDF阅读器在阅读某个PDF文档时崩溃,该文档包含PDF阅读器无法处理和崩溃的内容。这意味着存在漏洞的可能性,需要进一步研究。

最后,如果存在漏洞,我们甚至可以编写包含恶意代码的PDF文档,当受害者在目标计算机上使用易受攻击的PDF阅读器打开PDF文档时执行该恶意代码。在这种情况下,整个机器可能会受到损害,因为只需打开恶意PDF文档就可以执行任意恶意代码。

 

转载来源:https://resources.infosecinstitute.com/pdf-file-format-basic-structure/

  • 6
    点赞
  • 2
    评论
  • 33
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值