CanaryUsb
Tags: c, security, usb, linux
Published: 2023-09-09 16:48:52

## Introducing Canary Tokens

Some time ago I found [Thinkst Canary](https://canary.tools) and I fall in love with it. 

It's already well know but, the idea behind **Canary Tokens** is to have a notification if you have security breach. The notification is via email, and you have different types of tokens, these will trigger a notification under certain situation, for example a **URL token** will be triggered when a URL is visited.

One of my favorites is the QR code token, it's meant for physical things; e.g. You can stick the QR code inside of your prototype case, and if someone scans it, at least you know that someone is snooping around.

Just want to mention, that when you create a new Canary Token, apart of email, where you want to receive the notification, you need to provide a *reminder note* to describe the token.

![QR code token creation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/488wih5y7dq8gjmi33eg.png)    

You can check the different types of Canary tokens that [Thinkst Canary](https://canarytokens.org/generate#) have, and they explain all the things better than me.

## CanaryUsb

So now that we now about CanaryTokens; Lets see what CanaryUsb is.

### What is it?

[CanaryUsb](https://github.com/carvilsi/canaryusb) monitors the USB activity on a Linux system, and will call a CanaryToken when a not known USB is connected.

Here we are thinking about **removable media threats** like **BadUSB** or physical attacks to **extract data** e.g. on remote servers or on unattended laptops.

The code is in **c** and right now, and unless someone borrow me a Mac, **canaryusb** only works on Linux (is not even an idea to support Windows).

### The DNS Canary token

CanaryUsb uses a CanaryToken of type **DNS token** that *alerts when a hostname is requested*. As it's described at the [DNS token Documentation](https://docs.canarytokens.org/guide/dns-token.html#encoding-additional-information-in-your-token) one of the features is that the token can carry a small extra data.
This is used by canaryusb to send the *fingerprint* of the connected usb; so the notification via mail will include this info.

### A USB fingerprint

Since the total number of bytes that could be included among the DNS token is **~125 bytes**, we need to restrict the amount of data that we take from from USB attributes.
We choose the next format for the usb fingerprint:

`<vendor>:<product>-<product_name>-<serial>`

e.g. for a USB with the next attributes:

**vendor**: 18d1
**product**: 4ee8
**product name**: OnePlus Nord
**serial**: d3115c34

The USB fingerprint will be: **18d1:4ee8-OnePlus_Nord-d3115c34**

The struct that holds the *usb fingerprint* looks like:

```c
typedef struct
{
        char *vendor;
        char *product;
        char *product_name;
        char *serial;
        char *syspath;
} UsbAttrs;
```

Note that the *syspath* variable is there just for debugging pourposes and it's not used to define the *usb fingerptint*.
We initialize this struct as:

```c
UsbAttrs usbattr = {"0000", "0000", "no", "no", "no-path"};
```

So we fill the gaps in case of a missing attribute.
It's not guaranteed that the 4 attributes which with we want to build the *usb fingerprint* will be present.

### Monitoring the USB devices

The USB attributes, to build the *usb fingerprint*, are retrieved with **libsystemd**, specifically usage of [sd-device](https://man.archlinux.org/man/sd-device.3.en) and monitoring the USB devices activity.

The monitor code is quite brief; failure handling and finishing actions are omitted for brevity:

```c
void monitor_usb()
{
        sd_device_monitor *sddm = NULL;
        sd_device_monitor_new(&sddm);

        sd_device_monitor_filter_add_match_subsystem_devtype(sddm, SUBSYSTEM, DEVICE_TYPE);

        sd_device_monitor_start(sddm, usb_monitor_handler, NULL);

        sd_event *event = sd_device_monitor_get_event(sddm);
        sd_event_loop(event);

        /*
         * Deal with errors and exit actions
         * like stooping monitor and un-references
         */
}
```

Once the event is triggered the handler function, **usb_monitor_handler**, takes care of the rest; retrieve the USB attributes to build the the *usb fingerprint*, build the *DNS Canary Token* and perform the DNS call.

### Building the DNS Canary Token

We need to convert the *usb fingerprint* into **base32** removing the padding '=' characters adding a dot after every 63-bytes and prepare the hostname call for DNS token, from the [Documentation](https://docs.canarytokens.org/guide/dns-token.html#encoding-additional-information-in-your-token) is something like:

`<base32-string>.<base32-string>.G<2-random-digits>.<dns-token>`

Also we'll strip the *usb fingerprint* if the length exceeds the maximum data to encode; 63 bytes for each *base32-string* block.

### Calling the Canary

Once we have the DNS Canary Token, we just need to call it, using *getaddrinfo* (netdb.h):

```c
int call_the_canary(const char *canary_dns_token)
{
        int canaryrsp;
        struct addrinfo hints, *res;
        memset(&hints, 0, sizeof(hints));
        canaryrsp = getaddrinfo(canary_dns_token, CANARY_PORT, &hints, &res);
        return canaryrsp;
}
```

The parameter *canary_dns_token* it's the value that we get on previous step, and for *CANARY_PORT* we use 80.
We do not care about the response, variable *res* of *getaddrinfo* but the return integer of it, a nonzero means an error.

Here you can see the notification that I received from the above example of *usb fingerprint*:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bwhgqbvtcxf9qz61zt8x.png) 

### Some other things

In order to avoid notifications from your own devices, *canaryusb* supports a *usb trusted list*, so only the devices that are not at this list will send a notification.
To make the life easer *canaryusb* could read values for the *CanaryToken* and the *usb fingerprint trusted list* from a config file. The format of the config file is **toml** and I found very useful [tomlc99](https://github.com/cktan/tomlc99).