ソースを参照

working on UI stuff and tweaking how the program works

aeth 10 ヶ月 前
コミット
60c35dfbf6
6 ファイル変更176 行追加37 行削除
  1. 12 0
      cmd/kyoketsu/banner.txt
  2. 122 20
      cmd/kyoketsu/kyoketsu.go
  3. 3 0
      go.mod
  4. 9 0
      go.sum
  5. 21 0
      pkg/local.go
  6. 9 17
      pkg/scanner.go

+ 12 - 0
cmd/kyoketsu/banner.txt

@@ -0,0 +1,12 @@
+      ___           ___           ___           ___           ___           ___           ___           ___     
+     /\__\         |\__\         /\  \         /\__\         /\  \         /\  \         /\  \         /\__\    
+    /:/  /         |:|  |       /::\  \       /:/  /        /::\  \        \:\  \       /::\  \       /:/  /    
+   /:/__/          |:|  |      /:/\:\  \     /:/__/        /:/\:\  \        \:\  \     /:/\ \  \     /:/  /     
+  /::\__\____      |:|__|__   /:/  \:\  \   /::\__\____   /::\~\:\  \       /::\  \   _\:\~\ \  \   /:/  /  ___ 
+ /:/\:::::\__\     /::::\__\ /:/__/ \:\__\ /:/\:::::\__\ /:/\:\ \:\__\     /:/\:\__\ /\ \:\ \ \__\ /:/__/  /\__\
+ \/_|:|~~|~       /:/~~/~    \:\  \ /:/  / \/_|:|~~|~    \:\~\:\ \/__/    /:/  \/__/ \:\ \:\ \/__/ \:\  \ /:/  /
+    |:|  |       /:/  /       \:\  /:/  /     |:|  |      \:\ \:\__\     /:/  /       \:\ \:\__\    \:\  /:/  / 
+    |:|  |       \/__/         \:\/:/  /      |:|  |       \:\ \/__/     \/__/         \:\/:/  /     \:\/:/  /  
+    |:|  |                      \::/  /       |:|  |        \:\__\                      \::/  /       \::/  /   
+     \|__|                       \/__/         \|__|         \/__/                       \/__/         \/__/    
+                                                                                                                

+ 122 - 20
cmd/kyoketsu/kyoketsu.go

@@ -28,12 +28,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
 package main
 
 import (
+	"embed"
+	"encoding/json"
+	"errors"
 	"flag"
 	"fmt"
 	"log"
+	"net"
 	"os"
+	"strconv"
+	"strings"
+	"sync"
+	"time"
 
 	kyoketsu "git.aetherial.dev/aeth/kyoketsu/pkg"
+	"github.com/fatih/color"
 	"github.com/manifoldco/promptui"
 )
 
@@ -43,51 +52,144 @@ var redistMsg = "\n	This program is free software: you can redistribute it and/o
 
 var licenseMsgLong = "\n		GNU GENERAL PUBLIC LICENSE\n		Version 3, 29 June 2007\n	Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n	Everyone is permitted to copy and distribute verbatim copies\n	of this license document, but changing it is not allowed.\n\n	kyoketsu, An HTTP Proxying framework for bypassing DNS Security\n	Copyright (C) 2024 Russell Hrubesky, ChiralWorks Software LLC\n\n	This program is free software: you can redistribute it and/or modify\n	it under the terms of the GNU General Public License as published by\n	the Free Software Foundation, either version 3 of the License, or\n	(at your option) any later version.\n\n	This program is distributed in the hope that it will be useful,\n	but WITHOUT ANY WARRANTY; without even the implied warranty of\n	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n	GNU General Public License for more details.\n\n	You should have received a copy of the GNU General Public License\n	along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n"
 
