Compare commits

...

7 Commits

Author SHA1 Message Date
Kota Kanbe
f78dab50cb fix(fast-root): affectedProcs, ports bug (#1067) 2020-10-31 14:21:11 +09:00
Norihiro NAKAOKA
edb324c3d9 fix(portscan): ignore loopback address on remote scan (#1062)
* change ignore loop back address on remote scan

* fix test case

* change append simple

* fix format

* set golangci-lint timeout

* Revert "set golangci-lint timeout"

This reverts commit 56b1c7089a.
2020-10-23 16:40:03 +09:00
Norihiro NAKAOKA
83bcca6e66 experimental: add smart(fast, minimum ports, silently) TCP port scanner (#1060)
* add struct ListenPorts

* change parse to models.ListenPorts from string

* change support models.ListenPorts in TUI

* add scanPort template , detectScanDest

* add Test_detectScanDest

* change impl scanPorts template

* fix build error

* change collect scan success address

* add Test_matchListenPorts

* add Test_updatePortStatus

* change display port scan result on tui

* change display scan emoji on report

* Revert "change display scan emoji on report"

This reverts commit e281882cc6.

* add continue

* change display format

* change no use loop label

* remove comment code

* change display

* fix padding

* change refactoring var , fn name

* fix var name

* fix var name

* change eye icon

* change icon

* delete unuse mod
2020-10-19 17:47:20 +09:00
Kota Kanbe
a124518d78 fix: hard-coded version #1057 (#1059) 2020-10-16 20:42:31 +09:00
Alexander Stein
94bf630e29 Expand negative grep match for any error for lib scans. (#1056)
Many thanks 👍 

Sure, that's better.

Note: FreeBSD
find: `find: /var/run/ppp: Permission denied`
2020-10-12 11:30:11 +09:00
shopper
31bb33fd90 ignore apk warning (#1052) 2020-10-12 10:40:01 +09:00
Kota Kanbe
4b680b9960 fix(scan-freebsd): also get installed with pkg info #1042 (#1051)
* fix(scan-freebsd): also get installed with `pkg info` #1042

* fix test
2020-09-12 05:08:41 +09:00
15 changed files with 567 additions and 37 deletions

View File

@@ -16,7 +16,7 @@ import (
)
// Version of Vuls
var Version = "0.9.9"
var Version = "`make build` or `make install` will show the version"
// Revision of Git
var Revision string

View File

@@ -174,9 +174,29 @@ type Changelog struct {
// AffectedProcess keep a processes information affected by software update
type AffectedProcess struct {
PID string `json:"pid,omitempty"`
Name string `json:"name,omitempty"`
ListenPorts []string `json:"listenPorts,omitempty"`
PID string `json:"pid,omitempty"`
Name string `json:"name,omitempty"`
ListenPorts []ListenPort `json:"listenPorts,omitempty"`
}
// ListenPort has the result of parsing the port information to the address and port.
type ListenPort struct {
Address string `json:"address"`
Port string `json:"port"`
PortScanSuccessOn []string `json:"portScanSuccessOn"`
}
// HasPortScanSuccessOn checks if Package.AffectedProcs has PortScanSuccessOn
func (p Package) HasPortScanSuccessOn() bool {
for _, ap := range p.AffectedProcs {
for _, lp := range ap.ListenPorts {
if len(lp.PortScanSuccessOn) > 0 {
return true
}
}
}
return false
}
// NeedRestartProcess keep a processes information affected by software update

View File

@@ -416,6 +416,10 @@ func (r ScanResult) FormatAlertSummary() string {
}
func (r ScanResult) isDisplayUpdatableNum() bool {
if r.Family == config.FreeBSD {
return false
}
var mode config.ScanMode
s, _ := config.Conf.Servers[r.ServerName]
mode = s.Mode

View File

@@ -688,7 +688,7 @@ func TestIsDisplayUpdatableNum(t *testing.T) {
{
mode: []byte{config.Fast},
family: config.FreeBSD,
expected: true,
expected: false,
},
{
mode: []byte{config.Fast},

View File

@@ -13,7 +13,7 @@ type StdoutWriter struct{}
// WriteScanSummary prints Scan summary at the end of scan
func (w StdoutWriter) WriteScanSummary(rs ...models.ScanResult) {
fmt.Printf("\n\n")
fmt.Println("One Line Summary")
fmt.Println("Scan Summary")
fmt.Println("================")
fmt.Printf("%s\n", formatScanSummary(rs...))
}

View File

@@ -617,6 +617,14 @@ func summaryLines(r models.ScanResult) string {
pkgNames = append(pkgNames, vinfo.WpPackageFixStats.Names()...)
pkgNames = append(pkgNames, vinfo.LibraryFixedIns.Names()...)
av := vinfo.AttackVector()
for _, pname := range vinfo.AffectedPackages.Names() {
if r.Packages[pname].HasPortScanSuccessOn() {
av = fmt.Sprintf("%s ◉", av)
break
}
}
exploits := ""
if 0 < len(vinfo.Exploits) || 0 < len(vinfo.Metasploits) {
exploits = "POC"
@@ -627,7 +635,7 @@ func summaryLines(r models.ScanResult) string {
fmt.Sprintf(indexFormat, i+1),
vinfo.CveID,
cvssScore + " |",
fmt.Sprintf("%4s |", vinfo.AttackVector()),
fmt.Sprintf("%-6s |", av),
fmt.Sprintf("%3s |", exploits),
fmt.Sprintf("%6s |", vinfo.AlertDict.FormatSource()),
fmt.Sprintf("%7s |", vinfo.PatchStatus(r.Packages)),
@@ -639,6 +647,7 @@ func summaryLines(r models.ScanResult) string {
}
stable.AddRow(icols...)
}
return fmt.Sprintf("%s", stable)
}
@@ -710,8 +719,23 @@ func setChangelogLayout(g *gocui.Gui) error {
if len(pack.AffectedProcs) != 0 {
for _, p := range pack.AffectedProcs {
if len(p.ListenPorts) == 0 {
lines = append(lines, fmt.Sprintf(" * PID: %s %s Port: []",
p.PID, p.Name))
continue
}
var ports []string
for _, pp := range p.ListenPorts {
if len(pp.PortScanSuccessOn) == 0 {
ports = append(ports, fmt.Sprintf("%s:%s", pp.Address, pp.Port))
} else {
ports = append(ports, fmt.Sprintf("%s:%s(◉ Scannable: %s)", pp.Address, pp.Port, pp.PortScanSuccessOn))
}
}
lines = append(lines, fmt.Sprintf(" * PID: %s %s Port: %s",
p.PID, p.Name, p.ListenPorts))
p.PID, p.Name, ports))
}
}
}

View File

@@ -261,8 +261,22 @@ No CVE-IDs are found in updatable packages.
if len(pack.AffectedProcs) != 0 {
for _, p := range pack.AffectedProcs {
if len(p.ListenPorts) == 0 {
data = append(data, []string{"",
fmt.Sprintf(" - PID: %s %s, Port: []", p.PID, p.Name)})
}
var ports []string
for _, pp := range p.ListenPorts {
if len(pp.PortScanSuccessOn) == 0 {
ports = append(ports, fmt.Sprintf("%s:%s", pp.Address, pp.Port))
} else {
ports = append(ports, fmt.Sprintf("%s:%s(◉ Scannable: %s)", pp.Address, pp.Port, pp.PortScanSuccessOn))
}
}
data = append(data, []string{"",
fmt.Sprintf(" - PID: %s %s, Port: %s", p.PID, p.Name, p.ListenPorts)})
fmt.Sprintf(" - PID: %s %s, Port: %s", p.PID, p.Name, ports)})
}
}
}

View File

@@ -147,6 +147,9 @@ func (o *alpine) parseApkInfo(stdout string) (models.Packages, error) {
line := scanner.Text()
ss := strings.Split(line, "-")
if len(ss) < 3 {
if strings.Contains(ss[0], "WARNING") {
continue
}
return nil, xerrors.Errorf("Failed to parse apk info -v: %s", line)
}
name := strings.Join(ss[:len(ss)-2], "-")

View File

@@ -546,8 +546,8 @@ func (l *base) scanLibraries() (err error) {
}
// delete last "-o "
// find / -name "*package-lock.json" -o -name "*yarn.lock" ... 2>&1 | grep -v "Permission denied"
cmd := fmt.Sprintf(`find / ` + findopt[:len(findopt)-3] + ` 2>&1 | grep -v "Permission denied"`)
// find / -name "*package-lock.json" -o -name "*yarn.lock" ... 2>&1 | grep -v "find: "
cmd := fmt.Sprintf(`find / ` + findopt[:len(findopt)-3] + ` 2>&1 | grep -v "find: "`)
r := exec(l.ServerInfo, cmd, noSudo)
if r.ExitStatus != 0 && r.ExitStatus != 1 {
return xerrors.Errorf("Failed to find lock files")
@@ -729,6 +729,113 @@ func (l *base) detectWpPlugins() ([]models.WpPackage, error) {
return plugins, nil
}
func (l *base) scanPorts() (err error) {
dest := l.detectScanDest()
open, err := l.execPortsScan(dest)
if err != nil {
return err
}
l.updatePortStatus(open)
return nil
}
func (l *base) detectScanDest() map[string][]string {
scanIPPortsMap := map[string][]string{}
for _, p := range l.osPackages.Packages {
if p.AffectedProcs == nil {
continue
}
for _, proc := range p.AffectedProcs {
if proc.ListenPorts == nil {
continue
}
for _, port := range proc.ListenPorts {
scanIPPortsMap[port.Address] = append(scanIPPortsMap[port.Address], port.Port)
}
}
}
scanDestIPPorts := map[string][]string{}
for addr, ports := range scanIPPortsMap {
if addr == "*" {
for _, addr := range l.ServerInfo.IPv4Addrs {
scanDestIPPorts[addr] = append(scanDestIPPorts[addr], ports...)
}
} else {
scanDestIPPorts[addr] = append(scanDestIPPorts[addr], ports...)
}
}
uniqScanDestIPPorts := map[string][]string{}
for i, scanDest := range scanDestIPPorts {
m := map[string]bool{}
for _, e := range scanDest {
if !m[e] {
m[e] = true
uniqScanDestIPPorts[i] = append(uniqScanDestIPPorts[i], e)
}
}
}
return uniqScanDestIPPorts
}
func (l *base) execPortsScan(scanDestIPPorts map[string][]string) ([]string, error) {
listenIPPorts := []string{}
for ip, ports := range scanDestIPPorts {
if !isLocalExec(l.ServerInfo.Port, l.ServerInfo.Host) && net.ParseIP(ip).IsLoopback() {
continue
}
for _, port := range ports {
scanDest := ip + ":" + port
conn, err := net.DialTimeout("tcp", scanDest, time.Duration(1)*time.Second)
if err != nil {
continue
}
conn.Close()
listenIPPorts = append(listenIPPorts, scanDest)
}
}
return listenIPPorts, nil
}
func (l *base) updatePortStatus(listenIPPorts []string) {
for name, p := range l.osPackages.Packages {
if p.AffectedProcs == nil {
continue
}
for i, proc := range p.AffectedProcs {
if proc.ListenPorts == nil {
continue
}
for j, port := range proc.ListenPorts {
l.osPackages.Packages[name].AffectedProcs[i].ListenPorts[j].PortScanSuccessOn = l.findPortScanSuccessOn(listenIPPorts, port)
}
}
}
}
func (l *base) findPortScanSuccessOn(listenIPPorts []string, searchListenPort models.ListenPort) []string {
addrs := []string{}
for _, ipPort := range listenIPPorts {
ipPort := l.parseListenPorts(ipPort)
if searchListenPort.Address == "*" {
if searchListenPort.Port == ipPort.Port {
addrs = append(addrs, ipPort.Address)
}
} else if searchListenPort.Address == ipPort.Address && searchListenPort.Port == ipPort.Port {
addrs = append(addrs, ipPort.Address)
}
}
return addrs
}
func (l *base) ps() (stdout string, err error) {
cmd := `LANGUAGE=en_US.UTF-8 ps --no-headers --ppid 2 -p 2 --deselect -o pid,comm`
r := l.exec(util.PrependProxyEnv(cmd), noSudo)
@@ -791,13 +898,13 @@ func (l *base) lsOfListen() (stdout string, err error) {
cmd := `lsof -i -P -n | grep LISTEN`
r := l.exec(util.PrependProxyEnv(cmd), sudo)
if !r.isSuccess(0, 1) {
return "", xerrors.Errorf("Failed to SSH: %s", r)
return "", xerrors.Errorf("Failed to lsof: %s", r)
}
return r.Stdout, nil
}
func (l *base) parseLsOf(stdout string) map[string]string {
portPid := map[string]string{}
func (l *base) parseLsOf(stdout string) map[string][]string {
portPids := map[string][]string{}
scanner := bufio.NewScanner(strings.NewReader(stdout))
for scanner.Scan() {
ss := strings.Fields(scanner.Text())
@@ -805,7 +912,15 @@ func (l *base) parseLsOf(stdout string) map[string]string {
continue
}
pid, ipPort := ss[1], ss[8]
portPid[ipPort] = pid
portPids[ipPort] = util.AppendIfMissing(portPids[ipPort], pid)
}
return portPid
return portPids
}
func (l *base) parseListenPorts(port string) models.ListenPort {
sep := strings.LastIndex(port, ":")
if sep == -1 {
return models.ListenPort{}
}
return models.ListenPort{Address: port[:sep], Port: port[sep+1:]}
}

View File

@@ -12,6 +12,7 @@ import (
_ "github.com/aquasecurity/fanal/analyzer/library/poetry"
_ "github.com/aquasecurity/fanal/analyzer/library/yarn"
"github.com/future-architect/vuls/config"
"github.com/future-architect/vuls/models"
)
func TestParseDockerPs(t *testing.T) {
@@ -243,7 +244,7 @@ func Test_base_parseLsOf(t *testing.T) {
tests := []struct {
name string
args args
wantPortPid map[string]string
wantPortPid map[string][]string
}{
{
name: "lsof",
@@ -256,13 +257,34 @@ node 1498 ubuntu 21u IPv6 20132 0t0 TCP *:35401 (LISTEN
node 1498 ubuntu 22u IPv6 20133 0t0 TCP *:44801 (LISTEN)
docker-pr 9135 root 4u IPv6 297133 0t0 TCP *:6379 (LISTEN)`,
},
wantPortPid: map[string]string{
"localhost:53": "474",
"*:22": "644",
"*:3128": "959",
"*:35401": "1498",
"*:44801": "1498",
"*:6379": "9135",
wantPortPid: map[string][]string{
"localhost:53": {"474"},
"*:22": {"644"},
"*:3128": {"959"},
"*:35401": {"1498"},
"*:44801": {"1498"},
"*:6379": {"9135"},
},
},
{
name: "lsof-duplicate-port",
args: args{
stdout: `sshd 832 root 3u IPv4 15731 0t0 TCP *:22 (LISTEN)
sshd 832 root 4u IPv6 15740 0t0 TCP *:22 (LISTEN)
master 1099 root 13u IPv4 16657 0t0 TCP 127.0.0.1:25 (LISTEN)
master 1099 root 14u IPv6 16658 0t0 TCP [::1]:25 (LISTEN)
httpd 32250 root 4u IPv6 334982 0t0 TCP *:80 (LISTEN)
httpd 32251 apache 4u IPv6 334982 0t0 TCP *:80 (LISTEN)
httpd 32252 apache 4u IPv6 334982 0t0 TCP *:80 (LISTEN)
httpd 32253 apache 4u IPv6 334982 0t0 TCP *:80 (LISTEN)
httpd 32254 apache 4u IPv6 334982 0t0 TCP *:80 (LISTEN)
httpd 32255 apache 4u IPv6 334982 0t0 TCP *:80 (LISTEN)`,
},
wantPortPid: map[string][]string{
"*:22": {"832"},
"127.0.0.1:25": {"1099"},
"[::1]:25": {"1099"},
"*:80": {"32250", "32251", "32252", "32253", "32254", "32255"},
},
},
}
@@ -275,3 +297,242 @@ docker-pr 9135 root 4u IPv6 297133 0t0 TCP *:6379 (LISTEN)
})
}
}
func Test_detectScanDest(t *testing.T) {
tests := []struct {
name string
args base
expect map[string][]string
}{
{
name: "empty",
args: base{osPackages: osPackages{
Packages: models.Packages{"curl": models.Package{
Name: "curl",
Version: "7.64.0-4+deb10u1",
NewVersion: "7.64.0-4+deb10u1",
}},
}},
expect: map[string][]string{},
},
{
name: "single-addr",
args: base{osPackages: osPackages{
Packages: models.Packages{"libaudit1": models.Package{
Name: "libaudit1",
Version: "1:2.8.4-3",
NewVersion: "1:2.8.4-3",
AffectedProcs: []models.AffectedProcess{
{PID: "21", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "127.0.0.1", Port: "22"}}}, {PID: "10876", Name: "sshd"}},
},
}},
},
expect: map[string][]string{"127.0.0.1": {"22"}},
},
{
name: "dup-addr-port",
args: base{osPackages: osPackages{
Packages: models.Packages{"libaudit1": models.Package{
Name: "libaudit1",
Version: "1:2.8.4-3",
NewVersion: "1:2.8.4-3",
AffectedProcs: []models.AffectedProcess{
{PID: "21", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "127.0.0.1", Port: "22"}}}, {PID: "21", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "127.0.0.1", Port: "22"}}}},
},
}},
},
expect: map[string][]string{"127.0.0.1": {"22"}},
},
{
name: "multi-addr",
args: base{osPackages: osPackages{
Packages: models.Packages{"libaudit1": models.Package{
Name: "libaudit1",
Version: "1:2.8.4-3",
NewVersion: "1:2.8.4-3",
AffectedProcs: []models.AffectedProcess{
{PID: "21", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "127.0.0.1", Port: "22"}}}, {PID: "21", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "192.168.1.1", Port: "22"}}}, {PID: "6261", Name: "nginx", ListenPorts: []models.ListenPort{{Address: "127.0.0.1", Port: "80"}}}},
},
}},
},
expect: map[string][]string{"127.0.0.1": {"22", "80"}, "192.168.1.1": {"22"}},
},
{
name: "asterisk",
args: base{
osPackages: osPackages{
Packages: models.Packages{"libaudit1": models.Package{
Name: "libaudit1",
Version: "1:2.8.4-3",
NewVersion: "1:2.8.4-3",
AffectedProcs: []models.AffectedProcess{
{PID: "21", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "*", Port: "22"}}}},
},
}},
ServerInfo: config.ServerInfo{
IPv4Addrs: []string{"127.0.0.1", "192.168.1.1"},
},
},
expect: map[string][]string{"127.0.0.1": {"22"}, "192.168.1.1": {"22"}},
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if dest := tt.args.detectScanDest(); !reflect.DeepEqual(dest, tt.expect) {
t.Errorf("base.detectScanDest() = %v, want %v", dest, tt.expect)
}
})
}
}
func Test_updatePortStatus(t *testing.T) {
type args struct {
l base
listenIPPorts []string
}
tests := []struct {
name string
args args
expect models.Packages
}{
{name: "nil_affected_procs",
args: args{
l: base{osPackages: osPackages{
Packages: models.Packages{"libc-bin": models.Package{Name: "libc-bin"}},
}},
listenIPPorts: []string{"127.0.0.1:22"}},
expect: models.Packages{"libc-bin": models.Package{Name: "libc-bin"}}},
{name: "nil_listen_ports",
args: args{
l: base{osPackages: osPackages{
Packages: models.Packages{"bash": models.Package{Name: "bash", AffectedProcs: []models.AffectedProcess{{PID: "1", Name: "bash"}}}},
}},
listenIPPorts: []string{"127.0.0.1:22"}},
expect: models.Packages{"bash": models.Package{Name: "bash", AffectedProcs: []models.AffectedProcess{{PID: "1", Name: "bash"}}}}},
{name: "update_match_single_address",
args: args{
l: base{osPackages: osPackages{
Packages: models.Packages{"libc6": models.Package{Name: "libc6", AffectedProcs: []models.AffectedProcess{{PID: "1", Name: "bash"}, {PID: "75", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "127.0.0.1", Port: "22"}}}}}},
}},
listenIPPorts: []string{"127.0.0.1:22"}},
expect: models.Packages{"libc6": models.Package{Name: "libc6", AffectedProcs: []models.AffectedProcess{{PID: "1", Name: "bash"}, {PID: "75", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "127.0.0.1", Port: "22", PortScanSuccessOn: []string{"127.0.0.1"}}}}}}}},
{name: "update_match_multi_address",
args: args{
l: base{osPackages: osPackages{
Packages: models.Packages{"libc6": models.Package{Name: "libc6", AffectedProcs: []models.AffectedProcess{{PID: "1", Name: "bash"}, {PID: "75", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "127.0.0.1", Port: "22"}, {Address: "192.168.1.1", Port: "22"}}}}}},
}},
listenIPPorts: []string{"127.0.0.1:22", "192.168.1.1:22"}},
expect: models.Packages{"libc6": models.Package{Name: "libc6", AffectedProcs: []models.AffectedProcess{{PID: "1", Name: "bash"}, {PID: "75", Name: "sshd", ListenPorts: []models.ListenPort{
{Address: "127.0.0.1", Port: "22", PortScanSuccessOn: []string{"127.0.0.1"}},
{Address: "192.168.1.1", Port: "22", PortScanSuccessOn: []string{"192.168.1.1"}},
}}}}}},
{name: "update_match_asterisk",
args: args{
l: base{osPackages: osPackages{
Packages: models.Packages{"libc6": models.Package{Name: "libc6", AffectedProcs: []models.AffectedProcess{{PID: "1", Name: "bash"}, {PID: "75", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "*", Port: "22"}}}}}},
}},
listenIPPorts: []string{"127.0.0.1:22", "127.0.0.1:80", "192.168.1.1:22"}},
expect: models.Packages{"libc6": models.Package{Name: "libc6", AffectedProcs: []models.AffectedProcess{{PID: "1", Name: "bash"}, {PID: "75", Name: "sshd", ListenPorts: []models.ListenPort{
{Address: "*", Port: "22", PortScanSuccessOn: []string{"127.0.0.1", "192.168.1.1"}},
}}}}}},
{name: "update_multi_packages",
args: args{
l: base{osPackages: osPackages{
Packages: models.Packages{
"packa": models.Package{Name: "packa", AffectedProcs: []models.AffectedProcess{{PID: "75", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "127.0.0.1", Port: "80"}}}}},
"packb": models.Package{Name: "packb", AffectedProcs: []models.AffectedProcess{{PID: "75", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "127.0.0.1", Port: "22"}}}}},
"packc": models.Package{Name: "packc", AffectedProcs: []models.AffectedProcess{{PID: "75", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "127.0.0.1", Port: "22"}, {Address: "192.168.1.1", Port: "22"}}}}},
"packd": models.Package{Name: "packd", AffectedProcs: []models.AffectedProcess{{PID: "75", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "*", Port: "22"}}}}},
},
}},
listenIPPorts: []string{"127.0.0.1:22", "192.168.1.1:22"}},
expect: models.Packages{
"packa": models.Package{Name: "packa", AffectedProcs: []models.AffectedProcess{{PID: "75", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "127.0.0.1", Port: "80", PortScanSuccessOn: []string{}}}}}},
"packb": models.Package{Name: "packb", AffectedProcs: []models.AffectedProcess{{PID: "75", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "127.0.0.1", Port: "22", PortScanSuccessOn: []string{"127.0.0.1"}}}}}},
"packc": models.Package{Name: "packc", AffectedProcs: []models.AffectedProcess{{PID: "75", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "127.0.0.1", Port: "22", PortScanSuccessOn: []string{"127.0.0.1"}}, {Address: "192.168.1.1", Port: "22", PortScanSuccessOn: []string{"192.168.1.1"}}}}}},
"packd": models.Package{Name: "packd", AffectedProcs: []models.AffectedProcess{{PID: "75", Name: "sshd", ListenPorts: []models.ListenPort{{Address: "*", Port: "22", PortScanSuccessOn: []string{"127.0.0.1", "192.168.1.1"}}}}}},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.args.l.updatePortStatus(tt.args.listenIPPorts)
if !reflect.DeepEqual(tt.args.l.osPackages.Packages, tt.expect) {
t.Errorf("l.updatePortStatus() = %v, want %v", tt.args.l.osPackages.Packages, tt.expect)
}
})
}
}
func Test_matchListenPorts(t *testing.T) {
type args struct {
listenIPPorts []string
searchListenPort models.ListenPort
}
tests := []struct {
name string
args args
expect []string
}{
{name: "open_empty", args: args{listenIPPorts: []string{}, searchListenPort: models.ListenPort{Address: "127.0.0.1", Port: "22"}}, expect: []string{}},
{name: "port_empty", args: args{listenIPPorts: []string{"127.0.0.1:22"}, searchListenPort: models.ListenPort{}}, expect: []string{}},
{name: "single_match", args: args{listenIPPorts: []string{"127.0.0.1:22"}, searchListenPort: models.ListenPort{Address: "127.0.0.1", Port: "22"}}, expect: []string{"127.0.0.1"}},
{name: "no_match_address", args: args{listenIPPorts: []string{"127.0.0.1:22"}, searchListenPort: models.ListenPort{Address: "192.168.1.1", Port: "22"}}, expect: []string{}},
{name: "no_match_port", args: args{listenIPPorts: []string{"127.0.0.1:22"}, searchListenPort: models.ListenPort{Address: "127.0.0.1", Port: "80"}}, expect: []string{}},
{name: "asterisk_match", args: args{listenIPPorts: []string{"127.0.0.1:22", "127.0.0.1:80", "192.168.1.1:22"}, searchListenPort: models.ListenPort{Address: "*", Port: "22"}}, expect: []string{"127.0.0.1", "192.168.1.1"}},
}
l := base{}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if match := l.findPortScanSuccessOn(tt.args.listenIPPorts, tt.args.searchListenPort); !reflect.DeepEqual(match, tt.expect) {
t.Errorf("findPortScanSuccessOn() = %v, want %v", match, tt.expect)
}
})
}
}
func Test_base_parseListenPorts(t *testing.T) {
tests := []struct {
name string
args string
expect models.ListenPort
}{{
name: "empty",
args: "",
expect: models.ListenPort{
Address: "",
Port: "",
},
}, {
name: "normal",
args: "127.0.0.1:22",
expect: models.ListenPort{
Address: "127.0.0.1",
Port: "22",
},
}, {
name: "asterisk",
args: "*:22",
expect: models.ListenPort{
Address: "*",
Port: "22",
},
}, {
name: "ipv6_loopback",
args: "[::1]:22",
expect: models.ListenPort{
Address: "[::1]",
Port: "22",
},
}}
l := base{}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if listenPort := l.parseListenPorts(tt.args); !reflect.DeepEqual(listenPort, tt.expect) {
t.Errorf("base.parseListenPorts() = %v, want %v", listenPort, tt.expect)
}
})
}
}

View File

@@ -1294,14 +1294,16 @@ func (o *debian) dpkgPs() error {
pidLoadedFiles[pid] = append(pidLoadedFiles[pid], ss...)
}
pidListenPorts := map[string][]string{}
pidListenPorts := map[string][]models.ListenPort{}
stdout, err = o.lsOfListen()
if err != nil {
return xerrors.Errorf("Failed to ls of: %w", err)
}
portPid := o.parseLsOf(stdout)
for port, pid := range portPid {
pidListenPorts[pid] = append(pidListenPorts[pid], port)
portPids := o.parseLsOf(stdout)
for port, pids := range portPids {
for _, pid := range pids {
pidListenPorts[pid] = append(pidListenPorts[pid], o.parseListenPorts(port))
}
}
for pid, loadedFiles := range pidLoadedFiles {

View File

@@ -163,12 +163,24 @@ func (o *bsd) rebootRequired() (bool, error) {
}
func (o *bsd) scanInstalledPackages() (models.Packages, error) {
cmd := util.PrependProxyEnv("pkg version -v")
// https://github.com/future-architect/vuls/issues/1042
cmd := util.PrependProxyEnv("pkg info")
r := o.exec(cmd, noSudo)
if !r.isSuccess() {
return nil, xerrors.Errorf("Failed to SSH: %s", r)
}
return o.parsePkgVersion(r.Stdout), nil
pkgs := o.parsePkgInfo(r.Stdout)
cmd = util.PrependProxyEnv("pkg version -v")
r = o.exec(cmd, noSudo)
if !r.isSuccess() {
return nil, xerrors.Errorf("Failed to SSH: %s", r)
}
// `pkg-audit` has a new version, overwrite it.
for name, p := range o.parsePkgVersion(r.Stdout) {
pkgs[name] = p
}
return pkgs, nil
}
func (o *bsd) scanUnsecurePackages() (models.VulnInfos, error) {
@@ -247,6 +259,27 @@ func (o *bsd) scanUnsecurePackages() (models.VulnInfos, error) {
return vinfos, nil
}
func (o *bsd) parsePkgInfo(stdout string) models.Packages {
packs := models.Packages{}
lines := strings.Split(stdout, "\n")
for _, l := range lines {
fields := strings.Fields(l)
if len(fields) < 2 {
continue
}
packVer := fields[0]
splitted := strings.Split(packVer, "-")
ver := splitted[len(splitted)-1]
name := strings.Join(splitted[:len(splitted)-1], "-")
packs[name] = models.Package{
Name: name,
Version: ver,
}
}
return packs
}
func (o *bsd) parsePkgVersion(stdout string) models.Packages {
packs := models.Packages{}
lines := strings.Split(stdout, "\n")

View File

@@ -197,3 +197,50 @@ WWW: https://vuxml.FreeBSD.org/freebsd/ab3e98d9-8175-11e4-907d-d050992ecde8.html
}
}
}
func TestParsePkgInfo(t *testing.T) {
var tests = []struct {
in string
expected models.Packages
}{
{
`bash-4.2.45 Universal Command Line Interface for Amazon Web Services
gettext-0.18.3.1 Startup scripts for FreeBSD/EC2 environment
tcl84-8.4.20_2,1 Update the system using freebsd-update when it first boots
ntp-4.2.8p8_1 GNU gettext runtime libraries and programs
teTeX-base-3.0_25 Foreign Function Interface`,
models.Packages{
"bash": {
Name: "bash",
Version: "4.2.45",
},
"gettext": {
Name: "gettext",
Version: "0.18.3.1",
},
"tcl84": {
Name: "tcl84",
Version: "8.4.20_2,1",
},
"teTeX-base": {
Name: "teTeX-base",
Version: "3.0_25",
},
"ntp": {
Name: "ntp",
Version: "4.2.8p8_1",
},
},
},
}
d := newBsd(config.ServerInfo{})
for _, tt := range tests {
actual := d.parsePkgInfo(tt.in)
if !reflect.DeepEqual(tt.expected, actual) {
e := pp.Sprintf("%v", tt.expected)
a := pp.Sprintf("%v", actual)
t.Errorf("expected %s, actual %s", e, a)
}
}
}

View File

@@ -361,7 +361,7 @@ func (o *redhatBase) scanUpdatablePackages() (models.Packages, error) {
return nil, xerrors.Errorf("Failed to SSH: %s", r)
}
// Collect Updateble packages, installed, candidate version and repository.
// Collect Updatable packages, installed, candidate version and repository.
return o.parseUpdatablePacksLines(r.Stdout)
}
@@ -491,14 +491,16 @@ func (o *redhatBase) yumPs() error {
pidLoadedFiles[pid] = append(pidLoadedFiles[pid], ss...)
}
pidListenPorts := map[string][]string{}
pidListenPorts := map[string][]models.ListenPort{}
stdout, err = o.lsOfListen()
if err != nil {
return xerrors.Errorf("Failed to ls of: %w", err)
}
portPid := o.parseLsOf(stdout)
for port, pid := range portPid {
pidListenPorts[pid] = append(pidListenPorts[pid], port)
portPids := o.parseLsOf(stdout)
for port, pids := range portPids {
for _, pid := range pids {
pidListenPorts[pid] = append(pidListenPorts[pid], o.parseListenPorts(port))
}
}
for pid, loadedFiles := range pidLoadedFiles {
@@ -630,8 +632,8 @@ func (o *redhatBase) procPathToFQPN(execCommand string) (string, error) {
func (o *redhatBase) getPkgName(paths []string) (pkgNames []string, err error) {
cmd := o.rpmQf(o.Distro) + strings.Join(paths, " ")
r := o.exec(util.PrependProxyEnv(cmd), noSudo)
if !r.isSuccess() {
return nil, xerrors.Errorf("Failed to SSH: %s", r)
if !r.isSuccess(0, 2, 4, 8) {
return nil, xerrors.Errorf("Failed to rpm -qf: %s, cmd: %s", r, cmd)
}
scanner := bufio.NewScanner(strings.NewReader(r.Stdout))

View File

@@ -48,6 +48,7 @@ type osTypeInterface interface {
postScan() error
scanWordPress() error
scanLibraries() error
scanPorts() error
scanPackages() error
convertToModel() models.ScanResult
@@ -634,6 +635,9 @@ func GetScanResults(scannedAt time.Time, timeoutSec int) (results models.ScanRes
if err = o.scanLibraries(); err != nil {
return xerrors.Errorf("Failed to scan Library: %w", err)
}
if err = o.scanPorts(); err != nil {
return xerrors.Errorf("Failed to scan Ports: %w", err)
}
return nil
}, timeoutSec)
@@ -642,6 +646,7 @@ func GetScanResults(scannedAt time.Time, timeoutSec int) (results models.ScanRes
if err != nil {
util.Log.Errorf("Failed to fetch scannedIPs. err: %+v", err)
}
for _, s := range append(servers, errServers...) {
r := s.convertToModel()
r.ScannedAt = scannedAt