-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcommon_inventory.py
executable file
·171 lines (140 loc) · 6.13 KB
/
common_inventory.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/var/ossec/framework/python/bin/python3
######## common_inventory.py #######
#
# This is based on original work from Juan C. Tello
# Description:
# This wodle (Wazuh module) gives Wazuh the capability to query the manager's
# API to gather information on the inventory information from all agents.
# It is accompannied by the common_inventory.xml rule file which goes to
# /var/ossec/etc/rules/
#
# Configuration:
#
#
# <wodle name="command">
# <disabled>no</disabled>
# <tag>test</tag>
# <command>/var/ossec/framework/python/bin/python3 /var/ossec/wodles/vuln_report.py --manager WAZUH_MANAGER_IP_ADDRESS --user WAZUH_API_USER --password WAZUH_API_PASSWORD</command>
# <interval>1d</interval>
# <ignore_output>yes</ignore_output>
# <run_on_start>yes</run_on_start>
# <timeout>0</timeout>
# <!--
# <verify_sha256></verify_sha256>
# -->
# </wodle>
#
#
###############################
import logging
logging.basicConfig(format='%(asctime)s %(message)s',filename='common_inventory.log', encoding='utf-8', level=logging.DEBUG)
logging.info('Started common_inventory.py')
logging.info('Loading libraries')
import requests, urllib3, json, argparse
from socket import socket, AF_UNIX, SOCK_DGRAM
logging.info('Libraries loaded')
requests.packages.urllib3.disable_warnings()
HEADERS={}
VERIFY=False
socketAddr = '/var/ossec/queue/sockets/queue'
def get_token():
"""
Function to retrieve the Wazuh JWST token for the API
This was built for Wazuh 4.3.10. For Wazuh 4.4.0 this is expected to change
to a POST request: https://github.com/wazuh/wazuh/issues/12793
"""
request_result = requests.get(WAZUH_API + "/security/user/authenticate", auth=(WAZUH_USER, WAZUH_PASS), verify=VERIFY,timeout=5)
if request_result.status_code == 200:
token = json.loads(request_result.content.decode())['data']['token']
HEADERS['Authorization'] = f'Bearer {token}'
else:
raise Exception(f"Error obtaining response: {request_result.json()}")
def get_pages(URL,limit=500):
"""
Function to get navigate all pages of a result in the Wazuh API
"""
result = []
offset = 0
finished = False
while not finished:
request = requests.get(URL + f"?limit={limit}&offset={offset}", headers=HEADERS, verify=VERIFY,timeout=5)
if request.status_code == 200:
items = json.loads(request.content.decode())['data']
for i in items['affected_items']:
result.append(i)
# If there are more items to be gathered, iterate the offset
if items['total_affected_items'] > (limit + offset):
offset = offset + limit
if (offset + limit) > items['total_affected_items']:
limit = items['total_affected_items'] - offset
else:
finished = True
else:
if request.status_code == 401:
get_token() # Renew token
else:
raise Exception(f"Error obtaining response: {request.json()}")
return result
def get_non_paged(URL):
"""
Function to get single paged results off the Wazuh API
"""
result = []
request = requests.get(URL, headers=HEADERS, verify=VERIFY,timeout=5)
if request.status_code == 200:
result = json.loads(request.content.decode())['data']['affected_items']
else:
if request.status_code == 401:
get_token() # Renew token
else:
raise Exception(f"Error obtaining response: {request.json()}")
if len(result) > 0:
return result[0]
def get_inventory(agents):
"""
Function to retrieve the inventory of every agent
https://documentation.wazuh.com/current/user-manual/api/reference.html#tag/Syscollector
This function returns a dictionary with an inventory for each agent
"""
inventory = {}
for a in agents:
ID=a['id']
inventory[ID] = dict( hardware = {}, hotfixes={}, netaddr={}, netiface={}, netproto={}, os={}, packages={}, ports={}, processes={} )
#inventory[ID]['hotfixes'] = get_pages(WAZUH_API + "/syscollector/" + ID + "/hotfixes")
#inventory[ID]['netaddr'] = get_pages(WAZUH_API + "/syscollector/" + ID + "/netaddr")
#inventory[ID]['netiface'] = get_pages(WAZUH_API + "/syscollector/" + ID + "/netiface")
#inventory[ID]['netproto'] = get_pages(WAZUH_API + "/syscollector/" + ID + "/netproto")
#inventory[ID]['packages'] = get_pages(WAZUH_API + "/syscollector/" + ID + "/packages")
#inventory[ID]['ports'] = get_pages(WAZUH_API + "/syscollector/" + ID + "/ports")
#inventory[ID]['processes'] = get_pages(WAZUH_API + "/syscollector/" + ID + "/processes")[0]
inventory[ID]['hardware'] = get_non_paged(WAZUH_API + "/syscollector/" + ID + "/hardware")
inventory[ID]['os'] = get_non_paged(WAZUH_API + "/syscollector/" + ID + "/os")
return inventory
def send_event(msg,agentId,agentName):
string = f'1:[{agentId}] ({agentName}) any->inventory:{msg}'
sock = socket(AF_UNIX, SOCK_DGRAM)
sock.connect(socketAddr)
sock.send(string.encode())
sock.close()
if __name__ == "__main__":
# Parsing arguments
logging.info('Reading Arguments')
parser = argparse.ArgumentParser()
parser.add_argument('-m', '--manager', type=str, default='127.0.0.1', help='*Wazuh API IP or DNS name.(def. "127.0.0.1").')
parser.add_argument('-u', '--user', type=str, default='wazuh-wui', help='*Wazuh API user (def. "wazuh-wui").')
parser.add_argument('-p', '--password', type=str, default='wazuh-wui', help='*Wazuh API user password (def. "wazuh-wui").')
args = parser.parse_args()
WAZUH_IP = args.manager
WAZUH_USER = args.user
WAZUH_PASS = args.password
WAZUH_PORT = 55000
WAZUH_API=f"https://{WAZUH_IP}:{WAZUH_PORT}"
logging.info('Getting agents (paged)')
agents = get_pages(WAZUH_API + f"/agents")
logging.info('Getting inventory for agents')
inventory = get_inventory(agents)
logging.info('Pushing data to Wazuh Socket')
for a in agents:
ID=a['id']
NAME=a['name']
send_event(json.dumps(inventory[ID]),ID,NAME)