From b94123500776473b8f2a64926c6f08d68f271bec Mon Sep 17 00:00:00 2001 From: Kevin F Date: Mon, 13 Mar 2023 13:24:02 -0500 Subject: [PATCH] Moved control commands to their own file Delimit all messages to fix fifo race condition --- Client.md | 28 ++++++++++++++-------------- Makefile | 4 +++- ReadMe.md | 2 +- server/Sendkeys.md | 12 ++++++------ server/Server.md | 1 - server/Streaming.md | 8 +++++--- server/StringCommands.md | 37 +++++++++++++++++++++++++++++++++++++ server/XdotoolCommands.md | 10 +++++----- tools/RawCapture.md | 6 +++--- 9 files changed, 74 insertions(+), 34 deletions(-) create mode 100644 server/StringCommands.md diff --git a/Client.md b/Client.md index 551359c..09399ec 100644 --- a/Client.md +++ b/Client.md @@ -7,12 +7,11 @@ When the GoSmartKeyboard client is started, it does the following: 3. Connect to the server. 4 Send the auth token to the server. 5. If the server responds with "authenticated", we start reading keys from stdin and sending them to the server until EOF. -6. If KEYBOARD_FIFO is specified as an environment variable, we read from the path specified there instead as a named pipe. - + 5.1 If the environment variable `KEYBOARD_FIFO` is set, we read from the path specified there instead as a named pipe. + 5.2 Regardless, each message is sent to the server with the prefix `@{payload delimiter}`. ``` go --- handle client command - if len(os.Args) > 1 { @{get client fifo input file from environment} @{setup client} @@ -36,6 +35,7 @@ The base64 authentication token is loaded from the environment variable `KEYBOAR --- setup client +@{handle version command} @{load connection URL from second CLI argument} @{get authTokenInput from environment} @{add xdotool if non qwerty function} @@ -91,23 +91,24 @@ if !strings.HasPrefix(connectionURL, "ws://") && !strings.HasPrefix(connectionUR ## Sending keys from a named pipe + +We create a fifo and then continuously read from it in a loop. + ``` go --- start client with fifo - -var inputString string - syscall.Mkfifo(clientFifoInputFile, syscall.S_IFIFO|0666) +inputString := "" for { - input, err := ioutil.ReadFile(clientFifoInputFile) + readData, err := ioutil.ReadFile(clientFifoInputFile) if err != nil { log.Fatal(err) } - inputString = addXDoToolIfNonQWERTY(string(input)) - input = []byte(inputString) + + inputString = addXDoToolIfNonQWERTY(string(readData)) + input := []byte("@{payload delimiter}" + inputString) if len(input) > 0 { - fmt.Println("send" + strings.Replace(string(input), " ", "space", 10)) err = client.WriteMessage(websocket.TextMessage, input) if err != nil { log.Fatal("write:", err) @@ -146,8 +147,7 @@ for { } log.Fatal(err) } - fmt.Println("send" + strings.Replace(key, " ", "space", 10)) - err = client.WriteMessage(websocket.TextMessage, []byte(key)) + err = client.WriteMessage(websocket.TextMessage, []byte("@{payload delimiter}" + key)) if err != nil { log.Fatal("write:", err) } @@ -164,13 +164,13 @@ for { --- add xdotool if non qwerty function --- noWeave addXDoToolIfNonQWERTY := func(message string)(string) { - if strings.HasPrefix(message, "{kb_cmd:xdotool}:") { + if strings.HasPrefix(message, "@{use xdotool cmd}") { return message } for _, char := range message { if char < 32 || char > 126 { if char != 8 && char != 9 && char != 10 { - return "{kb_cmd:xdotool}:" + message + return "@{use xdotool cmd}" + message } } } diff --git a/Makefile b/Makefile index 35bbee8..a24ef1b 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,13 @@ weave: srcweave --formatter srcweave-format --weave docs/ ReadMe.md Building.md Dependencies.md EnvironmentVariables.md LICENSE.md \ security/Authentication.md security/ThreatModel.md Plumbing.md server/Server.md server/Streaming.md server/Sendkeys.md server/XdotoolCommands.md \ + server/StringCommands.md Client.md tools/Tools.md tools/Editor.md tools/Input.md tools/RawCapture.md tools/TUI.md util/clean.py tangle: srcweave --formatter srcweave-format --tangle smartkeyboard/ ReadMe.md Plumbing.md security/Authentication.md EnvironmentVariables.md Dependencies.md \ - server/Server.md server/Streaming.md server/Sendkeys.md server/XdotoolCommands.md security/ThreatModel.md Client.md tools/Tools.md tools/Editor.md tools/Input.md \ + server/Server.md server/Streaming.md server/Sendkeys.md server/XdotoolCommands.md server/StringCommands.md \ + security/ThreatModel.md Client.md tools/Tools.md tools/Editor.md tools/Input.md \ tools/RawCapture.md tools/TUI.md clean: rm -rf docs diff --git a/ReadMe.md b/ReadMe.md index a67e28a..97fc3fd 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -6,7 +6,7 @@ Copyright [Kevin Froman](https://chaoswebs.net/) [Licensed under GPLv3](LICENSE. Work in progress --- version -0.0.1 +2.0.0 --- diff --git a/server/Sendkeys.md b/server/Sendkeys.md index b61a7c3..ed84b93 100644 --- a/server/Sendkeys.md +++ b/server/Sendkeys.md @@ -5,14 +5,14 @@ --- do streaming keylogger approach key := "" -if strings.HasPrefix(message_string, "{KEYDWN}") { - key = strings.TrimPrefix(string(message_string), "{KEYDWN}") +if strings.HasPrefix(message_string, "@{keydown cmd}") { + key = strings.TrimPrefix(string(message_string), "@{keydown cmd}") k.Write(1, key) -} else if strings.HasPrefix(message_string, "{KEYUP}") { - key = strings.TrimPrefix(string(message_string), "{KEYUP}") +} else if strings.HasPrefix(message_string, "@{keyup cmd}") { + key = strings.TrimPrefix(string(message_string), "@{keyup cmd}") k.Write(0, key) -} else if strings.HasPrefix(message_string, "{KEYHLD}") { - key = strings.TrimPrefix(string(message_string), "{KEYHLD}") +} else if strings.HasPrefix(message_string, "@{keyheld cmd}") { + key = strings.TrimPrefix(string(message_string), "@{keyheld cmd}") k.Write(2, key) } else{ for _, key := range message_string { diff --git a/server/Server.md b/server/Server.md index 37a98df..0c9867f 100644 --- a/server/Server.md +++ b/server/Server.md @@ -102,7 +102,6 @@ package server import( "net" - "time" "os" "os/exec" "strings" diff --git a/server/Streaming.md b/server/Streaming.md index 9d28a84..2adfd57 100644 --- a/server/Streaming.md +++ b/server/Streaming.md @@ -6,7 +6,7 @@ Most of the time, we can use the keylogger library (which uses uinput) to effeci xdotool spawns a new process for each keypress, so it's not as effecient as keylogger. -To specify xdotool usage, the client should send a message with the format `{kb_cmd:xdotool}:message` where message is a utf-8 string. +To specify xdotool usage, the client should send a message with the format `@{use xdotool cmd}message` where message is a utf-8 string. ``` go --- streaming keyboard input @@ -67,8 +67,10 @@ func clientConnected(w http.ResponseWriter, r *http.Request) { if message_string == "" { message_string = "\n" } - - @{send keys to system} + for _, part := range strings.Split(message_string, "@{payload delimiter}") { + message_string = part + @{send keys to system} + } } } diff --git a/server/StringCommands.md b/server/StringCommands.md new file mode 100644 index 0000000..a301995 --- /dev/null +++ b/server/StringCommands.md @@ -0,0 +1,37 @@ +# String Commands + +To control key events and the input method we use special command strings at the beginning of a message. + +They are as follows: + +Payload delimiter: +--- payload delimiter +{KB_MSG} +--- + + +Xdotool typing: + +--- use xdotool cmd +{KEYDOXDOTOOL}: +--- + +Xdotool key command: + +--- use xdotool key cmd +{KEYDOXTOOLKEY}: +--- + +Send keys commands: + +--- keydown cmd +{KEYDWN} +--- + +--- keyup cmd +{KEYUP} +--- + +--- keyheld cmd +{KEYHLD} +--- \ No newline at end of file diff --git a/server/XdotoolCommands.md b/server/XdotoolCommands.md index f4ec348..c01f7a0 100644 --- a/server/XdotoolCommands.md +++ b/server/XdotoolCommands.md @@ -2,14 +2,14 @@ Currently the two commands are `type` and `key`. `type` is used to type a character and `key` is used to type a special character like `Enter` or `Backspace`. -`type` is specified by '{kb_cmd:xdotool}:', and `key` is specified by '{kb_cmd:kxdotool}:'. If the command is not specified and `alwaysUseXdotool` is set from the environment variable, it will default to `type`. +`type` is specified by '@{use xdotool cmd}', and `key` is specified by '@{use xdotool key cmd}'. If the command is not specified and `alwaysUseXdotool` is set from the environment variable, it will default to `type`. ``` go --- handle xdotoool commands -if alwaysUseXdotool || strings.HasPrefix(message_string, "{kb_cmd:xdotool}:") { - message_string = strings.TrimPrefix(message_string, "{kb_cmd:xdotool}:") +if alwaysUseXdotool || strings.HasPrefix(message_string, "@{use xdotool cmd}") { + message_string = strings.TrimPrefix(message_string, "@{use xdotool cmd}") if message_string == "" { message_string = "\n" } @@ -37,8 +37,8 @@ if alwaysUseXdotool || strings.HasPrefix(message_string, "{kb_cmd:xdotool}:") { doXDoTool("type", message_string) } continue -} else if strings.HasPrefix(message_string, "{kb_cmd:kxdotool}:") { - message_string = strings.TrimPrefix(message_string, "{kb_cmd:kxdotool}:") +} else if strings.HasPrefix(message_string, "@{use xdotool key cmd}") { + message_string = strings.TrimPrefix(message_string, "@{use xdotool key cmd}") if message_string == "" { message_string = "\n" } diff --git a/tools/RawCapture.md b/tools/RawCapture.md index 453fc80..ce28197 100644 --- a/tools/RawCapture.md +++ b/tools/RawCapture.md @@ -248,13 +248,13 @@ try: except KeyError: print("Unknown key: " + str(e_code)) if event.value == 1: - key_str = "{KEYDWN}" + key_str + key_str = "@{keydown cmd}" + key_str log.append(e_code) quit_if_necessry(log) elif event.value == 0: - key_str = "{KEYUP}" + key_str + key_str = "@{keyup cmd}" + key_str elif event.value == 2: - key_str = "{KEYHLD}" + key_str + key_str = "@{keyheld cmd}" + key_str else: print("Unknown value: " + str(event.value)) continue