using CommandLine; using System; using System.CodeDom; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; namespace SharpScan { class Program { public class Options { [Option('h', "hosts", Required = true, Separator = ',', HelpText = "Hosts to scan, coma separated. CIDR accepted")] public IEnumerable Hosts { get; set; } [Option('p', "ports", Required = false, Separator = ',', HelpText = "TCP port to scan, coma separated")] public IEnumerable Ports { get; set; } [Option('t', "timeout", Required = false, Default = 500, HelpText = "Timeout in milliseconds to check a port")] public int Timeout { get; set; } [Option('d', "delay", Required = false, Default = 0, HelpText = "Delay in milliseconds between 2 scan request")] public int Delay { get; set; } [Option('j', "jittler", Required = false, Default = 0, HelpText = "Jittler to apply to delay, in percent, new evalutation for each request")] public int Jittler { get; set; } [Option('r', "randomize", Required = false, Default = false, HelpText = "Randomize hosts/ports scan order. Results will be printed in normal order")] public bool Randomize { get; set; } [Option('f', "top-ports", Required = false, Default = 0, HelpText = "Equivalent of nmap --top-ports option")] public int TopPorts { get; set; } } public static List GetIpsFromCidr(string cidr) { var ipList = new List(); // Séparer l'adresse IP et le masque var parts = cidr.Split('/'); var ipAddress = parts[0]; var subnetMask = int.Parse(parts[1]); // Convertir l'adresse IP en un format numérique var ip = IPAddress.Parse(ipAddress); var ipBytes = ip.GetAddressBytes(); uint ipNumeric = BitConverter.ToUInt32(ipBytes.Reverse().ToArray(), 0); // Calculer le nombre total d'adresses IP dans le réseau uint totalAddresses = (uint)Math.Pow(2, 32 - subnetMask); // Calculer l'adresse de broadcast en ajoutant le nombre total d'adresses moins un uint broadcastIpNumeric = ipNumeric + totalAddresses - 1; // Générer les adresses IP en excluant l'adresse du réseau et de broadcast for (uint i = 1; i < totalAddresses - 1; i++) { uint currentIp = ipNumeric + i; byte[] bytes = BitConverter.GetBytes(currentIp); Array.Reverse(bytes); // Revertir l'ordre des octets pour obtenir une IP valide ipList.Add(new IPAddress(bytes).ToString()); } return ipList; } public static void Shuffle(List list) { Random rand = new Random(); int n = list.Count; while (n > 1) { n--; int k = rand.Next(n + 1); // Choisir un index aléatoire entre 0 et n T value = list[k]; list[k] = list[n]; list[n] = value; } } public static bool IsPortOpen(string hostname, int port, int timeoutMilliseconds) { using (var client = new TcpClient(AddressFamily.InterNetwork)) { var connectDone = new ManualResetEvent(false); bool connected = false; Exception connectException = null; Thread connectThread = new Thread(() => { try { client.Connect(hostname, port); connected = true; } catch (SocketException ex) { connectException = ex; connected = false; } finally { connectDone.Set(); } }); connectThread.Start(); if (!connectDone.WaitOne(timeoutMilliseconds)) { // Timeout connectThread.Abort(); // On tente d'interrompre le thread de connexion. return false; } if (connectException != null) { // La connexion a échoué. return false; } return connected; } } static void RunOptions(Options o) { List<(string address, int port)> cibles = new List<(string address, int port)>(); List addresses = new List(); List<(string address, int port)> results = new List<(string address, int port)>(); List ports = new List(); int timeout = 0; bool randomize = false; int delay = 0; int jittler = 0; int top_port = 0; // Gestion des hosts foreach (string host in o.Hosts) { if (host.Contains('/')) { addresses.AddRange(GetIpsFromCidr(host)); } else { addresses.Add(host); } } // Gestion des ports if (o.Ports.Count() > 0) { if (o.Ports.Count() == 1 && o.Ports.First() == -1) { foreach (int port in Enumerable.Range(0, 65536)) { ports.Add(port); } } else { foreach (int port in o.Ports) { ports.Add(port); } } } else { if (o.TopPorts > 0) { if (o.TopPorts <= Utils.top_ports_list.Count()) { ports = Utils.top_ports_list.GetRange(0, o.TopPorts); } else { ports = Utils.top_ports_list; } } else { ports = Utils.top_ports_list.GetRange(0, 12); } } timeout = o.Timeout; randomize = o.Randomize; delay = o.Delay; jittler = o.Jittler; top_port = o.TopPorts; // Construction des cibles foreach (string address in addresses) { foreach (int port in ports) { cibles.Add((address, port)); } } if (randomize) { Shuffle(cibles); } // Check wich ports are available Random r; int sleep_value; Console.WriteLine($"There is {cibles.Count} requests to send !!!"); int cpt = 1; Stopwatch chronometre = new Stopwatch(); chronometre.Start(); int fraction = cibles.Count / 10; int cpt_fraction = 0; // Estimation de la durée du scan int total = 0; total += ((delay + (jittler * delay / 100)) * cibles.Count) / 1000; total += (timeout * cibles.Count) / 1000; total += (2 * 100) / total; // On rajoute un chouilla pour le temps de traitement. TimeSpan temps = TimeSpan.FromSeconds(total); string total_formatee = temps.ToString(@"hh\:mm\:ss"); Console.WriteLine($"Duree estimée: {total_formatee}"); foreach ((string address, int port) in cibles) { if (cpt % fraction == 0) { cpt_fraction += 10; Console.WriteLine($"Request {cpt}/{cibles.Count} ({cpt_fraction})%"); } if (IsPortOpen(address, port, timeout)) { results.Add((address, port)); } // Sleep delay value r = new Random(); sleep_value = r.Next(delay, delay + (jittler * delay / 100)); Thread.Sleep(sleep_value); cpt += 1; } chronometre.Stop(); TimeSpan duree = chronometre.Elapsed; string dureeFormatee = duree.ToString(@"hh\:mm\:ss"); // Format : heures:minutes Console.WriteLine($"Durée (heures:minutes) : {dureeFormatee}"); // Affichage des résultats results = results.OrderBy(tuple => IPAddress.Parse(tuple.address).GetAddressBytes().Select(b => (int)b).Aggregate(0, (acc, b) => acc * 256 + b)).ThenBy(tuple => tuple.port).ToList(); string current_host = ""; Console.WriteLine("\n ===[ SCAN RESULTS ]==="); foreach ((string address, int port) in results) { if (!(address == current_host)) { Console.WriteLine($"\n{address}"); current_host = address; } Console.WriteLine($" {port} opened ({Utils.GetDesc(port)})"); } } static void HandleParseError(IEnumerable errs) { //handle errors } static void Main(string[] args) { CommandLine.Parser.Default.ParseArguments(args) .WithParsed(RunOptions) .WithNotParsed(HandleParseError); } } }