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 diff --git a/compile.sh b/compile.sh new file mode 100644 index 0000000..a1bcf7b --- /dev/null +++ b/compile.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +# 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 +GOOS=linux GOARCH=mips go build -o bin/portscraper_LINUX_MIPS main.go + +# 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 diff --git a/main.go b/main.go index 7b30be3..d7e5636 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) @@ -262,11 +345,26 @@ func main() { fmt.Println("\n--------------------------------------------------") fmt.Println("scan done at:", time.Now()) fmt.Println("--------------------------------------------------") - + 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") + } + } + } 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[+] %d scanned\n[+] %d hits\n", ipParts[0], ipParts[1], portStart, portEnd, len(ipList), len(openPorts))) + + } fmt.Println("[+] scan summary written to summary.txt") + } 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"},