【HUST】网络攻防实践|6_物联网设备固件安全实验|实验三 FreeRTOS-MPU 保护绕过

本文详细描述了一次针对FreeRTOS-MPU保护的逆向分析与提权实验,涉及子任务1的函数逆向、提权函数定位、溢出漏洞利用和模拟运行。子任务2则聚焦于另一个函数的逆向及栈结构分析。关键步骤包括代码修改、地址查找和模拟结果验证。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写在最前:一定要先将task3.sct文件链接到项目中,具体操作后文有写,而且我在附加内容里解释了sct文件的含义。

终于可以告别这个实践了。大家在心得里可以加一句“任务量较大,建议减少任务量”吗?

实验三 FreeRTOS-MPU 保护绕过

实验要求

MPU预设置:

在这里插入图片描述

a) 编写 C 代码实现基于 FreeRTOS-MPU v10.4 的提权代码和指定函数查找
b) 利用溢出漏洞实现在 FreeRTOS MPU V10.4 版本的系统提权和 Flag 函数打印

子任务1

首先,和上一个实验相似地,也是看一下.c文件的结构。

main函数:
① 定义无符号整型变量id,赋值为学号末4位;
② 调用prvSetupHardware(),硬件初始化;
③ 调用StartFreeRTOS(id, vTask3)
④ 使用for(;;)让程序不退出。

vTask3的内容,只有for(;;)

头文件和lib文件的作用与上一个实验差不多。

因此,所有任务要求都集中在StartFreeRTOS里了,我们需要进行进一步的逆向分析。

逆向分析StartFreeRTOS

IDA Pro打开并反编译StartFreeRTOS如下:

在这里插入图片描述

可以看到,该函数大致有如下几个操作:

① 将byte_7714的地址指向的内容拷贝给任务参数xTask3Parameters
② 设置任务参数xTask3Parameters的函数指针为vTask3
③ val *= id;
④ 调用xTaskCreateRetricted,结合任务参数xTask3Parameters创建被约束的任务;
⑤ 调用vTaskStartScheduler()启动任务序列。

我们要做的是在vTask3中调用提权函数,然后再调用打印flag的函数。

打印flag的函数好找,直接在IDA Pro的字符串窗口找就行,找到后双击点开,再查看引用:

在这里插入图片描述

总之能找到一个叫vTaskRemove的函数,它是无参数函数,能够打印flag。

找提权函数,我一开始完全不知道怎么找。
直到看了下实验讲解的PPT,看到了下面这张图:
在这里插入图片描述

可见,如果普通任务要使用内核API,不能直接使用,而是要添加MPU_,添加了这个的函数,其中包含提权操作。而且,提权操作应该是利用SVC中断。

因此,我们不妨在IDA Pro中随便打开一个MPU_的函数逆向分析一下,找到其中的提权操作。我以MPU_vTaskDelete为例。IDA Pro中分析如下:

在这里插入图片描述

上图中我框出来的就是提权操作。可以看到,就是先做了些进入函数的压栈操作,随后把要提权的Task传入R4,如果R4不为0就跳转提权函数(如果为0那么本身就是特权级)。然后再常规地执行xTaskDelete这个内核API。

很明显,提权函数就是xPortRaisePrivilege,而且利用寄存器R4传参,所以它也是个无参数的函数。

先不急着把地址填入,因为这个地址在修改了vTask3内容之后会发生改变。先假装已经找到了地址,并在vTask3中使用地址调用这些函数,这样,找到之后就只需要修改成对应的地址。添加代码如下:

注意,随便填的地址不得为全零、不得相同,最好是填得像一点,否则二度修改后,地址又会变化。

void (*pPrivilege)();
void (*pFunc)();
pPrivilege=(void(*)())0x00001051;
pFunc=(void(*)())0x000029AD;
pPrivilege();
pFunc();

Rebuild后,去IDA Pro中查找函数地址。在使用地址调用函数的时候,需要加一。

需要注意的是,当函数地址已经添加正确,但log.txt中却连vTask3都没有的时候,很可能是项目的配置出了问题,如内存地址分布,出问题的log.txt如下:

在这里插入图片描述

此时必须要导入老师发的task3.srt,导入方式如下:

在这里插入图片描述

导入完成后,重新构建项目,并重新逆向分析地址。(我导入后重新截了一遍图)

sct具体的作用见下文的附加内容1

打印 Flag 函数名称和地址

名称:vTaskRemove
地址:0x000005F4

内容如下图所示:

在这里插入图片描述

用于提权的函数名称和地址

