硬件 – 虫虫之家 http://ijz.me 略懂技术 Sat, 01 Mar 2025 15:31:05 +0000 zh-Hans hourly 1 https://wordpress.org/?v=6.7.2 处理器Meltdown(熔断)和Spectre(幽灵)漏洞分析 http://ijz.me/?p=990 http://ijz.me/?p=990#respond Mon, 08 Jan 2018 00:40:00 +0000 http://ijz.me/?p=990 Meltdown

Meltdown攻击利用现代CPU中乱序执行 (out-of-order execution)的特性,乱序执行(out-of-order execution)是指CPU允许将多条指令不按程序规定的顺序分开发送给各CPU单元处理的技术,我们通过参考资料[2]中的示例代码来说明这一攻击的原理。

一个简化的Meltdown攻击指令序列:

; rcx = kernel address
; rbx = probe array
retry:mov al, byte [rcx]
shl rax, 0xc
jz retry
mov rbx, qword [rbx + rax]

1、rcx寄存器指向用户代码不可访问的内核地址
2、攻击者在指令4中访问内核内存地址,由于访问了内核地址,这一条指令将会触发异常,但由于指令4在CPU内部执行时并不受权限检测,所以读取到的内核数据被存放在了CPU缓存中
3、在等待CPU完成执行指令4的同时,后两条指令因为乱序执行机制实际上已经在CPU的内部执行单元中被执行
4、在CPU内部执行单元执行过的指令5将会把获取到的内核数据(1个字节)乘以4096,并在指令6中将其作为offset来对数组probe array进行访问
5、由于一个内存页的大小是4KB,不同的数据将会导致不同的内存页被访问并存放到CPU缓存中,所以,另一个攻击者进程(任务)就可以通过缓存侧信道攻击(已经被缓存的内存读取时间会更快),来了解哪个内存页被访问过了,从而推断出被访问的内核内存数据。
Spectre
Spectre攻击利用了现代CPU中推测执行(Speculative Execution)的机制来对系统进行攻击。推测执行(Speculative Execution)同样是一种CPU优化特性。在执行类似if () {}这类分支指令,并且在分支指令执行结束之前,CPU会预测哪一个分支会被运行,提取相应的指令代码并执行,以提高CPU指令执行的性能。当预测执行发现预测错误时,预测执行的结果将会被丢弃,CPU的状态会被重置。然而,与乱序执行类似,预测执行时CPU获取到的内存数据会被保留在CPU缓存中(包括越权获取的数据,虽然这些数据用户代码无权访问),我们通过参考资料[3]中的示例代码来说明这一攻击的原理。

