0


HUST网络攻防实践|6_物联网设备固件安全实验|实验二 基于 MPU 的物联网设备攻击缓解技术

文章目录

写在最前:注意下载最新版lib(6月2日更新版),并结合自己的lib分析。分析过程我写得有点长,是为了帮助大家找到自己的地址、并理解它。实际上,需要写进报告的内容只有子任务2那么点

实验二比较麻烦,附加内容我其实已经写进博客了,如果想写的话,请自行整理吧。实验三很简单,实验二比较麻烦而且比较长,考虑到大家应该还要写一下报告,我就分开先发实验二了。

实验二 基于 MPU 的物联网设备攻击缓解技术

实验要求

实验的 lib 库代码中开启了多项 MPU 区域保护

请根据不同的子任务重配置 MPU 区域解除相应的区域保护

  • 子任务 1 解除代码段不可写入保护将指定代码段改为可写
  • 子任务 2 解除特定外设区域保护将指定外设区域改为可读写

注:请通过逆向分析出触发 Memfault 的指令,从而在满足任务要求的同时尽可能用最 少的 MPU 区域配置、最小的 MPU 区域范围,最小的特权级。

特权级排序:rwx(可读可写可执行)> rw>rx>r>无权限

注意:任务2要用架构

mps2-an386

实验准备

Keil安装及使用

安装破解过程:

  1. 安装Keil5:一路Next就行,名称邮箱全部任意填,安装驱动什么的一律选是,安装路径最好不要包含中文,或者直接默认
  2. 破解Keil5:以管理员权限打开刚刚安装的Keil5,关掉弹出来的让安装包的窗口,然后点击File-License Management,复制CID到破解软件中。破解软件填写CID、设置TargetARM之后,点击Generate生成LIC,粘贴到Keil5LIC输入框中。点击Add LIC就行。
  3. 安装ARM CMSDK_CM4_FP:老师发的Keil5默认是没有我们要的ARM CMSDK_CM4_FP。不过老师还发了两个.pack文件,双击安装就行。一路Next安装路径要和Keil5的安装目录相对应

新建项目并添加文件:

Project-New uVersion Project 

,然后配置直接按实验指导书就行,后面也直接按指导书。添加文件可以直接拖进去。编译就是

Project-build

注意:如果之前装过其他版本的

Keil

,并新建了项目,记得删掉项目目录中的

Listings、Objects、RTE

,否则它会自动优先从这些目录下读取配置,版本就不对。

如果配置项完全正确,和指导书完全一致,直接运行时就会0 Error。

可执行文件会生成在

Objects/

下,运行如下指令运行:

~/qemu-7.0.0/build/qemu-system-arm -M mps2-an386 -cpu cortex-m4 -m 16M -nographic -d in_asm,nochain -kernel ~/exp6/task2/task2.axf -D log.txt

分析给出的

.c

/

.h

/

.lib

文件的内容和作用

先简单地分析一下

task2.c

的内容。

main

函数:
① 定义无符号整型变量

a

,赋值为学号末4位;
② 调用

prvSetupHardware()

,硬件初始化;
③ 调用

xTaskCreate

,创建任务,任务内容为

vTaskStart

,任务名称为"

Task2

",权限为特权级;
④ 调用

StartFreeRTOS(a)


⑤ 使用

for(;;)

让程序不退出。

vTaskStart

的任务中,调用了

AttackTest()

在逆向分析过后,可以进一步确定:在

StartFreeRTOS(a)

中包含对任务序列的启动。当启动了Task2后,将会调用

AttackTest()

。如果AttackTest没有触发

MemMange_Handler

异常,在一定的条件下,就会顺利打印输出

flag

;当AttackTest触发异常后,该任务就会结束。

MemMange_Handler

异常有触发延时,所以旧的lib总是在异常还没被触发时,就已经打印了

flag

,所以老师更新了新版lib文件。

通过查看

task2.h

,可以看到

AttackTest

prvSetupHardware

StartFreeRTOS

的函数声明,而这些函数的具体实现,正是在

task2x_xx.lib

文件中。

当项目构建完成之后,所有的文件的内容都会被链接到可执行文件

task2.axf

中。

子任务1 解除代码段不可写入保护将指定代码段改为可写

本任务中,需要将

task2.c

task2.h

task2a_89.lib

添加到Project中,注意要下载最新版的

.lib

文件。

逆向分析 AttackTest 函数

首先,不加修改地直接编译项目,得到

task2.axf

,以便逆向分析

AttackTest

函数。编译结果如下图所示:

在这里插入图片描述

在IDA Pro中打开文件

task2.axf

,选择的选项和上一个实验一致。

根据之前对三个文件的分析,我们能很轻易地找到

AttackTest

函数在逆向中的位置,顺着点开它,它的内容如下图所示:
在这里插入图片描述

F5

反汇编得到的结果如下图所示:

在这里插入图片描述

接下来,先保证能正确进入输出flag的条件分支内。