+//go:embed banner.txt
+var banner embed.FS
+
 func main() {
 
 	licenseInfo := flag.Bool("license", false, "Pass this flag to display license and warantee information.")
 	redistInfo := flag.Bool("redist", false, "Pass this flag to display redistribution information.")
+	interactive := flag.Bool("i", false, "Pass this flag to run in interactive mode, which will let you define network parameters")
+	output := flag.String("output", "", "Pass path and filename to output the data too after the program exits.")
 	flag.Parse()
 
 	if *licenseInfo {
 		fmt.Println(licenseMsgLong)
 		os.Exit(0)
 	}
+
 	if *redistInfo {
 		fmt.Println(redistMsg)
 		os.Exit(0)
 	}
+
 	fmt.Println(licenseMsg)
 
-	var err error
-	localAddr, err := kyoketsu.RetrieveLocalAddresses()
+	banner, err := banner.ReadFile("banner.txt")
 	if err != nil {
-		log.Fatal(err)
-	}
-	prompt := promptui.Select{
-		Label: "Select the network you wish to scan",
-		Items: localAddr.Choice,
-	}
-	choice, _, err := prompt.Run()
-	if err != nil {
-		log.Fatal(err)
-	}
-	var addr kyoketsu.IpSubnetMapper
-	targetNet := fmt.Sprintf("%s/%s", localAddr.Choice[choice].HostAddress, localAddr.Choice[choice].Cidr)
-	addr, err = kyoketsu.GetNetworkAddresses(targetNet)
-	if err != nil {
-		log.Fatal(err)
+		log.Fatal(err, "couldnt read from the embedded banner file!\n")
 	}
+
+	fmt.Printf("%+v\n", string(banner))
 	scanned := make(chan kyoketsu.Host)
+	outform := []kyoketsu.Host{}
+	mu := &sync.Mutex{}
 	go func() {
+		green := color.New(color.FgHiGreen).Add(color.Bold)
 
 		for x := range scanned {
 			if len(x.ListeningPorts) > 0 {
-				fmt.Print(" |-|-|-| :::: HOST FOUND :::: |-|-|-|\n==================||==================\n")
-				fmt.Printf("IPv4 Address: %s\nFully Qualified Domain Name: %s\nListening Ports: %v\n=====================================\n", x.IpAddress, x.Fqdn, x.ListeningPorts)
+				green.Printf("Host found. IPv4 .... %s\n", x.IpAddress)
+				green.Printf("Domain name .... %s\n", x.Fqdn)
+				green.Printf("Listening Ports .... %v\n\n", x.ListeningPorts)
+				if *output != "" {
+					if mu.TryLock() {
+						outform = append(outform, x)
+						mu.Unlock()
+					}
+				}
 			}
 		}
 	}()
-	kyoketsu.NetSweep(addr.Ipv4s, addr.Mask, kyoketsu.RetrieveScanDirectives(), scanned)
+
+	if *interactive {
+		localAddr, err := kyoketsu.RetrieveLocalAddresses()
+		if err != nil {
+			log.Fatal(err)
+		}
+
+		searcher := func(input string, index int) bool {
+			address := localAddr.Choice[index]
+			return strings.Contains(address.NetworkAddress, input)
+		}
+
+		prompt := promptui.Select{
+			Label:     "Visible networks on current host:",
+			Items:     localAddr.Choice,
+			Templates: kyoketsu.TuiTemplate(),
+			Size:      len(localAddr.Choice),
+			Searcher:  searcher,
+		}
+		choice, _, err := prompt.Run()
+		if err != nil {
+			log.Fatal(err)
+		}
+
+		targetNet := fmt.Sprintf("%s/%s", localAddr.Choice[choice].HostAddress, localAddr.Choice[choice].Cidr)
+		subnet, err := kyoketsu.GetNetworkAddresses(targetNet)
+		if err != nil {
+			log.Fatal(err)
+		}
+		kyoketsu.NetSweep(subnet.Ipv4s, subnet.Mask, kyoketsu.RetrieveScanDirectives(), scanned)
+		os.Exit(0)
+	} else {
+		red := color.New(color.FgRed)
+		boldRed := red.Add(color.Bold)
+		ipValidate := func(input string) error {
+			if net.ParseIP(input).To4() == nil {
+				return errors.New(boldRed.Sprint("Please pass a valid IPv4 Address"))
+			}
+			return nil
+		}
+
+		prompt := promptui.Prompt{
+			Label:    "Enter IP address",
+			Validate: ipValidate,
+		}
+		ip, err := prompt.Run()
+		if err != nil {
+			log.Fatal(err)
+		}
+		cidrValidate := func(input string) error {
+			cidrInt, err := strconv.Atoi(strings.TrimPrefix(input, "/"))
+			if err != nil {
+				return err
+			}
+			if cidrInt < 12 {
+				return errors.New(boldRed.Sprint("Woah there partner, that's a pretty zesty IP range. Maybe try a smaller block?"))
+			}
+			if cidrInt > 32 {
+				return errors.New(boldRed.Sprint("That was a bad CIDR prefix. Careful not to skill issue yourself."))
+			}
+			return nil
+		}
+		prompt = promptui.Prompt{
+			Label:    "Enter corresponding CIDR notation",
+			Validate: cidrValidate,
+		}
+		mask, err := prompt.Run()
+		if err != nil {
+			log.Fatal(err)
+		}
+		targetNet := fmt.Sprintf("%s/%s", ip, strings.TrimPrefix(mask, "/"))
+		subnet, err := kyoketsu.GetNetworkAddresses(targetNet)
+		if err != nil {
+			log.Fatal(err)
+		}
+		start := time.Now()
+		kyoketsu.NetSweep(subnet.Ipv4s, subnet.Mask, kyoketsu.RetrieveScanDirectives(), scanned)
+
+		fmt.Printf("Time elapsed: %s", time.Since(start))
+		if *output != "" {
+			mu.Lock()
+			b, err := json.Marshal(&outform)
+			if err != nil {
+				log.Fatal(err)
+			}
+			os.WriteFile(*output, b, os.ModePerm)
+		}
+		os.Exit(0)
+
+	}
 
 }

