Jak używać osquery w Pythonie.
osquery to program stworzony przez Facebook, który za pomocą zapytań SQL pozwala pobierać informacje o systemie, sprzęcie, uruchomionych programach itp.
Program można pobrać z https://osquery.io/downloads/ w postaci paczki instalacyjnej pod Linux, MacOS lub Windows. Można też dodać repozytorium i instalować za pomocą np. apt
pod Debian/Ubuntu/Mint
.
Strona: https://osquery.io/
Dokumentacja: https://osquery.readthedocs.io
GitHub: https://github.com/facebook/osquery
Po instalacji programu osquery
(który jest dostępny z terminala jako osqueryi
) należy jeszcze doinstalować moduł dla Pythona.
$ pip install osquery
GitHub osquery-python: https://github.com/osquery/osquery-python
UWAGA: Część pobieranych informacji może wymagać uprawnień administratora więc wywołania zapytań mogą wymagać użycia sudo
.
$ sudo osqueryi 'ZAPYTANIE SQL'
$ sudo python skrypt.py
Przykładem informacji wymagających sudo
są dane o kościach pamięci RAM.
$ sudo osqueryi 'SELECT * FROM memory_devices'
Te same dane z użyciem Pythona (tyle, że zamiast tabeli mamy listę ze słownikami)
import osquery
import pprint
instance = osquery.SpawnInstance()
instance.open()
data = instance.client.query('SELECT * FROM memory_devices')
pprint.pprint(data.response)
Moduł Pythona dostarcza dane w postaci listy ze słownikami więc łatwo można wyświetlać tylko wybrane informacje:
import osquery
instance = osquery.SpawnInstance()
instance.open()
data = instance.client.query('SELECT * FROM memory_devices')
for item in data.response:
size = item['size']
if size != '0': # pominięcie pustych banków
print(item['form_factor'], item['memory_type'], size, item['max_speed'])
Ponieważ mam dwie kości (i dwa puste banki) więc otrzymuję wynik podobny do
SODIMM DDR3 4096 1334
SODIMM DDR3 4096 1334
To samo można także uzyskać z użyciem WHERE
w SQL zamiast if
w Pythonie.
import osquery
instance = osquery.SpawnInstance()
instance.open()
data = instance.client.query('SELECT * FROM memory_devices WHERE size != 0')
for item in data.response:
print(item['form_factor'], item['memory_type'], size, item['max_speed'])
Zapytania SQL pozwalają na używanie wiele innych elementów znanych z tradycyjnych zapytań do baz danych.
Nazwy tabel
osqueryi
posiada krótką komendę do listowania dostępnych tabel. Nie jest ona jednak dostępna z poziomu Pythona.
$ osqueryi '.tables'
To samo można otrzymać z użyciem zapytania, które można już zastosować w Pythonie.
$ osqueryi "SELECT name FROM osquery_registry WHERE registry = 'table'"
I to samo w Pythonie
import osquery
import pprint
instance = osquery.SpawnInstance()
instance.open()
data = instance.client.query("SELECT name FROM osquery_registry WHERE registry = 'table'")
pprint.pprint(data.response)
Używając count()
można nawet policzyć ilość dostępnych tabel.
$ osqueryi "SELECT count(name) FROM osquery_registry WHERE registry = 'table'"
I to samo w Pythonie
import osquery
import pprint
instance = osquery.SpawnInstance()
instance.open()
data = instance.client.query("SELECT count(name) FROM osquery_registry WHERE registry = 'table'")
pprint.pprint(data.response)
.tables
pozwala wyświetlić listę tabel zaczynających się na podany ciąg znaków np. me
$ osqueryi '.tables me'
=> memory_array_mapped_addresses
=> memory_arrays
=> memory_device_mapped_addresses
=> memory_devices
=> memory_error_info
=> memory_info
=> memory_map
To samo można uzyskać z pełnym zapytaniem i użyciem %
na końcu me%
$ osqueryi "SELECT name FROM osquery_registry WHERE registry = 'table' AND name LIKE 'me%'"
I to samo w Pythonie
import osquery
import pprint
instance = osquery.SpawnInstance()
instance.open()
data = instance.client.query("SELECT name FROM osquery_registry WHERE registry = 'table' AND name LIKE 'me%'")
pprint.pprint(data.response)
.tables
nie potrafi jedna wyświetlać listy tabel, które zawierają podany ciąg gdzieś wewnątrz nazwy - np. kończące się na info
A zapytanie SQL to potrafi z użyciem %
na początku %info
$ osqueryi "SELECT name FROM osquery_registry WHERE registry = 'table' AND name LIKE '%info'"
Podobnie Python
import osquery
import pprint
instance = osquery.SpawnInstance()
instance.open()
data = instance.client.query("SELECT name FROM osquery_registry WHERE registry = 'table' AND name LIKE '%info'")
pprint.pprint(data.response)
Nazwy kolumn
osqueryi
ma specjalną komendę do podania listy kolumn jakie zwróci zapytanie.
$ osqueryi '.types SELECT * FROM time;'
+----------------+---------+
| name | type |
+----------------+---------+
| weekday | TEXT |
| year | INTEGER |
| month | INTEGER |
| day | INTEGER |
| hour | INTEGER |
| minutes | INTEGER |
| seconds | INTEGER |
| timezone | TEXT |
| local_time | INTEGER |
| local_timezone | TEXT |
| unix_time | INTEGER |
| timestamp | TEXT |
| datetime | TEXT |
| iso_8601 | TEXT |
+----------------+---------+
Python ma na to osobną metodę: .getQueryColumns("ZAPYTANIE SQL")
import osquery
import pprint
instance = osquery.SpawnInstance()
instance.open()
data = instance.client.getQueryColumns("SELECT * FROM time")
pprint.pprint(data.response)
[{'weekday': 'TEXT'},
{'year': 'INTEGER'},
{'month': 'INTEGER'},
{'day': 'INTEGER'},
{'hour': 'INTEGER'},
{'minutes': 'INTEGER'},
{'seconds': 'INTEGER'},
{'timezone': 'TEXT'},
{'local_time': 'INTEGER'},
{'local_timezone': 'TEXT'},
{'unix_time': 'INTEGER'},
{'timestamp': 'TEXT'},
{'datetime': 'TEXT'},
{'iso_8601': 'TEXT'}]
Za pomocą zapytania z PRAGMA
można też dowiedzieć się coś więcej na temat kolumn z istniejącej tabeli.
$ osqueryi 'PRAGMA table_info(time);'
+-----+----------------+---------+---------+------------+----+
| cid | name | type | notnull | dflt_value | pk |
+-----+----------------+---------+---------+------------+----+
| 0 | weekday | TEXT | 0 | | 0 |
| 1 | year | INTEGER | 0 | | 0 |
| 2 | month | INTEGER | 0 | | 0 |
| 3 | day | INTEGER | 0 | | 0 |
| 4 | hour | INTEGER | 0 | | 0 |
| 5 | minutes | INTEGER | 0 | | 0 |
| 6 | seconds | INTEGER | 0 | | 0 |
| 7 | timezone | TEXT | 0 | | 0 |
| 8 | local_time | INTEGER | 0 | | 0 |
| 9 | local_timezone | TEXT | 0 | | 0 |
| 10 | unix_time | INTEGER | 0 | | 0 |
| 11 | timestamp | TEXT | 0 | | 0 |
| 12 | datetime | TEXT | 0 | | 0 |
| 13 | iso_8601 | TEXT | 0 | | 0 |
+-----+----------------+---------+---------+------------+----+
I podobnie w Pythonie
import osquery
import pprint
instance = osquery.SpawnInstance()
instance.open()
data = instance.client.query("PRAGMA table_info(time)")
pprint.pprint(data.response)
[{'cid': '0',
'dflt_value': '',
'name': 'weekday',
'notnull': '0',
'pk': '0',
'type': 'TEXT'},
{'cid': '1',
'dflt_value': '',
'name': 'year',
'notnull': '0',
'pk': '0',
'type': 'INTEGER'},
{'cid': '2',
'dflt_value': '',
'name': 'month',
'notnull': '0',
'pk': '0',
'type': 'INTEGER'},
{'cid': '3',
'dflt_value': '',
'name': 'day',
'notnull': '0',
'pk': '0',
'type': 'INTEGER'},
{'cid': '4',
'dflt_value': '',
'name': 'hour',
'notnull': '0',
'pk': '0',
'type': 'INTEGER'},
{'cid': '5',
'dflt_value': '',
'name': 'minutes',
'notnull': '0',
'pk': '0',
'type': 'INTEGER'},
{'cid': '6',
'dflt_value': '',
'name': 'seconds',
'notnull': '0',
'pk': '0',
'type': 'INTEGER'},
{'cid': '7',
'dflt_value': '',
'name': 'timezone',
'notnull': '0',
'pk': '0',
'type': 'TEXT'},
{'cid': '8',
'dflt_value': '',
'name': 'local_time',
'notnull': '0',
'pk': '0',
'type': 'INTEGER'},
{'cid': '9',
'dflt_value': '',
'name': 'local_timezone',
'notnull': '0',
'pk': '0',
'type': 'TEXT'},
{'cid': '10',
'dflt_value': '',
'name': 'unix_time',
'notnull': '0',
'pk': '0',
'type': 'INTEGER'},
{'cid': '11',
'dflt_value': '',
'name': 'timestamp',
'notnull': '0',
'pk': '0',
'type': 'TEXT'},
{'cid': '12',
'dflt_value': '',
'name': 'datetime',
'notnull': '0',
'pk': '0',
'type': 'TEXT'},
{'cid': '13',
'dflt_value': '',
'name': 'iso_8601',
'notnull': '0',
'pk': '0',
'type': 'TEXT'}]
Buy a Coffee