Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e788e6a5ad | ||
|
|
d00e912934 | ||
|
|
8ebb663368 | ||
|
|
445ffc4123 | ||
|
|
6af49f4d55 | ||
|
|
1de9e8c086 | ||
|
|
59b0812adf | ||
|
|
719785c1ed | ||
|
|
8e5f627e59 | ||
|
|
5ced3c72b8 | ||
|
|
c002f0168c | ||
|
|
00c690f516 | ||
|
|
ab68ad5cc5 | ||
|
|
5c84ebefab | ||
|
|
eb2acaff22 | ||
|
|
84d0655c52 | ||
|
|
e137ebb9c2 | ||
|
|
10d690d929 | ||
|
|
14611d2fd9 | ||
|
|
0665bfe15f |
@@ -1,5 +1,7 @@
|
||||
# Change Log
|
||||
|
||||
## v0.4.1 and later, see [GitHub release](https://github.com/future-architect/vuls/releases)
|
||||
|
||||
## [v0.4.0](https://github.com/future-architect/vuls/tree/v0.4.0) (2017-08-25)
|
||||
[Full Changelog](https://github.com/future-architect/vuls/compare/v0.3.0...v0.4.0)
|
||||
|
||||
@@ -509,4 +511,4 @@
|
||||
|
||||
|
||||
|
||||
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
||||
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
||||
|
||||
56
Gopkg.lock
generated
56
Gopkg.lock
generated
@@ -4,14 +4,14 @@
|
||||
[[projects]]
|
||||
name = "github.com/Azure/azure-sdk-for-go"
|
||||
packages = ["storage"]
|
||||
revision = "df4dd90d076ebbf6e87d08d3f00bfac8ff4bde1a"
|
||||
version = "v10.3.1-beta"
|
||||
revision = "7692b0cef22674113fcf71cc17ac3ccc1a7fef48"
|
||||
version = "v11.2.2-beta"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/Azure/go-autorest"
|
||||
packages = ["autorest","autorest/adal","autorest/azure","autorest/date"]
|
||||
revision = "f6be1abbb5abd0517522f850dd785990d373da7e"
|
||||
version = "v8.4.0"
|
||||
revision = "c67b24a8e30d876542a85022ebbdecf0e5a935e8"
|
||||
version = "v9.4.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/BurntSushi/toml"
|
||||
@@ -28,8 +28,8 @@
|
||||
[[projects]]
|
||||
name = "github.com/aws/aws-sdk-go"
|
||||
packages = ["aws","aws/awserr","aws/awsutil","aws/client","aws/client/metadata","aws/corehandlers","aws/credentials","aws/credentials/ec2rolecreds","aws/credentials/endpointcreds","aws/credentials/stscreds","aws/defaults","aws/ec2metadata","aws/endpoints","aws/request","aws/session","aws/signer/v4","internal/shareddefaults","private/protocol","private/protocol/query","private/protocol/query/queryutil","private/protocol/rest","private/protocol/restxml","private/protocol/xml/xmlutil","service/s3","service/sts"]
|
||||
revision = "c652f9369083515c3ddf1fbaf6df68da2c101545"
|
||||
version = "v1.12.1"
|
||||
revision = "e4f7e38b704e3ed0acc4a7f8196b777696f6f1f3"
|
||||
version = "v1.12.30"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/boltdb/bolt"
|
||||
@@ -52,20 +52,20 @@
|
||||
[[projects]]
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
packages = ["."]
|
||||
revision = "d2709f9f1f31ebcda9651b03077758c1f3a0018c"
|
||||
version = "v3.0.0"
|
||||
revision = "dbeaa9332f19a944acb5736b4456cfcc02140e29"
|
||||
version = "v3.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-ini/ini"
|
||||
packages = ["."]
|
||||
revision = "20b96f641a5ea98f2f8619ff4f3e061cff4833bd"
|
||||
version = "v1.28.2"
|
||||
revision = "32e4c1e6bc4e7d0d8451aa6b75200d19e37a536a"
|
||||
version = "v1.32.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-redis/redis"
|
||||
packages = [".","internal","internal/consistenthash","internal/hashtag","internal/pool","internal/proto"]
|
||||
revision = "975882d73d21759d45a4eb49652064083bc23e61"
|
||||
version = "v6.7.0"
|
||||
revision = "e5e021257bfc6d5fbf0beac33e30194311fb189f"
|
||||
version = "v6.7.4"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-sql-driver/mysql"
|
||||
@@ -136,7 +136,7 @@
|
||||
branch = "master"
|
||||
name = "github.com/kotakanbe/go-cve-dictionary"
|
||||
packages = ["config","db","jvn","log","models","nvd","util"]
|
||||
revision = "f5406ffe8226f01f64544723339c6a17b2bd74af"
|
||||
revision = "a64c5fc25cd9669b213986e1a02831c71a5c601d"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/kotakanbe/go-pingscanner"
|
||||
@@ -148,7 +148,7 @@
|
||||
branch = "master"
|
||||
name = "github.com/kotakanbe/goval-dictionary"
|
||||
packages = ["config","db","db/rdb","log","models"]
|
||||
revision = "fd8ff5a6343912117d1b7db16fbd5fa1f4116c3a"
|
||||
revision = "dca4f21940cbf2245a50817177fed7eb6793e72c"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -160,7 +160,7 @@
|
||||
branch = "master"
|
||||
name = "github.com/lib/pq"
|
||||
packages = [".","hstore","oid"]
|
||||
revision = "b77235e3890a962fe8a6f8c4c7198679ca7814e7"
|
||||
revision = "8c6ee72f3e6bcb1542298dd5f76cb74af9742cec"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-colorable"
|
||||
@@ -183,8 +183,8 @@
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-sqlite3"
|
||||
packages = ["."]
|
||||
revision = "ca5e3819723d8eeaf170ad510e7da1d6d2e94a08"
|
||||
version = "v1.2.0"
|
||||
revision = "ed69081a91fd053f17672236b0dd52ba7485e1a3"
|
||||
version = "v1.4.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -198,11 +198,17 @@
|
||||
packages = ["."]
|
||||
revision = "9ac6cf4d929b2fa8fd2d2e6dec5bb0feb4f4911d"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/nlopes/slack"
|
||||
packages = ["."]
|
||||
revision = "c86337c0ef2486a15edd804355d9c73d2f2caed1"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/nsf/termbox-go"
|
||||
packages = ["."]
|
||||
revision = "4ed959e0540971545eddb8c75514973d670cf739"
|
||||
revision = "aa4a75b1c20a2b03751b1a9f7e41d58bd6f71c43"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/parnurzeal/gorequest"
|
||||
@@ -232,7 +238,7 @@
|
||||
branch = "master"
|
||||
name = "github.com/sirupsen/logrus"
|
||||
packages = ["."]
|
||||
revision = "89742aefa4b206dcf400792f3bd35b542998eb3b"
|
||||
revision = "95cd2b9c79aa5e72ab0bc69b7ccc2be15bf850f6"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -244,29 +250,29 @@
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["curve25519","ed25519","ed25519/internal/edwards25519","ssh","ssh/agent","ssh/terminal"]
|
||||
revision = "c84b36c635ad003a10f0c755dff5685ceef18c71"
|
||||
revision = "9f005a07e0d31d45e6656d241bb5c0f2efd4bc94"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/net"
|
||||
packages = ["context","idna","publicsuffix"]
|
||||
revision = "0a9397675ba34b2845f758fe3cd68828369c6517"
|
||||
packages = ["context","idna","publicsuffix","websocket"]
|
||||
revision = "9dfe39835686865bff950a07b394c12a98ddc811"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix","windows"]
|
||||
revision = "314a259e304ff91bd6985da2a7149bbf91237993"
|
||||
revision = "0ac51a24ef1c37380f98ba8b98f56e3bffd59850"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/text"
|
||||
packages = ["collate","collate/build","internal/colltab","internal/gen","internal/tag","internal/triegen","internal/ucd","language","secure/bidirule","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable"]
|
||||
revision = "1cbadb444a806fd9430d14ad08967ed91da4fa0a"
|
||||
revision = "88f656faf3f37f690df1a32515b479415e1a6769"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "36d700add80d36c56484ed310b9a7e622b3e308ab22eb42bdfb02fd8f5c90407"
|
||||
inputs-digest = "58ae46498625e705c582d70591148e07dbac30bc4f75cadef3d2fda514cd5099"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
@@ -88,3 +88,7 @@
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/kotakanbe/go-cve-dictionary"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/kotakanbe/goval-dictionary"
|
||||
|
||||
224
README.fr.md
224
README.fr.md
@@ -1,224 +0,0 @@
|
||||
|
||||
# Vuls: VULnerability Scanner
|
||||
|
||||
[](http://goo.gl/forms/xm5KFo35tu)
|
||||
|
||||
Scanneur de vulnérabilité Linux, sans agent, écrit en golang
|
||||
|
||||
Nous avons une équipe Slack. [Rejoignez notre Slack Team](http://goo.gl/forms/xm5KFo35tu)
|
||||
|
||||
[README en English](https://github.com/future-architect/vuls/blob/master/README.md)
|
||||
[README en Japonais](https://github.com/future-architect/vuls/blob/master/README.ja.md)
|
||||
|
||||
[](https://asciinema.org/a/3y9zrf950agiko7klg8abvyck)
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
----
|
||||
|
||||
# Résumé
|
||||
|
||||
Effectuer des recherches de vulnérabilités et des mises à jour quotidiennes peut etre un fardeau pour un administrateur système.
|
||||
Afin d'éviter des interruptions systèmes dans un environnement de production, il est fréquent pour un administrateur système de choisir de ne pas utiliser la fonction de mise à jour automatique proposée par le gestionnaire de paquets et d'effecter ces mises à jour manuellement.
|
||||
Ce qui implique les problèmes suivants :
|
||||
- L'administrateur système devra surveiller constamment toutes les nouvelles vulnérabilités dans NVD (National Vulnerability Database) etc.
|
||||
- Il pourrait être impossible pour un administrateur système de surveiller tous les logiciels installés sur un serveur.
|
||||
- Il est coûteux d'effectuer une analyse pour déterminer quels sont les serveurs affectés par de nouvelles vulnérabilités. La possibilité de négliger un serveur ou deux est bien présente.
|
||||
|
||||
Vuls est un outil crée pour palier aux problèmes listés ci-dessus. Voici ses caractéristiques.
|
||||
- Informer les utilisateurs des vulnérabilités système.
|
||||
- Informer les utilisateurs des systèmes concernés.
|
||||
- La détection de vulnérabilités est effectuée automatiquement pour éviter toute négligence.
|
||||
- Les rapports sont générés régulièrement via CRON pour mieux gérer ces vulnérabilités.
|
||||
|
||||

|
||||
|
||||
----
|
||||
|
||||
# Caractéristiques principales
|
||||
|
||||
- Recherche de vulnérabilités sur des serveurs Linux
|
||||
- Supporte Ubuntu, Debian, CentOS, Amazon Linux, RHEL, Raspbian
|
||||
- Cloud, auto-hébergement, Docker
|
||||
- Scan d'intergiciels non inclus dans le gestionnaire de paquets de l'OS
|
||||
- Scan d'intergiciels, de libraries de language de programmation et framework pour des vulnérabilités
|
||||
- Supporte les logiciels inscrits au CPE
|
||||
- Architecture sans agent
|
||||
- L'utilisateur doit seulement mettre en place VULS sur une seule machine qui se connectera aux autres via SSH
|
||||
- Génération automatique des fichiers de configuration
|
||||
- Auto detection de serveurs via CIDR et génération de configuration
|
||||
- Email et notification Slack possibles (supporte le Japonais)
|
||||
- Les résultats d'un scan sont accessibles dans un shell via TUI Viewer terminal.
|
||||
|
||||
----
|
||||
|
||||
# Ce que Vuls ne fait pas
|
||||
|
||||
- Vuls ne met pas à jour les programmes affectés par les vulnérabilités découvertes.
|
||||
|
||||
----
|
||||
|
||||
# Hello Vuls
|
||||
|
||||
Ce tutoriel décrit la recherche de vulnérabilités sur une machine locale avec Vuls.
|
||||
Voici les étapes à suivre.
|
||||
|
||||
1. Démrarrage d'Amazon Linux
|
||||
1. Autoriser les connexions SSH depuis localhost
|
||||
1. Installation des prérequis
|
||||
1. Déploiement de go-cve-dictionary
|
||||
1. Deploiement de Vuls
|
||||
1. Configuration
|
||||
1. Préparation
|
||||
1. Scan
|
||||
1. TUI(Terminal-Based User Interface)
|
||||
|
||||
## Step1. Démrarrage d'Amazon Linux
|
||||
|
||||
- Nous utilisons dans cette exemple une vieille AMI (amzn-ami-hvm-2015.09.1.x86_64-gp2 - ami-383c1956)
|
||||
- Taille de l'instance : t2.medium
|
||||
- La première fois, t2.medium et plus sont requis pour la récupération des CVE depuis NVD (2.3GB de mémoire utilisé)
|
||||
- Une fois la récupération initiale des données NVD terminée vous pouvez passer sur une instance t2.nano.
|
||||
- Ajoutez la configuration suivante au cloud-init, afin d'éviter une mise à jour automatique lors du premier démarrage.
|
||||
|
||||
- [Q: How do I disable the automatic installation of critical and important security updates on initial launch?](https://aws.amazon.com/amazon-linux-ami/faqs/?nc1=h_ls)
|
||||
```
|
||||
#cloud-config
|
||||
repo_upgrade: none
|
||||
```
|
||||
|
||||
## Step2. Paramètres SSH
|
||||
|
||||
Il est obligatoire que le serveur puisse se connecter à son propre serveur SSH
|
||||
|
||||
Générez une paire de clés SSH et ajoutez la clé publique dans le fichier authorized_keys
|
||||
```bash
|
||||
$ ssh-keygen -t rsa
|
||||
$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
|
||||
$ chmod 600 ~/.ssh/authorized_keys
|
||||
```
|
||||
|
||||
## Step3. Installation des prérequis
|
||||
|
||||
Vuls requiert l'installation des paquets suivants :
|
||||
|
||||
- sqlite
|
||||
- git
|
||||
- gcc
|
||||
- go v1.7.1 or later
|
||||
- https://golang.org/doc/install
|
||||
|
||||
```bash
|
||||
$ ssh ec2-user@52.100.100.100 -i ~/.ssh/private.pem
|
||||
$ sudo yum -y install sqlite git gcc
|
||||
$ wget https://storage.googleapis.com/golang/go1.7.1.linux-amd64.tar.gz
|
||||
$ sudo tar -C /usr/local -xzf go1.7.1.linux-amd64.tar.gz
|
||||
$ mkdir $HOME/go
|
||||
```
|
||||
Ajoutez les lignes suivantes dans /etc/profile.d/goenv.sh
|
||||
|
||||
```bash
|
||||
export GOROOT=/usr/local/go
|
||||
export GOPATH=$HOME/go
|
||||
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
|
||||
```
|
||||
|
||||
Ajoutons ces nouvelles variables d’environnement au shell
|
||||
```bash
|
||||
$ source /etc/profile.d/goenv.sh
|
||||
```
|
||||
|
||||
## Step4. Déploiement de [go-cve-dictionary](https://github.com/kotakanbe/go-cve-dictionary)
|
||||
|
||||
go get
|
||||
|
||||
```bash
|
||||
$ sudo mkdir /var/log/vuls
|
||||
$ sudo chown ec2-user /var/log/vuls
|
||||
$ sudo chmod 700 /var/log/vuls
|
||||
$ go get github.com/kotakanbe/go-cve-dictionary
|
||||
```
|
||||
|
||||
Démarrez go-cve-dictionary en mode serveur.
|
||||
Lors de son premier démarrage go-cve-dictionary récupère la liste des vulnérabilités depuis NVD
|
||||
Cette opération prend environ 10 minutes (sur AWS).
|
||||
|
||||
## Step5. Déploiement de Vuls
|
||||
|
||||
Ouvrez un second terminal, connectez vous à l'instance ec2 via SSH
|
||||
|
||||
go get
|
||||
```
|
||||
$ go get github.com/future-architect/vuls
|
||||
```
|
||||
|
||||
## Step6. Configuration
|
||||
|
||||
Créez un fichier de configuration (TOML format).
|
||||
|
||||
```
|
||||
$ cat config.toml
|
||||
[servers]
|
||||
|
||||
[servers.172-31-4-82]
|
||||
host = "172.31.4.82"
|
||||
port = "22"
|
||||
user = "ec2-user"
|
||||
keyPath = "/home/ec2-user/.ssh/id_rsa"
|
||||
```
|
||||
|
||||
## Step7. Configuration des serveurs cibles vuls
|
||||
|
||||
```
|
||||
$ vuls prepare
|
||||
```
|
||||
|
||||
## Step8. Scan
|
||||
|
||||
```
|
||||
$ vuls scan -cve-dictionary-dbpath=$PWD/cve.sqlite3
|
||||
INFO[0000] Begin scanning (config: /home/ec2-user/config.toml)
|
||||
|
||||
... snip ...
|
||||
|
||||
172-31-4-82 (amazon 2015.09)
|
||||
============================
|
||||
CVE-2016-0494 10.0 Unspecified vulnerability in the Java SE and Java SE Embedded components in Oracle
|
||||
Java SE 6u105, 7u91, and 8u66 and Java SE Embedded 8u65 allows remote attackers to
|
||||
affect confidentiality, integrity, and availability via unknown vectors related to
|
||||
2D.
|
||||
... snip ...
|
||||
|
||||
CVE-2016-0494
|
||||
-------------
|
||||
Score 10.0 (High)
|
||||
Vector (AV:N/AC:L/Au:N/C:C/I:C/A:C)
|
||||
Summary Unspecified vulnerability in the Java SE and Java SE Embedded components in Oracle Java SE 6u105,
|
||||
7u91, and 8u66 and Java SE Embedded 8u65 allows remote attackers to affect confidentiality,
|
||||
integrity, and availability via unknown vectors related to 2D.
|
||||
NVD https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-0494
|
||||
MITRE https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-0494
|
||||
CVE Details http://www.cvedetails.com/cve/CVE-2016-0494
|
||||
CVSS Calculator https://nvd.nist.gov/cvss/v2-calculator?name=CVE-2016-0494&vector=(AV:N/AC:L/Au:N/C:C/I:C/A:C)
|
||||
RHEL-CVE https://access.redhat.com/security/cve/CVE-2016-0494
|
||||
ALAS-2016-643 https://alas.aws.amazon.com/ALAS-2016-643.html
|
||||
Package/CPE java-1.7.0-openjdk-1.7.0.91-2.6.2.2.63.amzn1 -> java-1.7.0-openjdk-1:1.7.0.95-2.6.4.0.65.amzn1
|
||||
|
||||
```
|
||||
|
||||
## Step9. TUI
|
||||
|
||||
Les résultats de Vuls peuvent etre affichés dans un Shell via TUI (Terminal-Based User Interface).
|
||||
|
||||
```
|
||||
$ vuls tui
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
----
|
||||
|
||||
For more information see [README in English](https://github.com/future-architect/vuls/blob/master/README.md)
|
||||
72
README.ja.md
72
README.ja.md
@@ -91,7 +91,7 @@ Table of Contents
|
||||
* [Example: Use MySQL as a DB storage back-end](#example-use-mysql-as-a-db-storage-back-end)
|
||||
* [Example: Use PostgreSQL as a DB storage back-end](#example-use-postgresql-as-a-db-storage-back-end)
|
||||
* [Example: Use Redis as a DB storage back-end](#example-use-redis-as-a-db-storage-back-end)
|
||||
* [Usage: Scan vulnerability of non-OS package](#usage-scan-vulnerability-of-non-os-package)
|
||||
* [Usage: Scan vulnerability of non-OS package](#usage-scan-vulnerabilites-of-non-os-packages)
|
||||
* [Usage: Integrate with OWASP Dependency Check to Automatic update when the libraries are updated (Experimental)](#usage-integrate-with-owasp-dependency-check-to-automatic-update-when-the-libraries-are-updated-experimental)
|
||||
* [Usage: TUI](#usage-tui)
|
||||
* [Display the latest scan results](#display-the-latest-scan-results)
|
||||
@@ -139,7 +139,7 @@ Vulsは上に挙げた手動運用での課題を解決するツールであり
|
||||
# Main Features
|
||||
|
||||
- サーバに存在する脆弱性をスキャン
|
||||
- FreeBSD, Ubuntu, Debian, CentOS, Amazon Linux, RHEL, Oracle Linux, SUSE Enterprise, Raspbianに対応
|
||||
- Alpine, Ubuntu, Debian, CentOS, Amazon Linux, RHEL, Oracle Linux, SUSE Enterprise, Raspbian, FreeBSD に対応
|
||||
- クラウド、オンプレミス、Docker
|
||||
- 高精度なスキャン
|
||||
- Vulsは複数の脆弱性データベース、複数の検知方法を組み合わせることで高精度なスキャンを実現している
|
||||
@@ -324,6 +324,7 @@ $ goval-dictionary fetch-redhat 7
|
||||
|
||||
今回はスキャン対象がCentOS 7なので、RedHat 7のOVALを取得している。
|
||||
他の種類のOSをスキャンする場合は以下を参照し、スキャン対象用のOVALを取得しておくこと
|
||||
- [Alpine](https://github.com/kotakanbe/goval-dictionary#usage-fetch-alpine-secdb-as-oval-data-type)
|
||||
- [RedHat, CentOS](https://github.com/kotakanbe/goval-dictionary#usage-fetch-oval-data-from-redhat)
|
||||
- [Debian](https://github.com/kotakanbe/goval-dictionary#usage-fetch-oval-data-from-debian)
|
||||
- [Ubuntu](https://github.com/kotakanbe/goval-dictionary#usage-fetch-oval-data-from-ubuntu)
|
||||
@@ -340,9 +341,20 @@ $ git clone https://github.com/future-architect/vuls.git
|
||||
$ cd vuls
|
||||
$ make install
|
||||
```
|
||||
|
||||
The binary was built under `$GOPATH/bin`
|
||||
もしもインストールプロセスが途中で止まる場合は、Out of memory errorが発生している可能性があるので、インスタンスタイプを大きくして再実行してみてください。
|
||||
|
||||
もし、あなたが以前にvulsをインストールしていて update をする場合は以下を実施してください。
|
||||
```
|
||||
$ rm -rf $GOPATH/pkg/linux_amd64/github.com/future-architect/vuls/
|
||||
$ rm -rf $GOPATH/src/github.com/future-architect/vuls/
|
||||
$ cd $GOPATH/src/github.com/future-architect
|
||||
$ git clone https://github.com/future-architect/vuls.git
|
||||
$ cd vuls
|
||||
$ make install
|
||||
```
|
||||
|
||||
## Step6. Config
|
||||
|
||||
Vulsの設定ファイルを作成する(TOMLフォーマット)
|
||||
@@ -582,15 +594,16 @@ Vulsをスキャン対象サーバにデプロイする。Vulsはローカルホ
|
||||
|
||||
| Distribution| Scan Speed | Need Root Privilege | OVAL | Need Internet Access <br>on scan tareget|
|
||||
|:------------|:--------------------------------------:|:-------------------:|:----------:|:---------------------------------------:|
|
||||
| CentOS | Fast | No | Supported | No |
|
||||
| Alpine | Fast | No | Supported | No |
|
||||
| CentOS | Fast | No | Supported | No |
|
||||
| RHEL | Fast | No | Supported | No |
|
||||
| Oracle | Fast | No | Supported | No |
|
||||
| Ubuntu | Fast | No | Supported | No |
|
||||
| Debian | Fast | No | Supported | No |
|
||||
| Raspbian |1st time: Slow <br> From 2nd time: Fast | Need | No | Need |
|
||||
| FreeBSD | Fast | No | No | Need |
|
||||
| Amazon | Fast | No | No | Need |
|
||||
| SUSE Enterprise | Fast | No | Supported | No|
|
||||
| Amazon | Fast | No | No | Need |
|
||||
| SUSE Enterprise | Fast | No | Supported | No |
|
||||
|
||||
----
|
||||
|
||||
@@ -601,7 +614,8 @@ Vulsをスキャン対象サーバにデプロイする。Vulsはローカルホ
|
||||
|
||||
| Distribution| Scan Speed | Need Root Privilege | OVAL | Need Internet Access <br>on scan tareget|
|
||||
|:------------|:-------------------------------------:|:-------------------------:|:---------:|:---------------------------------------:|
|
||||
| CentOS | Slow | No | Supported | Need |
|
||||
| Alpine | Fast | No | Supported | No |
|
||||
| CentOS | Slow | No | Supported | Need |
|
||||
| RHEL | Slow | Need | Supported | Need |
|
||||
| Oracle | Slow | Need | Supported | Need |
|
||||
| Ubuntu |1st time: Slow <br> From 2nd time: Fast| Need | Supported | Need |
|
||||
@@ -609,7 +623,7 @@ Vulsをスキャン対象サーバにデプロイする。Vulsはローカルホ
|
||||
| Raspbian |1st time: Slow <br> From 2nd time: Fast| Need | No | Need |
|
||||
| FreeBSD | Fast | No | No | Need |
|
||||
| Amazon | Slow | No | No | Need |
|
||||
| SUSE Enterprise | Fast | No | Supported | No|
|
||||
| SUSE Enterprise | Fast | No | Supported | No |
|
||||
|
||||
|
||||
- On Ubuntu, Debian and Raspbian
|
||||
@@ -623,7 +637,7 @@ Vulsをスキャン対象サーバにデプロイする。Vulsはローカルホ
|
||||
- On RHEL, Oracle, Amazon and FreeBSD
|
||||
`yum changelog`でアップデート対象のパッケージのチェンジログを取得する(パースはしない)。
|
||||
|
||||
- On SUSE Enterprise Linux
|
||||
- On SUSE Enterprise Linux and Alpine Linux
|
||||
Same as fast scan mode for now.
|
||||
|
||||
----
|
||||
@@ -646,6 +660,7 @@ web/app server in the same configuration under the load balancer
|
||||
|
||||
| Distribution| Release |
|
||||
|:------------|-------------------:|
|
||||
| Alpine | 3.2 and later |
|
||||
| Ubuntu | 12, 14, 16|
|
||||
| Debian | 7, 8, 9|
|
||||
| RHEL | 5, 6, 7|
|
||||
@@ -676,6 +691,7 @@ $ vuls discover 172.31.4.0/24
|
||||
|
||||
[slack]
|
||||
hookURL = "https://hooks.slack.com/services/abc123/defghijklmnopqrstuvwxyz"
|
||||
#legacyToken = "xoxp-11111111111-222222222222-3333333333"
|
||||
channel = "#channel-name"
|
||||
#channel = "${servername}"
|
||||
iconEmoji = ":ghost:"
|
||||
@@ -710,6 +726,7 @@ host = "172.31.4.82"
|
||||
#port = "22"
|
||||
#user = "root"
|
||||
#keyPath = "/home/username/.ssh/id_rsa"
|
||||
#type = "pseudo"
|
||||
#cpeNames = [
|
||||
# "cpe:/a:rubyonrails:ruby_on_rails:4.2.1",
|
||||
#]
|
||||
@@ -732,6 +749,7 @@ host = "172.31.4.82"
|
||||
```
|
||||
[slack]
|
||||
hookURL = "https://hooks.slack.com/services/abc123/defghijklmnopqrstuvwxyz"
|
||||
#legacyToken = "xoxp-11111111111-222222222222-3333333333"
|
||||
channel = "#channel-name"
|
||||
#channel = "${servername}"
|
||||
iconEmoji = ":ghost:"
|
||||
@@ -739,10 +757,21 @@ host = "172.31.4.82"
|
||||
notifyUsers = ["@username"]
|
||||
```
|
||||
|
||||
- hookURL : Incoming webhook's URL
|
||||
- hookURL or legacyToken
|
||||
どちらか一方を指定する。
|
||||
もし脆弱性が沢山有る場合はlegacyTokenの利用をおすすめする。legacyTokenはSlackのスレッド形式でポストされる。
|
||||
スキャンサーバ単位で集約されるのでSlack通知が氾濫しない。
|
||||
|
||||
- hookURL : Incoming webhook's URL (legacyTokenが設定されている場合、hookURLは無視される。)
|
||||

|
||||
|
||||
- legacyToken : slack legacy token (https://api.slack.com/custom-integrations/legacy-tokens)
|
||||

|
||||
|
||||
- channel : channel name.
|
||||
channelに`${servername}`を指定すると、結果レポートをサーバごとに別チャネルにすることが出来る。
|
||||
以下のサンプルでは、`#server1`チャネルと`#server2`チャネルに送信される。スキャン前にチャネルを作成する必要がある。
|
||||
**legacyTokenが設定されている場合、channelは実在するchannelでなければならない。**
|
||||
```
|
||||
[slack]
|
||||
channel = "${servername}"
|
||||
@@ -808,6 +837,7 @@ host = "172.31.4.82"
|
||||
#cpeNames = [
|
||||
# "cpe:/a:rubyonrails:ruby_on_rails:4.2.1",
|
||||
#]
|
||||
#type = "pseudo"
|
||||
#ignoreCves = ["CVE-2016-6314"]
|
||||
#optional = [
|
||||
# ["key", "value"],
|
||||
@@ -824,6 +854,7 @@ host = "172.31.4.82"
|
||||
- port: SSH Port number
|
||||
- user: SSH username
|
||||
- keyPath: SSH private key path
|
||||
- type: "pseudo" for non-ssh scanning. see [#531](https://github.com/future-architect/vuls/pull/531)
|
||||
- cpeNames: see [Usage: Scan vulnerability of non-OS package](#usage-scan-vulnerability-of-non-os-package)
|
||||
- ignoreCves: CVE IDs that will not be reported. But output to JSON file.
|
||||
- optional: JSONレポートに含めたい追加情報
|
||||
@@ -883,6 +914,7 @@ configtestサブコマンドは、config.tomlで定義されたサーバ/コン
|
||||
|
||||
| Distribution | Release | Requirements |
|
||||
|:-------------|-------------------:|:-------------|
|
||||
| Alpine | 3.2 and later | - |
|
||||
| Ubuntu | 12, 14, 16| - |
|
||||
| Debian | 7, 8, 9| reboot-notifier|
|
||||
| CentOS | 6, 7| - |
|
||||
@@ -906,6 +938,7 @@ Deep Scan Modeでスキャンするためには、下記のパッケージが必
|
||||
|
||||
| Distribution | Release | Requirements |
|
||||
|:-------------|-------------------:|:-------------|
|
||||
| Alpine | 3.2 and later | - |
|
||||
| Ubuntu | 12, 14, 16| - |
|
||||
| Debian | 7, 8, 9| aptitude, reboot-notifier |
|
||||
| CentOS | 6, 7| yum-plugin-changelog, yum-utils |
|
||||
@@ -928,13 +961,13 @@ For details, see [-ssh-native-insecure option](#-ssh-native-insecure-option)
|
||||
|
||||
- RHEL 5 / Oracle Linux 5
|
||||
```
|
||||
vuls ALL=(ALL) NOPASSWD:/usr/bin/yum --color=never repolist, /usr/bin/yum --color=never list-security --security, /usr/bin/yum --color=never info-security, /usr/bin/repoquery
|
||||
vuls ALL=(ALL) NOPASSWD:/usr/bin/yum --color=never repolist, /usr/bin/yum --color=never list-security --security, /usr/bin/yum --color=never info-security, /usr/bin/repoquery, /usr/bin/yum --color=never changelog all *
|
||||
Defaults:vuls env_keep="http_proxy https_proxy HTTP_PROXY HTTPS_PROXY"
|
||||
```
|
||||
|
||||
- RHEL 6, 7 / Oracle Linux 6, 7
|
||||
```
|
||||
vuls ALL=(ALL) NOPASSWD:/usr/bin/yum --color=never repolist, /usr/bin/yum --color=never --security updateinfo list updates, /usr/bin/yum --color=never --security updateinfo updates, /usr/bin/repoquery
|
||||
vuls ALL=(ALL) NOPASSWD:/usr/bin/yum --color=never repolist, /usr/bin/yum --color=never --security updateinfo list updates, /usr/bin/yum --color=never --security updateinfo updates, /usr/bin/repoquery, /usr/bin/yum --color=never changelog all *
|
||||
Defaults:vuls env_keep="http_proxy https_proxy HTTP_PROXY HTTPS_PROXY"
|
||||
```
|
||||
|
||||
@@ -1289,7 +1322,7 @@ CWE https://cwe.mitre.org/data/definitions/190.html
|
||||
NVD https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-5636
|
||||
MITRE https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-5636
|
||||
CVE Details http://www.cvedetails.com/cve/CVE-2016-5636
|
||||
CVSS Claculator https://nvd.nist.gov/cvss/v2-calculator?name=CVE-2016-5636&vector=(AV:N/AC:L/...
|
||||
CVSS Calculator https://nvd.nist.gov/cvss/v2-calculator?name=CVE-2016-5636&vector=(AV:N/AC:L/...
|
||||
RHEL-CVE https://access.redhat.com/security/cve/CVE-2016-5636
|
||||
ALAS-2016-724 https://alas.aws.amazon.com/ALAS-2016-724.html
|
||||
Package python27-2.7.10-4.119.amzn1 -> python27-2.7.12-2.120.amzn1
|
||||
@@ -1578,6 +1611,18 @@ Vulsは、[CPE](https://nvd.nist.gov/cpe.cfm)に登録されているソフト
|
||||
]
|
||||
```
|
||||
|
||||
- Configuration
|
||||
ネットワーク機器など、スキャン対象にSSH接続しない場合は`type="pseudo"`を指定する。
|
||||
```
|
||||
[servers]
|
||||
|
||||
[servers.172-31-4-82]
|
||||
type = "pseudo"
|
||||
cpeNames = [
|
||||
"cpe:/a:rubyonrails:ruby_on_rails:4.2.1",
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
# Usage: Integrate with OWASP Dependency Check to Automatic update when the libraries are updated (Experimental)
|
||||
[OWASP Dependency check](https://www.owasp.org/index.php/OWASP_Dependency_Check) は、プログラミング言語のライブラリを特定し(CPEを推測)、公開済みの脆弱性を検知するツール。
|
||||
@@ -1835,7 +1880,8 @@ Run with --debug, --sql-debug option.
|
||||
[Riak docs](http://docs.basho.com/riak/latest/ops/tuning/open-files-limit/) is awesome.
|
||||
|
||||
- Does Vuls accept ssh connections with fish-shell or old zsh as the login shell?
|
||||
No, Vuls needs a user on the server for bash login. see also [#8](/../../issues/8)
|
||||
~~No, Vuls needs a user on the server for bash login. see also [#8](/../../issues/8)~~
|
||||
Yes, fixed in [#545](https://github.com/future-architect/vuls/pull/545)
|
||||
|
||||
- Windows
|
||||
Use Microsoft Baseline Security Analyzer. [MBSA](https://technet.microsoft.com/en-us/security/cc184924.aspx)
|
||||
|
||||
83
README.md
83
README.md
@@ -14,7 +14,6 @@ We have a slack team. [Join slack team](http://goo.gl/forms/xm5KFo35tu)
|
||||
Twitter: [@vuls_en](https://twitter.com/vuls_en)
|
||||
|
||||
[README 日本語](https://github.com/future-architect/vuls/blob/master/README.ja.md)
|
||||
[README in French](https://github.com/future-architect/vuls/blob/master/README.fr.md)
|
||||
|
||||

|
||||
|
||||
@@ -145,7 +144,7 @@ Vuls is a tool created to solve the problems listed above. It has the following
|
||||
# Main Features
|
||||
|
||||
- Scan for any vulnerabilities in Linux/FreeBSD Server
|
||||
- Supports FreeBSD, Ubuntu, Debian, CentOS, Amazon Linux, RHEL, Oracle Linux, SUSE Enterprise Linux and Raspbian
|
||||
- Supports Alpine, Ubuntu, Debian, CentOS, Amazon Linux, RHEL, Oracle Linux, SUSE Enterprise Linux and Raspbian, FreeBSD
|
||||
- Cloud, on-premise, Docker
|
||||
- High quality scan
|
||||
- Vuls uses Multiple vulnerability databases
|
||||
@@ -332,6 +331,7 @@ $ goval-dictionary fetch-redhat 7
|
||||
```
|
||||
|
||||
If you want to scan other than CentOS 7, fetch OVAL data according to the OS type and version of scan target server in advance.
|
||||
- [Alpine](https://github.com/kotakanbe/goval-dictionary#usage-fetch-alpine-secdb-as-oval-data-type)
|
||||
- [RedHat, CentOS](https://github.com/kotakanbe/goval-dictionary#usage-fetch-oval-data-from-redhat)
|
||||
- [Debian](https://github.com/kotakanbe/goval-dictionary#usage-fetch-oval-data-from-debian)
|
||||
- [Ubuntu](https://github.com/kotakanbe/goval-dictionary#usage-fetch-oval-data-from-ubuntu)
|
||||
@@ -349,6 +349,16 @@ $ git clone https://github.com/future-architect/vuls.git
|
||||
$ cd vuls
|
||||
$ make install
|
||||
```
|
||||
If you have previously installed vuls and want to update, please do the following
|
||||
```
|
||||
$ rm -rf $GOPATH/pkg/linux_amd64/github.com/future-architect/vuls/
|
||||
$ rm -rf $GOPATH/src/github.com/future-architect/vuls/
|
||||
$ cd $GOPATH/src/github.com/future-architect
|
||||
$ git clone https://github.com/future-architect/vuls.git
|
||||
$ cd vuls
|
||||
$ make install
|
||||
```
|
||||
|
||||
The binary was built under `$GOPATH/bin`
|
||||
If the installation process stops halfway, try increasing the instance type of EC2. An out of memory error may have occurred.
|
||||
|
||||
@@ -591,16 +601,16 @@ On the aggregation server, you can refer to the scanning result of each scan tar
|
||||
|
||||
| Distribution| Scan Speed | Need Root Privilege | OVAL | Need Internet Access <br>on scan tareget|
|
||||
|:------------|:--------------------------------------:|:-------------------:|:----------:|:---------------------------------------:|
|
||||
| CentOS | Fast | No | Supported | No |
|
||||
| Alpine | Fast | No | Supported | No |
|
||||
| CentOS | Fast | No | Supported | No |
|
||||
| RHEL | Fast | No | Supported | No |
|
||||
| Oracle | Fast | No | Supported | No |
|
||||
| Ubuntu | Fast | No | Supported | No |
|
||||
| Debian | Fast | No | Supported | No |
|
||||
| Raspbian |1st time: Slow <br> From 2nd time: Fast | Need | No | Need |
|
||||
| FreeBSD | Fast | No | No | Need |
|
||||
| Amazon | Fast | No | No | Need |
|
||||
| SUSE Enterprise | Fast | No | Supported | No|
|
||||
|
||||
| Amazon | Fast | No | No | Need |
|
||||
| SUSE Enterprise | Fast | No | Supported | No |
|
||||
|
||||
---------
|
||||
|
||||
@@ -609,7 +619,8 @@ On the aggregation server, you can refer to the scanning result of each scan tar
|
||||
|
||||
| Distribution| Scan Speed | Need Root Privilege | OVAL | Need Internet Access <br>on scan tareget|
|
||||
|:------------|:-------------------------------------:|:-------------------------:|:---------:|:---------------------------------------:|
|
||||
| CentOS | Slow | No | Supported | Need |
|
||||
| Alpine | Fast | No | Supported | No |
|
||||
| CentOS | Slow | No | Supported | Need |
|
||||
| RHEL | Slow | Need | Supported | Need |
|
||||
| Oracle | Slow | Need | Supported | Need |
|
||||
| Ubuntu |1st time: Slow <br> From 2nd time: Fast| Need | Supported | Need |
|
||||
@@ -617,7 +628,7 @@ On the aggregation server, you can refer to the scanning result of each scan tar
|
||||
| Raspbian |1st time: Slow <br> From 2nd time: Fast| Need | No | Need |
|
||||
| FreeBSD | Fast | No | No | Need |
|
||||
| Amazon | Slow | No | No | Need |
|
||||
| SUSE Enterprise | Fast | No | Supported | No|
|
||||
| SUSE Enterprise | Fast | No | Supported | No |
|
||||
|
||||
|
||||
- On Ubuntu, Debian and Raspbian
|
||||
@@ -632,7 +643,7 @@ Vuls issues `yum changelog` to get changelogs of upgradable packages at once and
|
||||
- On RHEL, Oracle, Amazon and FreeBSD
|
||||
Detect CVE IDs by using package manager.
|
||||
|
||||
- On SUSE Enterprise Linux
|
||||
- On SUSE Enterprise Linux and Alpine Linux
|
||||
Same as fast scan mode for now.
|
||||
|
||||
----
|
||||
@@ -668,6 +679,7 @@ If there is a staging environment with the same configuration as the production
|
||||
| FreeBSD | 10, 11|
|
||||
| SUSE Enterprise | 11, 12|
|
||||
| Raspbian | Jessie, Stretch |
|
||||
| Alpine | 3.2 and later |
|
||||
|
||||
----
|
||||
|
||||
@@ -690,6 +702,7 @@ $ vuls discover 172.31.4.0/24
|
||||
|
||||
[slack]
|
||||
hookURL = "https://hooks.slack.com/services/abc123/defghijklmnopqrstuvwxyz"
|
||||
#legacyToken = "xoxp-11111111111-222222222222-3333333333"
|
||||
channel = "#channel-name"
|
||||
#channel = "${servername}"
|
||||
iconEmoji = ":ghost:"
|
||||
@@ -725,6 +738,7 @@ host = "172.31.4.82"
|
||||
#port = "22"
|
||||
#user = "root"
|
||||
#keyPath = "/home/username/.ssh/id_rsa"
|
||||
#type = "pseudo"
|
||||
#cpeNames = [
|
||||
# "cpe:/a:rubyonrails:ruby_on_rails:4.2.1",
|
||||
#]
|
||||
@@ -748,6 +762,7 @@ You can customize your configuration using this template.
|
||||
```
|
||||
[slack]
|
||||
hookURL = "https://hooks.slack.com/services/abc123/defghijklmnopqrstuvwxyz"
|
||||
#legacyToken = "xoxp-11111111111-222222222222-3333333333"
|
||||
channel = "#channel-name"
|
||||
#channel = "${servername}"
|
||||
iconEmoji = ":ghost:"
|
||||
@@ -755,8 +770,16 @@ You can customize your configuration using this template.
|
||||
notifyUsers = ["@username"]
|
||||
```
|
||||
|
||||
- hookURL : Incoming webhook's URL
|
||||
- channel : channel name.
|
||||
- hookURL or legacyToken.
|
||||
If there are a lot of vulnerabilities, it is better to use legacyToken since the Slack notification will be flooded.
|
||||
|
||||
- hookURL : Incoming webhook's URL (hookURL is ignored when legacyToken is set.)
|
||||

|
||||
|
||||
- legacyToken : slack legacy token (https://api.slack.com/custom-integrations/legacy-tokens)
|
||||

|
||||
|
||||
- channel : channel name.
|
||||
If you set `${servername}` to channel, the report will be sent to each channel.
|
||||
In the following example, the report will be sent to the `#server1` and `#server2`.
|
||||
Be sure to create these channels before scanning.
|
||||
@@ -820,6 +843,7 @@ You can customize your configuration using this template.
|
||||
#port = "22"
|
||||
#user = "root"
|
||||
#keyPath = "/home/username/.ssh/id_rsa"
|
||||
#type = "pseudo"
|
||||
#cpeNames = [
|
||||
# "cpe:/a:rubyonrails:ruby_on_rails:4.2.1",
|
||||
#]
|
||||
@@ -839,6 +863,7 @@ You can customize your configuration using this template.
|
||||
- port: SSH Port number
|
||||
- user: SSH username
|
||||
- keyPath: SSH private key path
|
||||
- type: "pseudo" for non-ssh scanning. see [#531](https://github.com/future-architect/vuls/pull/531)
|
||||
- cpeNames: see [Usage: Scan vulnerability of non-OS package](#usage-scan-vulnerability-of-non-os-package)
|
||||
- ignoreCves: CVE IDs that will not be reported. But output to JSON file.
|
||||
- optional: Add additional information to JSON report.
|
||||
@@ -896,6 +921,7 @@ The configtest subcommand checks whether vuls is able to connect via SSH to serv
|
||||
|
||||
| Distribution | Release | Requirements |
|
||||
|:-------------|-------------------:|:-------------|
|
||||
| Alpine | 3.2 and later | - |
|
||||
| Ubuntu | 12, 14, 16| - |
|
||||
| Debian | 7, 8, 9| reboot-notifier|
|
||||
| CentOS | 6, 7| - |
|
||||
@@ -917,6 +943,7 @@ In order to scan with deep scan mode, the following dependencies are required, s
|
||||
|
||||
| Distribution | Release | Requirements |
|
||||
|:-------------|-------------------:|:-------------|
|
||||
| Alpine | 3.2 and later | - |
|
||||
| Ubuntu | 12, 14, 16| - |
|
||||
| Debian | 7, 8, 9| aptitude, reboot-notifier |
|
||||
| CentOS | 6, 7| yum-plugin-changelog, yum-utils |
|
||||
@@ -939,13 +966,13 @@ Example of /etc/sudoers on target servers
|
||||
|
||||
- RHEL 5 / Oracle Linux 5
|
||||
```
|
||||
vuls ALL=(ALL) NOPASSWD:/usr/bin/yum --color=never repolist, /usr/bin/yum --color=never list-security --security, /usr/bin/yum --color=never info-security, /usr/bin/repoquery
|
||||
vuls ALL=(ALL) NOPASSWD:/usr/bin/yum --color=never repolist, /usr/bin/yum --color=never list-security --security, /usr/bin/yum --color=never info-security, /usr/bin/repoquery, /usr/bin/yum --color=never changelog all *
|
||||
Defaults:vuls env_keep="http_proxy https_proxy HTTP_PROXY HTTPS_PROXY"
|
||||
```
|
||||
|
||||
- RHEL 6, 7 / Oracle Linux 6, 7
|
||||
```
|
||||
vuls ALL=(ALL) NOPASSWD:/usr/bin/yum --color=never repolist, /usr/bin/yum --color=never --security updateinfo list updates, /usr/bin/yum --color=never --security updateinfo updates, /usr/bin/repoquery
|
||||
vuls ALL=(ALL) NOPASSWD:/usr/bin/yum --color=never repolist, /usr/bin/yum --color=never --security updateinfo list updates, /usr/bin/yum --color=never --security updateinfo updates, /usr/bin/repoquery, /usr/bin/yum --color=never changelog all *
|
||||
Defaults:vuls env_keep="http_proxy https_proxy HTTP_PROXY HTTPS_PROXY"
|
||||
```
|
||||
|
||||
@@ -1302,7 +1329,7 @@ CWE https://cwe.mitre.org/data/definitions/190.html
|
||||
NVD https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-5636
|
||||
MITRE https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-5636
|
||||
CVE Details http://www.cvedetails.com/cve/CVE-2016-5636
|
||||
CVSS Claculator https://nvd.nist.gov/cvss/v2-calculator?name=CVE-2016-5636&vector=(AV:N/AC:L/...
|
||||
CVSS Calculator https://nvd.nist.gov/cvss/v2-calculator?name=CVE-2016-5636&vector=(AV:N/AC:L/...
|
||||
RHEL-CVE https://access.redhat.com/security/cve/CVE-2016-5636
|
||||
ALAS-2016-724 https://alas.aws.amazon.com/ALAS-2016-724.html
|
||||
Package python27-2.7.10-4.119.amzn1 -> python27-2.7.12-2.120.amzn1
|
||||
@@ -1383,6 +1410,17 @@ With this sample command, it will ..
|
||||
- Only Report CVEs that CVSS score is over 7
|
||||
|
||||
|
||||
```
|
||||
$ vuls report \
|
||||
-to-slack \
|
||||
-cvss-over=7 \
|
||||
-cvedb-path=$PWD/cve.sqlite3
|
||||
```
|
||||
With this sample command, it will ..
|
||||
- Send scan results to slack
|
||||
- Only Report CVEs that CVSS score is over 7
|
||||
|
||||
|
||||
## Example: Put results in S3 bucket
|
||||
To put results in S3 bucket, configure following settings in AWS before reporting.
|
||||
- Create S3 bucket. see [Creating a Bucket](http://docs.aws.amazon.com/AmazonS3/latest/UG/CreatingaBucket.html)
|
||||
@@ -1583,6 +1621,20 @@ To detect the vulnerability of Ruby on Rails v4.2.1, cpeNames needs to be set in
|
||||
]
|
||||
```
|
||||
|
||||
- type="pseudo"
|
||||
Specify this when you want to detect vulnerability by specifying cpename without SSH connection.
|
||||
The pseudo type does not do anything when scanning.
|
||||
Search for NVD at report time and detect vulnerability of software specified as cpenamae.
|
||||
```
|
||||
[servers]
|
||||
|
||||
[servers.172-31-4-82]
|
||||
type = "pseudo"
|
||||
cpeNames = [
|
||||
"cpe:/a:rubyonrails:ruby_on_rails:4.2.1",
|
||||
]
|
||||
```
|
||||
|
||||
# Usage: Integrate with OWASP Dependency Check to Automatic update when the libraries are updated (Experimental)
|
||||
[OWASP Dependency check](https://www.owasp.org/index.php/OWASP_Dependency_Check) is a utility that identifies project dependencies and checks if there are any known, publicly disclosed, vulnerabilities.
|
||||
|
||||
@@ -1808,7 +1860,8 @@ Run with --debug, --sql-debug option.
|
||||
[Riak docs](http://docs.basho.com/riak/latest/ops/tuning/open-files-limit/) is awesome.
|
||||
|
||||
- Does Vuls accept SSH connections with fish-shell or old zsh as the login shell?
|
||||
No, Vuls needs a user on the server for bash login. see also [#8](/../../issues/8)
|
||||
~~No, Vuls needs a user on the server for bash login. see also [#8](/../../issues/8)~~
|
||||
Yes, fixed in [#545](https://github.com/future-architect/vuls/pull/545)
|
||||
|
||||
- Windows
|
||||
Use Microsoft Baseline Security Analyzer. [MBSA](https://technet.microsoft.com/en-us/security/cc184924.aspx)
|
||||
|
||||
@@ -92,6 +92,7 @@ func printConfigToml(ips []string) (err error) {
|
||||
const tomlTemplate = `
|
||||
[slack]
|
||||
hookURL = "https://hooks.slack.com/services/abc123/defghijklmnopqrstuvwxyz"
|
||||
#legacyToken = "xoxp-11111111111-222222222222-3333333333"
|
||||
channel = "#channel-name"
|
||||
#channel = "${servername}"
|
||||
iconEmoji = ":ghost:"
|
||||
@@ -131,6 +132,7 @@ host = "{{$ip}}"
|
||||
#port = "22"
|
||||
#user = "root"
|
||||
#keyPath = "/home/username/.ssh/id_rsa"
|
||||
#type = "pseudo"
|
||||
#cpeNames = [
|
||||
# "cpe:/a:rubyonrails:ruby_on_rails:4.2.1",
|
||||
#]
|
||||
|
||||
@@ -197,6 +197,7 @@ func (p *TuiCmd) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) s
|
||||
c.Conf.CvssScoreOver = p.cvssScoreOver
|
||||
c.Conf.IgnoreUnscoredCves = p.ignoreUnscoredCves
|
||||
c.Conf.IgnoreUnfixed = p.ignoreUnfixed
|
||||
c.Conf.RefreshCve = p.refreshCve
|
||||
|
||||
log.Info("Validating config...")
|
||||
if !c.Conf.ValidateOnTui() {
|
||||
|
||||
@@ -76,6 +76,14 @@ const (
|
||||
|
||||
// SUSEOpenstackCloud is
|
||||
SUSEOpenstackCloud = "suse.openstack.cloud"
|
||||
|
||||
// Alpine is
|
||||
Alpine = "alpine"
|
||||
)
|
||||
|
||||
const (
|
||||
// ServerTypePseudo is used for ServerInfo.Type
|
||||
ServerTypePseudo = "pseudo"
|
||||
)
|
||||
|
||||
//Config is struct of Configuration
|
||||
@@ -379,10 +387,11 @@ func (c *SMTPConf) Validate() (errs []error) {
|
||||
|
||||
// SlackConf is slack config
|
||||
type SlackConf struct {
|
||||
HookURL string `valid:"url" json:"-"`
|
||||
Channel string `json:"channel"`
|
||||
IconEmoji string `json:"icon_emoji"`
|
||||
AuthUser string `json:"username"`
|
||||
HookURL string `valid:"url" json:"-"`
|
||||
LegacyToken string `json:"token" toml:"legacyToken,omitempty"`
|
||||
Channel string `json:"channel"`
|
||||
IconEmoji string `json:"icon_emoji"`
|
||||
AuthUser string `json:"username"`
|
||||
|
||||
NotifyUsers []string
|
||||
Text string `json:"text"`
|
||||
@@ -445,6 +454,9 @@ type ServerInfo struct {
|
||||
// For CentOS, RHEL, Amazon
|
||||
Enablerepo []string
|
||||
|
||||
// "pseudo" or ""
|
||||
Type string
|
||||
|
||||
// used internal
|
||||
LogMsgAnsiColor string // DebugLog Color
|
||||
Container Container
|
||||
@@ -457,7 +469,7 @@ func (s ServerInfo) GetServerName() string {
|
||||
if len(s.Container.ContainerID) == 0 {
|
||||
return s.ServerName
|
||||
}
|
||||
return fmt.Sprintf("%s@%s", s.Container.ContainerID, s.ServerName)
|
||||
return fmt.Sprintf("%s@%s", s.Container.Name, s.ServerName)
|
||||
}
|
||||
|
||||
// Distro has distribution info
|
||||
|
||||
@@ -23,7 +23,7 @@ import "fmt"
|
||||
type JSONLoader struct {
|
||||
}
|
||||
|
||||
// Load load the configuraiton JSON file specified by path arg.
|
||||
// Load load the configuration JSON file specified by path arg.
|
||||
func (c JSONLoader) Load(path, sudoPass, keyPass string) (err error) {
|
||||
return fmt.Errorf("Not implement yet")
|
||||
}
|
||||
|
||||
@@ -61,46 +61,48 @@ func (c TOMLLoader) Load(pathToToml, keyPass string) error {
|
||||
|
||||
s := ServerInfo{ServerName: name}
|
||||
|
||||
s.Host = v.Host
|
||||
if len(s.Host) == 0 {
|
||||
return fmt.Errorf("%s is invalid. host is empty", name)
|
||||
}
|
||||
|
||||
switch {
|
||||
case v.Port != "":
|
||||
s.Port = v.Port
|
||||
case d.Port != "":
|
||||
s.Port = d.Port
|
||||
default:
|
||||
s.Port = "22"
|
||||
}
|
||||
|
||||
switch {
|
||||
case v.User != "":
|
||||
s.User = v.User
|
||||
case d.User != "":
|
||||
s.User = d.User
|
||||
default:
|
||||
if s.Port != "local" {
|
||||
return fmt.Errorf("%s is invalid. User is empty", name)
|
||||
if v.Type != ServerTypePseudo {
|
||||
s.Host = v.Host
|
||||
if len(s.Host) == 0 {
|
||||
return fmt.Errorf("%s is invalid. host is empty", name)
|
||||
}
|
||||
}
|
||||
|
||||
s.KeyPath = v.KeyPath
|
||||
if len(s.KeyPath) == 0 {
|
||||
s.KeyPath = d.KeyPath
|
||||
}
|
||||
if s.KeyPath != "" {
|
||||
if _, err := os.Stat(s.KeyPath); err != nil {
|
||||
return fmt.Errorf(
|
||||
"%s is invalid. keypath: %s not exists", name, s.KeyPath)
|
||||
switch {
|
||||
case v.Port != "":
|
||||
s.Port = v.Port
|
||||
case d.Port != "":
|
||||
s.Port = d.Port
|
||||
default:
|
||||
s.Port = "22"
|
||||
}
|
||||
}
|
||||
|
||||
// s.KeyPassword = keyPass
|
||||
s.KeyPassword = v.KeyPassword
|
||||
if len(s.KeyPassword) == 0 {
|
||||
s.KeyPassword = d.KeyPassword
|
||||
switch {
|
||||
case v.User != "":
|
||||
s.User = v.User
|
||||
case d.User != "":
|
||||
s.User = d.User
|
||||
default:
|
||||
if s.Port != "local" {
|
||||
return fmt.Errorf("%s is invalid. User is empty", name)
|
||||
}
|
||||
}
|
||||
|
||||
s.KeyPath = v.KeyPath
|
||||
if len(s.KeyPath) == 0 {
|
||||
s.KeyPath = d.KeyPath
|
||||
}
|
||||
if s.KeyPath != "" {
|
||||
if _, err := os.Stat(s.KeyPath); err != nil {
|
||||
return fmt.Errorf(
|
||||
"%s is invalid. keypath: %s not exists", name, s.KeyPath)
|
||||
}
|
||||
}
|
||||
|
||||
// s.KeyPassword = keyPass
|
||||
s.KeyPassword = v.KeyPassword
|
||||
if len(s.KeyPassword) == 0 {
|
||||
s.KeyPassword = d.KeyPassword
|
||||
}
|
||||
}
|
||||
|
||||
s.CpeNames = v.CpeNames
|
||||
@@ -175,6 +177,8 @@ func (c TOMLLoader) Load(pathToToml, keyPass string) error {
|
||||
}
|
||||
}
|
||||
|
||||
s.Type = v.Type
|
||||
|
||||
s.LogMsgAnsiColor = Colors[i%len(Colors)]
|
||||
i++
|
||||
|
||||
|
||||
@@ -53,9 +53,11 @@
|
||||
<y:Geometry height="90.44247787610618" width="268.0" x="309.6849206349206" y="86.0"/>
|
||||
<y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="60.53125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="170.763671875" x="48.61816406250006" y="14.95561393805309">Get installed packages
|
||||
<y:NodeLabel alignment="right" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="88.796875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="170.763671875" x="48.61816406250006" y="0.8228014380530908">Get installed packages
|
||||
Alpine: apk
|
||||
Debian/Ubuntu: dpkg-query
|
||||
Amazon/RHEL/CentOS: rpm
|
||||
SUSE: zypper
|
||||
FreeBSD: pkg<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
@@ -264,7 +266,7 @@ Debian/Ubuntu: aptitude changelog<y:LabelModel>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="32.265625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="51.806640625" x="183.35883739927397" y="2.000003510871693">Amazon
|
||||
<y:EdgeLabel alignment="right" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="32.265625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="51.806640625" x="183.35883739927397" y="2.000003510871693">Amazon
|
||||
FreeBSD<y:LabelModel>
|
||||
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
|
||||
</y:LabelModel>
|
||||
@@ -298,7 +300,6 @@ FreeBSD<y:LabelModel>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e4" source="n1" target="n3">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="-123.36984126984123" ty="0.0">
|
||||
@@ -306,11 +307,13 @@ FreeBSD<y:LabelModel>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="74.6640625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="77.078125" x="-97.68364242524859" y="5.005267793098369">CentOS
|
||||
<y:EdgeLabel alignment="right" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="102.9296875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="77.078125" x="-97.68364242524859" y="5.005267793098369">Alpine Linux
|
||||
CentOS
|
||||
RHEL
|
||||
Ubuntu
|
||||
Debian
|
||||
Oracle Linux<y:LabelModel>
|
||||
Oracle Linux
|
||||
Suse<y:LabelModel>
|
||||
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
@@ -323,7 +326,6 @@ Oracle Linux<y:LabelModel>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e5" source="n4" target="n3">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
@@ -364,7 +366,6 @@ Oracle Linux<y:LabelModel>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e9" source="n3" target="n5">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
@@ -375,7 +376,6 @@ Oracle Linux<y:LabelModel>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e10" source="n1" target="n7">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
|
||||
@@ -396,7 +396,6 @@ Oracle Linux<y:LabelModel>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e11" source="n10" target="n3">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="-125.78842258255952" ty="0.0">
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 78 KiB |
@@ -53,10 +53,12 @@
|
||||
<y:Geometry height="90.44247787610618" width="268.0" x="309.6849206349206" y="86.0"/>
|
||||
<y:Fill color="#E8EEF7" color2="#B7C9E3" transparent="false"/>
|
||||
<y:BorderStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="60.53125" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="170.763671875" x="48.61816406250006" y="14.95561393805309">Get installed packages
|
||||
<y:NodeLabel alignment="right" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="88.796875" horizontalTextPosition="center" iconTextGap="4" modelName="custom" textColor="#000000" verticalTextPosition="bottom" visible="true" width="170.763671875" x="48.61816406250006" y="0.8228014380530908">Get installed packages
|
||||
Alpine Linux: apk
|
||||
Debian/Ubuntu: dpkg-query
|
||||
Amazon/RHEL/CentOS: rpm
|
||||
FreeBSD: pkg<y:LabelModel>
|
||||
FreeBSD: pkg
|
||||
SUSE: zypper<y:LabelModel>
|
||||
<y:SmartNodeLabelModel distance="4.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
@@ -235,7 +237,6 @@ Amazon / RHEL: yum changelog<y:LabelModel>
|
||||
</node>
|
||||
<node id="n13" yfiles.foldertype="group">
|
||||
<data key="d4"/>
|
||||
<data key="d5"/>
|
||||
<data key="d6">
|
||||
<y:ProxyAutoBoundsNode>
|
||||
<y:Realizers active="0">
|
||||
@@ -315,13 +316,13 @@ Amazon / RHEL: yum changelog<y:LabelModel>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="46.3984375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="56.98046875" x="-66.95987036992159" y="-48.39843398912808">Debian
|
||||
<y:EdgeLabel alignment="right" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="46.3984375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="56.98046875" x="-257.65322875976574" y="2.0000035108718635">Debian
|
||||
Ubuntu
|
||||
Raspbian<y:LabelModel>
|
||||
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="1.9999999999998863" distanceToCenter="false" position="right" ratio="0.02215389573439544" segment="0"/>
|
||||
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="1.9999999999998863" distanceToCenter="false" position="left" ratio="0.8652035780364729" segment="0"/>
|
||||
</y:ModelParameter>
|
||||
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
|
||||
</y:EdgeLabel>
|
||||
@@ -379,13 +380,13 @@ Raspbian<y:LabelModel>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="standard"/>
|
||||
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="46.3984375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="51.806640625" x="10.125014629061297" y="-48.39843398912805">Amazon
|
||||
<y:EdgeLabel alignment="right" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="46.3984375" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="51.806640625" x="200.87829463898197" y="4.000003510871693">Amazon
|
||||
RHEL
|
||||
FreeBSD<y:LabelModel>
|
||||
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="1.9999999999998863" distanceToCenter="false" position="left" ratio="0.022401276994204813" segment="0"/>
|
||||
<y:SmartEdgeLabelModelParameter angle="6.283185307179586" distance="6.999999999999886" distanceToCenter="false" position="right" ratio="0.8192728556300707" segment="-1"/>
|
||||
</y:ModelParameter>
|
||||
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
|
||||
</y:EdgeLabel>
|
||||
@@ -442,7 +443,6 @@ FreeBSD<y:LabelModel>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e11" source="n11" target="n7">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="-24.34091537610618">
|
||||
@@ -455,7 +455,6 @@ FreeBSD<y:LabelModel>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e12" source="n8" target="n12">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
@@ -466,7 +465,6 @@ FreeBSD<y:LabelModel>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e13" source="n12" target="n7">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
|
||||
@@ -477,7 +475,6 @@ FreeBSD<y:LabelModel>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e14" source="n9" target="n13">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="10.8330078125"/>
|
||||
@@ -487,6 +484,30 @@ FreeBSD<y:LabelModel>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
<edge id="e15" source="n1" target="n7">
|
||||
<data key="d9"/>
|
||||
<data key="d10">
|
||||
<y:PolyLineEdge>
|
||||
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
|
||||
<y:Point x="999.0" y="226.44247787610618"/>
|
||||
<y:Point x="999.0" y="570.8409153761062"/>
|
||||
<y:Point x="743.3698412698412" y="570.8409153761062"/>
|
||||
</y:Path>
|
||||
<y:LineStyle color="#000000" type="line" width="1.0"/>
|
||||
<y:Arrows source="none" target="none"/>
|
||||
<y:EdgeLabel alignment="right" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="32.265625" horizontalTextPosition="center" iconTextGap="4" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" width="76.8203125" x="422.923942251054" y="13.867191010871807">Alpine Linux
|
||||
SUSE<y:LabelModel>
|
||||
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
|
||||
</y:LabelModel>
|
||||
<y:ModelParameter>
|
||||
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="right" ratio="0.8856709076027529" segment="0"/>
|
||||
</y:ModelParameter>
|
||||
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
|
||||
</y:EdgeLabel>
|
||||
<y:BendStyle smoothed="false"/>
|
||||
</y:PolyLineEdge>
|
||||
</data>
|
||||
</edge>
|
||||
</graph>
|
||||
<data key="d7">
|
||||
<y:Resources/>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 90 KiB |
2
main.go
2
main.go
@@ -29,7 +29,7 @@ import (
|
||||
)
|
||||
|
||||
// Version of Vuls
|
||||
var version = "0.4.0"
|
||||
var version = "0.4.2"
|
||||
|
||||
// Revision of Git
|
||||
var revision string
|
||||
|
||||
82
oval/alpine.go
Normal file
82
oval/alpine.go
Normal file
@@ -0,0 +1,82 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Architect, Inc. Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package oval
|
||||
|
||||
import (
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/util"
|
||||
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
|
||||
)
|
||||
|
||||
// Alpine is the struct of Alpine Linux
|
||||
type Alpine struct {
|
||||
Base
|
||||
}
|
||||
|
||||
// NewAlpine creates OVAL client for SUSE
|
||||
func NewAlpine() Alpine {
|
||||
return Alpine{
|
||||
Base{
|
||||
family: config.Alpine,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// FillWithOval returns scan result after updating CVE info by OVAL
|
||||
func (o Alpine) FillWithOval(r *models.ScanResult) (err error) {
|
||||
var relatedDefs ovalResult
|
||||
if o.isFetchViaHTTP() {
|
||||
if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if relatedDefs, err = getDefsByPackNameFromOvalDB(r); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, defPacks := range relatedDefs.entries {
|
||||
o.update(r, defPacks)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o Alpine) update(r *models.ScanResult, defPacks defPacks) {
|
||||
ovalContent := *o.convertToModel(&defPacks.def)
|
||||
cveID := defPacks.def.Advisory.Cves[0].CveID
|
||||
vinfo, ok := r.ScannedCves[cveID]
|
||||
if !ok {
|
||||
util.Log.Debugf("%s is newly detected by OVAL", cveID)
|
||||
vinfo = models.VulnInfo{
|
||||
CveID: cveID,
|
||||
Confidence: models.OvalMatch,
|
||||
CveContents: models.NewCveContents(ovalContent),
|
||||
}
|
||||
}
|
||||
|
||||
vinfo.AffectedPackages = defPacks.toPackStatuses(r.Family)
|
||||
vinfo.AffectedPackages.Sort()
|
||||
r.ScannedCves[cveID] = vinfo
|
||||
}
|
||||
|
||||
func (o Alpine) convertToModel(def *ovalmodels.Definition) *models.CveContent {
|
||||
return &models.CveContent{
|
||||
CveID: def.Advisory.Cves[0].CveID,
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ func (o DebianBase) update(r *models.ScanResult, defPacks defPacks) {
|
||||
defPacks.actuallyAffectedPackNames[pack.Name] = notFixedYet
|
||||
}
|
||||
|
||||
vinfo.AffectedPackages = defPacks.toPackStatuses(r.Family, r.Packages)
|
||||
vinfo.AffectedPackages = defPacks.toPackStatuses(r.Family)
|
||||
vinfo.AffectedPackages.Sort()
|
||||
r.ScannedCves[defPacks.def.Debian.CveID] = vinfo
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
@@ -132,15 +131,14 @@ func (b Base) CheckIfOvalFresh(osFamily, release string) (ok bool, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
major := strings.Split(release, ".")[0]
|
||||
since := time.Now()
|
||||
since = since.AddDate(0, 0, -3)
|
||||
if lastModified.Before(since) {
|
||||
util.Log.Warnf("OVAL for %s %s is old, last modified is %s. It's recommended to update OVAL to improve scanning accuracy. How to update OVAL database, see https://github.com/kotakanbe/goval-dictionary#usage",
|
||||
osFamily, major, lastModified)
|
||||
osFamily, release, lastModified)
|
||||
return false, nil
|
||||
}
|
||||
util.Log.Infof("OVAL is fresh: %s %s ", osFamily, major)
|
||||
util.Log.Infof("OVAL is fresh: %s %s ", osFamily, release)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,35 @@ func (o RedHatBase) FillWithOval(r *models.ScanResult) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var kernelRelatedPackNames = map[string]bool{
|
||||
"kernel": true,
|
||||
"kernel-aarch64": true,
|
||||
"kernel-abi-whitelists": true,
|
||||
"kernel-bootwrapper": true,
|
||||
"kernel-debug": true,
|
||||
"kernel-debug-devel": true,
|
||||
"kernel-devel": true,
|
||||
"kernel-doc": true,
|
||||
"kernel-headers": true,
|
||||
"kernel-kdump": true,
|
||||
"kernel-kdump-devel": true,
|
||||
"kernel-rt": true,
|
||||
"kernel-rt-debug": true,
|
||||
"kernel-rt-debug-devel": true,
|
||||
"kernel-rt-debug-kvm": true,
|
||||
"kernel-rt-devel": true,
|
||||
"kernel-rt-doc": true,
|
||||
"kernel-rt-kvm": true,
|
||||
"kernel-rt-trace": true,
|
||||
"kernel-rt-trace-devel": true,
|
||||
"kernel-rt-trace-kvm": true,
|
||||
"kernel-rt-virt": true,
|
||||
"kernel-rt-virt-devel": true,
|
||||
"kernel-tools": true,
|
||||
"kernel-tools-libs": true,
|
||||
"kernel-tools-libs-devel": true,
|
||||
}
|
||||
|
||||
func (o RedHatBase) update(r *models.ScanResult, defPacks defPacks) {
|
||||
ctype := models.NewCveContentType(o.family)
|
||||
for _, cve := range defPacks.def.Advisory.Cves {
|
||||
@@ -100,7 +129,7 @@ func (o RedHatBase) update(r *models.ScanResult, defPacks defPacks) {
|
||||
notFixedYet, _ := defPacks.actuallyAffectedPackNames[pack.Name]
|
||||
defPacks.actuallyAffectedPackNames[pack.Name] = notFixedYet
|
||||
}
|
||||
vinfo.AffectedPackages = defPacks.toPackStatuses(r.Family, r.Packages)
|
||||
vinfo.AffectedPackages = defPacks.toPackStatuses(r.Family)
|
||||
vinfo.AffectedPackages.Sort()
|
||||
r.ScannedCves[cve.CveID] = vinfo
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ func (o SUSE) update(r *models.ScanResult, defPacks defPacks) {
|
||||
notFixedYet, _ := defPacks.actuallyAffectedPackNames[pack.Name]
|
||||
defPacks.actuallyAffectedPackNames[pack.Name] = notFixedYet
|
||||
}
|
||||
vinfo.AffectedPackages = defPacks.toPackStatuses(r.Family, r.Packages)
|
||||
vinfo.AffectedPackages = defPacks.toPackStatuses(r.Family)
|
||||
vinfo.AffectedPackages.Sort()
|
||||
r.ScannedCves[defPacks.def.Title] = vinfo
|
||||
}
|
||||
|
||||
52
oval/util.go
52
oval/util.go
@@ -21,6 +21,8 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff"
|
||||
@@ -46,7 +48,7 @@ type defPacks struct {
|
||||
actuallyAffectedPackNames map[string]bool
|
||||
}
|
||||
|
||||
func (e defPacks) toPackStatuses(family string, packs models.Packages) (ps models.PackageStatuses) {
|
||||
func (e defPacks) toPackStatuses(family string) (ps models.PackageStatuses) {
|
||||
for name, notFixedYet := range e.actuallyAffectedPackNames {
|
||||
ps = append(ps, models.PackageStatus{
|
||||
Name: name,
|
||||
@@ -57,10 +59,13 @@ func (e defPacks) toPackStatuses(family string, packs models.Packages) (ps model
|
||||
}
|
||||
|
||||
func (e *ovalResult) upsert(def ovalmodels.Definition, packName string, notFixedYet bool) (upserted bool) {
|
||||
for i, entry := range e.entries {
|
||||
if entry.def.DefinitionID == def.DefinitionID {
|
||||
e.entries[i].actuallyAffectedPackNames[packName] = notFixedYet
|
||||
return true
|
||||
// alpine's entry is empty since Alpine secdb is not OVAL format
|
||||
if def.DefinitionID != "" {
|
||||
for i, entry := range e.entries {
|
||||
if entry.def.DefinitionID == def.DefinitionID {
|
||||
e.entries[i].actuallyAffectedPackNames[packName] = notFixedYet
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
e.entries = append(e.entries, defPacks{
|
||||
@@ -145,7 +150,7 @@ func getDefsByPackNameViaHTTP(r *models.ScanResult) (
|
||||
select {
|
||||
case res := <-resChan:
|
||||
for _, def := range res.defs {
|
||||
affected, notFixedYet := isOvalDefAffected(def, r.Family, res.request)
|
||||
affected, notFixedYet := isOvalDefAffected(def, res.request, r.Family, r.RunningKernel)
|
||||
if !affected {
|
||||
continue
|
||||
}
|
||||
@@ -252,7 +257,7 @@ func getDefsByPackNameFromOvalDB(r *models.ScanResult) (relatedDefs ovalResult,
|
||||
return relatedDefs, fmt.Errorf("Failed to get %s OVAL info by package name: %v", r.Family, err)
|
||||
}
|
||||
for _, def := range definitions {
|
||||
affected, notFixedYet := isOvalDefAffected(def, r.Family, req)
|
||||
affected, notFixedYet := isOvalDefAffected(def, req, r.Family, r.RunningKernel)
|
||||
if !affected {
|
||||
continue
|
||||
}
|
||||
@@ -269,12 +274,35 @@ func getDefsByPackNameFromOvalDB(r *models.ScanResult) (relatedDefs ovalResult,
|
||||
return
|
||||
}
|
||||
|
||||
func isOvalDefAffected(def ovalmodels.Definition, family string, req request) (affected, notFixedYet bool) {
|
||||
func major(version string) string {
|
||||
ss := strings.SplitN(version, ":", 2)
|
||||
ver := ""
|
||||
if len(ss) == 1 {
|
||||
ver = ss[0]
|
||||
} else {
|
||||
ver = ss[1]
|
||||
}
|
||||
return ver[0:strings.Index(ver, ".")]
|
||||
}
|
||||
|
||||
func isOvalDefAffected(def ovalmodels.Definition, req request, family string, running models.Kernel) (affected, notFixedYet bool) {
|
||||
for _, ovalPack := range def.AffectedPacks {
|
||||
if req.packName != ovalPack.Name {
|
||||
continue
|
||||
}
|
||||
|
||||
if running.Release != "" {
|
||||
switch family {
|
||||
case config.RedHat, config.CentOS:
|
||||
// For kernel related packages, ignore OVAL information with different major versions
|
||||
if _, ok := kernelRelatedPackNames[ovalPack.Name]; ok {
|
||||
if major(ovalPack.Version) != major(running.Release) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ovalPack.NotFixedYet {
|
||||
return true, true
|
||||
}
|
||||
@@ -320,10 +348,16 @@ func lessThan(family, versionRelease string, packB ovalmodels.Package) (bool, er
|
||||
return false, err
|
||||
}
|
||||
return vera.LessThan(verb), nil
|
||||
case config.RedHat, config.CentOS, config.Oracle, config.SUSEEnterpriseServer:
|
||||
case config.Oracle, config.SUSEEnterpriseServer, config.Alpine:
|
||||
vera := rpmver.NewVersion(versionRelease)
|
||||
verb := rpmver.NewVersion(packB.Version)
|
||||
return vera.LessThan(verb), nil
|
||||
case config.RedHat, config.CentOS: // TODO: Suport config.Scientific
|
||||
rea := regexp.MustCompile(`\.[es]l(\d+)(?:_\d+)?(?:\.centos)?`)
|
||||
reb := regexp.MustCompile(`\.el(\d+)(?:_\d+)?`)
|
||||
vera := rpmver.NewVersion(rea.ReplaceAllString(versionRelease, ".el$1"))
|
||||
verb := rpmver.NewVersion(reb.ReplaceAllString(packB.Version, ".el$1"))
|
||||
return vera.LessThan(verb), nil
|
||||
default:
|
||||
util.Log.Errorf("Not implemented yet: %s", family)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
|
||||
)
|
||||
@@ -116,7 +117,6 @@ func TestDefpacksToPackStatuses(t *testing.T) {
|
||||
{
|
||||
in: in{
|
||||
family: "ubuntu",
|
||||
packs: models.Packages{},
|
||||
dp: defPacks{
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
@@ -154,7 +154,7 @@ func TestDefpacksToPackStatuses(t *testing.T) {
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
actual := tt.in.dp.toPackStatuses(tt.in.family, tt.in.packs)
|
||||
actual := tt.in.dp.toPackStatuses(tt.in.family)
|
||||
sort.Slice(actual, func(i, j int) bool {
|
||||
return actual[i].Name < actual[j].Name
|
||||
})
|
||||
@@ -167,8 +167,9 @@ func TestDefpacksToPackStatuses(t *testing.T) {
|
||||
func TestIsOvalDefAffected(t *testing.T) {
|
||||
type in struct {
|
||||
def ovalmodels.Definition
|
||||
family string
|
||||
req request
|
||||
family string
|
||||
kernel models.Kernel
|
||||
}
|
||||
var tests = []struct {
|
||||
in in
|
||||
@@ -261,7 +262,7 @@ func TestIsOvalDefAffected(t *testing.T) {
|
||||
// req.isSrcPack == false
|
||||
// Version comparison
|
||||
// oval vs NewVersion
|
||||
// oval.version < installed.newVersion
|
||||
// oval.version > installed.newVersion
|
||||
{
|
||||
in: in{
|
||||
family: "ubuntu",
|
||||
@@ -320,9 +321,670 @@ func TestIsOvalDefAffected(t *testing.T) {
|
||||
affected: true,
|
||||
notFixedYet: false,
|
||||
},
|
||||
// RedHat
|
||||
{
|
||||
in: in{
|
||||
family: "redhat",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6_7.7",
|
||||
},
|
||||
},
|
||||
affected: true,
|
||||
notFixedYet: true,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "redhat",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
affected: false,
|
||||
notFixedYet: false,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "redhat",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6_7.9",
|
||||
},
|
||||
},
|
||||
affected: false,
|
||||
notFixedYet: false,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "redhat",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6_7.6",
|
||||
NewVersionRelease: "0:1.2.3-45.el6_7.7",
|
||||
},
|
||||
},
|
||||
affected: true,
|
||||
notFixedYet: true,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "redhat",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6_7.6",
|
||||
NewVersionRelease: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
affected: true,
|
||||
notFixedYet: false,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "redhat",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6_7.6",
|
||||
NewVersionRelease: "0:1.2.3-45.el6_7.9",
|
||||
},
|
||||
},
|
||||
affected: true,
|
||||
notFixedYet: false,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "redhat",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6.8",
|
||||
},
|
||||
},
|
||||
affected: false,
|
||||
notFixedYet: false,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "redhat",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
affected: false,
|
||||
notFixedYet: false,
|
||||
},
|
||||
// CentOS
|
||||
{
|
||||
in: in{
|
||||
family: "centos",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6.centos.7",
|
||||
},
|
||||
},
|
||||
affected: true,
|
||||
notFixedYet: true,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "centos",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6.centos.8",
|
||||
},
|
||||
},
|
||||
affected: false,
|
||||
notFixedYet: false,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "centos",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6.centos.9",
|
||||
},
|
||||
},
|
||||
affected: false,
|
||||
notFixedYet: false,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "centos",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6.centos.6",
|
||||
NewVersionRelease: "0:1.2.3-45.el6.centos.7",
|
||||
},
|
||||
},
|
||||
affected: true,
|
||||
notFixedYet: true,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "centos",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6.centos.6",
|
||||
NewVersionRelease: "0:1.2.3-45.el6.centos.8",
|
||||
},
|
||||
},
|
||||
affected: true,
|
||||
notFixedYet: false,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "centos",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6.centos.6",
|
||||
NewVersionRelease: "0:1.2.3-45.el6.centos.9",
|
||||
},
|
||||
},
|
||||
affected: true,
|
||||
notFixedYet: false,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "centos",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6.8",
|
||||
},
|
||||
},
|
||||
affected: false,
|
||||
notFixedYet: false,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "centos",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
affected: false,
|
||||
notFixedYet: false,
|
||||
},
|
||||
// TODO: If vuls support Scientific, replace "centos" below to "scientific".
|
||||
{
|
||||
in: in{
|
||||
family: "centos",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.sl6.7",
|
||||
},
|
||||
},
|
||||
affected: true,
|
||||
notFixedYet: true,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "centos",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.sl6.8",
|
||||
},
|
||||
},
|
||||
affected: false,
|
||||
notFixedYet: false,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "centos",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.sl6.9",
|
||||
},
|
||||
},
|
||||
affected: false,
|
||||
notFixedYet: false,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "centos",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.sl6.6",
|
||||
NewVersionRelease: "0:1.2.3-45.sl6.7",
|
||||
},
|
||||
},
|
||||
affected: true,
|
||||
notFixedYet: true,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "centos",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.sl6.6",
|
||||
NewVersionRelease: "0:1.2.3-45.sl6.8",
|
||||
},
|
||||
},
|
||||
affected: true,
|
||||
notFixedYet: false,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "centos",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.sl6.6",
|
||||
NewVersionRelease: "0:1.2.3-45.sl6.9",
|
||||
},
|
||||
},
|
||||
affected: true,
|
||||
notFixedYet: false,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "centos",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6.8",
|
||||
},
|
||||
},
|
||||
affected: false,
|
||||
notFixedYet: false,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: "centos",
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "a",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
{
|
||||
Name: "b",
|
||||
NotFixedYet: false,
|
||||
Version: "0:1.2.3-45.el6.8",
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "b",
|
||||
isSrcPack: false,
|
||||
versionRelease: "0:1.2.3-45.el6_7.8",
|
||||
},
|
||||
},
|
||||
affected: false,
|
||||
notFixedYet: false,
|
||||
},
|
||||
// For kernel related packages, ignore OVAL with different major versions
|
||||
{
|
||||
in: in{
|
||||
family: config.CentOS,
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "kernel",
|
||||
Version: "4.1.0",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "kernel",
|
||||
versionRelease: "3.0.0",
|
||||
NewVersionRelease: "3.2.0",
|
||||
},
|
||||
kernel: models.Kernel{
|
||||
Release: "3.0.0",
|
||||
},
|
||||
},
|
||||
affected: false,
|
||||
notFixedYet: false,
|
||||
},
|
||||
{
|
||||
in: in{
|
||||
family: config.CentOS,
|
||||
def: ovalmodels.Definition{
|
||||
AffectedPacks: []ovalmodels.Package{
|
||||
{
|
||||
Name: "kernel",
|
||||
Version: "3.1.0",
|
||||
NotFixedYet: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
req: request{
|
||||
packName: "kernel",
|
||||
versionRelease: "3.0.0",
|
||||
NewVersionRelease: "3.2.0",
|
||||
},
|
||||
kernel: models.Kernel{
|
||||
Release: "3.0.0",
|
||||
},
|
||||
},
|
||||
affected: true,
|
||||
notFixedYet: false,
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
affected, notFixedYet := isOvalDefAffected(tt.in.def, tt.in.family, tt.in.req)
|
||||
affected, notFixedYet := isOvalDefAffected(tt.in.def, tt.in.req, tt.in.family, tt.in.kernel)
|
||||
if tt.affected != affected {
|
||||
t.Errorf("[%d] affected\nexpected: %v\n actual: %v\n", i, tt.affected, affected)
|
||||
}
|
||||
@@ -331,3 +993,25 @@ func TestIsOvalDefAffected(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMajor(t *testing.T) {
|
||||
var tests = []struct {
|
||||
in string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
in: "4.1",
|
||||
expected: "4",
|
||||
},
|
||||
{
|
||||
in: "0:4.1",
|
||||
expected: "4",
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
a := major(tt.in)
|
||||
if tt.expected != a {
|
||||
t.Errorf("[%d]\nexpected: %s\n actual: %s\n", i, tt.expected, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,21 +142,11 @@ func (api cvedictClient) FetchCveDetailsFromCveDB(cveIDs []string) (cveDetails [
|
||||
cveconfig.Conf.DebugSQL = config.Conf.DebugSQL
|
||||
|
||||
var driver cvedb.DB
|
||||
if driver, err = cvedb.NewDB(cveconfig.Conf.DBType); err != nil {
|
||||
if driver, err = cvedb.NewDB(cveconfig.Conf.DBType, cveconfig.Conf.DBPath, cveconfig.Conf.DebugSQL); err != nil {
|
||||
log.Error(err)
|
||||
return []*cve.CveDetail{}, fmt.Errorf("Failed to New DB. err: %s", err)
|
||||
}
|
||||
|
||||
util.Log.Debugf("Opening DB (%s).", driver.Name())
|
||||
if err := driver.OpenDB(
|
||||
cveconfig.Conf.DBType,
|
||||
cveconfig.Conf.DBPath,
|
||||
cveconfig.Conf.DebugSQL,
|
||||
); err != nil {
|
||||
return []*cve.CveDetail{},
|
||||
fmt.Errorf("Failed to open DB. err: %s", err)
|
||||
}
|
||||
|
||||
for _, cveID := range cveIDs {
|
||||
cveDetail := driver.Get(cveID)
|
||||
if len(cveDetail.CveID) == 0 {
|
||||
@@ -276,19 +266,11 @@ func (api cvedictClient) FetchCveDetailsByCpeNameFromDB(cpeName string) (cveDeta
|
||||
cveconfig.Conf.DebugSQL = config.Conf.DebugSQL
|
||||
|
||||
var driver cvedb.DB
|
||||
if driver, err = cvedb.NewDB(cveconfig.Conf.DBType); err != nil {
|
||||
if driver, err = cvedb.NewDB(cveconfig.Conf.DBType, cveconfig.Conf.DBPath, cveconfig.Conf.DebugSQL); err != nil {
|
||||
log.Error(err)
|
||||
return []*cve.CveDetail{}, fmt.Errorf("Failed to New DB. err: %s", err)
|
||||
}
|
||||
|
||||
util.Log.Debugf("Opening DB (%s).", driver.Name())
|
||||
if err = driver.OpenDB(
|
||||
cveconfig.Conf.DBType,
|
||||
cveconfig.Conf.DBPath,
|
||||
cveconfig.Conf.DebugSQL,
|
||||
); err != nil {
|
||||
return []*cve.CveDetail{},
|
||||
fmt.Errorf("Failed to open DB. err: %s", err)
|
||||
}
|
||||
return driver.GetByCpeName(cpeName), nil
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ package report
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
c "github.com/future-architect/vuls/config"
|
||||
@@ -181,19 +180,25 @@ func FillWithOval(r *models.ScanResult) (err error) {
|
||||
// TODO other suse family
|
||||
ovalClient = oval.NewSUSE()
|
||||
ovalFamily = c.SUSEEnterpriseServer
|
||||
case c.Alpine:
|
||||
ovalClient = oval.NewAlpine()
|
||||
ovalFamily = c.Alpine
|
||||
case c.Amazon, c.Raspbian, c.FreeBSD, c.Windows:
|
||||
return nil
|
||||
case c.ServerTypePseudo:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("OVAL for %s is not implemented yet", r.Family)
|
||||
}
|
||||
|
||||
util.Log.Debugf("Check whether oval is already fetched: %s %s",
|
||||
ovalFamily, r.Release)
|
||||
ok, err := ovalClient.CheckIfOvalFetched(ovalFamily, r.Release)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
major := strings.Split(r.Release, ".")[0]
|
||||
util.Log.Warnf("OVAL entries of %s %s are not found. It's recommended to use OVAL to improve scanning accuracy. For details, see https://github.com/kotakanbe/goval-dictionary#usage , Then report with --ovaldb-path or --ovaldb-url flag", ovalFamily, major)
|
||||
util.Log.Warnf("OVAL entries of %s %s are not found. It's recommended to use OVAL to improve scanning accuracy. For details, see https://github.com/kotakanbe/goval-dictionary#usage , Then report with --ovaldb-path or --ovaldb-url flag", ovalFamily, r.Release)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"github.com/cenkalti/backoff"
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/nlopes/slack"
|
||||
"github.com/parnurzeal/gorequest"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -36,31 +37,23 @@ type field struct {
|
||||
Value string `json:"value"`
|
||||
Short bool `json:"short"`
|
||||
}
|
||||
type attachment struct {
|
||||
Title string `json:"title"`
|
||||
TitleLink string `json:"title_link"`
|
||||
Fallback string `json:"fallback"`
|
||||
Text string `json:"text"`
|
||||
Pretext string `json:"pretext"`
|
||||
Color string `json:"color"`
|
||||
Fields []*field `json:"fields"`
|
||||
MrkdwnIn []string `json:"mrkdwn_in"`
|
||||
Footer string `json:"footer"`
|
||||
}
|
||||
|
||||
type message struct {
|
||||
Text string `json:"text"`
|
||||
Username string `json:"username"`
|
||||
IconEmoji string `json:"icon_emoji"`
|
||||
Channel string `json:"channel"`
|
||||
Attachments []*attachment `json:"attachments"`
|
||||
Text string `json:"text"`
|
||||
Username string `json:"username"`
|
||||
IconEmoji string `json:"icon_emoji"`
|
||||
Channel string `json:"channel"`
|
||||
ThreadTimeStamp string `json:"thread_ts"`
|
||||
Attachments []slack.Attachment `json:"attachments"`
|
||||
}
|
||||
|
||||
// SlackWriter send report to slack
|
||||
type SlackWriter struct{}
|
||||
|
||||
func (w SlackWriter) Write(rs ...models.ScanResult) error {
|
||||
func (w SlackWriter) Write(rs ...models.ScanResult) (err error) {
|
||||
conf := config.Conf.Slack
|
||||
channel := conf.Channel
|
||||
token := conf.LegacyToken
|
||||
|
||||
for _, r := range rs {
|
||||
if channel == "${servername}" {
|
||||
@@ -78,7 +71,7 @@ func (w SlackWriter) Write(rs ...models.ScanResult) error {
|
||||
IconEmoji: conf.IconEmoji,
|
||||
Channel: channel,
|
||||
}
|
||||
if err := send(msg); err != nil {
|
||||
if err = send(msg); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
@@ -88,7 +81,7 @@ func (w SlackWriter) Write(rs ...models.ScanResult) error {
|
||||
// Split into chunks with 100 elements
|
||||
// https://api.slack.com/methods/chat.postMessage
|
||||
maxAttachments := 100
|
||||
m := map[int][]*attachment{}
|
||||
m := map[int][]slack.Attachment{}
|
||||
for i, a := range toSlackAttachments(r) {
|
||||
m[i/maxAttachments] = append(m[i/maxAttachments], a)
|
||||
}
|
||||
@@ -98,21 +91,49 @@ func (w SlackWriter) Write(rs ...models.ScanResult) error {
|
||||
}
|
||||
sort.Ints(chunkKeys)
|
||||
|
||||
for i, k := range chunkKeys {
|
||||
txt := ""
|
||||
if i == 0 {
|
||||
txt = msgText(r)
|
||||
// Send slack by API
|
||||
if 0 < len(token) {
|
||||
api := slack.New(token)
|
||||
ParentMsg := slack.PostMessageParameters{
|
||||
// Text: msgText(r),
|
||||
Username: conf.AuthUser,
|
||||
IconEmoji: conf.IconEmoji,
|
||||
}
|
||||
msg := message{
|
||||
Text: txt,
|
||||
Username: conf.AuthUser,
|
||||
IconEmoji: conf.IconEmoji,
|
||||
Channel: channel,
|
||||
Attachments: m[k],
|
||||
}
|
||||
if err := send(msg); err != nil {
|
||||
|
||||
var ts string
|
||||
if _, ts, err = api.PostMessage(channel, msgText(r), ParentMsg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, k := range chunkKeys {
|
||||
params := slack.PostMessageParameters{
|
||||
// Text: msgText(r),
|
||||
Username: conf.AuthUser,
|
||||
IconEmoji: conf.IconEmoji,
|
||||
Attachments: m[k],
|
||||
ThreadTimestamp: ts,
|
||||
}
|
||||
if _, _, err = api.PostMessage(channel, msgText(r), params); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i, k := range chunkKeys {
|
||||
txt := ""
|
||||
if i == 0 {
|
||||
txt = msgText(r)
|
||||
}
|
||||
msg := message{
|
||||
Text: txt,
|
||||
Username: conf.AuthUser,
|
||||
IconEmoji: conf.IconEmoji,
|
||||
Channel: channel,
|
||||
Attachments: m[k],
|
||||
}
|
||||
if err = send(msg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -164,7 +185,7 @@ func msgText(r models.ScanResult) string {
|
||||
r.ScannedCves.FormatCveSummary())
|
||||
}
|
||||
|
||||
func toSlackAttachments(r models.ScanResult) (attaches []*attachment) {
|
||||
func toSlackAttachments(r models.ScanResult) (attaches []slack.Attachment) {
|
||||
vinfos := r.ScannedCves.ToSortedSlice()
|
||||
for _, vinfo := range vinfos {
|
||||
curent := []string{}
|
||||
@@ -196,12 +217,12 @@ func toSlackAttachments(r models.ScanResult) (attaches []*attachment) {
|
||||
new = append(new, "?")
|
||||
}
|
||||
|
||||
a := attachment{
|
||||
Title: vinfo.CveID,
|
||||
TitleLink: "https://nvd.nist.gov/vuln/detail/" + vinfo.CveID,
|
||||
Text: attachmentText(vinfo, r.Family),
|
||||
MrkdwnIn: []string{"text", "pretext"},
|
||||
Fields: []*field{
|
||||
a := slack.Attachment{
|
||||
Title: vinfo.CveID,
|
||||
TitleLink: "https://nvd.nist.gov/vuln/detail/" + vinfo.CveID,
|
||||
Text: attachmentText(vinfo, r.Family),
|
||||
MarkdownIn: []string{"text", "pretext"},
|
||||
Fields: []slack.AttachmentField{
|
||||
{
|
||||
// Title: "Current Package/CPE",
|
||||
Title: "Installed",
|
||||
@@ -216,7 +237,7 @@ func toSlackAttachments(r models.ScanResult) (attaches []*attachment) {
|
||||
},
|
||||
Color: color(vinfo.MaxCvssScore().Value.Score),
|
||||
}
|
||||
attaches = append(attaches, &a)
|
||||
attaches = append(attaches, a)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ func loadPrevious(current models.ScanResults) (previous models.ScanResults, err
|
||||
}
|
||||
if r.Family == result.Family && r.Release == result.Release {
|
||||
previous = append(previous, *r)
|
||||
util.Log.Infof("Privious json found: %s", path)
|
||||
util.Log.Infof("Previous json found: %s", path)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
171
scan/alpine.go
Normal file
171
scan/alpine.go
Normal file
@@ -0,0 +1,171 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Architect, Inc. Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package scan
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/util"
|
||||
)
|
||||
|
||||
// inherit OsTypeInterface
|
||||
type alpine struct {
|
||||
base
|
||||
}
|
||||
|
||||
// NewAlpine is constructor
|
||||
func newAlpine(c config.ServerInfo) *alpine {
|
||||
d := &alpine{
|
||||
base: base{
|
||||
osPackages: osPackages{
|
||||
Packages: models.Packages{},
|
||||
VulnInfos: models.VulnInfos{},
|
||||
},
|
||||
},
|
||||
}
|
||||
d.log = util.NewCustomLogger(c)
|
||||
d.setServerInfo(c)
|
||||
return d
|
||||
}
|
||||
|
||||
// Alpine
|
||||
// https://github.com/mizzy/specinfra/blob/master/lib/specinfra/helper/detect_os/alpine.rb
|
||||
func detectAlpine(c config.ServerInfo) (itsMe bool, os osTypeInterface) {
|
||||
os = newAlpine(c)
|
||||
|
||||
if r := exec(c, "ls /etc/alpine-release", noSudo); !r.isSuccess() {
|
||||
return false, os
|
||||
}
|
||||
|
||||
if r := exec(c, "cat /etc/alpine-release", noSudo); r.isSuccess() {
|
||||
os.setDistro(config.Alpine, strings.TrimSpace(r.Stdout))
|
||||
return true, os
|
||||
}
|
||||
|
||||
return false, os
|
||||
}
|
||||
|
||||
func (o *alpine) checkDependencies() error {
|
||||
o.log.Infof("Dependencies... No need")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *alpine) checkIfSudoNoPasswd() error {
|
||||
o.log.Infof("sudo ... No need")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *alpine) apkUpdate() error {
|
||||
r := o.exec("apk update", noSudo)
|
||||
if !r.isSuccess() {
|
||||
return fmt.Errorf("Failed to SSH: %s", r)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *alpine) scanPackages() error {
|
||||
if err := o.apkUpdate(); err != nil {
|
||||
return err
|
||||
}
|
||||
// collect the running kernel information
|
||||
release, version, err := o.runningKernel()
|
||||
if err != nil {
|
||||
o.log.Errorf("Failed to scan the running kernel version: %s", err)
|
||||
return err
|
||||
}
|
||||
o.Kernel = models.Kernel{
|
||||
Release: release,
|
||||
Version: version,
|
||||
}
|
||||
|
||||
installed, err := o.scanInstalledPackages()
|
||||
if err != nil {
|
||||
o.log.Errorf("Failed to scan installed packages: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
updatable, err := o.scanUpdatablePackages()
|
||||
if err != nil {
|
||||
o.log.Errorf("Failed to scan installed packages: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
installed.MergeNewVersion(updatable)
|
||||
o.Packages = installed
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *alpine) scanInstalledPackages() (models.Packages, error) {
|
||||
cmd := util.PrependProxyEnv("apk info -v")
|
||||
r := o.exec(cmd, noSudo)
|
||||
if !r.isSuccess() {
|
||||
return nil, fmt.Errorf("Failed to SSH: %s", r)
|
||||
}
|
||||
return o.parseApkInfo(r.Stdout)
|
||||
}
|
||||
|
||||
func (o *alpine) parseApkInfo(stdout string) (models.Packages, error) {
|
||||
packs := models.Packages{}
|
||||
scanner := bufio.NewScanner(strings.NewReader(stdout))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
ss := strings.Split(line, "-")
|
||||
if len(ss) < 3 {
|
||||
return nil, fmt.Errorf("Failed to parse apk info -v: %s", line)
|
||||
}
|
||||
name := strings.Join(ss[:len(ss)-2], "-")
|
||||
packs[name] = models.Package{
|
||||
Name: name,
|
||||
Version: strings.Join(ss[len(ss)-2:], "-"),
|
||||
}
|
||||
}
|
||||
return packs, nil
|
||||
}
|
||||
|
||||
func (o *alpine) scanUpdatablePackages() (models.Packages, error) {
|
||||
cmd := util.PrependProxyEnv("apk version")
|
||||
r := o.exec(cmd, noSudo)
|
||||
if !r.isSuccess() {
|
||||
return nil, fmt.Errorf("Failed to SSH: %s", r)
|
||||
}
|
||||
return o.parseApkVersion(r.Stdout)
|
||||
}
|
||||
|
||||
func (o *alpine) parseApkVersion(stdout string) (models.Packages, error) {
|
||||
packs := models.Packages{}
|
||||
scanner := bufio.NewScanner(strings.NewReader(stdout))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if !strings.Contains(line, "<") {
|
||||
continue
|
||||
}
|
||||
ss := strings.Split(line, "<")
|
||||
namever := strings.TrimSpace(ss[0])
|
||||
tt := strings.Split(namever, "-")
|
||||
name := strings.Join(tt[:len(tt)-2], "-")
|
||||
packs[name] = models.Package{
|
||||
Name: name,
|
||||
NewVersion: strings.TrimSpace(ss[1]),
|
||||
}
|
||||
}
|
||||
return packs, nil
|
||||
}
|
||||
75
scan/alpine_test.go
Normal file
75
scan/alpine_test.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package scan
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
)
|
||||
|
||||
func TestParseApkInfo(t *testing.T) {
|
||||
var tests = []struct {
|
||||
in string
|
||||
packs models.Packages
|
||||
}{
|
||||
{
|
||||
in: `musl-1.1.16-r14
|
||||
busybox-1.26.2-r7
|
||||
`,
|
||||
packs: models.Packages{
|
||||
"musl": {
|
||||
Name: "musl",
|
||||
Version: "1.1.16-r14",
|
||||
},
|
||||
"busybox": {
|
||||
Name: "busybox",
|
||||
Version: "1.26.2-r7",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
d := newAlpine(config.ServerInfo{})
|
||||
for i, tt := range tests {
|
||||
pkgs, _ := d.parseApkInfo(tt.in)
|
||||
if !reflect.DeepEqual(tt.packs, pkgs) {
|
||||
t.Errorf("[%d] expected %v, actual %v", i, tt.packs, pkgs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseApkVersion(t *testing.T) {
|
||||
var tests = []struct {
|
||||
in string
|
||||
packs models.Packages
|
||||
}{
|
||||
{
|
||||
in: `Installed: Available:
|
||||
libcrypto1.0-1.0.1q-r0 < 1.0.2m-r0
|
||||
libssl1.0-1.0.1q-r0 < 1.0.2m-r0
|
||||
nrpe-2.14-r2 < 2.15-r5
|
||||
`,
|
||||
packs: models.Packages{
|
||||
"libcrypto1.0": {
|
||||
Name: "libcrypto1.0",
|
||||
NewVersion: "1.0.2m-r0",
|
||||
},
|
||||
"libssl1.0": {
|
||||
Name: "libssl1.0",
|
||||
NewVersion: "1.0.2m-r0",
|
||||
},
|
||||
"nrpe": {
|
||||
Name: "nrpe",
|
||||
NewVersion: "2.15-r5",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
d := newAlpine(config.ServerInfo{})
|
||||
for i, tt := range tests {
|
||||
pkgs, _ := d.parseApkVersion(tt.in)
|
||||
if !reflect.DeepEqual(tt.packs, pkgs) {
|
||||
t.Errorf("[%d] expected %v, actual %v", i, tt.packs, pkgs)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,8 +29,7 @@ import (
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/util"
|
||||
|
||||
"github.com/knqyf263/go-deb-version"
|
||||
version "github.com/knqyf263/go-deb-version"
|
||||
)
|
||||
|
||||
// inherit OsTypeInterface
|
||||
@@ -240,7 +239,7 @@ func (o *debian) rebootRequired() (bool, error) {
|
||||
|
||||
func (o *debian) scanInstalledPackages() (models.Packages, models.Packages, models.SrcPackages, error) {
|
||||
installed, updatable, srcPacks := models.Packages{}, models.Packages{}, models.SrcPackages{}
|
||||
r := o.exec(`dpkg-query -W -f='${binary:Package},${db:Status-Abbrev},${Version},${Source},${source:Version}\n'`, noSudo)
|
||||
r := o.exec(`dpkg-query -W -f="\${binary:Package},\${db:Status-Abbrev},\${Version},\${Source},\${source:Version}\n"`, noSudo)
|
||||
if !r.isSuccess() {
|
||||
return nil, nil, nil, fmt.Errorf("Failed to SSH: %s", r)
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import (
|
||||
|
||||
type execResult struct {
|
||||
Servername string
|
||||
Container conf.Container
|
||||
Host string
|
||||
Port string
|
||||
Cmd string
|
||||
@@ -51,9 +52,16 @@ type execResult struct {
|
||||
}
|
||||
|
||||
func (s execResult) String() string {
|
||||
sname := ""
|
||||
if s.Container.ContainerID == "" {
|
||||
sname = s.Servername
|
||||
} else {
|
||||
sname = s.Container.Name + "@" + s.Servername
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"execResult: servername: %s\n cmd: %s\n exitstatus: %d\n stdout: %s\n stderr: %s\n err: %s",
|
||||
s.Servername, s.Cmd, s.ExitStatus, s.Stdout, s.Stderr, s.Error)
|
||||
sname, s.Cmd, s.ExitStatus, s.Stdout, s.Stderr, s.Error)
|
||||
}
|
||||
|
||||
func (s execResult) isSuccess(expectedStatusCodes ...int) bool {
|
||||
@@ -167,10 +175,11 @@ func exec(c conf.ServerInfo, cmd string, sudo bool, log ...*logrus.Entry) (resul
|
||||
func localExec(c conf.ServerInfo, cmdstr string, sudo bool) (result execResult) {
|
||||
cmdstr = decorateCmd(c, cmdstr, sudo)
|
||||
var cmd *ex.Cmd
|
||||
if c.Distro.Family == conf.FreeBSD {
|
||||
switch c.Distro.Family {
|
||||
// case conf.FreeBSD, conf.Alpine, conf.Debian:
|
||||
// cmd = ex.Command("/bin/sh", "-c", cmdstr)
|
||||
default:
|
||||
cmd = ex.Command("/bin/sh", "-c", cmdstr)
|
||||
} else {
|
||||
cmd = ex.Command("/bin/bash", "-c", cmdstr)
|
||||
}
|
||||
var stdoutBuf, stderrBuf bytes.Buffer
|
||||
cmd.Stdout = &stdoutBuf
|
||||
@@ -196,6 +205,7 @@ func localExec(c conf.ServerInfo, cmdstr string, sudo bool) (result execResult)
|
||||
|
||||
func sshExecNative(c conf.ServerInfo, cmd string, sudo bool) (result execResult) {
|
||||
result.Servername = c.ServerName
|
||||
result.Container = c.Container
|
||||
result.Host = c.Host
|
||||
result.Port = c.Port
|
||||
|
||||
@@ -311,6 +321,7 @@ func sshExecExternal(c conf.ServerInfo, cmd string, sudo bool) (result execResul
|
||||
result.Stdout = stdoutBuf.String()
|
||||
result.Stderr = stderrBuf.String()
|
||||
result.Servername = c.ServerName
|
||||
result.Container = c.Container
|
||||
result.Host = c.Host
|
||||
result.Port = c.Port
|
||||
result.Cmd = fmt.Sprintf("%s %s", sshBinaryPath, strings.Join(args, " "))
|
||||
@@ -324,10 +335,19 @@ func getSSHLogger(log ...*logrus.Entry) *logrus.Entry {
|
||||
return log[0]
|
||||
}
|
||||
|
||||
func dockerShell(family string) string {
|
||||
switch family {
|
||||
// case conf.Alpine, conf.Debian:
|
||||
// return "/bin/sh"
|
||||
default:
|
||||
// return "/bin/bash"
|
||||
return "/bin/sh"
|
||||
}
|
||||
}
|
||||
|
||||
func decorateCmd(c conf.ServerInfo, cmd string, sudo bool) string {
|
||||
if sudo && c.User != "root" && !c.IsContainer() {
|
||||
cmd = fmt.Sprintf("sudo -S %s", cmd)
|
||||
cmd = strings.Replace(cmd, "|", "| sudo ", -1)
|
||||
}
|
||||
|
||||
// If you are using pipe and you want to detect preprocessing errors, remove comment out
|
||||
@@ -342,9 +362,11 @@ func decorateCmd(c conf.ServerInfo, cmd string, sudo bool) string {
|
||||
if c.IsContainer() {
|
||||
switch c.Containers.Type {
|
||||
case "", "docker":
|
||||
cmd = fmt.Sprintf(`docker exec --user 0 %s /bin/bash -c "%s"`, c.Container.ContainerID, cmd)
|
||||
cmd = fmt.Sprintf(`docker exec --user 0 %s %s -c '%s'`,
|
||||
c.Container.ContainerID, dockerShell(c.Distro.Family), cmd)
|
||||
case "lxd":
|
||||
cmd = fmt.Sprintf(`lxc exec %s -- /bin/bash -c "%s"`, c.Container.Name, cmd)
|
||||
cmd = fmt.Sprintf(`lxc exec %s -- %s -c '%s'`,
|
||||
c.Container.Name, dockerShell(c.Distro.Family), cmd)
|
||||
}
|
||||
}
|
||||
// cmd = fmt.Sprintf("set -x; %s", cmd)
|
||||
|
||||
@@ -63,7 +63,7 @@ func TestDecorateCmd(t *testing.T) {
|
||||
conf: config.ServerInfo{User: "non-roor"},
|
||||
cmd: "ls | grep hoge",
|
||||
sudo: true,
|
||||
expected: "sudo -S ls | sudo grep hoge",
|
||||
expected: "sudo -S ls | grep hoge",
|
||||
},
|
||||
// -------------docker-------------
|
||||
// root sudo false docker
|
||||
@@ -75,7 +75,7 @@ func TestDecorateCmd(t *testing.T) {
|
||||
},
|
||||
cmd: "ls",
|
||||
sudo: false,
|
||||
expected: `docker exec --user 0 abc /bin/bash -c "ls"`,
|
||||
expected: `docker exec --user 0 abc /bin/sh -c 'ls'`,
|
||||
},
|
||||
// root sudo true docker
|
||||
{
|
||||
@@ -86,7 +86,7 @@ func TestDecorateCmd(t *testing.T) {
|
||||
},
|
||||
cmd: "ls",
|
||||
sudo: true,
|
||||
expected: `docker exec --user 0 abc /bin/bash -c "ls"`,
|
||||
expected: `docker exec --user 0 abc /bin/sh -c 'ls'`,
|
||||
},
|
||||
// non-root sudo false, docker
|
||||
{
|
||||
@@ -97,7 +97,7 @@ func TestDecorateCmd(t *testing.T) {
|
||||
},
|
||||
cmd: "ls",
|
||||
sudo: false,
|
||||
expected: `docker exec --user 0 abc /bin/bash -c "ls"`,
|
||||
expected: `docker exec --user 0 abc /bin/sh -c 'ls'`,
|
||||
},
|
||||
// non-root sudo true, docker
|
||||
{
|
||||
@@ -108,7 +108,7 @@ func TestDecorateCmd(t *testing.T) {
|
||||
},
|
||||
cmd: "ls",
|
||||
sudo: true,
|
||||
expected: `docker exec --user 0 abc /bin/bash -c "ls"`,
|
||||
expected: `docker exec --user 0 abc /bin/sh -c 'ls'`,
|
||||
},
|
||||
// non-root sudo true, docker
|
||||
{
|
||||
@@ -119,7 +119,7 @@ func TestDecorateCmd(t *testing.T) {
|
||||
},
|
||||
cmd: "ls | grep hoge",
|
||||
sudo: true,
|
||||
expected: `docker exec --user 0 abc /bin/bash -c "ls | grep hoge"`,
|
||||
expected: `docker exec --user 0 abc /bin/sh -c 'ls | grep hoge'`,
|
||||
},
|
||||
// -------------lxd-------------
|
||||
// root sudo false lxd
|
||||
@@ -131,7 +131,7 @@ func TestDecorateCmd(t *testing.T) {
|
||||
},
|
||||
cmd: "ls",
|
||||
sudo: false,
|
||||
expected: `lxc exec def -- /bin/bash -c "ls"`,
|
||||
expected: `lxc exec def -- /bin/sh -c 'ls'`,
|
||||
},
|
||||
// root sudo true lxd
|
||||
{
|
||||
@@ -142,7 +142,7 @@ func TestDecorateCmd(t *testing.T) {
|
||||
},
|
||||
cmd: "ls",
|
||||
sudo: true,
|
||||
expected: `lxc exec def -- /bin/bash -c "ls"`,
|
||||
expected: `lxc exec def -- /bin/sh -c 'ls'`,
|
||||
},
|
||||
// non-root sudo false, lxd
|
||||
{
|
||||
@@ -153,7 +153,7 @@ func TestDecorateCmd(t *testing.T) {
|
||||
},
|
||||
cmd: "ls",
|
||||
sudo: false,
|
||||
expected: `lxc exec def -- /bin/bash -c "ls"`,
|
||||
expected: `lxc exec def -- /bin/sh -c 'ls'`,
|
||||
},
|
||||
// non-root sudo true, lxd
|
||||
{
|
||||
@@ -164,7 +164,7 @@ func TestDecorateCmd(t *testing.T) {
|
||||
},
|
||||
cmd: "ls",
|
||||
sudo: true,
|
||||
expected: `lxc exec def -- /bin/bash -c "ls"`,
|
||||
expected: `lxc exec def -- /bin/sh -c 'ls'`,
|
||||
},
|
||||
// non-root sudo true lxd
|
||||
{
|
||||
@@ -175,7 +175,7 @@ func TestDecorateCmd(t *testing.T) {
|
||||
},
|
||||
cmd: "ls | grep hoge",
|
||||
sudo: true,
|
||||
expected: `lxc exec def -- /bin/bash -c "ls | grep hoge"`,
|
||||
expected: `lxc exec def -- /bin/sh -c 'ls | grep hoge'`,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
66
scan/pseudo.go
Normal file
66
scan/pseudo.go
Normal file
@@ -0,0 +1,66 @@
|
||||
/* Vuls - Vulnerability Scanner
|
||||
Copyright (C) 2016 Future Architect, Inc. Japan.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package scan
|
||||
|
||||
import (
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/util"
|
||||
)
|
||||
|
||||
// inherit OsTypeInterface
|
||||
type pseudo struct {
|
||||
base
|
||||
}
|
||||
|
||||
func detectPseudo(c config.ServerInfo) (itsMe bool, pseudo osTypeInterface, err error) {
|
||||
p := newPseudo(c)
|
||||
p.setDistro(config.ServerTypePseudo, "")
|
||||
return c.Type == config.ServerTypePseudo, p, nil
|
||||
}
|
||||
|
||||
func newPseudo(c config.ServerInfo) *pseudo {
|
||||
d := &pseudo{
|
||||
base: base{
|
||||
osPackages: osPackages{
|
||||
Packages: models.Packages{},
|
||||
VulnInfos: models.VulnInfos{},
|
||||
},
|
||||
},
|
||||
}
|
||||
d.log = util.NewCustomLogger(c)
|
||||
d.setServerInfo(c)
|
||||
return d
|
||||
}
|
||||
|
||||
func (o *pseudo) checkIfSudoNoPasswd() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *pseudo) checkDependencies() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *pseudo) scanPackages() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *pseudo) detectPlatform() {
|
||||
o.setPlatform(models.Platform{Name: "other"})
|
||||
return
|
||||
}
|
||||
@@ -260,11 +260,13 @@ func (o *redhat) scanPackages() error {
|
||||
}
|
||||
|
||||
func (o *redhat) rebootRequired() (bool, error) {
|
||||
r := o.exec("rpm -q --last kernel | head -n1", noSudo)
|
||||
if !r.isSuccess() {
|
||||
return false, fmt.Errorf("Failed to detect the last installed kernel : %v", r)
|
||||
r := o.exec("rpm -q --last kernel", noSudo)
|
||||
scanner := bufio.NewScanner(strings.NewReader(r.Stdout))
|
||||
if !r.isSuccess() || !scanner.Scan() {
|
||||
o.log.Warn("Failed to detect the last installed kernel : %v", r)
|
||||
return false, nil
|
||||
}
|
||||
lastInstalledKernelVer := strings.Fields(r.Stdout)[0]
|
||||
lastInstalledKernelVer := strings.Fields(scanner.Text())[0]
|
||||
running := fmt.Sprintf("kernel-%s", o.Kernel.Release)
|
||||
return running != lastInstalledKernelVer, nil
|
||||
}
|
||||
@@ -397,7 +399,7 @@ func (o *redhat) parseUpdatablePacksLine(line string) (models.Package, error) {
|
||||
}
|
||||
|
||||
func (o *redhat) scanUnsecurePackages(updatable models.Packages) (models.VulnInfos, error) {
|
||||
if config.Conf.Deep {
|
||||
if config.Conf.Deep && o.Distro.Family != config.Amazon {
|
||||
//TODO Cache changelogs to bolt
|
||||
if err := o.fillChangelogs(updatable); err != nil {
|
||||
return nil, err
|
||||
@@ -451,7 +453,7 @@ func (o *redhat) getAvailableChangelogs(packNames []string) (map[string]string,
|
||||
if config.Conf.SkipBroken {
|
||||
yumopts += " --skip-broken"
|
||||
}
|
||||
cmd := `yum --color=never %s changelog all %s | grep -A 10000 '==================== Available Packages ===================='`
|
||||
cmd := `yum --color=never changelog all %s %s | grep -A 1000000 '==================== Available Packages ===================='`
|
||||
cmd = fmt.Sprintf(cmd, yumopts, strings.Join(packNames, " "))
|
||||
|
||||
r := o.exec(util.PrependProxyEnv(cmd), o.sudo())
|
||||
|
||||
@@ -41,7 +41,6 @@ type osTypeInterface interface {
|
||||
detectPlatform()
|
||||
getPlatform() models.Platform
|
||||
|
||||
// checkDependencies checks if dependencies are installed on the target server.
|
||||
checkDependencies() error
|
||||
checkIfSudoNoPasswd() error
|
||||
|
||||
@@ -75,6 +74,11 @@ func detectOS(c config.ServerInfo) (osType osTypeInterface) {
|
||||
var itsMe bool
|
||||
var fatalErr error
|
||||
|
||||
if itsMe, osType, _ = detectPseudo(c); itsMe {
|
||||
util.Log.Debugf("Pseudo")
|
||||
return
|
||||
}
|
||||
|
||||
itsMe, osType, fatalErr = detectDebian(c)
|
||||
if fatalErr != nil {
|
||||
osType.setErrs([]error{
|
||||
@@ -102,6 +106,11 @@ func detectOS(c config.ServerInfo) (osType osTypeInterface) {
|
||||
return
|
||||
}
|
||||
|
||||
if itsMe, osType = detectAlpine(c); itsMe {
|
||||
util.Log.Debugf("Alpine. Host: %s:%s", c.Host, c.Port)
|
||||
return
|
||||
}
|
||||
|
||||
//TODO darwin https://github.com/mizzy/specinfra/blob/master/lib/specinfra/helper/detect_os/darwin.rb
|
||||
osType.setErrs([]error{fmt.Errorf("Unknown OS Type")})
|
||||
return
|
||||
|
||||
@@ -157,8 +157,8 @@ func (o *suse) parseZypperLULines(stdout string) (models.Packages, error) {
|
||||
scanner := bufio.NewScanner(strings.NewReader(stdout))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.HasPrefix(line, "S | Repository") ||
|
||||
strings.HasPrefix(line, "--+----------------") {
|
||||
if strings.Index(line, "S | Repository") != -1 ||
|
||||
strings.Index(line, "--+----------------") != -1 {
|
||||
continue
|
||||
}
|
||||
pack, err := o.parseZypperLUOneLine(line)
|
||||
|
||||
@@ -109,7 +109,7 @@ func ProxyEnv() string {
|
||||
return httpProxyEnv
|
||||
}
|
||||
|
||||
// PrependProxyEnv prepends proxy enviroment variable
|
||||
// PrependProxyEnv prepends proxy environment variable
|
||||
func PrependProxyEnv(cmd string) string {
|
||||
if len(config.Conf.HTTPProxy) == 0 {
|
||||
return cmd
|
||||
|
||||
Reference in New Issue
Block a user