名称:xPortRaisePrivilege
地址:0x00008EDC

内容如下图所示:

在这里插入图片描述

填写的代码

注意,需要将上述找到的地址加1后再调用。填写的代码如下图所示:

在这里插入图片描述

模拟运行截图

运行并打印flag的结果如下:

在这里插入图片描述

log.txt如下:

在这里插入图片描述

之所以要把log.txt也截图出来,是因为之前分析的时候,可以看到xPortRaisePrivilege函数提权的任务是R4寄存器,而我们只是简单地调用了该函数,并未对R4寄存器做处理。可是也成功了。
查看log.txt会发现,并没有明显的对R4寄存器处理的内容,最近一次赋值是prvSVCHandler的pop。我猜测有可能只需要执行svc 2中断即可提权,具体情况尚未明确,不过对本实验无任何影响。

后来写flag5报告的时候,意识到当R4为0时,提权的应该就是本任务;或者,不论R4的取值,都会对本任务提权。

附加内容1:sct文件的作用

下图左是老师发的sct文件,下图右是软件自动生成的sct文件。

在这里插入图片描述

sct文件也就是内存映射布局文件。
一般情况,编译的时候,只是让所有的函数(如上图中的.ANY (+R0))按照函数名称排序放进内存里,并没有所谓特权访问还是用户访问的访问控制。
在我们设置了MPU之后,编译并不会跟着受影响。因此,非特权函数可能就放入了我们自己规定的MPU中特权函数的那个区域,非特权函数保存在了特权函数的地址范围,MPU就不会允许执行了。

而老师修改后的sct文件,对API的位置重新布局,把特权函数privileged_functions放到了第一段(就是MPU中只允许特权执行的那个位置ER_IROM1),把其他的放到了ER_IROM2。并把特权数据privileged_data放到了MPU中只允许特权可读写的段RW_IRAM1,把其他的放到了RW_IRAM2

这样,就会让内存映射与MPU设置一致了。

子任务2

逆向分析StartFreeRTOS

该任务逆向分析函数地址与上一个任务相似,在此不做赘述。

打印 Flag 函数名称和地址

名称:vTaskDelayBackup
地址:0x00001C7C

内容如下:

在这里插入图片描述

用于提权的函数名称和地址

名称:xPortRaisePrivilege
地址:0x000086E2

内容如下:

在这里插入图片描述

分析过程

该文件的main函数超长,不过很简单,如下图所示:

在这里插入图片描述

暂时只能看到,最后输入的字符串InputBuffer长度最大为0x63。

再点开StartFreeRTOS:

在这里插入图片描述

只是运行了受约束的vTask3任务,其他啥也没干。

由于这是传参传进来的,不能直接点开,所以先返回上一级,然后再点开vTask3任务:

在这里插入图片描述

vTask3调用了Function(),根据经验,这就是出问题的代码了。

找到存在在溢出的缓冲区

点开Function

在这里插入图片描述

发现居然Function传进来了参数,更重要的是出现了lengthInputBuffer,而且赋值给HelperBuffer,并且HelperBuffer的大小只有12,说明HelperBuffer可能就是溢出的缓冲区。

以汇编形式显示Function函数如下:

在这里插入图片描述

对PUSH和POP的解释:ARM架构的栈是递减栈,PUSH的时候从右至左,POP的时候从左至右。

查看汇编之后,会发现其实严格来说,压根就没有什么溢出缓冲区。Function函数,它先push了4个寄存器,然后在函数的最开始使用mov buffer, sp,直接改变栈顶指针sp,接下来立马用InputBuffer的内容逐一填充buffer(在我的IDA中该变量名被解析成HelpBuffer)。最后pop的时候,pop的内容不就是HelpBuffer[0]HelpBuffer[1]HelpBuffer[2]等吗?
覆盖寄存器的值,就是Function的目的,也是设置buffer的作用,它就是想往栈上写、往寄存器上写。
既然,该缓冲区的每一个比特,目的都是向不应该写的寄存器或栈上写数据,它就压根没有与正常功能有关的部分。就像拿一张纸画画,正常操作画在纸上,但是涂多了就溢出到桌上了,这张纸叫做溢出缓冲区;而这个代码就是连纸都没有。

综上,我认为这并不是一个典型的缓冲区溢出代码。如果非要说有个溢出缓冲区,那就是故意构造的这个HelpBuffer,而且该溢出缓冲区的长度为0,没有正常功能

栈示意图

点开Function的bp,可以看到IDA Pro中的栈帧。

在这里插入图片描述