1、首先申请一块内存,并写入如下数据
char * secret="www.ijz.me";
2、获取secret和array1的相对偏移量malicious_x
int main(int argc, const char **argv) {
size_t malicious_x=(size_t)(secret-(char*)array1);
/* default for malicious_x */
int i, score[2], len=10;
uint8_t value[2]

3、循环调用readMemoryByte函数,分别将malicious递增值作为其中一个参数

while (--len >= 0) {
printf("Reading at malicious_x = %p... ", (void*)malicious_x);
readMemoryByte(malicious_x++, value, score);
printf("%s: ", (score[0] >= 2*score[1] ? "Success" : "Unclear"));
printf("0x%02X=’%c’ score=%d ", value[0],
(value[0] > 31 && value[0] < 127 ? value[0] : ’?’), score[0]); if (score[1] > 0)
printf("(second best: 0x%02X score=%d)", value[1], score[1]);
printf("\n");
}
return (0);

4、调用漏洞函数victim_function,利用CPU的预测执行机制将越权读取的数据cache到CPU缓存中
void victim_function(size_t x) {
if (x < array1_size) {
temp &= array2[array1[x] * 512];
}

5、由于array2[array1[x]*512]的值被缓存,所以代码中通过rdtscp函数计算指令执行时间来判断哪个内存页被访问过(缓存的字节被当做另一系列被预测执行指令访问的数组下标,被访问的数组同样是在CPU中被预测读取),从而推断出被访问的secret内存数据
2018/* Time reads. Order is lightly mixed up to prevent stride prediction */
for (i = 0; i < 256; i++) {
mix_i = ((i * 167) + 13) & 255;
addr = &array2[mix_i * 512];
time1 = __rdtscp(&junk);
/* READ TIMER */
junk = *addr;
/* MEMORY ACCESS TO TIME */
time2 = __rdtscp(&junk) - time1;
/* READ TIMER & COMPUTE ELAPSED TIME */
if (time2 <= CACHE_HIT_THRESHOLD && mix_i != array1[tries % array1_size])
results[mix_i]++;
/* cache hit - add +1 to score for this value */
}

6、POC验证执行结果,读取进程内的机密数据

限制条件

本质上讲Meltdown和Spectra都是基于侧信道的攻击,主要用于信息泄露,并不能对目标内存地址进行任意修改,以下分别介绍两种攻击的限制条件。

Meltdown

Meltdown攻击目前仅限于在Intel系列的现代CPU中访问受限内存,包括内核的地址空间
由于Meltdown攻击所使用的特殊代码无法在浏览器JIT中生成,所以该攻击几乎只能在本地进行
Spectre

Spectre攻击需要目标程序具有特殊结构(比如浏览器JIT即时编译出的代码具有Spectra攻击所需要的特殊结构),所以受到目标软件的限制
Spectre攻击虽然适用于远程攻击,但是浏览器类JIT代码生成的Spectra攻击只能获取当前进程的内存数据,无法获取内核数据
Spectre攻击在Intel系列CPU上也可以读取目标内核内存数据


Meltdown和Spectre影响/防御对比


我们整理下两类攻击的影响范围和防御方式,如下:
Meltdown Spectre
读取系统内核层数据 是 是(测试Intel CPU)
通过KAISER/KTPI技术修复 是 否
读取任意用户层数据 是 是
远程攻击 极难 容易
主要影响范围 内核所有数据 浏览器进程数据
受影响CPU厂商 Intel Intel AMD ARM等

参考资料
[1] https://meltdownattack.com/meltdown.pdf

[2] https://spectreattack.com/spectre.pdf

[3] https://github.com/Pl4gue/spectre-attack-demo

]]>
http://ijz.me/?feed=rss2&p=990 0
如何判断 Linux 是否运行在虚拟机上/zz/ http://ijz.me/?p=685 http://ijz.me/?p=685#respond Fri, 14 Nov 2014 07:56:25 +0000 http://ijz.me/?p=685  

在 WebHostingTalk 论坛上有些国外奸商会把虚拟机当作独立服务器卖,去年7月份的时候就有一位中国同胞上当受骗, 并在 WHT 上发帖声讨,证据确凿,甚至连服务商自己也承认,回帖达355篇。这家独立服务器/VPS 提供商 HostATree.com 居然大胆的把 OpenVZ VPS 这种一看就知道是虚拟机的虚拟机当作独立服务器卖,晕,至少也要弄个 VMWare/KVM/Xen HVM 吧(更难发现是虚拟机),用 OpenVZ 这种容器也太欺负人了:)昨天恰好收到网友一封邮件问到了如何判断自己买的是独立服务器还是虚拟机的问题。这里 VPSee 简单介绍一下市面上常用虚拟技术(包括容器技术)的判别小技巧。

判断 OpenVZ/Xen PV/UML

判断 OpenVZ/Xen PV/UML 是最容易的,直接检查 /proc 下的相关目录和文件就可以知道,比如 OpenVZ VPS 上会有 /proc/vz 这个文件;Xen PV 虚拟机上会有 /proc/xen/ 这个目录,并且目录下有一些东西;UML 上打印 /proc/cpuinfo 会找到 UML 标志。写了一个简单的 Python 脚本来检测:

#!/usr/bin/python

# check if a linux system running on a virtual machine (openvz/xen pv/uml)

# written by http://www.vpsee.com

 

import sys, os

 

def main():

if os.getuid() != 0:

print “must be run as root”

sys.exit(0)

 

# check OpenVZ/Virtuozzo

if os.path.exists(“/proc/vz”):

if not os.path.exists(“/proc/bc”):

print “openvz container”

