Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(configtest,scan): detect known_hosts error #1386

Merged
merged 1 commit into from
Feb 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions scanner/debian.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ func detectDebian(c config.ServerInfo) (bool, osTypeInterface, error) {
return false, nil, nil
}
if r.ExitStatus == 255 {
deb := newDebian(c) // Panic occur when return value 2 is nil and 3 is non-nil
return false, deb, xerrors.Errorf("Unable to connect via SSH. Scan with -vvv option to print SSH debugging messages and check SSH settings. If you have never SSH to the host to be scanned, SSH to the host before scanning in order to add the HostKey. %s@%s port: %s\n%s", c.User, c.Host, c.Port, r)
return false, &unknown{base{ServerInfo: c}}, xerrors.Errorf("Unable to connect via SSH. Scan with -vvv option to print SSH debugging messages and check SSH settings.\n%s", r)
}
logging.Log.Debugf("Not Debian like Linux. %s", r)
return false, nil, nil
Expand Down
76 changes: 72 additions & 4 deletions scanner/serverapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"math/rand"
"net/http"
"os"
"strings"
"time"

"github.com/future-architect/vuls/cache"
Expand Down Expand Up @@ -278,6 +279,12 @@ func (s Scanner) detectServerOSes() (servers, errServers []osTypeInterface) {
logging.Log.Debugf("Panic: %s on %s", p, srv.ServerName)
}
}()
if err := checkHostinKnownHosts(srv); err != nil {
checkOS := unknown{base{ServerInfo: srv}}
checkOS.setErrs([]error{err})
osTypeChan <- &checkOS
return
}
osTypeChan <- s.detectOS(srv)
}(target)
}
Expand All @@ -288,12 +295,10 @@ func (s Scanner) detectServerOSes() (servers, errServers []osTypeInterface) {
case res := <-osTypeChan:
if 0 < len(res.getErrs()) {
errServers = append(errServers, res)
logging.Log.Errorf("(%d/%d) Failed: %s, err: %+v",
i+1, len(s.Targets), res.getServerInfo().ServerName, res.getErrs())
logging.Log.Errorf("(%d/%d) Failed: %s, err: %+v", i+1, len(s.Targets), res.getServerInfo().ServerName, res.getErrs())
} else {
servers = append(servers, res)
logging.Log.Infof("(%d/%d) Detected: %s: %s",
i+1, len(s.Targets), res.getServerInfo().ServerName, res.getDistro())
logging.Log.Infof("(%d/%d) Detected: %s: %s", i+1, len(s.Targets), res.getServerInfo().ServerName, res.getDistro())
}
case <-timeout:
msg := "Timed out while detecting servers"
Expand All @@ -319,6 +324,69 @@ func (s Scanner) detectServerOSes() (servers, errServers []osTypeInterface) {
return
}

func checkHostinKnownHosts(c config.ServerInfo) error {
if isLocalExec(c.Port, c.Host) {
return nil
}

args := []string{"-G"}
if len(c.SSHConfigPath) > 0 {
args = []string{"-G", "-F", c.SSHConfigPath}
}
r := localExec(c, fmt.Sprintf("ssh %s %s", strings.Join(args, " "), c.Host), noSudo)
if !r.isSuccess() {
return xerrors.Errorf("Failed to print SSH configuration. err: %w", r.Error)
}

var (
hostname string
globalKnownHosts string
userKnownHosts string
)
for _, line := range strings.Split(r.Stdout, "\n") {
if strings.HasPrefix(line, "hostname ") {
hostname = strings.TrimPrefix(line, "hostname ")
} else if strings.HasPrefix(line, "globalknownhostsfile ") {
globalKnownHosts = strings.TrimPrefix(line, "globalknownhostsfile ")
} else if strings.HasPrefix(line, "userknownhostsfile ") {
userKnownHosts = strings.TrimPrefix(line, "userknownhostsfile ")
}
}

knownHostsPaths := []string{}
for _, knownHosts := range []string{userKnownHosts, globalKnownHosts} {
for _, knownHost := range strings.Split(knownHosts, " ") {
if knownHost != "" {
knownHostsPaths = append(knownHostsPaths, knownHost)
}
}
}
if len(knownHostsPaths) == 0 {
return xerrors.New("Failed to find any known_hosts to use. Please check the UserKnownHostsFile and GlobalKnownHostsFile settings for SSH.")
}

for _, knownHosts := range knownHostsPaths {
if c.Port != "" && c.Port != "22" {
cmd := fmt.Sprintf("ssh-keygen -F %s -f %s", fmt.Sprintf("\"[%s]:%s\"", c.Host, c.Port), knownHosts)
if r := localExec(c, cmd, noSudo); r.isSuccess() {
return nil
}
}
cmd := fmt.Sprintf("ssh-keygen -F %s -f %s", c.Host, knownHosts)
if r := localExec(c, cmd, noSudo); r.isSuccess() {
return nil
}
}

sshCmd := fmt.Sprintf("ssh -i %s %s@%s", c.KeyPath, c.User, c.Host)
sshKeyScancmd := fmt.Sprintf("ssh-keyscan -H %s >> %s", hostname, knownHostsPaths[0])
if c.Port != "" && c.Port != "22" {
sshCmd = fmt.Sprintf("ssh -i %s -p %s %s@%s", c.KeyPath, c.Port, c.User, c.Host)
sshKeyScancmd = fmt.Sprintf("ssh-keyscan -H -p %s %s >> %s", c.Port, hostname, knownHostsPaths[0])
}
return xerrors.Errorf("Failed to find the host in known_hosts. Plaese exec `$ %s` or `$ %s`", sshCmd, sshKeyScancmd)
}

func (s Scanner) detectContainerOSes(hosts []osTypeInterface) (actives, inactives []osTypeInterface) {
logging.Log.Info("Detecting OS of containers... ")
osTypesChan := make(chan []osTypeInterface, len(hosts))
Expand Down