不过,这并不能很好地解释栈中的内容。我重新绘制了栈示意图。

当执行mov buffer, sp前后的栈示意图如下:

在这里插入图片描述

LR(Function)需要覆盖成提权函数,而调用提权函数之后,还需要调用打印flag的函数,所以还要构造溢出提权调用的返回地址的栈结构。完全构造完毕的栈示意图在后续“溢出提权”中会画出

溢出提权

溢出提权调用xPortRaisePrivilege,地址是0x000086E2。该函数第一行是PUSH {xRunningPrivileged,LR}。如果执行这一句,就会改变我们已经构造好的栈帧结构,也会导致返回地址无法被覆盖,因此需要跳过这一句,从地址0x000086E4开始。再加上基地址是1,因此LR(Function)需要被覆盖成0x000086E5

顺利进入并执行提权函数后,还要继续执行打印flag的函数。返回时执行了POP {xRunningPrivileged,LR}因此需要构造8个HelpBuffer字节,完整的栈示意图如下:

在这里插入图片描述

覆盖返回地址的解析过程

Function中返回值被覆盖成xPortRaisePrivilege第二行地址加1,即0x000086E5,因此它返回时会从xPortRaisePrivilege的第二行代码开始执行,并完成提权;

xPortRaisePrivilege中返回值被覆盖成vTaskDelayBackup地址加1,即0x00001C7C,因此它返回时会从vTaskDelayBackup的第一行代码执行,并完成flag打印。

模拟运行截图

在这里插入图片描述

完结撒花!!!

