Skip to content

Commit

Permalink
Merge pull request #11 from olgaKiseleva/master
Browse files Browse the repository at this point in the history
Windows support
  • Loading branch information
vulnersCom authored Dec 31, 2022
2 parents 345ec69 + 87156ed commit 41c29e2
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 47 deletions.
81 changes: 50 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
# Vulners Agent
# Vulners agent

![Vulners Agent](img/vulners_logo.png)

Vulners Agent is open source agent, which provides vulnerability assessment for linux-based systems. Agent solution perfoms scanning with minimum commands for execution and as a result achieve extremely fast scan. Agent is developed with Python and uses OS environment variables to detect used Python version.
Vulners agent is an open source solution, which provides vulnerability assessment for Linux-based and Windows operating systems. The agent performs scans with minimum execution commands and, as a result, achieves extremely fast scanning speed. You will need the **Python 3** to install the agent.

Agent gathers information about operating system, it's version and installed packages. These information is sent to vulners.com API and results can be viewed via [vulners.com audit result](https://vulners.com/audit)
The agent gathers information about your operating system, its version, and any installed packages. This information is then sent to Vulners API to find out which software is vulnerable. You can check how it works in [manual mode](https://vulners.com/audit) to evaluate the results.

![Vulners Audit IP Summary](img/audit_ipsummary.png)

# Agent installation
## Installation for Linux-based operating systems

## Configure repository

### For rhel-based linux:
### Configure a repository for RHEL-based Linux:

Create file **/etc/yum.repos.d/vulners.repo**

Expand All @@ -37,55 +35,57 @@ gpgcheck=1
gpgkey=https://repo.vulners.com/pubkey.txt
```

### For debian-based linux:
### Configure a repository for Debian-based Linux:

First add vulners.com pubkey:
First, add vulners.com pubkey:
```
wget -O- https://repo.vulners.com/pubkey.txt | apt-key add -
```

After this create file **/etc/apt/sources.list.d/vulners.list**
Then, create file **/etc/apt/sources.list.d/vulners.list**
```
deb http://repo.vulners.com/debian jessie main
deb http://repo.vulners.com/debian focal main
```

## Install packet:
### Install packet:

### RHEL
#### RHEL
```yum install vulners-agent```

### Debian
#### Debian
```apt-get update && apt-get install vulners-agent```

### Source code (We don't recommend this way)
You could clone source code of package and perform scans using python.
According best practices you should use virtual environment
* install requirements.txt with ```pip3 install -r vulners-agent/requirements.txt```
* configure agent as described below
* run ```python3 vulners-agent/application --app Scanner```
### Source code (NOT recommended)
You could clone the source code of a package and perform scans using Python. According to best practices, this should be done in a virtual environment:

* install requirements.txt with ```pip3 install -r vulners-agent/requirements.txt```,
* configure the agent as described below,
* run ```python3 vulners-agent/application --app Scanner```.

## Configuration for Linux-based operating systems
Now, you have to generate an API key to register the agent. [Log in](https://vulners.com/userinfo) to Vulners, go to the userinfo space and click on the API KEYS tab. In the "Scope" field, select "scan", click SAVE and then copy the generated key. The result should look something like this:

## Agent configuration
Now you should get api-key for agent registration. Log in to vulners.com, go to [userinfo space] (https://vulners.com/userinfo) . Then you should choose "apikey" section.
Choose "scan" in scope menu and click "Generate new key". You will get an api-key, which looks like this:
**RGB9YPJG7CFAXP35PMDVYFFJPGZ9ZIRO1VGO9K9269B0K86K6XQQQR32O6007NUK**

You'll need to write this key into agent configuration. You should use only one api key for all your agents. Agent configuration is located in file /etc/vulners/vulners_agent.conf
Change parameter api_key in section agent. Here is example of config file:
Now, you can embed the generated key into the agent. The agent configuration file is located at /etc/vulners/vulners_agent.conf.

Example of the config file:

```
[DEFAULT]
api_key = RGB9YPJG7CFAXP35PMDVYFFJPGZ9ZIRO1VGO9K9269B0K86K6XQQQR32O6007NUK
```
You can use one API key for all your agents.

## Agent execution
### Execution

During first run agent will automatically register with configured api_key
During the first run, the agent will be automatically registered with the configured API key.

To perform your system scan run ```vulners-agent --app Scanner```.
Perform a system scan by running ```vulners-agent --app Scanner```.

After this you may look at agent status and scanning results at https://vulners.com/audit
Once finished, you can view agent status and scan results in the [Audit](https://vulners.com/linux-scanner/audit) section of your personal account.

## Advanced configuration
### Advanced configuration

Using /etc/vulners/vulners_agent.conf you can override part of the identification parameters.

Expand All @@ -98,5 +98,24 @@ ip_address = 10.0.0.1
fqdn = my.host.example.com
mac_address = 00:01:02:03:04:06
interval = 3h30m
```

## Installation and configuration for Windows
Run VulnersAgentInstaller_v2.2.0.msi and follow wizard.

Generate API-key to register the agent and paste it during the configuration step.
If necessary, you can set an alternate Vulners host or Vulners proxy address. You can also set agent identification parameters, such as IP address and FQDN. You will see these parameters in the Dashboard.

<img src="img/configuration.png" alt="drawing" width="450"/>

Press Next and finish installation. Scanning process will be started automatically.

To run installer silently use following arguments
- APIKEY (required)
- INSTALLDIR
- HOST
- IP
- FQDN
- MAC

The installation process will create a scheduled task that performs the scan and a configuration file. You can use the Windows Task Scheduler console to adjust the scan interval. The configuration and logs are located in the Program Data folder.
5 changes: 4 additions & 1 deletion app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class ClientApplication(object):
singleton = False
random_run_delay = True

def __init__(self, config_file, log_level, log_path, inheritor_apps, ignore_proxy):
def __init__(self, config_file, log_level, log_path, inheritor_apps, ignore_proxy, data_dir):
self.initialized = False
self.ignore_proxy = ignore_proxy
# Set up logger namespace and levels
Expand All @@ -58,6 +58,9 @@ def __init__(self, config_file, log_level, log_path, inheritor_apps, ignore_prox
self.application_list = inheritor_apps
self.log.debug("Application %s: Inherited apps loaded as %s" % (self.__class__.__name__, inheritor_apps))

if data_dir:
self.data_file = os.path.join(data_dir, 'application.data')

def singleton_init(self):
flavor_id = self.__class__.__name__
self.initialized = False
Expand Down
2 changes: 1 addition & 1 deletion app/migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#
__author__ = "Kir Ermakov <[email protected]>"

from . import ClientApplication
from app import ClientApplication
import os
from os import access, R_OK
from common.configreader import get_full_config
Expand Down
29 changes: 22 additions & 7 deletions app/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
# All Rights Reserved.
#
__author__ = "Kir Ermakov <[email protected]>"
from . import ClientApplication
import re

from app import ClientApplication
from common import osdetect, oscommands


Expand Down Expand Up @@ -51,17 +53,30 @@ def linux_scan(self, os_name, os_version, os_data):
package=packages)
return scan_results

def windows_scan(self, os_name, os_version, os_data):
from common.winutils import get_windows_installed_software, get_windows_updates, get_windows_data
windows_data = get_windows_data()
def windows_scan(self, os_name, os_version, os_data, os_family='windows'):
from common.winutils import get_windows_installed_software, get_windows_updates

missing_kb, missing_updates, installed_kb, installed_updates = get_windows_updates()
installed_software_list = get_windows_installed_software()

software = []
for name, version in installed_software_list.items():
if re.match(r'^[\d+?.]+$', name.split()[-1]):
name = ' '.join(name.split()[:-1])
software.append({
'software': name,
'version': version,
})
self.log.debug("Found missing KB's: %s" % missing_kb)
self.log.debug("Enumerated Windows Software List: %s" % installed_software_list)

return None
agent_id = self.get_var('agent_id', namespace='shared')
scan_results = self.vulners.agent_winaudit(
agent_id=agent_id,
os=os_data['osType'],
os_version=os_version,
software=software,
kb_list=installed_kb
)
return scan_results

def run(self):
agent_id = self.get_var('agent_id', namespace='shared')
Expand Down
2 changes: 1 addition & 1 deletion app/ticker.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import arrow
import datetime
import concurrent.futures
from . import ClientApplication
from app import ClientApplication
from common import __version__ as __agent_version__, __agent_type__
from common import osdetect
from pytimeparse.timeparse import timeparse
Expand Down
5 changes: 5 additions & 0 deletions application.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import app
from common.extargparse import *
from common.modloader import get_inheritors
from app import scanner,ticker


def available_apps(app_name):
Expand Down Expand Up @@ -51,6 +52,9 @@ def available_apps(app_name):
parser.add_argument('--ignore-proxy', default=False, const=True, nargs='?',
help='Ignore proxy configuration and environment')

parser.add_argument('--data_dir', type=data_dir_exists_accessible, nargs='?', default=None,
help='Application data directory location')

args = parser.parse_args()

# Initialize applications
Expand All @@ -63,6 +67,7 @@ def available_apps(app_name):
'log_path': args.logpath,
'ignore_proxy': args.ignore_proxy,
'inheritor_apps': inheritors,
'data_dir': args.data_dir
}

