Name changes to library, remove global config

This commit is contained in:
Alex 2017-10-14 19:54:37 -04:00
parent f99445c05b
commit 9bbc2ea8f4
7 changed files with 157 additions and 38 deletions

@ -13,7 +13,7 @@ import (
// clientAuthenticate authenticates with the remote server. See RFC 4252.
func (c *connection) clientAuthenticate(config *ClientConfig) error {
if c.transport.config.ConnLog != nil && !pkgConfig.CollectUserAuth {
if c.transport.config.ConnLog != nil && !config.DontAuthenticate {
// Use ConnLog existence to indicate that this is a run and not testing
return nil
}

@ -225,6 +225,14 @@ type Config struct {
// A pointer to the handshake log IOT allow incremental building
ConnLog *HandshakeLog
// Whether or not the package should operate in verbose mode
// (save more output)
Verbose bool
GexMinBits uint
GexMaxBits uint
GexPreferredBits uint
}
// SetDefaults sets sensible values for unset fields in config. This is

@ -1,11 +1,74 @@
package ssh
import (
"errors"
"fmt"
"strings"
)
func MakeXSSHConfig() *ClientConfig {
ret := new(ClientConfig)
ret.DontAuthenticate = true // IOT scan ethically, never attempt to authenticate
ret.ClientVersion = pkgConfig.ClientID
ret.HostKeyAlgorithms = pkgConfig.HostKeyAlgorithms.Get()
ret.KeyExchanges = pkgConfig.KexAlgorithms.Get()
ret.Ciphers = pkgConfig.Ciphers.Get()
ret.HostKeyAlgorithms = supportedHostKeyAlgos
ret.KeyExchanges = defaultKexAlgos
ret.Ciphers = defaultCiphers
return ret
}
func (c *ClientConfig) SetHostKeyAlgorithms(value string) error {
for _, alg := range strings.Split(value, ",") {
isValid := false
for _, val := range supportedHostKeyAlgos {
if val == alg {
isValid = true
break
}
}
if !isValid {
return errors.New(fmt.Sprintf(`host key algorithm not supported: "%s"`, alg))
}
c.HostKeyAlgorithms = append(c.HostKeyAlgorithms, alg)
}
return nil
}
func (c *ClientConfig) SetKexAlgorithms(value string) error {
for _, alg := range strings.Split(value, ",") {
isValid := false
for _, val := range allSupportedKexAlgos {
if val == alg {
isValid = true
break
}
}
if !isValid {
return errors.New(fmt.Sprintf(`DH KEX algorithm not supported: "%s"`, alg))
}
c.KeyExchanges = append(c.KeyExchanges, alg)
}
return nil
}
func (c *ClientConfig) SetCiphers(value string) error {
for _, inCipher := range strings.Split(value, ",") {
isValid := false
for _, knownCipher := range allSupportedCiphers {
if inCipher == knownCipher {
isValid = true
break
}
}
if !isValid {
return errors.New(fmt.Sprintf(`cipher not supported: "%s"`, inCipher))
}
c.Ciphers = append(c.Ciphers, inCipher)
}
return nil
}

@ -343,7 +343,7 @@ func (t *handshakeTransport) enterKeyExchangeLocked(otherInitPacket []byte) erro
return err
}
if pkgConfig.Verbose {
if t.config.Verbose {
if t.config.ConnLog != nil {
t.config.ConnLog.ClientKex = myInit
}
@ -417,7 +417,7 @@ func (t *handshakeTransport) enterKeyExchangeLocked(otherInitPacket []byte) erro
} else {
result, err = t.client(kex, algs, &magics)
}
if pkgConfig.Verbose {
if t.config.Verbose {
if t.config.ConnLog != nil {
t.config.ConnLog.Crypto = result
}
@ -452,12 +452,12 @@ func (t *handshakeTransport) server(kex kexAlgorithm, algs *algorithms, magics *
}
}
r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey)
r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey, t.config)
return r, err
}
func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) {
result, err := kex.Client(t.conn, t.config.Rand, magics)
result, err := kex.Client(t.conn, t.config.Rand, magics, t.config)
if err != nil {
return nil, err
}

@ -145,11 +145,11 @@ func LogServerHostKey(sshRawKey []byte) *ServerHostKeyJsonLog {
type kexAlgorithm interface {
// Server runs server-side key agreement, signing the result
// with a hostkey.
Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error)
Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer, c *Config) (*kexResult, error)
// Client runs the client-side key agreement. Caller is
// responsible for verifying the host key signature.
Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error)
Client(p packetConn, rand io.Reader, magics *handshakeMagics, c *Config) (*kexResult, error)
// Create a JSON object for the kexAlgorithm group
MarshalJSON() ([]byte, error)
@ -276,7 +276,7 @@ func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handsha
}, nil
}
func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer, config *Config) (result *kexResult, err error) {
hashFunc := crypto.SHA1
packet, err := c.readPacket()
if err != nil {
@ -381,10 +381,10 @@ func (kex *ecdh) GetNew(keyType string) kexAlgorithm {
return ret
}
func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics, config *Config) (*kexResult, error) {
kex.JsonLog.Parameters = new(ztoolsKeys.ECDHParams)
kex.JsonLog.Parameters.ServerPublic = new(ztoolsKeys.ECPoint)
if pkgConfig.Verbose {
if config.Verbose {
kex.JsonLog.Parameters.ClientPublic = new(ztoolsKeys.ECPoint)
kex.JsonLog.Parameters.ClientPrivate = new(ztoolsKeys.ECDHPrivateParams)
}
@ -394,7 +394,7 @@ func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (
return nil, err
}
if pkgConfig.Verbose {
if config.Verbose {
kex.JsonLog.Parameters.ClientPublic.X = ephKey.PublicKey.X
kex.JsonLog.Parameters.ClientPublic.Y = ephKey.PublicKey.Y
kex.JsonLog.Parameters.ClientPrivate.Value = ephKey.D.Bytes()
@ -494,7 +494,7 @@ func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool {
return true
}
func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer, config *Config) (result *kexResult, err error) {
packet, err := c.readPacket()
if err != nil {
return nil, err
@ -639,13 +639,13 @@ func (kp *curve25519KeyPair) generate(rand io.Reader) error {
// wrong order.
var curve25519Zeros [32]byte
func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics, config *Config) (*kexResult, error) {
var kp curve25519KeyPair
if err := kp.generate(rand); err != nil {
return nil, err
}
if pkgConfig.Verbose {
if config.Verbose {
kex.JsonLog.Parameters.ClientPublic = kp.pub[:]
kex.JsonLog.Parameters.ClientPrivate = kp.priv[:]
}
@ -700,7 +700,7 @@ func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handsh
}, nil
}
func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer, config *Config) (result *kexResult, err error) {
packet, err := c.readPacket()
if err != nil {
return

@ -83,12 +83,12 @@ func (gex *dhGEXSHA) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, e
return new(big.Int).Exp(theirPublic, myPrivate, gex.p), nil
}
func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshakeMagics, config *Config) (*kexResult, error) {
// Send GexRequest
kexDHGexRequest := kexDHGexRequestMsg{
MinBits: uint32(pkgConfig.GexMinBits),
PreferedBits: uint32(pkgConfig.GexPreferredBits),
MaxBits: uint32(pkgConfig.GexMaxBits),
MinBits: uint32(config.GexMinBits),
PreferedBits: uint32(config.GexPreferredBits),
MaxBits: uint32(config.GexMaxBits),
}
if err := c.writePacket(Marshal(&kexDHGexRequest)); err != nil {
return nil, err
@ -111,7 +111,7 @@ func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshak
}
// reject if p's bit length < pkgConfig.GexMinBits or > pkgConfig.GexMaxBits
if kexDHGexGroup.P.BitLen() < int(pkgConfig.GexMinBits) || kexDHGexGroup.P.BitLen() > int(pkgConfig.GexMaxBits) {
if kexDHGexGroup.P.BitLen() < int(config.GexMinBits) || kexDHGexGroup.P.BitLen() > int(config.GexMaxBits) {
return nil, fmt.Errorf("Server-generated gex p (dont't ask) is out of range (%d bits)", kexDHGexGroup.P.BitLen())
}
@ -128,7 +128,7 @@ func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshak
X: X,
}
if gex.JsonLog != nil && pkgConfig.Verbose {
if gex.JsonLog != nil && config.Verbose {
gex.JsonLog.Parameters.ClientPrivate = x
gex.JsonLog.Parameters.ClientPublic = X
}
@ -164,9 +164,9 @@ func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshak
h := gex.hashFunc.New()
magics.write(h)
writeString(h, kexDHGexReply.HostKey)
binary.Write(h, binary.BigEndian, uint32(pkgConfig.GexMinBits))
binary.Write(h, binary.BigEndian, uint32(pkgConfig.GexPreferredBits))
binary.Write(h, binary.BigEndian, uint32(pkgConfig.GexMaxBits))
binary.Write(h, binary.BigEndian, uint32(config.GexMinBits))
binary.Write(h, binary.BigEndian, uint32(config.GexPreferredBits))
binary.Write(h, binary.BigEndian, uint32(config.GexMaxBits))
writeInt(h, gex.p)
writeInt(h, gex.g)
writeInt(h, X)
@ -184,7 +184,7 @@ func (gex *dhGEXSHA) Client(c packetConn, randSource io.Reader, magics *handshak
}, nil
}
func (gex *dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
func (gex *dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer, config *Config) (result *kexResult, err error) {
// *Receive GexRequest*
packet, err := c.readPacket()
if err != nil {
@ -196,11 +196,11 @@ func (gex *dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshak
}
// smoosh the user's preferred size into our own limits
if kexDHGexRequest.PreferedBits > uint32(pkgConfig.GexMaxBits) {
kexDHGexRequest.PreferedBits = uint32(pkgConfig.GexMaxBits)
if kexDHGexRequest.PreferedBits > uint32(config.GexMaxBits) {
kexDHGexRequest.PreferedBits = uint32(config.GexMaxBits)
}
if kexDHGexRequest.PreferedBits < uint32(pkgConfig.GexMinBits) {
kexDHGexRequest.PreferedBits = uint32(pkgConfig.GexMinBits)
if kexDHGexRequest.PreferedBits < uint32(config.GexMinBits) {
kexDHGexRequest.PreferedBits = uint32(config.GexMinBits)
}
// fix min/max if they're inconsistent. technically, we could just pout
// and hang up, but there's no harm in giving them the benefit of the
@ -251,9 +251,9 @@ func (gex *dhGEXSHA) Server(c packetConn, randSource io.Reader, magics *handshak
h := gex.hashFunc.New()
magics.write(h)
writeString(h, hostKeyBytes)
binary.Write(h, binary.BigEndian, uint32(pkgConfig.GexMinBits))
binary.Write(h, binary.BigEndian, uint32(pkgConfig.GexPreferredBits))
binary.Write(h, binary.BigEndian, uint32(pkgConfig.GexMaxBits))
binary.Write(h, binary.BigEndian, uint32(config.GexMinBits))
binary.Write(h, binary.BigEndian, uint32(config.GexPreferredBits))
binary.Write(h, binary.BigEndian, uint32(config.GexMaxBits))
writeInt(h, gex.p)
writeInt(h, gex.g)
writeInt(h, kexDHGexInit.X)

@ -1,8 +1,13 @@
package modules
import (
"net"
"strconv"
"time"
log "github.com/sirupsen/logrus"
"github.com/zmap/zgrab2"
"github.com/zmap/zgrab2/lib/ssh"
)
type SSHFlags struct {
@ -11,6 +16,11 @@ type SSHFlags struct {
KexAlgorithms string `long:"kex-algorithms" description:"Set SSH Key Exchange Algorithms"`
HostKeyAlgorithms string `long:"host-key-algorithms" description:"Set SSH Host Key Algorithms"`
NegativeOne bool `long:"negative-one" description:"Set SSH DH kex value to -1 in the selected group"`
Ciphers string `long:"ciphers" description:"A comma-separated list of which ciphers to offer."`
CollectUserAuth bool `long:"userauth" description:"Use the 'none' authentication request to see what userauth methods are allowed"`
GexMinBits uint `long:"gex-min-bits" description:"The minimum number of bits for the DH GEX prime." default:"1024"`
GexMaxBits uint `long:"gex-max-bits" description:"The maximum number of bits for the DH GEX prime." default:"8192"`
GexPreferredBits uint `long:"gex-preferred-bits" description:"The preferred number of bits for the DH GEX prime." default:"2048"`
}
type SSHModule struct {
@ -57,6 +67,44 @@ func (s *SSHScanner) InitPerSender(senderID int) error {
func (s *SSHScanner) GetName() string {
return s.config.Name
}
func (s *SSHScanner) Scan(t zgrab2.ScanTarget, port uint) (interface{}, error) {
return nil, nil
func (s *SSHScanner) makeSSHGrabber(hlog *ssh.HandshakeLog) func(string) error {
return func(netAddr string) error {
sshConfig := ssh.MakeSSHConfig()
sshConfig.Timeout = time.Duration(s.config.Timeout) * time.Second
sshConfig.ConnLog = hlog
sshConfig.ClientVersion = s.ClientID
if err := sshConfig.SetHostKeyAlgorithms(s.config.HostKeyAlgorithms); err != nil {
log.Fatal(err)
}
if err := sshConfig.SetKexAlgorithms(s.config.KexAlgorithms); err != nil {
log.Fatal(err)
}
if err := sshConfig.SetCiphers(s.config.Ciphers); err != nil {
log.Fatal(err)
}
sshConfig.Verbose = s.config.Verbose
sshConfig.DontAuthenticate = s.config.CollectUserAuth
sshConfig.GexMinBits = s.config.GexMinBits
sshConfig.GexMaxBits = s.config.GexMaxBits
sshConfig.GexPreferredBits = s.config.GexPreferredBits
_, err := ssh.Dial("tcp", netAddr, sshConfig)
if err != nil {
return err
}
return nil
}
}
func (s *SSHScanner) Scan(t zgrab2.ScanTarget) (interface{}, error) {
data := new(ssh.HandshakeLog)
sshGrabber := s.makeSSHGrabber(data)
//TODO: domain name?
port := strconv.FormatUint(uint64(s.config.Port), 10)
rhost := net.JoinHostPort(t.IP.String(), port)
err := sshGrabber(rhost)
return data, err
}