1、PGP概述 PGP(Pretty Good Privacy)的创始人是美国的Phil Zimmermann(菲利普•齐默曼),他在1991年把 RSA 公钥体系的方便和传统加密体系的高速度结合起来,并且在数字签名和密钥认证管理机制上有巧妙的设计。因此 PGP 成为几乎最流行的公匙加密软件包。PGP有不同的实现,如GnuPG和Gpg4win,其中GnuPG(Gnu Private Guard,简写为GPG)的核心算法是PGP,GnuPG本身是为Linux等开源操作系统设计的;而Gpg4win是windows下GnuGPG及图形前端的合集安装包,其核心为GnuPG,包括:(1)Kleopatra和GPA:GPG的密钥管理器,用于生成、导入和导出GPG密钥(包括公钥和私钥);(2)GpgOL:Outlook 的GPG支持插件;(3)GpgEX:资源管理器的GPG支持插件;(4)Claws Mail:内置GPG支持的邮件客户端。 PGP是一个基于RSA公钥加密体系的加密软件,是开源且免费的,后经互联网志愿者发展完善并广泛应用,具有如下特点:(1)选择最可用的加密算法作为系统的构造模块,所用算法已被广泛检验过,相当安全;并将这些算法集成到一个通用的应用程序中,该程序独立于操作系统和处理器,并且基于一个使用方便的小命令集;(2)是一个开源项目,程序、文档在Internet上公开;(3)可以免费得到运行于多种平台上的PGP版本,具有广泛的可用性;(4)不由任一政府或标准化组织所控制,使得PGP得到了广泛信任;(5)与商业公司(Network Associates)合作,提供一个全面兼容的、低价位的商业版本PGP。2010年6月被赛门铁克公司收购。由于这些特点,使得PGP得到了广泛的应用。 PGP常用的版本是PGP Desktop Professional,它可以用来加密文件,可以用来对邮件保密以防止非授权者阅读,还能对邮件加上数字签名从而使收信人可以确认邮件的发送者,并能确信邮件没有被篡改。同时,通过使用公钥密码算法,可以提供一种事先并不需要任何保密的渠道用来传递密匙的安全通讯方式。PGP功能强大,而且具有很快的速度,PGP提供的主要功能如表1.7.1所示。 表1.7.1 PGP的功能概述 功能 使用的算法 描述 消息加密 IDEA、CAST、3DES、TwoFish、ElGamal、RSA 发信人产生一次性会话密钥加密,用IDEA或CAST-128或3DES算法对消息进行加密;采用ElGamal或RSA算法用接收方的公钥加密会话密钥 数字签名 DSS/SHA-1、RSA/MD5 采用SHA-1或MD5消息摘要算法计算消息的摘要值(散列码),用发送者的私钥按DSS或RSA算法加密消息摘要 压缩 PKZIP 消息在传送和存储时可使用PKZIP压缩 E-mail兼容性 Radix-64 对E-mail应用提供透明性,采用基数64编码将加密后的消息(二进制流)转换为ASCII字符串 数据分段 - 为了适应最大消息长度限制,PGP执行分段和重新组装 2、PGP的密钥管理 PGP是一种混合密码系统,应用了多个密码算法,包括对称密码算法、非对称密码算法、消息摘要算法、数字签名等经典的密码学算法。为用户生成密钥对之后,可以进行邮件的加密、签名、解密和认证。在PGP中使用的加密算法和用途如表1.7.2所示。 表1.7.2 PGP中采用的各种密码算法及用途 密钥名 加密算法 用途 会话密钥 IDEA、AES 对传送消息的加解密,随机生成,一次性使用 公钥 RSA、Diffie-Hellman 对会话密钥加密,收信人和发信人共用 私钥 DSS/SHA、RSA/SHA 对消息的杂凑值加密以形成签名,发信人专用 口令 IDEA 对私钥加密以存储于发送端 从上表可以看出,PGP使用了四种类型的密钥:一次性会话传统密钥、公钥、私钥和基于口令短语的传统密钥/通行字短语。 会话密钥按ANSI X9.17标准,采用IDEA算法,以密文反馈模式(CFB)生成。当PGP用RSA算法为用户生成一个新的公钥/私钥对时,PGP会要求用户提供一个口令短语,对该短语使用MD5/SHA-1消息摘要算法生成一个散列码后,销毁该短语,从而把用户输入的口令短语转化为IDEA/CAST-128密钥,再使用这个密钥加密私钥,然后销毁这个散列码,并将加密后的私钥存储到私钥环中。当用户要访问私钥环中的私钥时,必须提供口令短语。PGP将取出加密后的私钥,生成散列码,解密私钥。 一个用户可能拥有多个公钥/私钥对,正确识别加密会话密钥和签名所用的特定公钥/私钥对的一个最简单的解决方案是将公钥和消息一起传送。但这种方式浪费了不必要的空间。PGP采用的解决方案是给每个公钥分配一个密钥标识(KeyID),并以极大的概率与用户标识(UserID)一一对应,即UserID和KeyID标识一个密钥。密钥标识至少为64位,因而密钥标识重复的可能性非常小。 PGP提供一种系统化的密钥管理方案来存储和组织这些密钥以保证有效使用这些密钥,它为每个节点(用户机器)提供一对数据结构,一个用于存放本节点自身的公钥/私钥对(即私钥环),另一个用于存放本节点知道的其他用户的公钥(即公钥环)。私钥环信息:时间戳、KeyID、公钥、私钥、UserID,其中UserID通常是用户的邮件地址。也可以是一个名字,可以重名;公钥环信息:时间戳、KeyID、公钥、对所有者信任度、用户ID、密钥合法度、签名、对签名者信任度,其中UserID为公钥的拥有者。多个UserID可以对应一个公钥。公钥环可以用UserID或KeyID索引。 如何保证用户公钥环上的公钥确实是指定实体的合法公钥,这是一个至关重要的问题。PGP提供几种可选的方案以减少用户公钥环中包含错误公钥的可能性:(1)物理上得到对方的公钥。这种方式最可靠,但有一定局限性;(2)通过电话验证公钥;(3)从双方都信任的第方(个体或CA)处获得对方的公钥。 此外,PGP支持密钥管理服务器,用户可以将公钥发布在集中的密钥服务器上,供他人访问。 3、PGP的消息处理过程 PGP消息分成原始消息、签名部分和会话密钥部分个部分。 PGP发送方处理消息的过程为:(1)签名:利用UserID作为索引,从私钥环中得到私钥;PGP提示输入口令短语,恢复私钥;构造签名部分;(2)加密:PGP产生一个会话密钥,并加密消息;PGP用接收者UserID从公钥环中获取其公钥;构造消息的会话密钥部分。 PGP接收方处理消息的过程为:(1)解密消息:PGP用消息的会话密钥部分中的KeyID作为索引,从私钥环中获取私钥;PGP提示输入口令短语,恢复私钥;PGP恢复会话密钥,并解密消息;(2)验证消息:PGP用消息的签名部分中的KeyID作为索引,从公钥环中获取发送者的公钥;PGP恢复被传输过来的消息摘要;PGP对于接收到的消息计算摘要,并与上一步的结果作比较。 4、PGP的信任模型 由于PGP重在广泛地在正式或非正式环境下的应用,所以它没有建立严格的公钥管理模式。尽管PGP没有包含任何建立认证权威机构或建立信任体系的规范,但它提供了一个利用信任关系的方法,将信任关系与公钥联系起来。PGP定义了与基于X.509真实的公钥基础设施(PKI)不同的证书模型,即所谓“信任网(Web of Trust)”模型。传统PKI模型依赖于CA层次体系验证证书和其中的密钥。而PGP模型则允许多重地、独立地而非特殊可信个体签署的“名字/密钥”关联来证明证书的有效性,其理论是认为“只要有足够的签名,<名字/密钥>关联就是可信的,因为不会所有的签名者都是‘坏’的”。PGP的信任网就像人际关系网一样,通过下述方式让使用公钥的人相信公钥是其所声称的持有者:(1)直接来自所信任人的公钥;(2)由所信赖的人为某个自己并不认识的人签署的公钥。因此,在PGP中得到一个公钥后,检验其签名,如果签名人自己认识并信赖他,就认为此公钥可用或合法。这样,通过所认识并信赖的人,就可以和总多不认识的人实现PGP的安全E-mail通信。 具体而言,在PGP中是通过在公钥环中的下述3个字段来实现Web of Trust信任模型的:(1)密钥合法性字段(key legitimacy field):指示用户公钥合法性的可信等级。信任级别越高,则用户标识UserID与密钥间的绑定关系就越强。这个字段是由PGP计算的;(2)签名信任字段(signature trust field):每一个公钥项都有一个或者多个签名,这是公钥环主人收集到的、能够认证该公钥项的签名。每一个签名与一个signature trust field关联,指示PGP用户信任签名者对此公钥证明的程度。key legitimacy field 是由多个signeture trust field 导出的;(3)所有者信任字段(owner trust field):指示此公钥对其他公钥证书进行签名的信任程度。这个信任程度是由用户给出的。 PGP使用以个人为中心的信任模型,采取一种“社会信任链”的方式进行公钥分发。在这种方式下,用户可以自行决定对周围的联系人是否信任,并可以决定信任度的高低。用户只接收信任的朋友传送来的公钥,并且这些公钥都带有签名。这种方式反映了社会交往的本质,比较适合一般场合下的安全通信。 本实验通过实际操作,了解PGP/GPG4Win软件的常用功能,利用PGP/GPG4Win软件实现密钥管理、对文件和电子邮件的签名与加密等操作。
凯撒密码(caeser)是罗马扩张时期朱利斯•凯撒(Julius Caesar)创造的,用于加密通过信使传递的作战命令。它将字母表中的字母移动一定位置而实现加密。 古罗马随笔作家修托尼厄斯在他的作品中披露,凯撒常用一种“密表”给他的朋友写信。这里所说的密表,在密码学上称为“凯撒密表”。用现代的眼光看,凯撒密表是一种相当简单的加密变换,就是把明文中的每一个字母用它在字母表上位置后面的第个字母代替。古罗马文字就是现在所称的拉丁文,其字母就是我们从英语中熟知的那26个拉丁字母。因此,凯撒密表就是用d代a,用e代b,……,用z代w。这些代替规则也可用一张表格来表示,所以叫“密表”。 基本原理 在密码学中存在着各种各样的置换方式,但所有不同的置换方式都包含2个相同的元素。密钥和协议(算法)。凯撒密码的密钥是3,算法是将普通字母表中的字母用密钥对应的字母替换。置换加密的优点就在于它易于实施却难于破解. 发送方和接收方很容易事先商量好一个密钥,然后通过密钥从明文中生成密文,即是敌人若获取密文,通过密文直接猜测其代表的意义,在实践中是不可能的。 凯撒密码的加密算法极其简单。其加解密过程如下: 加密解密算法 凯撒密码的替换方法是通过排列明文和密文字母表,密文字母表示通过将明文字母表向左或向右移动一个固定数目的位置。例如,当偏移量是左移3的时候(解密时的密钥就是3): 明文字母表:ABCDEFGHIJKLMNOPQRSTUVWXYZ 密文字母表:DEFGHIJKLMNOPQRSTUVWXYZABC 使用时,加密者查找明文字母表中需要加密的消息中的每一个字母所在位置,并且写下密文字母表中对应的字母。需要解密的人则根据事先已知的密钥反过来操作,得到原来的明文。例如: 明文:THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG 密文:WKH TXLFN EURZQ IRA MXPSV RYHU WKH ODCB GRJ 凯撒密码的加密、解密方法还能够通过同余数的数学方法进行计算。首先将字母用数字代替,A=0,B=1,...,Z=25。此时偏移量为n的加密方法即为: E (x)= (x+n) mod 26 解密就是: D (x)= (x-n) mod 26
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shandianchengzi

谢谢你

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值