for app_name in inheritors:
Expand Down
4 changes: 2 additions & 2 deletions common/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Agent version
__version__ = "2.1.3"
__agent_type__ = 'Vulners Agent'
__version__ = "2.2.0"
__agent_type__ = 'Vulners Agent'
13 changes: 13 additions & 0 deletions common/extargparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,19 @@ def config_file_exists_accessible(config_file_path_name):

return config_file_path_name

def data_dir_exists_accessible(data_dir_name):

if not os.path.exists(data_dir_name):
message = 'invalid file path: {0} Error: {1}'.format(data_dir_name,
"Directory do not exist.")
raise argparse.ArgumentTypeError(message)

if not access(data_dir_name, W_OK):
message = 'invalid file path: {0} Error: {1}'.format(data_dir_name,
"Directory is not accessible.")
raise argparse.ArgumentTypeError(message)

return data_dir_name

class StoreDictKeyPair(argparse.Action):
def __init__(self, option_strings, dest, nargs=None, **kwargs):
Expand Down
30 changes: 26 additions & 4 deletions common/vulnersagent.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class AgentAPI(vulners.Vulners):
'agent_register': '/api/v3/agent/register/',
'agent_update': '/api/v3/agent/update/',
'agent_audit': '/api/v3/agent/audit/',
'agent_winsoftware': '/api/v3/agent/winsoftware',
'supported_os': '/api/v3/agent/supported/'
}

