Skip to content

Commit

Permalink
ftp: Add support for implicit TLS
Browse files Browse the repository at this point in the history
The command line option `--implicit-tls` will attempt connecting via
TLS before intiating the FTP handshake.
  • Loading branch information
codyprime committed May 29, 2020
1 parent 2d92ae7 commit 4ae6898
Showing 1 changed file with 41 additions and 10 deletions.
51 changes: 41 additions & 10 deletions modules/ftp/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
package ftp

import (
"fmt"
"net"
"regexp"
"strings"
Expand All @@ -33,6 +34,10 @@ type ScanResults struct {
// Only present if the FTPAuthTLS flag is set and AUTH TLS failed.
AuthSSLResp string `json:"auth_ssl,omitempty"`

// ImplicitTLS is true if the connection is wrapped in TLS, as opposed
// to via AUTH TLS or AUTH SSL.
ImplicitTLS bool `json:"implicit_tls,omitempty"`

// TLSLog is the standard shared TLS handshake log.
// Only present if the FTPAuthTLS flag is set.
TLSLog *zgrab2.TLSLog `json:"tls,omitempty"`
Expand All @@ -44,8 +49,9 @@ type Flags struct {
zgrab2.BaseFlags
zgrab2.TLSFlags

Verbose bool `long:"verbose" description:"More verbose logging, include debug fields in the scan results"`
FTPAuthTLS bool `long:"authtls" description:"Collect FTPS certificates in addition to FTP banners"`
Verbose bool `long:"verbose" description:"More verbose logging, include debug fields in the scan results"`
FTPAuthTLS bool `long:"authtls" description:"Collect FTPS certificates in addition to FTP banners"`
ImplicitTLS bool `long:"implicit-tls" description:"Attempt to connect via a TLS wrapped connection first"`
}

// Module implements the zgrab2.Module interface.
Expand Down Expand Up @@ -93,9 +99,12 @@ func (m *Module) Description() string {
return "Grab an FTP banner"
}

// Validate does nothing in this module.
func (f *Flags) Validate(args []string) error {
return nil
// Validate flags
func (f *Flags) Validate(args []string) (err error) {
if f.FTPAuthTLS && f.ImplicitTLS {
err = fmt.Errorf("Cannot specify both '--authtls' and '--implicit-tls' together")
}
return
}

// Help returns this module's help string.
Expand Down Expand Up @@ -131,13 +140,16 @@ func (scanner *Scanner) GetTrigger() string {
return scanner.config.Trigger
}

// ftpEndRegex matches zero or more lines followed by a numeric FTP status code and linebreak, e.g. "200 OK\r\n"
// ftpEndRegex matches zero or more lines followed by a numeric FTP status code
// and linebreak, e.g. "200 OK\r\n"
var ftpEndRegex = regexp.MustCompile(`^(?:.*\r?\n)*([0-9]{3})( [^\r\n]*)?\r?\n$`)

// isOKResponse returns true iff and only if the given response code indicates
// success (e.g. 2XX)
func (ftp *Connection) isOKResponse(retCode string) bool {
// TODO: This is the current behavior; should it check that it isn't garbage that happens to start with 2 (e.g. it's only ASCII chars, the prefix is 2[0-9]+, etc)?
// TODO: This is the current behavior; should it check that it isn't
// garbage that happens to start with 2 (e.g. it's only ASCII chars, the
// prefix is 2[0-9]+, etc)?
return strings.HasPrefix(retCode, "2")
}

Expand Down Expand Up @@ -216,7 +228,10 @@ func (ftp *Connection) GetFTPSCertificates() error {
ftp.results.TLSLog = conn.GetLog()

if err = conn.Handshake(); err != nil {
// NOTE: With the default config of vsftp (without ssl_ciphers=HIGH), AUTH TLS succeeds, but the handshake fails, dumping "error:1408A0C1:SSL routines:ssl3_get_client_hello:no shared cipher" to the socket.
// NOTE: With the default config of vsftp (without ssl_ciphers=HIGH),
// AUTH TLS succeeds, but the handshake fails, dumping
// "error:1408A0C1:SSL routines:ssl3_get_client_hello:no shared cipher"
// to the socket.
return err
}
ftp.conn = conn
Expand All @@ -237,8 +252,24 @@ func (s *Scanner) Scan(t zgrab2.ScanTarget) (status zgrab2.ScanStatus, result in
if err != nil {
return zgrab2.TryGetScanStatus(err), nil, err
}
defer conn.Close()
ftp := Connection{conn: conn, config: s.config, results: ScanResults{}}
cn := conn
defer func() {
cn.Close()
}()

results := ScanResults{}
if s.config.ImplicitTLS {
tlsConn, err := s.config.TLSFlags.GetTLSConnection(conn)
if err != nil {
return zgrab2.TryGetScanStatus(err), nil, err
}
results.ImplicitTLS = true
results.TLSLog = tlsConn.GetLog()
tlsConn.Handshake()
cn = tlsConn
}

ftp := Connection{conn: cn, config: s.config, results: results}
is200Banner, err := ftp.GetFTPBanner()
if err != nil {
return zgrab2.TryGetScanStatus(err), &ftp.results, err
Expand Down

0 comments on commit 4ae6898

Please sign in to comment.