
A história da
Bloomberg de que alguns implantes foram supostamente instalados nas placas-mãe [os
chineses usavam um microchip para controlar os computadores americanos ] não passou despercebida. Depois disso, muitas pessoas compartilharam idéias sobre a possibilidade de criar esses implantes (tamanho estimado, capacidade ou método de detecção).
Alguns dias depois, a revista
Bloomberg publicou um artigo com evidências adicionais. Aqui está o que especificamente despertou nosso interesse:
O servidor jurídico enviou mensagens de uma maneira, o implante da outra, mas parecia que todo o tráfego vinha de um servidor confiável.
Existem maneiras de interagir com a placa de rede diretamente da placa-mãe. Várias pessoas indicaram que você pode jogar com o BMC (Baseboard Management Controller - um componente que permite acesso ao servidor além do canal principal), o que permitirá ao implante controlar o BMC e obter acesso à placa de rede. Mas como isso funciona na prática? Vamos ver se podemos reproduzir isso.
Posição inicial
Vejamos as possíveis interfaces entre a NIC (placa de
rede ) e o BMC. Um dos principais protocolos para trabalhar em um canal dedicado é a interface inteligente de gerenciamento da plataforma IPMI.
IPMI
A Wikipedia diz que o IPMI é “uma interface inteligente de gerenciamento de plataforma projetada para monitorar e gerenciar autonomamente os recursos criados diretamente no hardware e firmware das plataformas de servidor. Os principais recursos do IPMI são monitoramento, restauração de funções de gerenciamento, registro e inventário, disponíveis independentemente do processador, BIOS e sistema operacional. Os recursos de gerenciamento de plataforma podem estar disponíveis mesmo quando o sistema está desligado. ” Muito parecido com o que precisamos.
O fluxograma a seguir mostra um possível caminho de implementação do projeto:

O IPMI realmente define dois canais de banda lateral para a NIC: SMBus e NC-SI. O NC-SI é uma substituição SMBus de ponta que suporta velocidades aprimoradas de transferência de dados e outros novos recursos. O problema é que ela precisa de mais sinais (cerca de 10) e é muito mais difícil intervir em seu trabalho quando estamos trabalhando com um implante. Então, por enquanto, vamos nos concentrar no SMBus.
SMBus
O SMBus (System Management Bus) é um protocolo de comunicação serial para dispositivos de energia. Barramento de dois fios simples de um lado, fornecendo comunicações simples. Geralmente usado em computadores para conectar a placa-mãe a uma fonte de energia e enviar / ativar instruções. Baseado no barramento
I 2 C , comumente usado em microcontroladores. A interface precisa apenas de dois sinais (frequência do relógio e dados), e o terceiro sinal é uma interrupção. Perfeito para o protocolo de jogos de implantes.
Primeiro contato
Você precisa ser inteligente, sem ter acesso à placa-mãe com o BMC. Estudando as características técnicas das placas-mãe de servidor, descobrimos que algumas delas usam o chip
Intel 82574L . De acordo com a
documentação , ele fornece a "interface avançada de passagem SMBus" - exatamente o que você precisa. E o melhor de tudo, ele vem no formato de cartão PCI-E.
Acesso SMBus
Fomos à loja e agora temos placas
Intel EXPI9301CTBLK com o chip 82574L. O que agora
A documentação pode rastrear SMB_DAT e SMB_ALRT_N. Felizmente, todos estavam disponíveis nos blocos de contato. Tudo parece ser bem fácil.
NIC PCB. Superior esquerdo - EEPROM, superior direito - conector para SMBus [ALRT | CLK | DAT]. Observe que o R39 e o R40 estão fechados, o que proíbe o acesso ao SMBus para o conector PCIe.Conectamos a
sonda I 2 C e examinamos o SMBus, mas não contamos nada de útil. A documentação diz que o SMBus é ativado apenas quando um registro de bits específico é definido. Este valor é carregado a partir da EEPROM. É hora de ir mais fundo.
Ativar acesso ao SMBus
A documentação nos ajuda novamente. O acesso ao SMBus é determinado pelo valor do registro carregado na NIC EEPROM. Felizmente, a EEPROM pode ser lida com flashrom. Ao despejar o conteúdo da EEPROM, podemos analisar e alterar os valores:
> ./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.
A julgar pelo mapa NVM (capítulo 6.1 da documentação), fica claro que precisamos alterar dois valores:
- Palavra de controle de inicialização 2 [MNGM] (folha de dados capítulo 6.1.1.6)
- Compatibilidade [ASF SMBus Connected] (capítulo 6.1.2.1.1 da folha de dados)
- Compatibilidade [SMBus Connected] (capítulo 6.1.2.1.1 da folha de dados)
É necessário considerar apenas que na EEPROM os dados são armazenados no formato little endian.
Depois disso, ainda precisamos lidar com o valor da soma de verificação. O capítulo 6.1.2.11 afirma que a soma de todas as palavras no intervalo [0x00-0x40] deve ser 0xBABA. Um pouco de Python nos ajudará a calcular a soma de verificação correta:
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
E, finalmente, todas as nossas alterações na 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.....
Depois de fazer alterações e piscar a EEPROM, conectamos uma sonda I
2 C e:
i2c1> scan
Device found at address 0x49
i2c1>
O endereço I
2 C é codificado em sete bits, o endereço que precisamos é obtido como 0x49 << 1 = 0x92.
Agora, temos um diagrama de trabalho para o nosso implante. Podemos enviar comandos para a NIC:

