Skip to content

Commit

Permalink
Merge pull request #1406 from rwincey/ssh_cert_auth
Browse files Browse the repository at this point in the history
Added ssh certificate auth to ssh module
  • Loading branch information
moloch-- authored Sep 17, 2023
2 parents ad2be94 + aaaed91 commit 1ca6c76
Show file tree
Hide file tree
Showing 6 changed files with 272 additions and 232 deletions.
1 change: 1 addition & 0 deletions client/command/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -1295,6 +1295,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Int("t", "timeout", defaultTimeout, "command timeout in seconds")
f.Uint("p", "port", 22, "SSH port")
f.String("i", "private-key", "", "path to private key file")
f.String("u", "signed-user-cert", "", "path to user signed certificate (certificate based auth)")
f.String("P", "password", "", "SSH user password")
f.String("l", "login", "", "username to use to connect")
f.Bool("s", "skip-loot", false, "skip the prompt to use loot credentials")
Expand Down
35 changes: 23 additions & 12 deletions client/command/exec/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ import (
// SSHCmd - A built-in SSH client command for the remote system (doesn't shell out)
func SSHCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
var (
privKey []byte
err error
privKey []byte
signeUserCert []byte
err error
)
session := con.ActiveTarget.GetSessionInteractive()
if session == nil {
Expand All @@ -59,6 +60,15 @@ func SSHCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}
password := ctx.Flags.String("password")

signeUserCertPath := ctx.Flags.String("signed-user-cert")
if signeUserCertPath != "" {
signeUserCert, err = os.ReadFile(signeUserCertPath)
if err != nil {
con.PrintErrorf("%s\n", err)
return
}
}

hostname := ctx.Args.String("hostname")
command := ctx.Args.StringList("command")
kerberosRealm := ctx.Flags.String("kerberos-realm")
Expand Down Expand Up @@ -87,16 +97,17 @@ func SSHCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
}

sshCmd, err := con.Rpc.RunSSHCommand(context.Background(), &sliverpb.SSHCommandReq{
Username: username,
Hostname: hostname,
Port: uint32(port),
PrivKey: privKey,
Password: password,
Command: strings.Join(command, " "),
Realm: kerberosRealm,
Krb5Conf: kerberosConfig,
Keytab: kerberosKeytab,
Request: con.ActiveTarget.Request(ctx),
Username: username,
Hostname: hostname,
Port: uint32(port),
PrivKey: privKey,
Password: password,
Command: strings.Join(command, " "),
Realm: kerberosRealm,
Krb5Conf: kerberosConfig,
Keytab: kerberosKeytab,
Request: con.ActiveTarget.Request(ctx),
SignedUserCert: signeUserCert,
})
if err != nil {
con.PrintErrorf("%s\n", err)
Expand Down
1 change: 1 addition & 0 deletions implant/sliver/handlers/rpc-handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ func runSSHCommandHandler(data []byte, resp RPCResponse) {
commandReq.Username,
commandReq.Password,
commandReq.PrivKey,
commandReq.SignedUserCert,
commandReq.Krb5Conf,
commandReq.Keytab,
commandReq.Realm,
Expand Down
22 changes: 19 additions & 3 deletions implant/sliver/shell/ssh/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
"golang.org/x/crypto/ssh/agent"
)

func getClient(host string, port uint16, username string, password string, privKey []byte, krb5conf string, keytab []byte, realm string) (*ssh.Client, error) {
func getClient(host string, port uint16, username string, password string, privKey []byte, signedUserCert []byte, krb5conf string, keytab []byte, realm string) (*ssh.Client, error) {
var authMethods []ssh.AuthMethod
if password != "" {
// Try password auth first
Expand All @@ -28,6 +28,22 @@ func getClient(host string, port uint16, username string, password string, privK
if err != nil {
return nil, err
}
// If certificate based auth add signed public key
if len(signedUserCert) != 0 {
cert, _, _, _, err := ssh.ParseAuthorizedKey(signedUserCert)
if err != nil {
return nil, err
}

// create a signer using both the certificate and the private key:
certSigner, err := ssh.NewCertSigner(cert.(*ssh.Certificate), signer)
if err != nil {
return nil, err
}
//Update signer
signer = certSigner
}

authMethods = append(authMethods, ssh.PublicKeys(signer))
} else if krb5conf != "" && keytab != nil && realm != "" {
// Then try kerberos auth
Expand Down Expand Up @@ -74,12 +90,12 @@ func getClient(host string, port uint16, username string, password string, privK
}

// RunSSHCommand - SSH to a host and execute a command
func RunSSHCommand(host string, port uint16, username string, password string, privKey []byte, krb5conf string, keytab []byte, realm string, command string) (string, string, error) {
func RunSSHCommand(host string, port uint16, username string, password string, privKey []byte, signedUserCert []byte, krb5conf string, keytab []byte, realm string, command string) (string, string, error) {
var (
stdout bytes.Buffer
stderr bytes.Buffer
)
sshc, err := getClient(host, port, username, password, privKey, krb5conf, keytab, realm)
sshc, err := getClient(host, port, username, password, privKey, signedUserCert, krb5conf, keytab, realm)
if err != nil {
return "", "", err
}
Expand Down
Loading

0 comments on commit 1ca6c76

Please sign in to comment.