You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
star/net/sshjar.go

146 lines
3.7 KiB
Go

package net
import (
"b612.me/starcrypto"
"b612.me/starlog"
"b612.me/starnet"
"crypto/elliptic"
"encoding/json"
"fmt"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh"
"net"
"os"
"os/signal"
"strings"
)
var (
listenAddr string
keyFile string
KeyPasswd string
outpath string
curlUrl string
curlArg []string
)
func init() {
cmdSSHJar.Flags().StringVarP(&listenAddr, "listen", "l", "0.0.0.0:22", "监听地址")
cmdSSHJar.Flags().StringVarP(&keyFile, "key", "k", "", "私钥文件")
cmdSSHJar.Flags().StringVarP(&KeyPasswd, "passwd", "p", "", "私钥密码")
cmdSSHJar.Flags().StringVarP(&outpath, "output", "o", "", "输出文件")
}
var cmdSSHJar = &cobra.Command{
Use: "sshjar",
Short: "SSH蜜罐",
Long: "SSH蜜罐",
Run: func(cmd *cobra.Command, args []string) {
runSSHHoneyJar(listenAddr, keyFile, KeyPasswd, outpath)
},
}
func runSSHHoneyJar(listenAddr, keyFile, KeyPasswd, outpath string) {
var f *os.File
var err error
if outpath != "" {
f, err = os.OpenFile(outpath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
starlog.Errorf("Failed to open file %s (%s)", outpath, err)
return
}
}
defer f.Close()
config := &ssh.ServerConfig{
// 密码验证回调函数
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
starlog.Infof("Login attempt from %s with %s %s\n", c.RemoteAddr(), c.User(), string(pass))
data := []string{c.RemoteAddr().String(), c.User(), string(pass)}
bts, _ := json.Marshal(data)
if f != nil {
f.Write(bts)
f.Write([]byte("\n"))
}
if curlUrl != "" {
go func() {
data := map[string]string{
"ip": c.RemoteAddr().String(),
"user": c.User(),
"passwd": string(pass),
}
if curlArg != nil && len(curlArg) > 0 {
for _, v := range curlArg {
args := strings.SplitN(v, ":", 2)
if len(args) == 2 {
data[args[0]] = args[1]
}
}
starnet.Curl(starnet.NewRequests(curlUrl, []byte(starnet.BuildQuery(data)), "POST"))
}
}()
}
return nil, fmt.Errorf("password rejected for %q", c.User())
},
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
return nil, fmt.Errorf("public key rejected for %q", conn.User())
},
}
if keyFile == "" {
secKey, _, err := starcrypto.GenerateEcdsaKey(elliptic.P256())
if err != nil {
starlog.Errorf("Failed to generate ECDSA key (%s)", err)
return
}
key, err := ssh.NewSignerFromKey(secKey)
if err != nil {
starlog.Errorf("Failed to generate signer from key (%s)", err)
return
}
config.AddHostKey(key)
} else {
keyByte, err := os.ReadFile(keyFile)
if err != nil {
starlog.Errorf("Failed to read private key from %s (%s)", keyFile, err)
return
}
var key ssh.Signer
if KeyPasswd != "" {
key, err = ssh.ParsePrivateKeyWithPassphrase(keyByte, []byte(KeyPasswd))
} else {
key, err = ssh.ParsePrivateKey(keyByte)
}
if err != nil {
starlog.Errorf("Failed to load private key from %s (%s)", keyFile, err)
return
}
config.AddHostKey(key)
}
listener, err := net.Listen("tcp", listenAddr)
if err != nil {
starlog.Errorf("Failed to listen on %s (%s)", listenAddr, err)
return
}
starlog.Noticeln("SSH HoneyJar is listening on", listenAddr)
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, os.Kill)
for {
select {
case <-sig:
starlog.Noticef("SSH HoneyJar is shutting down")
listener.Close()
return
default:
}
conn, err := listener.Accept()
if err != nil {
continue
}
starlog.Infof("New connection from %s\n", conn.RemoteAddr())
go func(conn net.Conn) {
ssh.NewServerConn(conn, config)
conn.Close()
}(conn)
}
}