+ 3 - 0
go.mod

@@ -4,6 +4,7 @@ go 1.21.1
 
 require (
 	github.com/chzyer/readline v1.5.1 // indirect
+	github.com/fatih/color v1.16.0 // indirect
 	github.com/go-ping/ping v1.1.0 // indirect
 	github.com/golang/snappy v0.0.1 // indirect
 	github.com/google/go-cmp v0.6.0 // indirect
@@ -12,6 +13,8 @@ require (
 	github.com/ianlancetaylor/demangle v0.0.0-20240312041847-bd984b5ce465 // indirect
 	github.com/klauspost/compress v1.13.6 // indirect
 	github.com/manifoldco/promptui v0.9.0 // indirect
+	github.com/mattn/go-colorable v0.1.13 // indirect
+	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/mattn/go-sqlite3 v1.14.22 // indirect
 	github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
 	github.com/xdg-go/pbkdf2 v1.0.0 // indirect

+ 9 - 0
go.sum

@@ -6,6 +6,8 @@ github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI
 github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
+github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
+github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
 github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw=
 github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
 github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
@@ -22,6 +24,11 @@ github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQ
 github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
 github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
 github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
 github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
 github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
@@ -63,6 +70,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
 golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=

+ 21 - 0
pkg/local.go

@@ -35,6 +35,9 @@ import (
 	"net/netip"
 	"strconv"
 	"strings"
+
+	"github.com/fatih/color"
+	"github.com/manifoldco/promptui"
 )
 
 const IPV4_BITLEN = 32
@@ -238,3 +241,21 @@ func RetrieveLocalAddresses() (TuiSelectionFeed, error) {
 	return tuidata, nil
 
 }
+
+// This is a helper function to return the TUI template for interactive mode
+func TuiTemplate() *promptui.SelectTemplates {
+	green := color.New(color.FgGreen).Add(color.Bold)
+	templ := &promptui.SelectTemplates{
+		Label:    "{{ . }}",
+		Active:   green.Sprint("      Network Address: {{ .NetworkAddress }}"),
+		Inactive: "    {{ .NetworkAddress}}",
+		Selected: green.Sprint("    {{ .NetworkAddress }}"),
+		Details: ` 
+{{ "Network Address: " | green | bold }}    {{ .NetworkAddress }}   
+{{ "Interface Name: " | green | bold }}    {{ .InterfaceName }}   
+{{ "Mac Address: " | green | bold }}    {{ .MacAddress }}
+{{ "Subnet Mask: " | green | bold }}    {{ .SubnetMask }}
+{{ "CIDR Notation: " | green | bold }}  /{{ .Cidr }}`,
+	}
+	return templ
+}

+ 9 - 17
pkg/scanner.go

@@ -25,7 +25,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
 package kyoketsu
 
 import (
-	"context"
 	"fmt"
 	"log"
 	"net"
@@ -99,6 +98,7 @@ func singlePortScan(addr string, port int) int {
 		return 0
 		//	return PortScanResult{PortNumber: port, Protocol: "tcp", Listening: false}
 	}
+	fmt.Printf("Host %s responded.\n", addr)
 	conn.Close()
 	return port
 	//return PortScanResult{PortNumber: port, Protocol: "tcp", Listening: true}
@@ -112,26 +112,18 @@ Perform a port scan sweep across an entire subnet
 */
 func NetSweep(ips []net.IP, cidr int, ports []int, scanned chan Host) {
 	wg := &sync.WaitGroup{}
-	killswitch, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second))
-	defer cancel()
 	network := getNetwork(ips[0].String(), cidr)
 	for i := range ips {
 		wg.Add(1)
 		go func(target string, ntwrk string, portnum []int, wgrp *sync.WaitGroup, output chan Host) {
-			select {
-			case <-killswitch.Done():
-				fmt.Println("UNTO DEATH :::: WHILE THE SUN BEAMS DOWN")
-				return
-			default:
-				defer wgrp.Done()
-				portscanned := PortWalk(target, portnum)
-				output <- Host{
-					Fqdn:           getFqdn(target),
-					IpAddress:      target,
-					ListeningPorts: portscanned,
-					PortString:     strings.Trim(strings.Join(strings.Fields(fmt.Sprint(portscanned)), ","), "[]"),
-					Network:        ntwrk,
-				}
+			defer wgrp.Done()
+			portscanned := PortWalk(target, portnum)
+			output <- Host{
+				Fqdn:           getFqdn(target),
+				IpAddress:      target,
+				ListeningPorts: portscanned,
+				PortString:     strings.Trim(strings.Join(strings.Fields(fmt.Sprint(portscanned)), ","), "[]"),
+				Network:        ntwrk,
 			}
 		}(ips[i].String(), network, ports, wg, scanned)