// Scaning unsecure packages using yum-plugin-security. //TODO return whether already expired. func (o *redhat) scanUnsecurePackagesUsingYumPluginSecurity() (CvePacksList, error) { if o.Family == "centos" { // CentOS has no security channel. // So use yum check-update && parse changelog return CvePacksList{}, fmt.Errorf( "yum updateinfo is not suppported on CentOS") } cmd := "yum --color=never repolist" r := o.ssh(util.PrependProxyEnv(cmd), sudo) if !r.isSuccess() { return nil, fmt.Errorf( "Failed to %s. status: %d, stdout: %s, stderr: %s", cmd, r.ExitStatus, r.Stdout, r.Stderr) } // get advisoryID(RHSA, ALAS) - package name,version cmd = "yum --color=never updateinfo list available --security" r = o.ssh(util.PrependProxyEnv(cmd), sudo) if !r.isSuccess() { return nil, fmt.Errorf( "Failed to %s. status: %d, stdout: %s, stderr: %s", cmd, r.ExitStatus, r.Stdout, r.Stderr) } advIDPackNamesList, err := o.parseYumUpdateinfoListAvailable(r.Stdout) // get package name, version, rel to be upgrade. // cmd = "yum check-update --security" cmd = "LANG=en_US.UTF-8 yum --color=never check-update" r = o.ssh(util.PrependProxyEnv(cmd), sudo) if !r.isSuccess(0, 100) { //returns an exit code of 100 if there are available updates. return nil, fmt.Errorf( "Failed to %s. status: %d, stdout: %s, stderr: %s", cmd, r.ExitStatus, r.Stdout, r.Stderr) } updatable, err := o.parseYumCheckUpdateLines(r.Stdout) if err != nil { return nil, fmt.Errorf("Failed to parse %s. err: %s", cmd, err) } o.log.Debugf("%s", pp.Sprintf("%v", updatable)) dict := map[string][]models.PackageInfo{} for _, advIDPackNames := range advIDPackNamesList { packInfoList := models.PackageInfoList{} for _, packName := range advIDPackNames.PackNames { packInfo, found := updatable.FindByName(packName) if !found { return nil, fmt.Errorf( "PackInfo not found. packInfo: %#v", packName) } packInfoList = append(packInfoList, packInfo) continue } dict[advIDPackNames.AdvisoryID] = packInfoList } // get advisoryID(RHSA, ALAS) - CVE IDs cmd = "yum --color=never updateinfo --security update" r = o.ssh(util.PrependProxyEnv(cmd), sudo) if !r.isSuccess() { return nil, fmt.Errorf( "Failed to %s. status: %d, stdout: %s, stderr: %s", cmd, r.ExitStatus, r.Stdout, r.Stderr) } advisoryCveIDsList, err := o.parseYumUpdateinfo(r.Stdout) if err != nil { return CvePacksList{}, err } // pp.Println(advisoryCveIDsList) // All information collected. // Convert to CvePacksList. o.log.Info("Fetching CVE details...") result := CvePacksList{} for _, advIDCveIDs := range advisoryCveIDsList { cveDetails, err := cveapi.CveClient.FetchCveDetails(advIDCveIDs.CveIDs) if err != nil { return nil, err } for _, cveDetail := range cveDetails { found := false for i, p := range result { if cveDetail.CveID == p.CveID { advAppended := append(p.DistroAdvisories, advIDCveIDs.DistroAdvisory) result[i].DistroAdvisories = advAppended packs := dict[advIDCveIDs.DistroAdvisory.AdvisoryID] result[i].Packs = append(result[i].Packs, packs...) found = true break } } if !found { cpinfo := CvePacksInfo{ CveID: cveDetail.CveID, CveDetail: cveDetail, DistroAdvisories: []models.DistroAdvisory{advIDCveIDs.DistroAdvisory}, Packs: dict[advIDCveIDs.DistroAdvisory.AdvisoryID], } result = append(result, cpinfo) } } } o.log.Info("Done") return result, nil }
// For CentOS func (o *redhat) scanUnsecurePackagesUsingYumCheckUpdate() (models.VulnInfos, error) { cmd := "LANGUAGE=en_US.UTF-8 yum --color=never %s check-update" if o.getServerInfo().Enablerepo != "" { cmd = fmt.Sprintf(cmd, "--enablerepo="+o.getServerInfo().Enablerepo) } else { cmd = fmt.Sprintf(cmd, "") } r := o.exec(util.PrependProxyEnv(cmd), sudo) if !r.isSuccess(0, 100) { //returns an exit code of 100 if there are available updates. return nil, fmt.Errorf("Failed to SSH: %s", r) } // get Updateble package name, installed, candidate version. packInfoList, err := o.parseYumCheckUpdateLines(r.Stdout) if err != nil { return nil, fmt.Errorf("Failed to parse %s. err: %s", cmd, err) } o.log.Debugf("%s", pp.Sprintf("%v", packInfoList)) // set candidate version info o.Packages.MergeNewVersion(packInfoList) // Collect CVE-IDs in changelog type PackInfoCveIDs struct { PackInfo models.PackageInfo CveIDs []string } allChangelog, err := o.getAllChangelog(packInfoList) if err != nil { o.log.Errorf("Failed to getAllchangelog. err: %s", err) return nil, err } // { packageName: changelog-lines } var rpm2changelog map[string]*string rpm2changelog, err = o.parseAllChangelog(allChangelog) if err != nil { return nil, fmt.Errorf("Failed to parseAllChangelog. err: %s", err) } var results []PackInfoCveIDs for i, packInfo := range packInfoList { changelog := o.getChangelogCVELines(rpm2changelog, packInfo) // Collect unique set of CVE-ID in each changelog uniqueCveIDMap := make(map[string]bool) lines := strings.Split(changelog, "\n") for _, line := range lines { cveIDs := o.parseYumUpdateinfoLineToGetCveIDs(line) for _, c := range cveIDs { uniqueCveIDMap[c] = true } } // keys var cveIDs []string for k := range uniqueCveIDMap { cveIDs = append(cveIDs, k) } p := PackInfoCveIDs{ PackInfo: packInfo, CveIDs: cveIDs, } results = append(results, p) o.log.Infof("(%d/%d) Scanned %s-%s-%s -> %s-%s : %s", i+1, len(packInfoList), p.PackInfo.Name, p.PackInfo.Version, p.PackInfo.Release, p.PackInfo.NewVersion, p.PackInfo.NewRelease, p.CveIDs) } // transform datastructure // - From // [ // { // PackInfo: models.PackageInfo, // CveIDs: []string, // }, // ] // - To // map { // CveID: []models.PackageInfo // } cveIDPackInfoMap := make(map[string][]models.PackageInfo) for _, res := range results { for _, cveID := range res.CveIDs { cveIDPackInfoMap[cveID] = append( cveIDPackInfoMap[cveID], res.PackInfo) } } vinfos := []models.VulnInfo{} for k, v := range cveIDPackInfoMap { // Amazon, RHEL do not use this method, so VendorAdvisory do not set. vinfos = append(vinfos, models.VulnInfo{ CveID: k, Packages: v, }) } return vinfos, nil }
//TODO return whether already expired. func (o *redhat) scanUnsecurePackagesUsingYumCheckUpdate() (CvePacksList, error) { cmd := "LANG=en_US.UTF-8 yum --color=never check-update" r := o.ssh(util.PrependProxyEnv(cmd), sudo) if !r.isSuccess(0, 100) { //returns an exit code of 100 if there are available updates. return nil, fmt.Errorf( "Failed to %s. status: %d, stdout: %s, stderr: %s", cmd, r.ExitStatus, r.Stdout, r.Stderr) } // get Updateble package name, installed, candidate version. packInfoList, err := o.parseYumCheckUpdateLines(r.Stdout) if err != nil { return nil, fmt.Errorf("Failed to parse %s. err: %s", cmd, err) } o.log.Debugf("%s", pp.Sprintf("%v", packInfoList)) // Collect CVE-IDs in changelog type PackInfoCveIDs struct { PackInfo models.PackageInfo CveIDs []string } var results []PackInfoCveIDs for i, packInfo := range packInfoList { changelog, err := o.getChangelog(packInfo.Name) if err != nil { o.log.Errorf("Failed to collect CVE IDs. err: %s", err) return nil, err } // Collect unique set of CVE-ID in each changelog uniqueCveIDMap := make(map[string]bool) lines := strings.Split(changelog, "\n") for _, line := range lines { cveIDs := o.parseYumUpdateinfoLineToGetCveIDs(line) for _, c := range cveIDs { uniqueCveIDMap[c] = true } } // keys var cveIDs []string for k := range uniqueCveIDMap { cveIDs = append(cveIDs, k) } p := PackInfoCveIDs{ PackInfo: packInfo, CveIDs: cveIDs, } results = append(results, p) o.log.Infof("(%d/%d) Scanned %s-%s-%s -> %s-%s : %s", i+1, len(packInfoList), p.PackInfo.Name, p.PackInfo.Version, p.PackInfo.Release, p.PackInfo.NewVersion, p.PackInfo.NewRelease, p.CveIDs) } // transform datastructure // - From // [ // { // PackInfo: models.PackageInfo, // CveIDs: []string, // }, // ] // - To // map { // CveID: []models.PackageInfo // } cveIDPackInfoMap := make(map[string][]models.PackageInfo) for _, res := range results { for _, cveID := range res.CveIDs { // packInfo, found := o.Packages.FindByName(res.Packname) // if !found { // return CvePacksList{}, fmt.Errorf( // "Faild to transform data structure: %v", res.Packname) // } cveIDPackInfoMap[cveID] = append(cveIDPackInfoMap[cveID], res.PackInfo) } } var uniqueCveIDs []string for cveID := range cveIDPackInfoMap { uniqueCveIDs = append(uniqueCveIDs, cveID) } // cveIDs => []cve.CveInfo o.log.Info("Fetching CVE details...") cveDetails, err := cveapi.CveClient.FetchCveDetails(uniqueCveIDs) if err != nil { return nil, err } o.log.Info("Done") cvePacksList := []CvePacksInfo{} for _, detail := range cveDetails { // Amazon, RHEL do not use this method, so VendorAdvisory do not set. cvePacksList = append(cvePacksList, CvePacksInfo{ CveID: detail.CveID, CveDetail: detail, Packs: cveIDPackInfoMap[detail.CveID], // CvssScore: cinfo.CvssScore(conf.Lang), }) } return cvePacksList, nil }
// Scaning unsecure packages using yum-plugin-security. // Amazon, RHEL func (o *redhat) scanUnsecurePackagesUsingYumPluginSecurity() (models.VulnInfos, error) { if o.Distro.Family == "centos" { // CentOS has no security channel. // So use yum check-update && parse changelog return nil, fmt.Errorf( "yum updateinfo is not suppported on CentOS") } cmd := "yum --color=never repolist" r := o.exec(util.PrependProxyEnv(cmd), o.sudo()) if !r.isSuccess() { return nil, fmt.Errorf("Failed to SSH: %s", r) } // get advisoryID(RHSA, ALAS) - package name,version major, err := (o.Distro.MajorVersion()) if err != nil { return nil, fmt.Errorf("Not implemented yet: %s, err: %s", o.Distro, err) } if o.Distro.Family == "rhel" && major == 5 { cmd = "yum --color=never list-security --security" } else { cmd = "yum --color=never --security updateinfo list updates" } r = o.exec(util.PrependProxyEnv(cmd), o.sudo()) if !r.isSuccess() { return nil, fmt.Errorf("Failed to SSH: %s", r) } advIDPackNamesList, err := o.parseYumUpdateinfoListAvailable(r.Stdout) // get package name, version, rel to be upgrade. // cmd = "yum check-update --security" cmd = "LANGUAGE=en_US.UTF-8 yum --color=never check-update" r = o.exec(util.PrependProxyEnv(cmd), o.sudo()) if !r.isSuccess(0, 100) { //returns an exit code of 100 if there are available updates. return nil, fmt.Errorf("Failed to SSH: %s", r) } updatable, err := o.parseYumCheckUpdateLines(r.Stdout) if err != nil { return nil, fmt.Errorf("Failed to parse %s. err: %s", cmd, err) } o.log.Debugf("%s", pp.Sprintf("%v", updatable)) // set candidate version info o.Packages.MergeNewVersion(updatable) dict := map[string][]models.PackageInfo{} for _, advIDPackNames := range advIDPackNamesList { packInfoList := models.PackageInfoList{} for _, packName := range advIDPackNames.PackNames { packInfo, found := updatable.FindByName(packName) if !found { return nil, fmt.Errorf( "PackInfo not found. packInfo: %#v", packName) } packInfoList = append(packInfoList, packInfo) continue } dict[advIDPackNames.AdvisoryID] = packInfoList } // get advisoryID(RHSA, ALAS) - CVE IDs if o.Distro.Family == "rhel" && major == 5 { cmd = "yum --color=never info-sec" } else { cmd = "yum --color=never --security updateinfo updates" } r = o.exec(util.PrependProxyEnv(cmd), o.sudo()) if !r.isSuccess() { return nil, fmt.Errorf("Failed to SSH: %s", r) } advisoryCveIDsList, err := o.parseYumUpdateinfo(r.Stdout) if err != nil { return nil, err } // pp.Println(advisoryCveIDsList) // All information collected. // Convert to VulnInfos. vinfos := models.VulnInfos{} for _, advIDCveIDs := range advisoryCveIDsList { for _, cveID := range advIDCveIDs.CveIDs { found := false for i, p := range vinfos { if cveID == p.CveID { advAppended := append(p.DistroAdvisories, advIDCveIDs.DistroAdvisory) vinfos[i].DistroAdvisories = advAppended packs := dict[advIDCveIDs.DistroAdvisory.AdvisoryID] vinfos[i].Packages = append(vinfos[i].Packages, packs...) found = true break } } if !found { cpinfo := models.VulnInfo{ CveID: cveID, DistroAdvisories: []models.DistroAdvisory{advIDCveIDs.DistroAdvisory}, Packages: dict[advIDCveIDs.DistroAdvisory.AdvisoryID], } vinfos = append(vinfos, cpinfo) } } } return vinfos, nil }
func (o *debian) install() error { if len(o.lackDependencies) == 0 { return nil } // apt-get update o.log.Infof("apt-get update...") cmd := util.PrependProxyEnv("apt-get update") if r := o.exec(cmd, sudo); !r.isSuccess() { msg := fmt.Sprintf("Failed to SSH: %s", r) o.log.Errorf(msg) return fmt.Errorf(msg) } for _, name := range o.lackDependencies { cmd = util.PrependProxyEnv("apt-get install -y " + name) if r := o.exec(cmd, sudo); !r.isSuccess() { msg := fmt.Sprintf("Failed to SSH: %s", r) o.log.Errorf(msg) return fmt.Errorf(msg) } o.log.Infof("Installed: " + name) } return nil }
func (o *debian) GetUnsecurePackNamesUsingUnattendedUpgrades() (packNames []string, err error) { cmd := util.PrependProxyEnv("unattended-upgrades --dry-run -d 2>&1 ") release, err := strconv.ParseFloat(o.Release, 64) if err != nil { return packNames, fmt.Errorf( "OS Release Version is invalid, %s, %s", o.Family, o.Release) } switch { case release < 12: return packNames, fmt.Errorf( "Support expired. %s, %s", o.Family, o.Release) case 12 < release && release < 14: cmd += `| grep 'pkgs that look like they should be upgraded:' | sed -e 's/pkgs that look like they should be upgraded://g'` case 14 < release: cmd += `| grep 'Packages that will be upgraded:' | sed -e 's/Packages that will be upgraded://g'` default: return packNames, fmt.Errorf( "Not supported yet. %s, %s", o.Family, o.Release) } r := o.ssh(cmd, sudo) if r.isSuccess(0, 1) { packNames = strings.Split(strings.TrimSpace(r.Stdout), " ") return packNames, nil } return packNames, fmt.Errorf( "Failed to %s. status: %d, stdout: %s, stderr: %s", cmd, r.ExitStatus, r.Stdout, r.Stderr) }
func (o *debian) scanPackageCveIDs(pack models.PackageInfo) ([]string, error) { cmd := "" switch o.Distro.Family { case "ubuntu": cmd = fmt.Sprintf(`apt-get changelog %s | grep '\(urgency\|CVE\)'`, pack.Name) case "debian": cmd = fmt.Sprintf(`aptitude changelog %s | grep '\(urgency\|CVE\)'`, pack.Name) } cmd = util.PrependProxyEnv(cmd) r := o.exec(cmd, noSudo) if !r.isSuccess() { o.log.Warnf("Failed to SSH: %s", r) // Ignore this Error. return nil, nil } if 0 < len(strings.TrimSpace(r.Stdout)) { err := cache.DB.PutChangelog(o.getServerInfo().GetServerName(), pack.Name, r.Stdout) if err != nil { return nil, fmt.Errorf("Failed to put changelog into cache") } } // No error will be returned. Only logging. return o.getCveIDFromChangelog(r.Stdout, pack.Name, pack.Version), nil }
func (o *debian) install() error { // apt-get update o.log.Infof("apt-get update...") cmd := util.PrependProxyEnv("apt-get update") if r := o.ssh(cmd, sudo); !r.isSuccess() { msg := fmt.Sprintf("Failed to %s. status: %d, stdout: %s, stderr: %s", cmd, r.ExitStatus, r.Stdout, r.Stderr) o.log.Errorf(msg) return fmt.Errorf(msg) } if o.Family == "debian" { // install aptitude cmd = util.PrependProxyEnv("apt-get install --force-yes -y aptitude") if r := o.ssh(cmd, sudo); !r.isSuccess() { msg := fmt.Sprintf("Failed to %s. status: %d, stdout: %s, stderr: %s", cmd, r.ExitStatus, r.Stdout, r.Stderr) o.log.Errorf(msg) return fmt.Errorf(msg) } o.log.Infof("Installed: aptitude") } // install unattended-upgrades if !config.Conf.UseUnattendedUpgrades { return nil } if r := o.ssh("type unattended-upgrade", noSudo); r.isSuccess() { o.log.Infof( "Ignored: unattended-upgrade already installed") return nil } cmd = util.PrependProxyEnv( "apt-get install --force-yes -y unattended-upgrades") if r := o.ssh(cmd, sudo); !r.isSuccess() { msg := fmt.Sprintf("Failed to %s. status: %d, stdout: %s, stderr: %s", cmd, r.ExitStatus, r.Stdout, r.Stderr) o.log.Errorf(msg) return fmt.Errorf(msg) } o.log.Infof("Installed: unattended-upgrades") return nil }
func (o *bsd) scanInstalledPackages() ([]models.PackageInfo, error) { cmd := util.PrependProxyEnv("pkg version -v") r := o.exec(cmd, noSudo) if !r.isSuccess() { return nil, fmt.Errorf("Failed to SSH: %s", r) } return o.parsePkgVersion(r.Stdout), nil }
func (o *bsd) scanInstalledPackages() ([]models.PackageInfo, error) { cmd := util.PrependProxyEnv("pkg version -v") r := o.ssh(cmd, noSudo) if !r.isSuccess() { return nil, fmt.Errorf("Failed to %s. status: %d, stdout:%s, Stderr: %s", cmd, r.ExitStatus, r.Stdout, r.Stderr) } return o.parsePkgVersion(r.Stdout), nil }
func (o *debian) GetUpgradablePackNames() (packNames []string, err error) { cmd := util.PrependProxyEnv("LANGUAGE=en_US.UTF-8 apt-get upgrade --dry-run") r := o.exec(cmd, sudo) if r.isSuccess(0, 1) { return o.parseAptGetUpgrade(r.Stdout) } return packNames, fmt.Errorf( "Failed to %s. status: %d, stdout: %s, stderr: %s", cmd, r.ExitStatus, r.Stdout, r.Stderr) }
func (o *redhat) install() error { for _, name := range o.lackDependencies { cmd := util.PrependProxyEnv("yum install -y " + name) if r := o.exec(cmd, sudo); !r.isSuccess() { return fmt.Errorf("Failed to SSH: %s", r) } o.log.Infof("Installed: %s", name) } return nil }
func (o *debian) scanUnsecurePackages(installed []models.PackageInfo) ([]models.VulnInfo, error) { o.log.Infof("apt-get update...") cmd := util.PrependProxyEnv("apt-get update") if r := o.exec(cmd, sudo); !r.isSuccess() { return nil, fmt.Errorf("Failed to SSH: %s", r) } // Convert the name of upgradable packages to PackageInfo struct upgradableNames, err := o.GetUpgradablePackNames() if err != nil { return nil, err } var upgradablePacks []models.PackageInfo for _, name := range upgradableNames { for _, pack := range installed { if pack.Name == name { upgradablePacks = append(upgradablePacks, pack) break } } } // Fill the candidate versions of upgradable packages upgradablePacks, err = o.fillCandidateVersion(upgradablePacks) if err != nil { return nil, fmt.Errorf("Failed to fill candidate versions. err: %s", err) } o.Packages.MergeNewVersion(upgradablePacks) // Setup changelog cache current := cache.Meta{ Name: o.getServerInfo().GetServerName(), Distro: o.getServerInfo().Distro, Packs: upgradablePacks, } o.log.Debugf("Ensure changelog cache: %s", current.Name) var meta *cache.Meta if meta, err = o.ensureChangelogCache(current); err != nil { return nil, err } // Collect CVE information of upgradable packages vulnInfos, err := o.scanVulnInfos(upgradablePacks, meta) if err != nil { return nil, fmt.Errorf("Failed to scan unsecure packages. err: %s", err) } return vulnInfos, nil }
//TODO return whether already expired. func (o *debian) scanUnsecurePackages(packs []models.PackageInfo) ([]CvePacksInfo, error) { // cmd := prependProxyEnv(conf.HTTPProxy, "apt-get update | cat; echo 1") cmd := util.PrependProxyEnv("apt-get update") if r := o.ssh(cmd, sudo); !r.isSuccess() { return nil, fmt.Errorf( "Failed to %s. status: %d, stdout: %s, stderr: %s", cmd, r.ExitStatus, r.Stdout, r.Stderr, ) } var upgradablePackNames []string var err error if config.Conf.UseUnattendedUpgrades { upgradablePackNames, err = o.GetUnsecurePackNamesUsingUnattendedUpgrades() if err != nil { return []CvePacksInfo{}, err } } else { upgradablePackNames, err = o.GetUpgradablePackNames() if err != nil { return []CvePacksInfo{}, err } } // Convert package name to PackageInfo struct var unsecurePacks []models.PackageInfo for _, name := range upgradablePackNames { for _, pack := range packs { if pack.Name == name { unsecurePacks = append(unsecurePacks, pack) break } } } unsecurePacks, err = o.fillCandidateVersion(unsecurePacks) if err != nil { return nil, fmt.Errorf("Failed to fill candidate versions. err: %s", err) } // Collect CVE information of upgradable packages cvePacksInfos, err := o.scanPackageCveInfos(unsecurePacks) if err != nil { return nil, fmt.Errorf("Failed to scan unsecure packages. err: %s", err) } return cvePacksInfos, nil }
func (o *redhat) installYumPluginSecurity() error { if r := o.ssh("rpm -q yum-plugin-security", noSudo); r.isSuccess() { o.log.Infof("Ignored: yum-plugin-security already installed") return nil } o.log.Info("Installing yum-plugin-security...") cmd := util.PrependProxyEnv("yum install -y yum-plugin-security") if r := o.ssh(cmd, sudo); !r.isSuccess() { return fmt.Errorf( "Failed to %s. status: %d, stdout: %s, stderr: %s", cmd, r.ExitStatus, r.Stdout, r.Stderr) } return nil }
func (o *debian) scanPackageCveIDs(pack models.PackageInfo) ([]string, error) { cmd := "" switch o.Family { case "ubuntu": cmd = fmt.Sprintf(`apt-get changelog %s | grep '\(urgency\|CVE\)'`, pack.Name) case "debian": cmd = fmt.Sprintf(`aptitude changelog %s | grep '\(urgency\|CVE\)'`, pack.Name) } cmd = util.PrependProxyEnv(cmd) r := o.ssh(cmd, noSudo) if !r.isSuccess() { o.log.Warnf( "Failed to %s. status: %d, stdout: %s, stderr: %s", cmd, r.ExitStatus, r.Stdout, r.Stderr) // Ignore this Error. return nil, nil } return o.getCveIDParsingChangelog(r.Stdout, pack.Name, pack.Version) }
func (o *redhat) installYumChangelog() error { if o.Family == "centos" { var majorVersion int if 0 < len(o.Release) { majorVersion, _ = strconv.Atoi(strings.Split(o.Release, ".")[0]) } else { return fmt.Errorf( "Not implemented yet. family: %s, release: %s", o.Family, o.Release) } var packName = "" if majorVersion < 6 { packName = "yum-changelog" } else { packName = "yum-plugin-changelog" } cmd := "rpm -q " + packName if r := o.ssh(cmd, noSudo); r.isSuccess() { o.log.Infof("Ignored: %s already installed", packName) return nil } o.log.Infof("Installing %s...", packName) cmd = util.PrependProxyEnv("yum install -y " + packName) if r := o.ssh(cmd, sudo); !r.isSuccess() { return fmt.Errorf( "Failed to install %s. status: %d, stdout: %s, stderr: %s", packName, r.ExitStatus, r.Stdout, r.Stderr) } o.log.Infof("Installed: %s", packName) } return nil }
func (o *bsd) scanUnsecurePackages() (vulnInfos []models.VulnInfo, err error) { const vulndbPath = "/tmp/vuln.db" cmd := "rm -f " + vulndbPath r := o.exec(cmd, noSudo) if !r.isSuccess(0) { return nil, fmt.Errorf("Failed to SSH: %s", r) } cmd = util.PrependProxyEnv("pkg audit -F -r -f " + vulndbPath) r = o.exec(cmd, noSudo) if !r.isSuccess(0, 1) { return nil, fmt.Errorf("Failed to SSH: %s", r) } if r.ExitStatus == 0 { // no vulnerabilities return []models.VulnInfo{}, nil } var packAdtRslt []pkgAuditResult blocks := o.splitIntoBlocks(r.Stdout) for _, b := range blocks { name, cveIDs, vulnID := o.parseBlock(b) if len(cveIDs) == 0 { continue } pack, found := o.Packages.FindByName(name) if !found { return nil, fmt.Errorf("Vulnerable package: %s is not found", name) } packAdtRslt = append(packAdtRslt, pkgAuditResult{ pack: pack, vulnIDCveIDs: vulnIDCveIDs{ vulnID: vulnID, cveIDs: cveIDs, }, }) } // { CVE ID: []pkgAuditResult } cveIDAdtMap := make(map[string][]pkgAuditResult) for _, p := range packAdtRslt { for _, cid := range p.vulnIDCveIDs.cveIDs { cveIDAdtMap[cid] = append(cveIDAdtMap[cid], p) } } for k := range cveIDAdtMap { packs := []models.PackageInfo{} for _, r := range cveIDAdtMap[k] { packs = append(packs, r.pack) } disAdvs := []models.DistroAdvisory{} for _, r := range cveIDAdtMap[k] { disAdvs = append(disAdvs, models.DistroAdvisory{ AdvisoryID: r.vulnIDCveIDs.vulnID, }) } vulnInfos = append(vulnInfos, models.VulnInfo{ CveID: k, Packages: packs, DistroAdvisories: disAdvs, }) } return }
func (o *bsd) scanUnsecurePackages() (cvePacksList []CvePacksInfo, err error) { const vulndbPath = "/tmp/vuln.db" cmd := "rm -f " + vulndbPath r := o.ssh(cmd, noSudo) if !r.isSuccess(0) { return nil, fmt.Errorf("Failed to %s. status: %d, stdout:%s, Stderr: %s", cmd, r.ExitStatus, r.Stdout, r.Stderr) } cmd = util.PrependProxyEnv("pkg audit -F -r -f " + vulndbPath) r = o.ssh(cmd, noSudo) if !r.isSuccess(0, 1) { return nil, fmt.Errorf("Failed to %s. status: %d, stdout:%s, Stderr: %s", cmd, r.ExitStatus, r.Stdout, r.Stderr) } if r.ExitStatus == 0 { // no vulnerabilities return []CvePacksInfo{}, nil } var packAdtRslt []pkgAuditResult blocks := o.splitIntoBlocks(r.Stdout) for _, b := range blocks { name, cveIDs, vulnID := o.parseBlock(b) if len(cveIDs) == 0 { continue } pack, found := o.Packages.FindByName(name) if !found { return nil, fmt.Errorf("Vulnerable package: %s is not found", name) } packAdtRslt = append(packAdtRslt, pkgAuditResult{ pack: pack, vulnIDCveIDs: vulnIDCveIDs{ vulnID: vulnID, cveIDs: cveIDs, }, }) } // { CVE ID: []pkgAuditResult } cveIDAdtMap := make(map[string][]pkgAuditResult) for _, p := range packAdtRslt { for _, cid := range p.vulnIDCveIDs.cveIDs { cveIDAdtMap[cid] = append(cveIDAdtMap[cid], p) } } cveIDs := []string{} for k := range cveIDAdtMap { cveIDs = append(cveIDs, k) } cveDetails, err := cveapi.CveClient.FetchCveDetails(cveIDs) if err != nil { return nil, err } o.log.Info("Done") for _, d := range cveDetails { packs := []models.PackageInfo{} for _, r := range cveIDAdtMap[d.CveID] { packs = append(packs, r.pack) } disAdvs := []models.DistroAdvisory{} for _, r := range cveIDAdtMap[d.CveID] { disAdvs = append(disAdvs, models.DistroAdvisory{ AdvisoryID: r.vulnIDCveIDs.vulnID, }) } cvePacksList = append(cvePacksList, CvePacksInfo{ CveID: d.CveID, CveDetail: d, Packs: packs, DistroAdvisories: disAdvs, }) } return }