|
|
|
package net
|
|
|
|
|
|
|
|
import (
|
|
|
|
"b612.me/starcrypto"
|
|
|
|
"b612.me/starlog"
|
|
|
|
"b612.me/starnet"
|
|
|
|
"crypto/elliptic"
|
|
|
|
"encoding/csv"
|
|
|
|
"fmt"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"golang.org/x/crypto/ssh"
|
|
|
|
"net"
|
|
|
|
"os"
|
|
|
|
"os/signal"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
listenAddr string
|
|
|
|
keyFile string
|
|
|
|
KeyPasswd string
|
|
|
|
outpath string
|
|
|
|
curlUrl string
|
|
|
|
serverVersion 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", "", "输出文件")
|
|
|
|
cmdSSHJar.Flags().StringVarP(&serverVersion, "version", "v", "OpenSSH", "SSH版本")
|
|
|
|
}
|
|
|
|
|
|
|
|
var cmdSSHJar = &cobra.Command{
|
|
|
|
Use: "sshjar",
|
|
|
|
Short: "SSH蜜罐",
|
|
|
|
Long: "SSH蜜罐",
|
|
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
|
|
runSSHHoneyJar(listenAddr, keyFile, KeyPasswd, outpath, serverVersion)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
func runSSHHoneyJar(listenAddr, keyFile, KeyPasswd, outpath, version 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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
conn := csv.NewWriter(f)
|
|
|
|
defer f.Close()
|
|
|
|
defer conn.Flush()
|
|
|
|
config := &ssh.ServerConfig{
|
|
|
|
ServerVersion: version,
|
|
|
|
// 密码验证回调函数
|
|
|
|
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{time.Now().Format("2006-01-02 15:04:05"), c.RemoteAddr().String(), c.User(), string(pass)}
|
|
|
|
if f != nil {
|
|
|
|
conn.Write(data)
|
|
|
|
}
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|