Files
rdp-brute/rdpthread.cs

213 lines
7.5 KiB
C#

// 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;
}
}
}