-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathapi-whoami.py
executable file
·166 lines (143 loc) · 6.57 KB
/
api-whoami.py
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/usr/bin/env python3
import argparse
import re
import slack_sdk
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
print("====== Welcome to API Whoami ======\n")
ap = argparse.ArgumentParser()
ap.add_argument("-a", "--apikey", required=True, help="Define apikey to lookup")
ap.add_argument("-v", "--verbose", action="store_true", help="We display the output of all API calls after the Overview")
args = vars(ap.parse_args())
api_key = args['apikey']
verbose = args['verbose']
print("[*] Guessing API key: {}".format(api_key))
guess_prefix_dict = {
"slack-bot" : "xoxb-",
"slack-user": "xoxp-",
"slack-work": "xoxa-2",
"slack-web": "xoxc-",
"slack-unknown": "xoxs-"
}
def main():
platform = guess_api_key(api_key)
if not platform:
print("[X] api key not recongised")
exit()
print("[\u2713] Guessing API key done.. Platform is {}".format(platform))
print("[*] Trying to get details for API key.")
info = get_more_info(api_key, platform)
if len(info) == 0:
print("[X] No details found using this key. Im sorry")
exit()
print("[\u2713] API Key Overview: \n{}".format(info['overview']))
if verbose:
print("[\u2713] Below details were found: \n{}".format(info if 'summary' not in info else info['summary']))
print("[*] Thanks for using API-Whoami.")
else:
print("[*] Thanks for using API-Whoami. If you would like to see all the results of the APIs used, try --verbose")
def get_more_info(api_key, platform):
"""
Here we try use the key or get some information from the key by
hitting platform specific endpoints that may leak some info to us.
"""
results = {}
if platform.startswith('slack-'):
results.update(_get_more_slack_info(api_key, platform))
return results
def _get_more_slack_info(api_key, platform):
client = slack_sdk.WebClient(token=api_key)
# We start a couple api calls to try get a feel for what we can do with this api key
data = {}
try:
## auth_test : https://slack.com/api/auth.test => check response at https://api.slack.com/methods/auth.test
## this works with both bot and user api tokens
data['auth_test'] = client.auth_test().data
except slack_sdk.errors.SlackApiError as e:
data['auth_test'] = e.response
if 'error' in data['auth_test']:
return _intepret_responses_slack(data, platform)
try:
## users_info : https://slack.com/api/users.info => check response at https://api.slack.com/methods/users.info
## note: only works with user token type with `users:read` scope, and bot token type with `bot` scope
if 'user_id' in data['auth_test']:
data['users_info'] = client.users_info(user=data['auth_test']['user_id']).data
else:
data['users_info'] = client.users_info(user="asdzxciu").data
except slack_sdk.errors.SlackApiError as e:
data['users_info'] = e.response
try:
## conversations_info : https://slack.com/api/conversations.info => check response at https://api.slack.com/methods/conversations.info
## note: only works with user token type with `channels:read, groups:read, im:read, mpim:read` scope, and bot token type with `bot` scope
data['conversations_info'] = client.conversations_info(channel="ASDJALKSBNCX123")
except slack_sdk.errors.SlackApiError as e:
data['conversations_info'] = e.response
try:
## users_identity : https://slack.com/api/users.identity => check response at https://api.slack.com/methods/users.identity
## note: only works with user token type with `identity.basic` scope and NOT bot token type.
data['users_identity'] = client.users_identity()
except slack_sdk.errors.SlackApiError as e:
data['users_identity'] = e.response
except slack_sdk.errors.BotUserAccessError as e:
data['users_identity'] = {'token' :'Bot Token cannot user users_identity API'}
return _intepret_responses_slack(data, platform)
def _intepret_responses_slack(data, platform):
d = {}
d['raw'] = data
d['overview'] = "▶ Slack API Token Overview:\n\t\tToken Type: {key}\n\t\t".format(key=platform.split('-')[1].upper())
if 'error' in data['auth_test']:
d['overview'] += "Permissions: {perms}\n\t\t".format(perms="This token has been revoked already.")
overview = {}
d['summary'] = " ▼ Slack API Token Summary:"
for key in data.keys():
if 'error' in data[key] and data[key]['error'] == 'missing_scope':
overview['permissions_provided'] = data[key]['provided']
d['summary'] += _add_api_response_to_summary(key, data[key])
if 'permissions_provided' in overview:
d['overview'] += "Permissions: {perms}\n\t\t".format(perms=overview['permissions_provided'])
if 'users_identity' in data and data['users_identity'].get('token'):
d['overview'] += "Permissions: {perms}\n\t\t".format(perms="Bots have many permissions")
d['overview'] += "Read about the allowed bot permissions here: https://api.slack.com/bot-users#methods"
return d
def _add_api_response_to_summary(api, resp, heading=True):
s = "\n\t▶ API {} returned:\n\t\t".format(api) if heading else " "
if type(resp) == slack_sdk.web.slack_response.SlackResponse:
keys = resp.data.keys()
else:
keys = resp.keys()
for k in keys:
if type(resp[k]) == bool:
# this if is specifically slack based; we may need to add for others
if k == 'ok' or not resp[k]:
continue
s += (' '.join(k.split('_')))+'\n\t\t'
elif type(resp[k]) == dict:
s += _add_api_response_to_summary(k, resp[k], heading=False)
else:
s += "{}: {}\n\t\t".format(k, resp[k])
return s
## we should consider some bot only api calls
### https://api.slack.com/bot-users#methods
## interesting slack api calls to come back to look at:
### https://api.slack.com/methods/team.integrationLogs
### https://api.slack.com/methods/team.accessLogs
def guess_api_key(api_key):
"""
Here we guess by some heuristics what platform/company this API
key belongs to.
"""
# print("**** starting initial guesses ****")
for platform, key_pattern in guess_prefix_dict.items():
p = re.compile(key_pattern+'\w+', re.IGNORECASE)
m = p.match(api_key)
if m:
return platform
return None
class Platform(object):
def __init__(self, platform, api_key):
self.platform = platform
self.key = api_key
def get_more_info(self,):
pass
if __name__ == "__main__":
main()