Compare commits

..

3 Commits

Author SHA1 Message Date
Kevin F
a2e9ce6aeb Fixed race condition 2023-03-13 22:25:04 -05:00
Kevin F
b941235007 Moved control commands to their own file
Delimit all messages to fix fifo race condition
2023-03-13 13:24:02 -05:00
Kevin F
a8574dfebe Don't sleep on server between messages 2023-03-12 16:25:54 -05:00
9 changed files with 73 additions and 34 deletions

View File

@ -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(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,7 +147,6 @@ for {
}
log.Fatal(err)
}
fmt.Println("send" + strings.Replace(key, " ", "space", 10))
err = client.WriteMessage(websocket.TextMessage, []byte(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
}
}
}

View File

@ -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

View File

@ -6,7 +6,7 @@ Copyright [Kevin Froman](https://chaoswebs.net/) [Licensed under GPLv3](LICENSE.
Work in progress
--- version
0.0.1
3.0.0
---

View File

@ -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 {

View File

@ -102,7 +102,6 @@ package server
import(
"net"
"time"
"os"
"os/exec"
"strings"

View File

@ -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
@ -57,7 +57,6 @@ func clientConnected(w http.ResponseWriter, r *http.Request) {
c.WriteMessage(websocket.TextMessage, []byte("authenticated"))
for {
time.Sleep(25 * time.Millisecond)
_, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
@ -68,9 +67,11 @@ func clientConnected(w http.ResponseWriter, r *http.Request) {
if message_string == "" {
message_string = "\n"
}
for _, part := range strings.Split(message_string, "@{payload delimiter}") {
message_string = part
@{send keys to system}
}
}
}
---

37
server/StringCommands.md Normal file
View File

@ -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}
---

View File

@ -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"
}

View File

@ -248,13 +248,13 @@ try:
except KeyError:
print("Unknown key: " + str(e_code))
if event.value == 1:
key_str = "{KEYDWN}" + key_str
key_str = "@{payload delimiter}@{keydown cmd}" + key_str
log.append(e_code)
quit_if_necessry(log)
elif event.value == 0:
key_str = "{KEYUP}" + key_str
key_str = "@{payload delimiter}@{keyup cmd}" + key_str
elif event.value == 2:
key_str = "{KEYHLD}" + key_str
key_str = "@{payload delimiter}@{keyheld cmd}" + key_str
else:
print("Unknown value: " + str(event.value))
continue