《ARM Cortex-M3与Cortex权威指南》(后简称为权威指南),第11章写了与MPU区域设置相关的寄存器,其中

0xE000ED94

就是寄存器

CTRL

。根据静态地址和寄存器的对应关系,预定义如下:

#defineMACRO_CTRL0xE000ED94#defineMACRO_RNR0xE000ED98#defineMACRO_RBAR0xE000ED9C#defineMACRO_RASR0xE000EDA0

然后,在

vTaskStart

里添加如下几行代码,以便通过指针形式来访问寄存器,并打印所有原始区域:

volatileunsignedint* pCTRL=(volatileunsignedint*)MACRO_CTRL;volatileunsignedint* pRNR=(volatileunsignedint*)MACRO_RNR;volatileunsignedint* pRBAR=(volatileunsignedint*)MACRO_RBAR;volatileunsignedint* pRASR=(volatileunsignedint*)MACRO_RASR;for(int i=0;i<8;i++){*pRNR=i;printf("%d,%d,%08x,%08x\n",*pRNR,*pCTRL,*pRBAR,*pRASR);}

寄存器有自己的结构,这里先定义结构体、再定义结构体指针会更合适一些。但是,由于实验任务简单,并没有太多需要修改的内容,所以我干脆直接用无符号整数赋值了。

为保证至少有一个MPU是使能的,再在

vTaskStart

里的循环体后添加一行代码:

*pCTRL=5;

然后Rebuild并直接运行一下,看看在哪里触发了异常,运行后的结果如下图:

在这里插入图片描述

根据老师的说法,MemMange_Handler这个异常会有延时,所以违反 MPU 区域保护的指令是触发异常的部分上面几行代码,而不是紧随其后的其他代码。即:

0x000002c2:  f44f 40e0  mov.w    r0, #0x7000
0x000002c6:  490c       ldr      r1, [pc, #0x30]
0x000002c8:  6001       str      r1, [r0]
0x000002ca:  f8c0 1080  str.w    r1, [r0, #0x80]
0x000002ce:  e7ec       b        #0x2aa

对应的

AttackTest

在IDA Pro中的汇编代码如下:

LDR指令的作用:将存储器地址所指地址处连续的4个字节的数据传送到目的寄存器中。

MOV.W    R0, #0x7000        ; 将0x7000赋值给R0寄存器
LDR          R1, =0x12345678    ; 将0x12345678赋值给R1寄存器
STR          R1, [R0]               ; 将R1的连续4字节的数据传送到R0寄存器指向的地址中
STR.W      R1, [R0,#0x80]      ; 将R1的连续4字节的数据传送到(R0寄存器指向的地址+0x80)中
B          Judge               ; 跳转执行Judge

显然,访问了

#0x7000

#0x7080

这两个地址,并且都需要写权限。

分析老师设置的所有的MPU的RASR的AP属性,可以看出,区域0、1、3都是只读的,其他区域对特权级都是可读可写的,区域6和7暂时没有设置。AP域编码对应的访问权限如下图所示(摘自权威指南):

在这里插入图片描述

而结合基址RBAR和RASR中的区域大小属性,可以看出,

#0x7000

#0x7080

这两个地址都在区域0和1内,而它们都是不可写的。

不过,除了这几行指令,保不齐后面还有别的访问不了的呢?继续往后看。

打印flag函数的条件分支体如下:

在这里插入图片描述

其中打印flag的条件分支体对应的代码解释如下:

1    ldr R0, #0x20000038    ; 将0x20000038赋值给R0寄存器
2    ldr R1, [R0]         ; 将R0寄存器指向的地址上的值读出并赋值给R1
3    adds R1, R1, #2         ; R1 = R1 + 2,影响进位标志位C的加操作
4    str R1, [R0]         ; 将R1的连续4字节的数据传送到R0寄存器指向的地址中
5    adr R0, aFlagU        ; 把格式化字符串的地址赋值给R0
6    b.w __2printf           ; 调用__2printf

总之,Judge中还涉及了内存地址

0xE000ED94

的读权限和

0x20000038

的读写权限。好在,通过MPU的信息可以看出,

0x20000038

虽然在区域2内,但是区域2可读写。

0xE000ED94

则不被约束。

因此这两个地址并不是违反MPU保护的地址。

违反 MPU 区域保护的指令

综合以上所有分析,可知,违反MPU区域保护的指令是AttackTest函数中的:

STR          R1, [R0]              ; 将R1的连续4字节的数据传送到R0寄存器指向的地址中
STR.W      R1, [R0,#0x80]      ; 将R1的连续4字节的数据传送到(R0寄存器指向的地址+0x80)中

违反的权限

0x7000

0x7080

这两个地址的写权限。

解除 AttackTest 函数违反规则的新 MPU 区域重配置代码

总的来说,我添加的解除AttackTest函数违反规则的新 MPU 区域重配置代码如下:

在这里插入图片描述

运行并得到flag的结果如下图:

在这里插入图片描述

设置的区域说明

CTRL

CTRL=

5

。表示使能。

RNR

RNR=

6

,表示区域6。

为了不覆盖老师的设置,我选择区域6来配置新的MPU区域。

RBSR

RBSR设置为

0x7000

RBSR的结构如下图(摘自权威指南):

在这里插入图片描述

上表的误导性非常强,我起初以为ADDR是独立出来的,比如当地址是0x7000、区域是1时,对应ADDR部分是0x7000,对应RBAR是0x70001。好在一位同学及时点醒了我,往后看一下权威指南,会发现地址部分是直接赋值的,根本没有考虑最后四位数。

经过实践,可以得到结论如下:

一方面,当倒数第五位数VALID是0的时候,REGION位的设置不会影响修改的MPU区域编号寄存器,程序会使用MPU区域编号寄存器选择的区域,因此最后四位数可以是任意值

另一方面,地址必须是REGION域大小的整数倍。首先,我们需要知道每一位地址能索引8比特的数据。对于大小为32B即(32×8)bits的数据,理论上需要用

     l
    
    
     o
    
    
     
      g
     
     
      2
     
    
    
     (
    
    
     32
    
    
     )
    
   
   
    log_2(32)
   
  
 log2​(32)位、也就是5位地址去表示,而每4位二进制数对应一个16进制数。因此,使用(00~1f)即可表示32B的数据,而每32B的数据之间的间隔,应当是0x20。

REGION域大小最小为32B,地址是N×0x20,N为整数。因此,非零地址最小是0x20。即使直接令RBAR=0x20,都不会影响到倒数5位二进制数的设置。(相当于,倒数5位本来是保留位,只是为了方便,所以多定义了VALID域和REGION域)
地址对应容量大小参考博客:【嵌入式基础】为什么0x100是256个字节、0x400是1KB、0x800是2KB、0x1000是4KB?。

总之,RBSR=

0x7000

,意思就是MPU的基址是

0x7000

RASR

RASR=

0x0102EE0F

,对应属性如下:

  • AP = 001,对应只支持特权级读/写;
  • TEX S C B = 000 0 1 0,对应ROM, Flash(可编程存储器);
  • SRD = 11101110,对应子区域0和4启用,其他禁用;
  • 区域大小 = 00111,对应区域大小256B;
  • 使能 = 1,使这块MPU能用。

接下来解释一下我设置的AP、SRD、区域大小、类型为什么是最小的:

  • APAP编码与访问权限的对应关系如下图(摘自权威指南):在这里插入图片描述对比上表可以看出,满足我们特权级任务、读写权限要求的最小访问权限就是001
  • 区域大小区域大小的编码如下图(摘自权威指南):在这里插入图片描述想要取最小的,那就取32B,也就是b00100。可惜我需要访问0x70000x7080这两个地址,只取128B都不行,因为取128B、基址是0x7000的时候,MPU对应的区域只有0x7000~0x707F。所以取256B,对应b00111
  • SRD当区域大小达到256B的时候,这个MPU足够大,能够设置8个子区域了。因此,我还得考虑子区域禁止属性SRD的设置。(我问过别人,别人的lib只访问了一个地址,或者访问的地址跨度没这么大。因此,我这居然是属于特殊情况)我的子区域0和子区域4是必须启用的,其他都可以禁用。所以设置为11101110
  • 类型只是简单介绍一下大类,不对TEX、S、C、B做详细介绍。本实验涉及到的TEX、S、C、B的设置如下图(摘自权威指南):在这里插入图片描述 显然,设置成ROM,Flash是权限最小的。

子任务 2 解除特定外设区域保护将指定外设区域改为可读写

在子任务1的分析基础上,不需要太多解释。
再加上预设的MPU没变,所以基本上只要改改地址范围即可。
实验结果如下。

逆向分析 AttackTest 函数

在这里插入图片描述

违反 MPU 区域保护的指令

AttackTest中的

STR R0, [R1]

违反的权限

0x40010000

的写权限。

解除 attackTest 函数违反规则的新 MPU 区域重配置代码

代码,以及相比子任务1的关键修改:

在这里插入图片描述

运行结果:
在这里插入图片描述

设置的区域说明

RNR=6。

CTRL=5。

RBSR设置为

0x40010000

RASR=

0x01020009

,对应属性如下:

  • AP = 001,对应只支持特权级读/写;
  • TEX S C B = 000 0 1 0,对应ROM, Flash(可编程存储器);
  • SRD = 00000000,区域大小未达到256B,因此该属性不需要配置;
  • 区域大小 = 00100,对应区域大小32B;
  • 使能 = 1,使这块MPU能用。
标签: 物联网 安全 MPU

本文转载自: https://blog.csdn.net/qq_46106285/article/details/125455204
版权归原作者 shandianchengzi 所有, 如有侵权,请联系我们删除。

“HUST网络攻防实践|6_物联网设备固件安全实验|实验二 基于 MPU 的物联网设备攻击缓解技术”的评论:

还没有评论