Expand Down Expand Up @@ -105,7 +106,28 @@ def agent_audit(self, agent_id, os, os_version, package):
raise TypeError("OS Version expected to be a string")
if not isinstance(package, (list, set)):
raise TypeError("Package expected to be a list or set")
return self.vulners_post_request(
'agent_audit',
{"os": os, 'version': os_version, 'package': package, 'agentId': agent_id}
)
return self.vulners_post_request('agent_audit',
{"os": os, 'version': os_version,
'package': package, 'agentId': agent_id})

def agent_winaudit(self, agent_id, os, os_version, software, kb_list):
"""
Tech Agent Audit for Windows OS call
:return: {'packages':[LIST OF VULNERABLE PACKAGES], 'reasons':LIST OF REASONS, 'vulnerabilities':[LIST OF VULNERABILITY IDs]}
"""
if not isinstance(agent_id, string_types) or not agent_id:
raise TypeError("agent_id expected to be a non empty string")
if not isinstance(os, string_types):
raise TypeError("OS expected to be a string")
if not isinstance(os_version, string_types):
raise TypeError("OS Version expected to be a string")
if not isinstance(software, (list, set)):
raise TypeError("Software expected to be a list or set")
if not isinstance(kb_list, (list, set)):
raise TypeError("Installed KB expected to be a list or set")
return self.vulners_post_request('agent_winsoftware', {"os": os,
'os_version': os_version,
'software': software,
'kb_list': kb_list,
'agentId': agent_id})
2 changes: 2 additions & 0 deletions common/winutils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import winreg
import re
import pythoncom
import win32com.client
import ctypes
import wmi
Expand Down Expand Up @@ -28,6 +29,7 @@ class OSVersionInfo(ctypes.Structure):
version.dwOSVersionInfoSize = ctypes.sizeof(OSVersionInfo)
GetVersionEx(ctypes.byref(version))

pythoncom.CoInitialize()
c = wmi.WMI()
os = c.Win32_OperatingSystem()[0]

Expand Down
Binary file added img/configuration.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 41c29e2

Please sign in to comment.