else:

print “openvz node”

 

# check Xen

if os.path.exists(“/proc/xen/capabilities”):

if (os.path.getsize(“/proc/xen/capabilities”) > 0):

print “xen dom0”

else:

print “xen domU”

 

# check User Mode Linux (UML)

f = open(“/proc/cpuinfo”, “r”); t = f.read(); f.close()

if (t.find(“UML”) > 0):

print “uml”

 

if __name__==”__main__”:

main()

判断 VMware/Xen HVM/KVM

如果使用的是 VMware/Xen HVM/KVM 这样的全虚拟就更难判断一些,最准确的办法是读取 CPUID 来判断,Xen 源代码下面有一段检测是否是 Xen 的 C 语言代码 tools/misc/xen-detect.c,这段代码提供了一个很好的例子,VPSee 重写了代码,用宏替代了函数,增加了对 VMware 和 KVM 的识别,用 gcc 编译后就可以运行:

/*

* check if a linux system running on a virtual machine (vmware/xen hvm/kvm)

* written by http://www.vpsee.com

*/

#include stdio.h

#include string.h

 

#define HYPERVISOR_INFO 0x40000000

 

#define CPUID(idx, eax, ebx, ecx, edx)

asm volatile (

“test %1,%1 ; jz 1f ; ud2a ; .ascii “xen” ; 1: cpuid”

: “=b” (*ebx), “=a” (*eax), “=c” (*ecx), “=d” (*edx)

: “0” (idx) );

 

int main(void)

{

unsigned int eax, ebx, ecx, edx;

char string[13];

 

CPUID(HYPERVISOR_INFO, &eax, &ebx, &ecx, &edx);

*(unsigned int *)(string+0) = ebx;

*(unsigned int *)(string+4) = ecx;

*(unsigned int *)(string+8) = edx;

 

string[12] = 0;

if (strncmp(string, “XenVMMXenVMM”, 12) == 0) {

printf(“xen hvmn”);

} else if (strncmp(string, “VMwareVMware”, 12) == 0) {

printf(“vmwaren”);

} else if (strncmp(string, “KVMKVMKVM”, 12) == 0) {

printf(“kvmn”);

} else

printf(“bare hardwaren”);

 

return 0;

}

判断 VirtualBox/Virtual PC

什么?这种家用桌面虚拟机自己装的还会不知道?!如果不知道的话也有办法,在 Linux 下运行 dmidecode 工具然后查找 Manufacturer: innotek GmbH, Manufacturer: Microsoft Corporation 关键字就能对应上 VirtualBox 和 Virtual PC.

 

]]>
http://ijz.me/?feed=rss2&p=685 0
Linux内核报错日志与硬盘I/O故障对应关系/zz/ http://ijz.me/?p=626 http://ijz.me/?p=626#respond Thu, 17 Jul 2014 02:40:50 +0000 http://ijz.me/?p=626  

 

日志信息 故障现象描述 与硬盘关系
scsi1: ERROR on channel 0, id 7, lun 0, CDB: Read (10) 00 73 fc 62 bf 00 00 80 00

Info fld=0x73fc6326, Current sdi: sense key Medium Error

Additional sense: Unrecovered read error

SMART规范定义“Medium Error”错误是一种不可恢复的错误,可能由于介质的缺陷或记录的数据错误。该错误有别于“Hardware Error”。

出现Medium Error的主要原因是硬盘坏,或者硬盘的数据无法读写。

  1. 硬盘扇区坏
  2. 硬盘与磁盘控制器连接信号质量不稳定,导致数据出现异常
mptbase: ioc1: IOCStatus=804b LogInfo=31080000

Originator={PL}, Code={SATA NCQ Fail All Commands After Error}, SubCode(0×0000)

原生指令排序(Native Command Queuing,简称NCQ),原先是改善服务器硬盘存取控制技术,应用在SCSI和SATA 1.0/2.0/3.0接口硬盘读写的加速技术,其接口开启磁盘阵列RAID亦有所提升。透过硬盘固件、硬盘控制器以及操作系统三者的互相配合,改善硬盘内部磁区的读取顺序,可以提高硬盘效能约30%,亦能够轻微减轻硬盘损耗的速率。NCQ对用于服务器上的硬盘的效率提升尤为明显。

