侧信道攻击笔记

侧信道攻击

简述

侧信道攻击是基于从计算机系统中获得的信息的任何攻击,而不是算法本身的弱点(例如密码分析和软件错误)。时间信息、功耗、电磁泄漏甚至是声音都可以提供额外的信息来源,可以加以利用。

Web 2.0应用程序和软件即服务(SaaS)的兴起显著增加了 Web 侧信道攻击的可能性,即使 Web 浏览器和服务器之间的传输是加密的,比如说盲注攻击。

侧信道攻击一般类别包括:

  • 缓存攻击 → 攻击基于攻击者监控受害者在共享物理系统(如在虚拟化环境或某种云服务中)进行的缓存访问的能力。
  • 定时攻击 → 基于测量各种计算(例如,将攻击者的给定密码与受害者的未知密码进行比较)执行的时间的攻击。
  • 电源监控攻击 → 在计算过程中利用硬件不同功耗的攻击。
  • 电磁攻击 → 基于泄露的电磁辐射的攻击,可以直接提供明文等信息。此类测量可用于使用与功率分析中的技术等效的技术来推断密码密钥,或者可用于非密码攻击。
  • 声学密码分析 → 利用计算过程中产生的声音的攻击(类似于功率分析)。
  • 差分故障分析 → 通过在计算中引入故障来发现秘密。
  • 数据残留 → 敏感数据在被删除后被读取。
  • 软件发起的故障攻击 → 目前是一种罕见的侧通道,Row_hammer是一个示例
  • 光学 → 可以使用高分辨率相机或其他具有此类功能的设备,通过视觉记录来读取机密和敏感数据。

在所有情况下,基本原则是由密码系统(在侧面)的操作引起的物理效应可以提供有关系统中秘密的有用的额外信息,例如,密码密钥、部分状态信息、完整或部分明文和等等。

定时攻击

简述

在定时攻击中,攻击者试图通过分析执行密码算法所花费的时间来破坏密码系统。因为计算机中的每个逻辑操作都需要时间来执行,并且时间可能因输入而异,所以通过精确测量每个操作的时间,攻击者可以回溯到输入。通过时间信息发现秘密可能比使用已知明文、密文对的密码分析要容易得多。有时,时序信息与密码分析相结合,以增加信息泄漏率。

例如模幂运算中使用的平方和乘法算法的执行时间线性地取决于密钥中“1”位的数量。虽然“1”位的数量不足以使找到密钥变得容易,但使用相同的密钥和不同的输入重复执行可用于执行时序信息的统计相关性分析以完全恢复密钥,即使通过被动攻击者。

但是需要注意到的是,观察到的时序测量通常包括噪声(来自诸如网络延迟、访问与访问之间的磁盘驱动器访问差异以及用于从传输错误中恢复的纠错技术等来源)。

当然,定时攻击对许多加密算法是实用的,包括 RSA、ElGamal 和数字签名算法。

实例

假设我们有一个程序,有一个简单的不安全的密码验证函数:

1
2
3
4
5
6
7
8
9
10
11
bool insecureStringCompare(const char* a, const char* b, size_t length)
{
for (size_t i = 0; i < length; i++)
{
if (a[i] != b[i])
{
return false;
}
}
return true;
}

程序需要输入一个 8 位数字 PIN,当输入长度不为 8 时,程序会提示 length error

这个时候我们可以用定时攻击,脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pwn
import time

def run(PIN):
io = pwn.process("./pin_checker")
io.recvall()
start = time.time()
io.sendline(PIN.encode())
io.recvall()
end = time.time()
io.close()
return end - start

result = ""
for i in range(8):
t = []
for j in range(10):
ret = run(result + str(j) + "0" * (7 - i))
t.append(ret)
result += str(t.index(max(t)))

print(f"PIN: {result}")

通过对每个密码运行时间的不同,我们便可以不通过密码分析得到 PIN。

同时如果需要对定时攻击进行防御,我们可以将比较函数稍稍修改:

1
2
3
4
5
6
7
bool constantTimeStringCompare(const char* a, const char* b, size_t length)
{
int result = 1;
for (size_t i = 0; i < length; i++)
result &= a[i] == b[i];
return result;
}

这个密码比较函数在时间上是安全的。