123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- /*
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
- kyoketsu, a Client-To-Client Network Enumeration System
- Copyright (C) 2024 Russell Hrubesky, ChiralWorks Software LLC
- Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License,
- or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- package kyoketsu
- import (
- "fmt"
- "net"
- "strconv"
- "strings"
- "sync"
- "time"
- )
- /*
- Need to work with with a database schema in mind, and revolve functionality around that
- */
- type Host struct {
- Fqdn string // The FQDN of the address targeted as per the systems default resolver
- IpAddress string // the IPv4 address (no ipv6 support yet)
- PingResponse bool // boolean value representing if the host responded to ICMP
- ListeningPorts map[int]string // list of maps depicting a port number -> service name
- PortString string
- Id int64
- }
- /*
- Perform a concurrent TCP port dial on a host, either by domain name or IP.
- :param addr: the address of fqdn to scan
- :param portmap: a key/value pair of port numbers to service names to dial the host with
- */
- func PortWalk(addr string, portmap map[int]string) Host {
- wg := &sync.WaitGroup{}
- mu := &sync.Mutex{}
- out := map[int]string{}
- for p, s := range portmap {
- wg.Add(1)
- go func(target string, p int, s string, mu *sync.Mutex) {
- defer wg.Done()
- scanout := singlePortScan(target, p, s)
- if scanout.Listening {
- mu.Lock()
- out[scanout.PortNumber] = scanout.Service
- mu.Unlock()
- }
- }(addr, p, s, mu)
- }
- wg.Wait()
- var dnames string
- var portstring string
- dns, _ := net.LookupAddr(addr)
- dnames = strings.Join(dns, ", ")
- for key, _ := range out {
- portstring = portstring + "," + strconv.Itoa(key)
- }
- return Host{
- IpAddress: addr,
- Fqdn: dnames,
- PingResponse: false,
- ListeningPorts: out,
- PortString: portstring,
- }
- }
- type PortScanResult struct {
- // This is used to represent the results of a port scan against one host
- PortNumber int `json:"port_number"` // The port number that was scanned
- Service string `json:"service"` // the name of the service that the port was identified/mapped to
- Protocol string `json:"protocol"` // The IP protocol (TCP/UDP)
- Listening bool `json:"listening"` // A boolean value that depicts if the service is listening or not
- }
- /*
- Wrapper function to dependency inject the resource for a port -> service name mapping.
- May move to a database, or something.
- */
- func RetrieveScanDirectives() map[int]string {
- var portmap = map[int]string{
- 22: "ssh", 23: "telnet", 53: "dns", 80: "http", 25: "smtp", 443: "https", 8080: "unknown", 8081: "unknown",
- 8082: "unknown", 8085: "unknown", 8090: "unknown", 8091: "unknown", 9010: "unknown", 9012: "unknown", 10000: "unknown", 1433: "microsoft_sql",
- 3306: "mysql", 3050: "firebird", 5432: "postgres", 27017: "mongo", 6379: "redis", 8005: "tomcat", 6443: "kubernetes", 853: "dns-tls", 143: "imap",
- 389: "ldap", 445: "smb", 543: "kerberos", 544: "kerberos", 749: "kerberos", 760: "kerberos",
- }
- return portmap
- }
- /*
- Scans a single host on a single port
- :param addr: the address to dial
- :param port: the port number to dial
- :param svcs: the name of the service that the port is associate with
- */
- func singlePortScan(addr string, port int, svcs string) PortScanResult {
- address := fmt.Sprintf("%v:%d", addr, port)
- _, err := net.DialTimeout("tcp", address, 2*time.Second)
- if err != nil {
- return PortScanResult{PortNumber: port, Protocol: "tcp", Service: svcs, Listening: false}
- }
- return PortScanResult{PortNumber: port, Protocol: "tcp", Service: svcs, Listening: true}
- }
- /*
- Perform a port scan sweep across an entire subnet
- :param ip: the IPv4 address WITH CIDR notation
- :param portmap: the mapping of ports to scan with (port number mapped to protocol name)
- */
- func NetSweep(ips []net.IP, portmap map[int]string, scanned chan Host) {
- wg := &sync.WaitGroup{}
- for i := range ips {
- wg.Add(1)
- go func(target string, wg *sync.WaitGroup) {
- defer wg.Done()
- scanned <- PortWalk(target, portmap)
- }(ips[i].String(), wg)
- }
- wg.Wait()
- }
|