Recebendo informações
Como você deve ter adivinhado, continuamos lendo a documentação e enviando comandos especialmente preparados para a NIC para verificar se tudo estava funcionando conforme o esperado.
A documentação descreve tudo o que você precisa saber sobre o formato da transação no capítulo 8.4.4. A única diferença é que não precisamos calcular o PEC (soma de verificação para SMBus, calculada para cada pacote). Por exemplo, podemos enviar o comando CMD para o endereço
SLAVE usando a seguinte sequência:
[START] [@SLAVE] [CMD] ( [START] [@SLAVE] [READ_DATA] ) [STOP]
[START] e [STOP] são as condições de START e STOP definidas por I
2 C.
Por exemplo, o comando para ler o endereço MAC (descrito no capítulo 8.8.2.3) será 0xD4. Enviamos o comando para SMBus no modo I
2 C:
[START] [0x92] [0xD4] [START] [0x92] [read 8 bytes] [STOP]
Quando transferido para as equipes Hydrabus, será:
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
E sim, obtemos o nosso endereço MAC!
Fazendo um implante
Agora, sabendo como você pode se comunicar com a NIC, vamos ver como você pode usar esse canal para roubar o tráfego da rede e enviar dados pela rede. O capítulo 8 da documentação descreve tudo o que você precisa para fazer isso.
Enviando pacotes
Descrito nos capítulos 8.6 e 8.8.1. Podemos simplesmente criar um quadro Ethernet usando comandos. Aqui está um exemplo de script para
Hydrabus ou
Bus Pirate enviar um pacote:
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+'\x00\x00')
ser.write("\x92\xc4"+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('\x0F\n')
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('\x0F\n')
Depois de executar o script, você pode ver o pacote vindo da máquina com o implante e, mais interessante, o próprio servidor não vê esse pacote:
Tcpdump da máquina do atacante à esquerda, servidor à direitaPacotes de leitura
Filtragem
Para descobrir quais quadros devem ir para o SMBus, a NIC usa filtros de controle. Eles mapeiam o tráfego da rede e o redirecionam para o PCIe, ou para o SMBus, ou para lá e para lá. Do nosso ponto de vista, isso nos dá uma grande flexibilidade:
- Você pode rastrear o tráfego definindo um filtro que o varrerá e o redirecionará para PCIe e SMBus.
- Você pode fazer com que o tráfego desapareça direcionando-o apenas para SMBus.
- Você pode criar um canal oculto que não ficará visível para o servidor com o implante.
O mais interessante é que o filtro pode ser configurado para rastrear vários elementos do quadro:
- Porta UDP / TCP
- VLAN
- IPv4 - IPv6
- Endereço MAC
- ...
(Para uma lista completa, consulte o capítulo 8.4.2.1)
Sete filtros MDEF independentes [0: 6] estão disponíveis e cada um deles pode ser configurado para redirecionar o tráfego correspondente ao PCIe sobre SMBus usando o registro MANC2H (para obter mais detalhes, consulte o capítulo 8.4.3).
Implementação
Foi muito difícil configurar tudo corretamente. Tentamos várias combinações diferentes para fazer o filtro funcionar. Felizmente, a
nota sobre
o aplicativo da Intel nos deu mais detalhes sobre como executar filtros da maneira que precisamos.
Usando nosso probe I
2 C, podemos configurar tudo isso com quatro comandos:
//
[ 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 ]
Conforme descrito no capítulo 8.8.1.3, é necessário definir vários bits para permitir a recepção de dados e enviar quadros de volta ao nosso implante. Escolhemos o alerta SMBus porque outros modelos permitem que a placa de rede faça solicitações assíncronas ao SMBus (para detalhes, consulte o capítulo 8.4.5).
Quadros de leitura
Como usamos o método de alerta SMBus, esperávamos que o sinal SMB_ALRT_N se desligasse antes de enviar o comando Receive TCO Packet. Se esperássemos muito tempo, o pacote seria rejeitado pela NIC.
Para ilustrar apenas o diagrama, enviaremos quadros periodicamente e enviaremos comandos de leitura - apenas para confirmar que esse princípio funciona. O esquema é assim:
- Um servidor com um implante possui filtros que monitoram o tráfego com o UDP / 623 (capítulo 3.6.1.2).
- O implante é simulado usando Hydrabus.
- Outro servidor envia pacotes que se enquadram no filtro usando o script Scapy:
from scapy.all import *
p=Ether()/IP(dst="10.31.32.81")/UDP(dport=0x26f)/"MALICIOUS PAYLOAD"
while(1):sendp(p)
Acontece algo interessante:

À esquerda, o SMBus lê o quadro; os dados do quadro são mostrados abaixo. À direita, o tcpdump, executando em um servidor com um implante, não mostra os quadros recebidos.
Frame Relay
Alterando o registro do MANC2H, é possível garantir que o tráfego enviado ao SMBus e ao PCIe seja exibido corretamente no servidor. Por exemplo, vamos criar um filtro de interceptação que responda ao tráfego UDP / 161 (SNMP) e o envie para SMBus e 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 ]
Ao ativar os filtros, podemos enviar uma solicitação SNMP ao servidor com o implante e ver o pacote que interceptou o implante. Ao mesmo tempo, o servidor responde à solicitação - o que significa que o pacote foi redirecionado corretamente para SMBus e PCIe:
Acima está uma solicitação SNMP interceptada do implante. Abaixo - a solicitação SNMP chegou ao servidor.Conclusões
Descrevemos um método possível para a introdução de um microcontrolador pequeno e barato como implante no nível da NIC. Esse implante precisa de pelo menos quatro contatos (Vcc, GND, CLK, DAT) e pode controlar a placa do servidor. Entre suas características:
- Escutando o tráfego de rede recebido no servidor.
- Recebendo comandos da rede sem o conhecimento do servidor.
- Transmissão de dados pela rede sem o conhecimento do servidor.
Em nosso exemplo, por simplicidade, o Hydrabus foi usado como interface para I
2 C / SMBus, mas isso pode ser feito com a mesma facilidade em um pequeno microcontrolador, por exemplo, ATtiny85 (é do tamanho de uma EEPROM para NIC).
No entanto, na vida real, o acesso a esse implante seria apenas para o SMBus. Dependendo do esquema da placa-mãe, este dispositivo pode ser o único disponível e, portanto, a interação com o sistema operacional do servidor será impossível. No caso em que é necessário controle total sobre o sistema operacional, é melhor alterar o código BMC, pois ele já tem acesso a todos os barramentos interessantes e não deixa rastros visíveis na placa-mãe.
Outra desvantagem desse implante é que ele pode transmitir dados em velocidades da ordem de 100 Kb / s, o que não é suficiente para um estudo completo do tráfego. Além disso, o implante é capaz de interceptar apenas o tráfego proveniente da rede. Como resultado, essa solução parece ineficaz em comparação com os esforços necessários para sua implementação no equipamento de destino.