From 2f5cacd57be4825a710ffe8f530423603df53c6f Mon Sep 17 00:00:00 2001 From: WhatDidYouExpect <89535984+WhatDidYouExpect@users.noreply.github.com> Date: Sat, 26 Jul 2025 15:11:41 +0200 Subject: [PATCH 01/11] forgot to push whoopsie --- main.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/main.py b/main.py index f0f3aac..4539f26 100644 --- a/main.py +++ b/main.py @@ -220,10 +220,19 @@ def main(): ip_line_map[ip] = idx + 1 for ip in ips_to_scan: print_status_line(ip, "waiting to scan...") - for ip in ips_to_scan: - if shutdown_event.is_set(): - break - scan_ports_for_ip(ip, port_start, port_end) + with ThreadPoolExecutor(max_workers=50) as ip_executor: + futures = [] + for ip in ips_to_scan: + if shutdown_event.is_set(): + break + futures.append(ip_executor.submit(scan_ports_for_ip, ip, port_start, port_end)) + + for future in as_completed(futures): + try: + future.result() + except Exception as e: + print(f"[!] error scanning IP: {e}") + bottom_line = len(ip_line_map) + 3 + len(open_port_msgs) move_cursor(bottom_line, 0) From 98cfb706cf595828cc25797e6dc3c205b14a5ad8 Mon Sep 17 00:00:00 2001 From: WhatDidYouExpect <89535984+WhatDidYouExpect@users.noreply.github.com> Date: Sat, 26 Jul 2025 16:54:35 +0200 Subject: [PATCH 02/11] swapped to golang --- main.go | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.py | 262 --------------------------------------- 2 files changed, 372 insertions(+), 262 deletions(-) create mode 100644 main.go delete mode 100644 main.py diff --git a/main.go b/main.go new file mode 100644 index 0000000..c980bfc --- /dev/null +++ b/main.go @@ -0,0 +1,372 @@ +package main +// sorry in advance for anyone who has to read this +import ( + "bufio" + "encoding/json" + "fmt" + "net" + "os" + "os/exec" + "runtime" + "strconv" + "strings" + "sync" + "time" +) + +type OpenPort struct { + IP string + Port int + Hostname string + Fingerprint string +} +const batchSize = 255 +var printMutex sync.Mutex +var ( + summaryFile *os.File + writer *bufio.Writer + fileLock sync.Mutex +) +var ( + openPorts []OpenPort + openPortsLock sync.Mutex + ipLineMap = make(map[string]int) + openPortMsgs []string +) + +func clearScreen() { + fmt.Print("\033[2J") +} + +func moveCursor(row, col int) { + fmt.Printf("\033[%d;%dH", row, col) +} + +func clearLine() { + fmt.Print("\033[K") +} + +func safePrint(format string, a ...interface{}) { + printMutex.Lock() + defer printMutex.Unlock() + fmt.Printf(format, a...) +} + +func safePrintln(a ...interface{}) { + printMutex.Lock() + defer printMutex.Unlock() + fmt.Println(a...) +} + +func printStatusLine(ip, msg string) { + if line, ok := ipLineMap[ip]; ok { + moveCursor(line, 0) + clearLine() + fmt.Printf("[%s] %s", ip, msg) + } +} + +func printOpenPortLine(msg string) { + openPortsLock.Lock() + defer openPortsLock.Unlock() + openPortMsgs = append(openPortMsgs, msg) + moveCursor(len(ipLineMap)+2+len(openPortMsgs), 0) + clearLine() + fmt.Println(msg) +} + +func isPrivateIP(ipStr string) bool { + ip := net.ParseIP(ipStr) + if ip == nil { + return false + } + privateBlocks := []string{ + "10.0.0.0/8", + "172.16.0.0/12", + "192.168.0.0/16", + "127.0.0.0/8", + } + for _, cidr := range privateBlocks { + _, block, _ := net.ParseCIDR(cidr) + if block.Contains(ip) { + return true + } + } + return false +} + + +func pingIP(ip string, pingCmd []string) bool { + cmd := exec.Command(pingCmd[0], append(pingCmd[1:], ip)...) + err := cmd.Run() + return err == nil +} + +func grabBanner(ip string, port int) string { + conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, port), 1*time.Second) + if err != nil { + return "" + } + defer conn.Close() + conn.SetReadDeadline(time.Now().Add(1 * time.Second)) + buf := make([]byte, 1024) + n, _ := conn.Read(buf) + return strings.TrimSpace(string(buf[:n])) +} + +func identifyServiceAndOS(ip string, port int) string { + data, err := os.ReadFile("services.json") + if err != nil { + return "" + } + var services map[string]map[string]string + json.Unmarshal(data, &services) + + portStr := strconv.Itoa(port) + if info, ok := services[portStr]; ok { + banner := grabBanner(ip, port) + if banner != "" { + return fmt.Sprintf("%s banner: %s", info["name"], banner) + } + return info["name"] + } + return "" +} + +func scanPort(ip string, port int, wg *sync.WaitGroup) { + printStatusLine(ip, fmt.Sprintf("scanning port %d...", port)) + conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, port), 500*time.Millisecond) + if err == nil { + conn.Close() + host, err := net.LookupAddr(ip) + hostname := "unknown hostname" + if err == nil && len(host) > 0 { + hostname = strings.TrimSuffix(host[0], ".") + } + fingerprint := identifyServiceAndOS(ip, port) + openPortsLock.Lock() + openPorts = append(openPorts, OpenPort{ip, port, hostname, fingerprint}) + line := fmt.Sprintf(" - %s : port %d open - hostname: %s", ip, port, hostname) + if fingerprint != "" { + line += " | " + fingerprint + } + + fileLock.Lock() + summaryFile.WriteString(line + "\n") + fileLock.Unlock() + openPortsLock.Unlock() + msg := fmt.Sprintf("[%s] port %d is OPEN (%s)", ip, port, hostname) + if fingerprint != "" { + msg += " | " + fingerprint + } + printOpenPortLine(msg) + printStatusLine(ip, fmt.Sprintf("open port found: %d", port)) + } +} + + +func scanPortsForIP(ip string, portStart, portEnd int) { + const maxGoroutines = 50 + guard := make(chan struct{}, maxGoroutines) + var wg sync.WaitGroup + + for port := portStart; port <= portEnd; port++ { + guard <- struct{}{} + wg.Add(1) + go func(p int) { + defer wg.Done() + scanPort(ip, p, &wg) + <-guard + }(port) + } + wg.Wait() + printStatusLine(ip, "scan done.") +} + +func pingIPsConcurrently(ips []string, pingCmd []string) []string { + var alive []string + var wg sync.WaitGroup + var lock sync.Mutex + for _, ip := range ips { + wg.Add(1) + go func(ip string) { + defer wg.Done() + if !isPrivateIP(ip) { + fmt.Printf("[+] skipping ping for public IP %s\n", ip) + lock.Lock() + alive = append(alive, ip) + lock.Unlock() + return + } + + if pingIP(ip, pingCmd) { + fmt.Printf("[+] found %s\n", ip) + lock.Lock() + alive = append(alive, ip) + lock.Unlock() + } else { + fmt.Printf("[~] no response from %s\n", ip) + } + + }(ip) + } + wg.Wait() + return alive +} + +func ipRange(start, end string) ([]string, error) { + startIP := net.ParseIP(start).To4() + endIP := net.ParseIP(end).To4() + if startIP == nil || endIP == nil { + return nil, fmt.Errorf("invalid IP") + } + + var ips []string + for ip := startIP; !ipAfter(ip, endIP); ip = nextIP(ip) { + ips = append(ips, ip.String()) + } + return ips, nil +} + +func ipAfter(a, b net.IP) bool { + for i := 0; i < 4; i++ { + if a[i] > b[i] { + return true + } + if a[i] < b[i] { + return false + } + } + return false +} + +func nextIP(ip net.IP) net.IP { + next := make(net.IP, len(ip)) + copy(next, ip) + for i := 3; i >= 0; i-- { + next[i]++ + if next[i] != 0 { + break + } + } + return next +} + +func main() { + var err error + summaryFile, err = os.Create("summary.txt") + if err != nil { + fmt.Println("[!] failed to open summary file:", err) + os.Exit(1) + } + defer summaryFile.Close() + reader := bufio.NewReader(os.Stdin) + fmt.Print("enter IP range (e.g., 192.168.1.1-192.168.1.20): ") + ipInput, _ := reader.ReadString('\n') + ipInput = strings.TrimSpace(ipInput) + if ipInput == "" { + ipInput = "192.168.0.0-192.168.255.255" + } + fmt.Print("port range (e.g., 1-65535): ") + portInput, _ := reader.ReadString('\n') + portInput = strings.TrimSpace(portInput) + if portInput == "" { + portInput = "1-10000" + } + ipParts := strings.Split(ipInput, "-") + portParts := strings.Split(portInput, "-") + if len(ipParts) != 2 || len(portParts) != 2 { + fmt.Println("[!] bad input.") + os.Exit(1) + } + ipList, err := ipRange(ipParts[0], ipParts[1]) + if err != nil { + fmt.Println("[!] bad IP range:", err) + os.Exit(1) + } + portStart, _ := strconv.Atoi(portParts[0]) + portEnd, _ := strconv.Atoi(portParts[1]) + + fmt.Println("--------------------------------------------------") + fmt.Printf("scanning %s to %s\n", ipParts[0], ipParts[1]) + fmt.Printf("ports %d to %d\n", portStart, portEnd) + fmt.Println("started at:", time.Now()) + fmt.Println("--------------------------------------------------") + + pingCmd := []string{} + switch runtime.GOOS { + case "windows": + pingCmd = []string{"ping", "-n", "1", "-w", "1000"} + case "darwin": + pingCmd = []string{"ping", "-c", "1"} + default: + pingCmd = []string{"ping", "-c", "1", "-W", "1"} + } + + fmt.Println("[~] pinging IPs...") + var alive []string + for i := 0; i < len(ipList); i += batchSize { + end := i + batchSize + if end > len(ipList) { + end = len(ipList) + } + batch := ipList[i:end] + fmt.Printf("[~] pinging IPs %d to %d...\n", i+1, end) + batchAlive := pingIPsConcurrently(batch, pingCmd) + alive = append(alive, batchAlive...) + } + if len(alive) == 0 { + fmt.Println("[-] no IPs responded to ping. exiting.") + return + } + + clearScreen() + for idx, ip := range alive { + ipLineMap[ip] = idx + 1 + printStatusLine(ip, "waiting to scan...") + } + + var wg sync.WaitGroup + for i := 0; i < len(alive); i += batchSize { + end := i + batchSize + if end > len(alive) { + end = len(alive) + } + batch := alive[i:end] + for _, ip := range batch { + wg.Add(1) + go func(ip string) { + defer wg.Done() + scanPortsForIP(ip, portStart, portEnd) + }(ip) + } + wg.Wait() + } + + moveCursor(len(ipLineMap)+3+len(openPortMsgs), 0) + clearLine() + fmt.Println("\n--------------------------------------------------") + fmt.Println("scan done at:", time.Now()) + fmt.Println("--------------------------------------------------") + + file, err := os.Create("summary.txt") + if err != nil { + fmt.Println("[!] failed to write summary:", err) + return + } + defer file.Close() + + if len(openPorts) == 0 { + file.WriteString("no open ports found.\n") + } else { + file.WriteString("[+] scan summary: open ports found with fingerprints\n") + for _, p := range openPorts { + line := fmt.Sprintf(" - %s : port %d open - hostname: %s", p.IP, p.Port, p.Hostname) + if p.Fingerprint != "" { + line += " | " + p.Fingerprint + } + file.WriteString(line + "\n") + } + } + fmt.Println("[+] scan summary written to summary.txt") +} diff --git a/main.py b/main.py deleted file mode 100644 index 4539f26..0000000 --- a/main.py +++ /dev/null @@ -1,262 +0,0 @@ -import socket -from datetime import datetime -import ipaddress -import sys -import subprocess -import platform -from concurrent.futures import ThreadPoolExecutor, as_completed -import threading -import queue -import json - -log_queue = queue.Queue() - -print_lock = threading.Lock() -ip_status_lock = threading.Lock() -shutdown_event = threading.Event() -ip_line_map = {} -open_ports = [] -open_ports_lock = threading.Lock() -open_port_msgs = [] -open_port_msgs_lock = threading.Lock() -bottom_log_start_line = 0 - -def clear_screen(): - sys.stdout.write("\033[2J") - sys.stdout.flush() - -def move_cursor(row, col=0): - sys.stdout.write(f"\033[{row};{col}H") - -def clear_line(): - sys.stdout.write("\033[K") - -def print_status_line(ip, msg): - with ip_status_lock: - line = ip_line_map.get(ip) - if line: - move_cursor(line) - clear_line() - sys.stdout.write(f"[{ip}] {msg}") - sys.stdout.flush() - -def print_open_port_line(msg): - with open_port_msgs_lock: - open_port_msgs.append(msg) - bottom_line = len(ip_line_map) + 2 + len(open_port_msgs) - move_cursor(bottom_line) - clear_line() - sys.stdout.write(msg + "\n") - sys.stdout.flush() - -def ping_ip(ip, ping_cmd): - try: - cmd = ping_cmd + [ip] - result = subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=1) - return result.returncode == 0 - except subprocess.TimeoutExpired: - return False - except: - return False - - -def is_private_ip(ip): - return ipaddress.IPv4Address(ip).is_private - -def grab_banner(ip, port): - try: - s = socket.socket() - s.settimeout(1) - s.connect((ip, port)) - if port == 22: - banner = s.recv(1024).decode(errors='ignore').strip() - return banner - elif port == 5900: - banner = s.recv(12).decode(errors='ignore').strip() - return banner - else: - return None - except: - return None - finally: - s.close() - -def identify_service_and_os(ip, port): - json_path = "services.json" - try: - with open(json_path, "r") as f: - data = json.load(f) - services = {int(k): v for k, v in data.items()} - except Exception: - services = {} - - service_info = services.get(port) - fingerprint = None - if service_info: - banner = grab_banner(ip, port) - if banner: - fingerprint = f"{service_info['name']} banner: {banner}" - else: - fingerprint = f"{service_info['name']}" - - return fingerprint - -def scan_port(ip, port): - print_status_line(ip, f"scanning port {port}...") - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.settimeout(0.5) - try: - result = s.connect_ex((ip, port)) - if result == 0: - try: - hostname = socket.gethostbyaddr(ip)[0] - except socket.herror: - hostname = "unknown hostname" - fingerprint = identify_service_and_os(ip, port) - with open_ports_lock: - open_ports.append((ip, port, hostname, fingerprint)) - msg = f"[{ip}] port {port} is OPEN ({hostname})" - if fingerprint: - msg += f" | {fingerprint}" - print_open_port_line(msg) - print_status_line(ip, f"open port found: {port}") - finally: - s.close() - -def scan_ports_for_ip(ip, port_start, port_end): - with ThreadPoolExecutor(max_workers=10) as p_exec: - futures = [p_exec.submit(scan_port, ip, port) for port in range(port_start, port_end + 1)] - for future in as_completed(futures): - if shutdown_event.is_set(): - break - try: - future.result() - except Exception as e: - with print_lock: - print(f"[!] port scan err on {ip}: {e}") - print_status_line(ip, "scan done.") - -def ping_ip_threaded(ip, ping_cmd): - if shutdown_event.is_set(): - return None - return ip if ping_ip(ip, ping_cmd) else None - -def ping_ips_concurrently(ips, ping_cmd, max_workers=50): - alive_ips = [] - with ThreadPoolExecutor(max_workers=max_workers) as executor: - futures = {executor.submit(ping_ip_threaded, ip, ping_cmd): ip for ip in ips} - for future in as_completed(futures): - if shutdown_event.is_set(): - break - ip = futures[future] - try: - result = future.result() - if result: - alive_ips.append(ip) - print(f"[+] found {ip}") - else: - print(f"[~] no response from {ip}") - except Exception as e: - print(f"[!] ping error for {ip}: {e}") - return alive_ips - -def main(): - try: - ip_range = input("enter ip range (e.g., 192.168.1.1-192.168.1.20) [default 192.168.0.0-192.168.255.255]: ").strip() - port_range = input("port range (e.g., 1-65535) [default 1-10000]: ").strip() - if ip_range == "": - ip_start_str, ip_end_str = "192.168.0.0", "192.168.255.255" - else: - ip_start_str, ip_end_str = ip_range.split('-') - if port_range == "": - port_start, port_end = 1, 10000 - else: - port_start, port_end = map(int, port_range.split('-')) - ip_start = ipaddress.IPv4Address(ip_start_str) - ip_end = ipaddress.IPv4Address(ip_end_str) - if ip_start > ip_end: - raise ValueError("start ip > end ip") - except Exception as e: - print(f"[!] bad input: {e}") - sys.exit(1) - - print("-"*60) - print(f"scanning {ip_start} to {ip_end}") - print(f"ports {port_start} to {port_end}") - print("started at:", str(datetime.now())) - print("-"*60) - - osname = platform.system().lower() - if osname == "windows": - ping_cmd = ["ping", "-n", "1", "-w", "1000"] - elif osname == "darwin": - ping_cmd = ["ping", "-c", "1"] - else: - ping_cmd = ["ping", "-c", "1", "-W", "1"] - - all_ips = [str(ipaddress.IPv4Address(i)) for i in range(int(ip_start), int(ip_end)+1)] - - any_public = False - for ip_str in all_ips: - ip_obj = ipaddress.IPv4Address(ip_str) - if not (ip_obj.is_private or ip_obj.is_loopback or ip_obj.is_reserved): - any_public = True - break - - if any_public: - print("[~] public IPs detected, skipping ping and scanning directly...") - ips_to_scan = all_ips - else: - private_ips = [ip for ip in all_ips if is_private_ip(ip)] - print("[~] pinging private IPs...") - alive_ips = ping_ips_concurrently(private_ips, ping_cmd) - if not alive_ips: - print("[-] no IPs responded to ping. exiting.") - sys.exit(0) - ips_to_scan = alive_ips - - clear_screen() - for idx, ip in enumerate(ips_to_scan): - ip_line_map[ip] = idx + 1 - for ip in ips_to_scan: - print_status_line(ip, "waiting to scan...") - with ThreadPoolExecutor(max_workers=50) as ip_executor: - futures = [] - for ip in ips_to_scan: - if shutdown_event.is_set(): - break - futures.append(ip_executor.submit(scan_ports_for_ip, ip, port_start, port_end)) - - for future in as_completed(futures): - try: - future.result() - except Exception as e: - print(f"[!] error scanning IP: {e}") - - - bottom_line = len(ip_line_map) + 3 + len(open_port_msgs) - move_cursor(bottom_line, 0) - clear_line() - - print("\n" + "-"*60) - print("scan done at:", str(datetime.now())) - print("-"*60 + "\n") - - with open("summary.txt", "w") as f: - if open_ports: - f.write("[+] scan summary: open ports found with fingerprints\n") - for ip, port, host, fingerprint in open_ports: - f.write(f" - {ip} : port {port} open - hostname: {host}") - if fingerprint: - f.write(f" | {fingerprint}") - f.write("\n") - else: - f.write("no open ports found.\n") - - print("[+] scan summary written to summary.txt :p\n") -if __name__ == "__main__": - try: - main() - except KeyboardInterrupt: - print("\n[!] ctrl+c caught. stopping...") - sys.exit(1) From 4b95f5f25f4aaef7440df89129976e768e0a2c1b Mon Sep 17 00:00:00 2001 From: WhatDidYouExpect <89535984+WhatDidYouExpect@users.noreply.github.com> Date: Sat, 26 Jul 2025 18:49:35 +0200 Subject: [PATCH 03/11] frack it why not dont ping anything --- main.go | 210 +++++++++++++++----------------------------------------- 1 file changed, 55 insertions(+), 155 deletions(-) diff --git a/main.go b/main.go index c980bfc..7b30be3 100644 --- a/main.go +++ b/main.go @@ -1,13 +1,11 @@ package main -// sorry in advance for anyone who has to read this + import ( "bufio" "encoding/json" "fmt" "net" "os" - "os/exec" - "runtime" "strconv" "strings" "sync" @@ -15,23 +13,22 @@ import ( ) type OpenPort struct { - IP string - Port int - Hostname string + IP string + Port int + Hostname string Fingerprint string } + const batchSize = 255 -var printMutex sync.Mutex + var ( - summaryFile *os.File - writer *bufio.Writer - fileLock sync.Mutex -) -var ( - openPorts []OpenPort + printMutex sync.Mutex + fileLock sync.Mutex + openPorts []OpenPort openPortsLock sync.Mutex - ipLineMap = make(map[string]int) - openPortMsgs []string + ipLineMap = make(map[string]int) + openPortMsgs []string + summaryFile *os.File ) func clearScreen() { @@ -47,15 +44,15 @@ func clearLine() { } func safePrint(format string, a ...interface{}) { - printMutex.Lock() - defer printMutex.Unlock() - fmt.Printf(format, a...) + printMutex.Lock() + defer printMutex.Unlock() + fmt.Printf(format, a...) } func safePrintln(a ...interface{}) { - printMutex.Lock() - defer printMutex.Unlock() - fmt.Println(a...) + printMutex.Lock() + defer printMutex.Unlock() + fmt.Println(a...) } func printStatusLine(ip, msg string) { @@ -75,33 +72,6 @@ func printOpenPortLine(msg string) { fmt.Println(msg) } -func isPrivateIP(ipStr string) bool { - ip := net.ParseIP(ipStr) - if ip == nil { - return false - } - privateBlocks := []string{ - "10.0.0.0/8", - "172.16.0.0/12", - "192.168.0.0/16", - "127.0.0.0/8", - } - for _, cidr := range privateBlocks { - _, block, _ := net.ParseCIDR(cidr) - if block.Contains(ip) { - return true - } - } - return false -} - - -func pingIP(ip string, pingCmd []string) bool { - cmd := exec.Command(pingCmd[0], append(pingCmd[1:], ip)...) - err := cmd.Run() - return err == nil -} - func grabBanner(ip string, port int) string { conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, port), 1*time.Second) if err != nil { @@ -134,18 +104,19 @@ func identifyServiceAndOS(ip string, port int) string { } func scanPort(ip string, port int, wg *sync.WaitGroup) { - printStatusLine(ip, fmt.Sprintf("scanning port %d...", port)) - conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, port), 500*time.Millisecond) - if err == nil { - conn.Close() - host, err := net.LookupAddr(ip) - hostname := "unknown hostname" - if err == nil && len(host) > 0 { - hostname = strings.TrimSuffix(host[0], ".") - } - fingerprint := identifyServiceAndOS(ip, port) - openPortsLock.Lock() - openPorts = append(openPorts, OpenPort{ip, port, hostname, fingerprint}) + printStatusLine(ip, fmt.Sprintf("scanning port %d...", port)) + conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, port), 500*time.Millisecond) + if err == nil { + conn.Close() + host, err := net.LookupAddr(ip) + hostname := "unknown hostname" + if err == nil && len(host) > 0 { + hostname = strings.TrimSuffix(host[0], ".") + } + fingerprint := identifyServiceAndOS(ip, port) + + openPortsLock.Lock() + openPorts = append(openPorts, OpenPort{ip, port, hostname, fingerprint}) line := fmt.Sprintf(" - %s : port %d open - hostname: %s", ip, port, hostname) if fingerprint != "" { line += " | " + fingerprint @@ -154,16 +125,16 @@ func scanPort(ip string, port int, wg *sync.WaitGroup) { fileLock.Lock() summaryFile.WriteString(line + "\n") fileLock.Unlock() - openPortsLock.Unlock() - msg := fmt.Sprintf("[%s] port %d is OPEN (%s)", ip, port, hostname) - if fingerprint != "" { - msg += " | " + fingerprint - } - printOpenPortLine(msg) - printStatusLine(ip, fmt.Sprintf("open port found: %d", port)) - } -} + openPortsLock.Unlock() + msg := fmt.Sprintf("[%s] port %d is OPEN (%s)", ip, port, hostname) + if fingerprint != "" { + msg += " | " + fingerprint + } + printOpenPortLine(msg) + printStatusLine(ip, fmt.Sprintf("open port found: %d", port)) + } +} func scanPortsForIP(ip string, portStart, portEnd int) { const maxGoroutines = 50 @@ -183,37 +154,6 @@ func scanPortsForIP(ip string, portStart, portEnd int) { printStatusLine(ip, "scan done.") } -func pingIPsConcurrently(ips []string, pingCmd []string) []string { - var alive []string - var wg sync.WaitGroup - var lock sync.Mutex - for _, ip := range ips { - wg.Add(1) - go func(ip string) { - defer wg.Done() - if !isPrivateIP(ip) { - fmt.Printf("[+] skipping ping for public IP %s\n", ip) - lock.Lock() - alive = append(alive, ip) - lock.Unlock() - return - } - - if pingIP(ip, pingCmd) { - fmt.Printf("[+] found %s\n", ip) - lock.Lock() - alive = append(alive, ip) - lock.Unlock() - } else { - fmt.Printf("[~] no response from %s\n", ip) - } - - }(ip) - } - wg.Wait() - return alive -} - func ipRange(start, end string) ([]string, error) { startIP := net.ParseIP(start).To4() endIP := net.ParseIP(end).To4() @@ -253,13 +193,14 @@ func nextIP(ip net.IP) net.IP { } func main() { - var err error - summaryFile, err = os.Create("summary.txt") - if err != nil { - fmt.Println("[!] failed to open summary file:", err) - os.Exit(1) - } - defer summaryFile.Close() + var err error + summaryFile, err = os.Create("summary.txt") + if err != nil { + fmt.Println("[!] failed to open summary file:", err) + os.Exit(1) + } + defer summaryFile.Close() + reader := bufio.NewReader(os.Stdin) fmt.Print("enter IP range (e.g., 192.168.1.1-192.168.1.20): ") ipInput, _ := reader.ReadString('\n') @@ -293,46 +234,19 @@ func main() { fmt.Println("started at:", time.Now()) fmt.Println("--------------------------------------------------") - pingCmd := []string{} - switch runtime.GOOS { - case "windows": - pingCmd = []string{"ping", "-n", "1", "-w", "1000"} - case "darwin": - pingCmd = []string{"ping", "-c", "1"} - default: - pingCmd = []string{"ping", "-c", "1", "-W", "1"} + clearScreen() + for idx, ip := range ipList { + ipLineMap[ip] = idx + 1 + printStatusLine(ip, "waiting to scan...") } - fmt.Println("[~] pinging IPs...") - var alive []string + var wg sync.WaitGroup for i := 0; i < len(ipList); i += batchSize { end := i + batchSize if end > len(ipList) { end = len(ipList) } batch := ipList[i:end] - fmt.Printf("[~] pinging IPs %d to %d...\n", i+1, end) - batchAlive := pingIPsConcurrently(batch, pingCmd) - alive = append(alive, batchAlive...) - } - if len(alive) == 0 { - fmt.Println("[-] no IPs responded to ping. exiting.") - return - } - - clearScreen() - for idx, ip := range alive { - ipLineMap[ip] = idx + 1 - printStatusLine(ip, "waiting to scan...") - } - - var wg sync.WaitGroup - for i := 0; i < len(alive); i += batchSize { - end := i + batchSize - if end > len(alive) { - end = len(alive) - } - batch := alive[i:end] for _, ip := range batch { wg.Add(1) go func(ip string) { @@ -349,24 +263,10 @@ func main() { fmt.Println("scan done at:", time.Now()) fmt.Println("--------------------------------------------------") - file, err := os.Create("summary.txt") - if err != nil { - fmt.Println("[!] failed to write summary:", err) - return - } - defer file.Close() - if len(openPorts) == 0 { - file.WriteString("no open ports found.\n") + summaryFile.WriteString("no open ports found.\n") } else { - file.WriteString("[+] scan summary: open ports found with fingerprints\n") - for _, p := range openPorts { - line := fmt.Sprintf(" - %s : port %d open - hostname: %s", p.IP, p.Port, p.Hostname) - if p.Fingerprint != "" { - line += " | " + p.Fingerprint - } - file.WriteString(line + "\n") - } + summaryFile.WriteString("[+] scan summary: open ports found with fingerprints\n") } fmt.Println("[+] scan summary written to summary.txt") } From 70d0a9948e101b44e037a472267b842592711391 Mon Sep 17 00:00:00 2001 From: WhatDidYouExpect <89535984+WhatDidYouExpect@users.noreply.github.com> Date: Sat, 26 Jul 2025 18:57:08 +0200 Subject: [PATCH 04/11] added HTTPS --- services.json | 1 + 1 file changed, 1 insertion(+) diff --git a/services.json b/services.json index d6f6b2a..8cb0264 100644 --- a/services.json +++ b/services.json @@ -11,6 +11,7 @@ "143": {"name": "IMAP"}, "161": {"name": "SNMP"}, "445": {"name": "SMB (Windows File Sharing)"}, + "443": {"name": "HTTPS"}, "1433": {"name": "MSSQL"}, "1521": {"name": "Oracle DB"}, "3306": {"name": "MySQL"}, From bc02105dfa9d23495d4e1293df073b70696cc67b Mon Sep 17 00:00:00 2001 From: WhatDidYouExpect <89535984+WhatDidYouExpect@users.noreply.github.com> Date: Sat, 26 Jul 2025 21:09:11 +0200 Subject: [PATCH 05/11] simple compile script so i dont have to type it out each time --- compile.sh | 3 ++ main.go | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 compile.sh diff --git a/compile.sh b/compile.sh new file mode 100644 index 0000000..5f996bd --- /dev/null +++ b/compile.sh @@ -0,0 +1,3 @@ +#!/bin/sh +go build -o portscraper main.go +GOOS=windows GOARCH=amd64 go build -o portscraper.exe main.go diff --git a/main.go b/main.go index 7b30be3..a151d5f 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,7 @@ package main import ( "bufio" + "bytes" "encoding/json" "fmt" "net" @@ -20,7 +21,7 @@ type OpenPort struct { } const batchSize = 255 - +var minecraftServers []string var ( printMutex sync.Mutex fileLock sync.Mutex @@ -103,6 +104,86 @@ func identifyServiceAndOS(ip string, port int) string { return "" } +func queryMinecraftServer(ip string, port int) string { + conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, port), 3*time.Second) + if err != nil { + return "" + } + defer conn.Close() + writeVarInt := func(val int) []byte { + var out []byte + for { + temp := byte(val & 0x7F) + val >>= 7 + if val != 0 { + temp |= 0x80 + } + out = append(out, temp) + if val == 0 { + break + } + } + return out + } + + protocolVersion := 754 + serverAddr := ip + state := 1 + // so confusing for me i actually had to comment stuff + var payload []byte + payload = append(payload, 0x00) // fackin packet ID for handshake + payload = append(payload, writeVarInt(protocolVersion)...) // protocol version + payload = append(payload, writeVarInt(len(serverAddr))...) // address length + payload = append(payload, []byte(serverAddr)...) // address + payload = append(payload, byte(port>>8), byte(port&0xFF)) // port + payload = append(payload, byte(state)) // next state: status + + packet := append(writeVarInt(len(payload)), payload...) // full packet = length + payload + conn.Write(packet) // send handshake + conn.Write([]byte{0x01, 0x00}) // send status request + + conn.SetReadDeadline(time.Now().Add(3 * time.Second)) + buf := make([]byte, 4096) + n, err := conn.Read(buf) + if err != nil || n == 0 { + return "" + } + + start := bytes.IndexByte(buf, '{') + if start == -1 { + return "" + } + jsonData := string(buf[start:n]) + + var status struct { + Version struct { + Name string `json:"name"` + } `json:"version"` + Description interface{} `json:"description"` + Players struct { + Online int `json:"online"` + Max int `json:"max"` + } `json:"players"` + } + + if err := json.Unmarshal([]byte(jsonData), &status); err != nil { + return "" + } + + desc := "" + switch v := status.Description.(type) { + case string: + desc = v + case map[string]interface{}: + if text, ok := v["text"].(string); ok { + desc = text + } + } + + return fmt.Sprintf("%s | %d/%d players | %s", status.Version.Name, status.Players.Online, status.Players.Max, desc) +} + + func scanPort(ip string, port int, wg *sync.WaitGroup) { printStatusLine(ip, fmt.Sprintf("scanning port %d...", port)) conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", ip, port), 500*time.Millisecond) @@ -114,7 +195,9 @@ func scanPort(ip string, port int, wg *sync.WaitGroup) { hostname = strings.TrimSuffix(host[0], ".") } fingerprint := identifyServiceAndOS(ip, port) - + if port == 25565 { + minecraftServers = append(minecraftServers, ip) + } openPortsLock.Lock() openPorts = append(openPorts, OpenPort{ip, port, hostname, fingerprint}) line := fmt.Sprintf(" - %s : port %d open - hostname: %s", ip, port, hostname) @@ -269,4 +352,16 @@ func main() { summaryFile.WriteString("[+] scan summary: open ports found with fingerprints\n") } fmt.Println("[+] scan summary written to summary.txt") + if len(minecraftServers) > 0 { + safePrintln("[*] querying Minecraft servers on port 25565...") + for _, ip := range minecraftServers { + status := queryMinecraftServer(ip, 25565) + if status != "" { + safePrintln("[MC] Server at", ip, "responded.") + summaryFile.WriteString("[MC] " + ip + ":25565 " + status + "\n") + } else { + summaryFile.WriteString("[MC] " + ip + ":25565 no response or malformed\n") + } + } + } } From 4d114889a512bfb1dabef7dfb8aa96434ff011dd Mon Sep 17 00:00:00 2001 From: WhatDidYouExpect <89535984+WhatDidYouExpect@users.noreply.github.com> Date: Sat, 26 Jul 2025 21:39:15 +0200 Subject: [PATCH 06/11] compiles for literally everything --- compile.sh | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/compile.sh b/compile.sh index 5f996bd..1e25ed2 100644 --- a/compile.sh +++ b/compile.sh @@ -1,3 +1,15 @@ #!/bin/sh -go build -o portscraper main.go -GOOS=windows GOARCH=amd64 go build -o portscraper.exe main.go + +# Existing builds +GOOS=darwin GOARCH=arm64 go build -o bin/portscraper_OSX_ARM64 main.go +GOOS=darwin GOARCH=amd64 go build -o bin/portscraper_OSX_X64 main.go +GOOS=windows GOARCH=amd64 go build -o bin/portscraper_WIN_X64_86.exe main.go +GOOS=windows GOARCH=386 go build -o bin/portscraper_WIN_X86.exe main.go +GOOS=freebsd GOARCH=amd64 go build -o bin/portscraper_FREEBSD_X64 main.go +GOOS=freebsd GOARCH=386 go build -o bin/portscraper_FREEBSD_X32 main.go +GOOS=freebsd GOARCH=arm64 go build -o bin/portscraper_FREEBSD_ARM64 main.go +GOOS=linux GOARCH=386 go build -o bin/portscraper_LINUX_X32 main.go +GOOS=linux GOARCH=amd64 go build -o bin/portscraper_LINUX_X64 main.go +GOOS=linux GOARCH=arm64 go build -o bin/portscraper_LINUX_ARM64 main.go +GOOS=linux GOARCH=arm go build -o bin/portscraper_LINUX_ARM main.go +GOOS=linux GOARCH=mipsle go build -o bin/portscraper_LINUX_MIPSLE main.go \ No newline at end of file From e59b76e4623a43b3f0409037179968e7e798ccfb Mon Sep 17 00:00:00 2001 From: WhatDidYouExpect <89535984+WhatDidYouExpect@users.noreply.github.com> Date: Sat, 26 Jul 2025 21:39:55 +0200 Subject: [PATCH 07/11] sigh --- compile.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compile.sh b/compile.sh index 1e25ed2..1989f63 100644 --- a/compile.sh +++ b/compile.sh @@ -12,4 +12,6 @@ GOOS=linux GOARCH=386 go build -o bin/portscraper_LINUX_X32 main.go GOOS=linux GOARCH=amd64 go build -o bin/portscraper_LINUX_X64 main.go GOOS=linux GOARCH=arm64 go build -o bin/portscraper_LINUX_ARM64 main.go GOOS=linux GOARCH=arm go build -o bin/portscraper_LINUX_ARM main.go -GOOS=linux GOARCH=mipsle go build -o bin/portscraper_LINUX_MIPSLE main.go \ No newline at end of file +GOOS=linux GOARCH=mipsle go build -o bin/portscraper_LINUX_MIPSLE main.go + +# Add more later \ No newline at end of file From 0235c630260d6ad19591b44212dc499d9033d03d Mon Sep 17 00:00:00 2001 From: WhatDidYouExpect <89535984+WhatDidYouExpect@users.noreply.github.com> Date: Sat, 26 Jul 2025 22:06:38 +0200 Subject: [PATCH 08/11] compiles for my stupid fucking minirouter --- compile.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compile.sh b/compile.sh index 1989f63..a1bcf7b 100644 --- a/compile.sh +++ b/compile.sh @@ -13,5 +13,9 @@ GOOS=linux GOARCH=amd64 go build -o bin/portscraper_LINUX_X64 main.go GOOS=linux GOARCH=arm64 go build -o bin/portscraper_LINUX_ARM64 main.go GOOS=linux GOARCH=arm go build -o bin/portscraper_LINUX_ARM main.go GOOS=linux GOARCH=mipsle go build -o bin/portscraper_LINUX_MIPSLE main.go +GOOS=linux GOARCH=mips go build -o bin/portscraper_LINUX_MIPS main.go -# Add more later \ No newline at end of file +# my stupid fucking router GL.iNet GL-E750 +GOOS=linux GOARCH=mips GOMIPS=softfloat CGO_ENABLED=0 go build \ + -ldflags="-s -w -extldflags '-static'" \ + -o bin/portscraper_LINUX_MIPS_SOFT main.go \ No newline at end of file From e329a754f7c25036347c2290882e4d2b0f0ba0a8 Mon Sep 17 00:00:00 2001 From: WhatDidYouExpect <89535984+WhatDidYouExpect@users.noreply.github.com> Date: Sat, 26 Jul 2025 23:09:42 +0200 Subject: [PATCH 09/11] dumbass cunt --- main.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index a151d5f..d7eb771 100644 --- a/main.go +++ b/main.go @@ -349,7 +349,10 @@ func main() { if len(openPorts) == 0 { summaryFile.WriteString("no open ports found.\n") } else { - summaryFile.WriteString("[+] scan summary: open ports found with fingerprints\n") + summaryFile.WriteString("[+] scan summary: open ports found with fingerprints above\n") + summaryFile.WriteString(fmt.Sprintf("[+] scanned %s to %s\n[+] ports %d to %d\n", ipParts[0], ipParts[1], portStart, portEnd)) + + } fmt.Println("[+] scan summary written to summary.txt") if len(minecraftServers) > 0 { From 9b95e8d9835fc871a3b80a86edbe1749b2997d43 Mon Sep 17 00:00:00 2001 From: WhatDidYouExpect <89535984+WhatDidYouExpect@users.noreply.github.com> Date: Sun, 27 Jul 2025 14:01:46 +0200 Subject: [PATCH 10/11] show more output and organized it a tiny bit --- main.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/main.go b/main.go index d7eb771..d7e5636 100644 --- a/main.go +++ b/main.go @@ -345,16 +345,6 @@ func main() { fmt.Println("\n--------------------------------------------------") fmt.Println("scan done at:", time.Now()) fmt.Println("--------------------------------------------------") - - if len(openPorts) == 0 { - summaryFile.WriteString("no open ports found.\n") - } else { - summaryFile.WriteString("[+] scan summary: open ports found with fingerprints above\n") - summaryFile.WriteString(fmt.Sprintf("[+] scanned %s to %s\n[+] ports %d to %d\n", ipParts[0], ipParts[1], portStart, portEnd)) - - - } - fmt.Println("[+] scan summary written to summary.txt") if len(minecraftServers) > 0 { safePrintln("[*] querying Minecraft servers on port 25565...") for _, ip := range minecraftServers { @@ -367,4 +357,14 @@ func main() { } } } + if len(openPorts) == 0 { + summaryFile.WriteString("no open ports found.\n") + } else { + summaryFile.WriteString("[+] scan summary: open ports found with fingerprints above\n") + summaryFile.WriteString(fmt.Sprintf("[+] scanned %s to %s\n[+] ports %d to %d\n[+] %d scanned\n[+] %d hits\n", ipParts[0], ipParts[1], portStart, portEnd, len(ipList), len(openPorts))) + + + } + fmt.Println("[+] scan summary written to summary.txt") + } From c70ec9ad9d0a031ff8c3906b142c52f29ce3bb41 Mon Sep 17 00:00:00 2001 From: WhatDidYouExpect Date: Sun, 27 Jul 2025 19:04:11 +0200 Subject: [PATCH 11/11] Aggiungi README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..c49b386 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# this is NOT for scraping public IPs +i had like zero clue that it was a legal gray zone in europe so like i suggest you do NOT use it on public ips \ No newline at end of file