---
# System prepended metadata

title: 'Отчёт о киберугрозе АСД-С:2023-00007 (SmallWorm)'

---

# Отчёт о киберугрозе АСД-С:2023-00007 (SmallWorm)

## Общее описание
SmallWorm - сетевой червь, заражающий сетевые маршрутизаторы посредством уязвимости АСД-А:2023-00002

Когда червь попадает на устройство, он начинает атаку по следующему алгоритму:

1. Взламывает устройства в сети (не перемещаясь на них) -- считывает данные взломанного устройства, затем уничтожает его. Данные, считанные со взломанного устройства добавляются к данным текущего.
2. Шифрует данные текущего устройства [(xor-шифрованием)](#xor-шифрование), оставляя на машине вместе с зашифрованными данными 4-байтный хеш ключа шифрования
3. Перемещается на новое устройство, запоминая на нём ключ, которым зашифрованы данные, и подсеть, из которой пришёл [(адрес и маска подсети)](#подсети)

![](https://i.imgur.com/s1ifQhP.png)

## Форматы данных

![](https://i.imgur.com/yoeZZ9T.png)


### Формат-A

Когда червь переезжает на новое устройство, вместе с изначальными данными машины он хранит ключ шифрования данных предыдущего устройства; подсеть, из которой пришёл (адрес и маску подсети); и данные со взломанных машин, вместе с их IP адресами в формате-А.

![](https://i.imgur.com/ZRoXlWG.png)

### Формат-B

Перед переездом на новую машину, червь шифрует все данные на ней (то есть, после дешифровки мы получаем данные в формате A или C). Шифрование происходит 4-битным ключом, хеш которого сохраняется перед зашифрованными данными.

Хеширование происходит следующем алгоритмом, представленном в псевдокоде (все числа в бинарном формате находятся в little-endian):

```Rust
uint32 hash(uint32 key) {
    int32 n = 12;
    do
        key = ((key >> 8) ^ key) * 0x6B + n;
    while (--n != 0);
    return key;
}
```

### Формат-C

Первое заражённое устройство не имеет предка, то есть, червю не требуется хранить ключ и маску подсети, из которой он пришёл. Помимо этого, с первой машины не происходит взлома других устройств, червь просто упаковывает данные машины в формат-C (то есть, добавляет перед данными 4 байта нулей), шифрует данные (в формат-B), и переезжает на новую машину.

Вероятно, 4-байтовая заглушка из нулей нужна чтобы после дешифровки данных нельзя было перепутать формат-А и C, т.к. формат-A начинается с 4-байтного ключа, который не может быть нулём.

![](https://i.imgur.com/RT5rPoE.png)

## Справочные данные

### Подсети

В протоколе IP адрес устройства задаётся 32-битным числом, обычно записываемого по байтам, например `192.168.1.2` это число `3232235778`.

Адреса объединяются в подсети, задаваемые базовым адресом и маской подсети - количеством значащих бит в числе, например все адреса от `192.168.1.0` до `192.168.1.255` задаются маской `192.168.1.0/24`, это значит что первые `24` бита (три байта) одинаковые для всех машин подсети, а отличается последний байт. Таким образом, подсети `192.168.1.0/24` и `192.168.1.57/24` эквивалентны, но обычно принято обращать незначащие биты в `0`.

### XOR-шифрование

Один из самых простых способов зашифровать данные, основанный на том, что операция исключающего ИЛИ (XOR) является обратимой, то есть если `x = data ^ key`, то `data = x ^ key`.

Простая реализация xor шифрования (и одновременно дешифрования) на C++ может выглядеть так

```C++
std::vector<char> xor_encrypt(const std::vector<char>& data, const std::vector<char>& key) {
    std::vector<char> result(data.size());
    for (int i = 0; i < data.size(); ++i)
        result[i] = data[i] ^ key[i % key.size()];
    return result;
}
```
