osquery extension in Ruby - create new table

262 Views Asked by At

I'm trying to implement an extension for osquery in Ruby.

I found some libs and examples doing the same in Java, Node and Python, but nothing helpful implemented in Ruby language.

According to this documention, it's possible generating the code using Thrift: https://osquery.readthedocs.io/en/stable/development/osquery-sdk/#thrift-api

The steps I did, so far:

  • Generated the code using thrift -r --gen rb osquery.thrift
  • Created a class and some code to connect to the server and register the extension

This is the code of the class

# include thrift-generated code
$:.push('./gen-rb')

require 'thrift'
require 'extension_manager'

socket = Thrift::UNIXSocket.new(<path_to_socket>)
transport = Thrift::FramedTransport.new(socket)
protocol = Thrift::BinaryProtocol.new(transport)
client = ExtensionManager::Client.new(protocol)

transport.open()

info = InternalExtensionInfo.new
info.name = "zzz"
info.version = "1.0"

extension = ExtensionManager::RegisterExtension_args.new
extension.info = info

client.registerExtension(extension, {'table' => {'zzz' => [{'name' => 'TEXT'}]}})

To get the <path_to_socket> you can use:

> osqueryi --nodisable_extensions
osquery> select value from osquery_flags where name = 'extensions_socket';
+-----------------------------------+
| value                             |
+-----------------------------------+
| /Users/USERNAME/.osquery/shell.em |
+-----------------------------------+

When I try to get this table using osqueryi, I don't see the table when I run select * from osquery_registry;.

Have anybody by any chance implemented an osquery extension already? I'm stuck and I don't know how to proceed from here.

2

There are 2 best solutions below

0
On

I find myself playing around with thrift via ruby. And it seems to work if I used a BufferedTransport:

socket = Thrift::UNIXSocket.new('/tmp/osq.sock')
transport = Thrift::BufferedTransport.new(socket)
protocol = Thrift::BinaryProtocol.new(transport)
client = ExtensionManager::Client.new(protocol)

transport.open()
client.ping()
client.query("select 1")
2
On

I don't think I've seen anyone make a ruby extension, but once you have the thrift side, it should be pretty simple.

As a tool, osquery supports a lot of options. So there's no single way to do this. Generally speaking, extensions run as their own process and the communicate over that thrift socket.

Usually, they're very simple and osquery invokes extensions directly with appropriate command line arguments. This is alluded to in the doc you linked with the example accepting --interval, --socket, and --timeout. If you do this, you'll want to look at osquery's --extensions_autoload and --extensions_require option. (I would recommend this route)

Less common, is to start osquery with a specified socket path using --extensions_socket. And then your extension can use that. This way is more common is the extension cannot be a simple binary, and instead is a large complex system.