PL:Protocol Layer,指磁盘控制器中的协议层

该信息与硬盘是否故障无直接联系
end_request: I/O error, dev sdi, sector 1945920256

EXT2-fs error (device sdi1): read_inode_bitmap: Cannot read inode bitmap – block_group = 222, inode_bitmap = 14547217

EXT2-fs error (device sdi1): ext2_get_inode: unable to read inode block – inode=951895, block=15202501

内核不能从硬盘上的文件系统读取数据。
  1. 硬盘扇区坏。
  2. 硬盘与磁盘控制器连接信号质量不稳定,导致数据出现异常。
mptbase: ioc1: IOCStatus=8000 LogInfo=31110d00

Originator={PL}, Code={Reset}, SubCode(0x0d00)

mptbase: ioc1: IOCStatus=804b LogInfo=31110d00

Originator={PL}, Code={Reset}, SubCode(0x0d00)

驱动准备让磁盘控制器IOC单元复位,出现该操作原因为驱动发现多次读写硬盘数据失败。

IOCStatus=0×8000

磁盘控制器配置页面处于共享的递归方式。

IOCStatus=0×8048

尝试读取不存在的超级配置数据。

IOCStatus=0x804b

超级数据序列号由0xffffffff变为0

该信息不能作为硬盘故障的依据。打印该信息的原因,与硬盘/磁盘控制器IOC单元/硬盘与控制器之间的链路有关。IOC错误码含义见前面。
mptscsih: ioc1: attempting task abort! (sc=000001007b4cf340)

scsi1 : destination target 8, lun 0

command = Read (10) 00 5f 2a 4d 3f 00 10 00 00

磁盘控制器驱动尝试取消读写任务。本示例代码中,表明取消在target 8,lun 0的读数据任务。 该信息与硬盘是否故障无直接联系
mptbase: ioc1: IOCStatus=8048 LogInfo=31130000

Originator={PL}, Code={IO Not Yet Executed}, SubCode(0×0000)

磁盘控制器驱动报告报告当前IOC(I/O Controller)单元状态码 该信息与硬盘是否故障无直接联系
mptscsih: ioc1: task abort: SUCCESS (sc=000001007b4cf340) 磁盘控制器驱动报告读写任务取消成功 该信息与硬盘是否故障无直接联系
mptscsih: ioc1: attempting target reset!

mptscsih: ioc1: attempting bus reset! (sc=000001007b4cf340)

mptscsih: ioc1: Attempting host reset! (sc=000001007b4cf340)

mptbase: Initiating ioc1 recovery

磁盘控制器驱动尝试复位target/bus/host,并重新恢复IOC(I/O Controller)单元 该信息不能作为硬盘故障的依据。打印该信息的原因,与硬盘/磁盘控制器IOC单元/硬盘与控制器之间的链路有关。
scsi: Device offlined – not ready after error recovery: host 1 channel 0 id 8 lun 0 硬盘offline,硬盘的位置为host 1 channel 0 id 8 lun 0 硬盘处于故障状态或丢失
SCSI error : <1 0 8 0> return code = 0×10000

end_request: I/O error, dev sdj, sector 1596607807

scsi1 (8:0): rejecting I/O to offline device

SCSI层报告在host 1 channel 0 id 8 lun 0设备上读写错误,返回码为0×10000,表明设备已不在位。 硬盘处于故障状态或丢失
mptsas: ioc1: attaching sata device, channel 0, id 11, lun 0, phy 0 系统新加入新的硬盘,硬盘所在位置为phy 0,即第一个物理槽位。 插入新的硬盘
mptsas: ioc0: removing sata device, channel 0, id 21, phy 2 从系统中拔掉一块硬盘,硬盘对应的物理位置为phy 2,即第3个物理槽位。 拔除一块硬盘
Remounting filesystem read-only 文件系统变为只读,原因为文件系统遭到破坏 与硬盘是否故障无直接关系

 

]]>
http://ijz.me/?feed=rss2&p=626 0