Created
July 5, 2021 16:41
-
-
Save ezr/224840e81883d6be08b9b7c45e2cff8f to your computer and use it in GitHub Desktop.
A fake ssh server that logs usernames/passwords that get submitted
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// A fake SSH server that logs passwords | |
// tweaked from https://gist.github.com/jpillora/b480fde82bff51a06238 | |
// | |
// # generate server keypair with | |
// ssh-keygen -t rsa | |
// the server expects to find id_rsa in the PWD | |
package main | |
import ( | |
"flag" | |
"fmt" | |
"io/ioutil" | |
"log" | |
"net" | |
"os" | |
"strconv" | |
"golang.org/x/crypto/ssh" | |
) | |
func main() { | |
port := flag.Int("port", 22, "port to listen on") | |
addr := flag.String("addr", "0.0.0.0", "address to listen on") | |
flag.Parse() | |
listenPort := strconv.Itoa(*port) | |
logFile, err := os.OpenFile("ssh.log", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600) | |
if err != nil { | |
log.Fatal(err) | |
} | |
defer logFile.Close() | |
log.SetOutput(logFile) | |
// A ssh.ServerConn is created by passing an existing net.Conn and a ssh.ServerConfig | |
// to ssh.NewServerConn, in effect, upgrading the net.Con into an ssh.ServerConn | |
config := &ssh.ServerConfig{ | |
// function to run when a client attempts a password login | |
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) { | |
log.Println("[password attempt]", c.User(), string(pass), c.RemoteAddr()) | |
return nil, fmt.Errorf("password rejected for %q", c.User()) | |
}, | |
// Deny any attempt to authenticate with a key | |
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { | |
log.Println("[pubkey attempt]", key.Type(), ssh.FingerprintSHA256(key)) | |
return nil, fmt.Errorf("denied") | |
}, | |
} | |
// You can generate a keypair with 'ssh-keygen -t rsa' | |
privateBytes, err := ioutil.ReadFile("id_rsa") | |
if err != nil { | |
log.Fatal("Failed to load private key (./id_rsa)") | |
} | |
private, err := ssh.ParsePrivateKey(privateBytes) | |
if err != nil { | |
log.Fatal("Failed to parse private key") | |
} | |
// this is needed for an initial handshake even if the client is only using password auth | |
config.AddHostKey(private) | |
// Once a ServerConfig has been configured, connections can be accepted. | |
listenAddr := *addr + ":" + listenPort | |
listener, err := net.Listen("tcp", listenAddr) | |
if err != nil { | |
log.Fatalf("Failed to listen on %s (%s)", listenAddr, err) | |
} | |
// Accept all connections | |
log.Println("Listening on", listenAddr) | |
for { | |
tcpConn, err := listener.Accept() | |
if err != nil { | |
log.Printf("Failed to accept incoming connection (%s)", err) | |
continue | |
} | |
// Before use, a handshake must be performed on the incoming net.Conn. | |
//sshConn, chans, reqs, err := ssh.NewServerConn(tcpConn, config) | |
sshConn, _, reqs, err := ssh.NewServerConn(tcpConn, config) | |
if err != nil { | |
log.Printf("Failed to handshake (%s)", err) | |
continue | |
} | |
log.Printf("New SSH connection from %s (%s)", sshConn.RemoteAddr(), sshConn.ClientVersion()) | |
// Discard all global out-of-band Requests | |
go ssh.DiscardRequests(reqs) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment