官方WP | 可信赛题的创新与线上赛题目解说

WriteUp 5个月前 admin
147 0 0
编者荐语:
本文分享了胡俊老师对可信赛题的创新点以及在第十七届全国大学生信息安全竞赛—创新实践能力赛初赛中,两道可信赛题的深入分析。同时,也分享了成功解出这两道题目的队伍所采用的方法和技巧。
“用户信息访问控制”、“平台可信认证”赛题均已部署在伽玛实验场,欢迎前去挑战。

官方WP | 可信赛题的创新与线上赛题目解说

官方WP | 可信赛题的创新与线上赛题目解说https://www.ichunqiu.com/battalion?t=1&r=70899

+ + + + + + + + + + + 

可信赛题的创新与线上赛题目解说

作者:北京工业大学国家等级保护2.0与可信计算3.0攻关示范基地 胡俊

1.可信度量赛题部署裁决机制的创新

本次国赛初赛是我第6次提供可信计算赛题支持。在全国大学生信息安全竞赛中提供可信计算赛题则是第4次。以前的比赛主要精力是放在题目本身的设计,题目裁决机制做的比较随意。本次比赛我们准备参考可信3.0的设计思想,设计一个通用性更强的裁决机制,以方便开发更多种类型的可信赛题。

在前几次出题时,我们确定了可信计算赛题采用选手练习环境、评判环境与裁决计分环境并行的赛题出题模式。其基本示意图如图1所示:

官方WP | 可信赛题的创新与线上赛题目解说

图1:2024年前可信赛题裁决机制原理

这一机制为可信赛题提供了类似信息奥赛、蓝桥杯的“编程式”解题体验,但是这个解题机制实际上是第二次出可信题目时用了一个通宵临时构建的架构,后来也只做了较小的改动,其评分机制是根据题目定做的,通用性不强,不利于可信赛题的推广。
本次比赛准备时间稍多一些,因此,我们决定借这个机会,对裁决机制做一个改进,以方便可信赛题的推广。新的裁决机制借鉴了可信3.0的设计思路,在验证环境部署了验证代理,在裁决环境中,则是将定制的评分机制换成了通用的评分机制,通过评分策略来支持不同赛题共用评分机制。这一修改使得裁决环境变成了一个通用的模块,不但使得解题过程中信息输出方式更加多样化,同时也方便了赛题的独立部署以及在不同平台上的移植。新的赛题裁决机制原理如图2所示:

官方WP | 可信赛题的创新与线上赛题目解说

图2:2024年可信赛题裁决机制原理

我们希望能够让网络安全相关的教师、学生以及技术人员都可以设计赛题,同时也希望能够让可信赛题既能在专用的可信计算平台上部署,也能以传统方式部署在成熟的赛事平台上,还可以让成熟赛事平台通过标准的接口与可信计算平台互联,使得成熟平台上也可以体验新型赛题,而不受系统和安全运行环境的限制。

2.“用户信息访问控制”赛题解题思路

本次比赛我们调整了赛题的难度,其中用户信息访问控制题目我们期望设计成一个不需要太多编程工作,仅靠对访问控制理论和安全模型的理解就可以基本完成解答的题目。同时,为了让大家解题时更有带入感,我们设计了一个公司内部数据访问需求作为赛题的背景。
本题主要考核的是选手对于强制访问控制的理解。题目给出的场景整体上符合BLP模型,但是有两个例外情况需要处理。第一个是对电话和邮箱访问的限制,第二个则是本人可访问自己薪水的要求。本题就是通过选手对这两个例外情况的处理方式,来考察选手对BLP模型的理解。
我们知道,BLP模型的要求是主体对客体的访问遵循“不可上读,不可下写”原则,它体现的是对上下级间以保密需求为核心的信息流控制。要正确实施BLP模型,首先要对主体和客体进行准确的标记。以往的可信计算赛题中,主体和客体的级别和类别是明确的,标记起来很容易,但现实社会中的需求往往并不那么清晰。本题中,对电话和邮箱的访问限制可以理解为现实生活中下级向上级汇报需求的体现,其仍旧符合BLP模型对信息流进行控制的要求,但是需要对系统中的客体对象进行准确的标记,才能够正确实施这一控制。因此,这一点考察的是对BLP模型中客体如何进行安全标记的问题。
在题目的这一环节,我们又设计了一个机制与策略分离的机制,以使题目更能反映数字应用场景的实际需求,同时也降低题目这部分的实现难度。题目中数据项的数量有限,因此直接用代码来实现正确的客体标记也并非难事。但如果数据项有成千上万项,那么用编程方式来做正确标记工作量很大,也不易管理。因此,题目设计为实现了一种标记赋值机制,可以根据为不同数据项制定的标记策略来标记客体。这样,对于每一个数据项只要设置一个正确的标记策略,就可以实现对客体的正确标记。
按照题目的设计,电话和邮件地址属于属主,因此要继承属主安全属性。又因为分别需要低一个级别和低两个级别的人员观看,所以需要对级别进行调节。因此解题时,是否调整级别项(isleveladjust)应设为1,是否自有类别项(isselfdefine)应设为0,调整级别则应分别设为-1和-2。
题目的第二个需处理的情况则不能用级别和类别来包含。在BLP模型中,该情况可以看做是一种可信读取行为:个人理应可读取本人的薪水,这个不会导致泄密事件。因此,我们在题目的访问控制逻辑中添加了一个例外规则函数except_rule,学生只要在这里判断数据项是否为salary,以及主客体属主是否一致,如两项均为是,则该项符合,except_rule函数返回1,用户即可获得自己薪水信息。
except_rule函数的参考写法如下:
int except_rule(char * record_name, char * read_user, char * record_user)
{
    if(strcmp(record_name,”salary”)==0)
    {
        if((strcmp(read_user,record_user)==0)
        return 1;
    }
    return 0;
}
本题难度不大,且策略配置部分有参考示例。解出题目的队伍有50队,比起去年仅有3队解出可信赛题,说明赛题难度确实降低了,但是50比起总共2500的参赛队伍总数而言,仍然是一个小数字。或许我们的高校、职校网络安全专业应当更多地重视访问控制方面的教学内容?

3.“平台可信验证赛题解题思路

这一道题实际上可以理解为去年赛题的延续,核心内容是类似的。今年的主要改动是为平台的可信验证提供了一个实用的场景:对平台系统和安全机制的验证需求,并结合以往可信赛题中的身份认证机制,让学生体验在登录中同时验证用户身份和平台可信状态的可信验证过程。而题目的考点则是PCR寄存器预期值的计算和报告值-预期值对比。
本题目的关键是对比预期寄存器值的生成与报告中寄存器值的生成。通过查看运行过程中message.log的信息,很容易就能找到报告中寄存器的取值,因此题目的关键就是预期值的获取以及验证工作。
提示中给出了不同度量结果摘要值的存储位置和名称。这里,用memdb_find_first函数是可以查询到摘要值内容的。以trust_boot度量结果为例,具体方式如下:
RECORD(GENERAL_RETURN,UUID) * policy; // 度量项数据结构
char * policy_name = “trust_boot”; // 度量项名称
DB_RECORD * db_record;  //内存数据库的存储项
db_record = memdb_find_first(TYPE_PAIR(GENERAL_RETURN,UUID),
“name”,policy_name); //从内存数据库中找到度量项
policy=db_record->record;
此时,policy->return_value中就是度量值。
我们查到度量值后,再使用PCR值计算公式:PCR新值 = SM3(PCR旧值|输入值)即可分别算出PCR7,PCR11和PCR14寄存器的预期值。
而pcr报告中的pcrvalue取值,则包括pcr7,pcr11和pcr14的三个32字节sm3摘要组成的一个96字节摘要值集合,以及一个三字节位图,该位图中7位、11位和14位置1。我们只要计算出预期的摘要值,构造摘要值集合,再生成pcr位置位图,并与报告中pcrValue值比较,即可得出结论。
下面是参考答案。这里我们使用了一个函数TCM_ExAddPcrComposite来计算预期值,但了解了pcrValue计算的原理,完全可以使用sm3函数来自行完成计算。
for(i=0; trust_policy[i].name!=NULL; i++)
// 循环处理所有的度量项
{
    // 查找度量值
    db_record = memdb_find_first(TYPE_PAIR(GENERAL_RETURN,UUID),
                                 "name",trust_policy[i].name);

    if(db_record == NULL)
        return -EINVAL;
    policy_digest = db_record->record;
    // 针对度量项计算预期值
    result = TCM_ExAddPcrComposite(pcr_result,trust_policy[i].value,
                                   policy_digest->return_value);
    printf("policy name : %s value :",policy_digest->name);
    print_bin_data(policy_digest->return_value,32,16);
}

//获取pcr报告值
pcr_report=&(quote_report->pcrComp);
//对比pcr报告和pcr预期值,并根据对比结果设置不同返回值。
if((Memcmp(pcr_result->select.pcrSelect,
           pcr_report->select.pcrSelect,3)==0)
        && (Memcmp(pcr_result->pcrValue,pcr_report->pcrValue,
                   pcr_report->valueSize)==0))
{
    verify_result->name=dup_str("trust verify succeed",0);
}
else
{
    verify_result->name=dup_str("trust verify fail",0);
}
由于当前的赛题平台不支持设备访问,我们在构造题目时,采取了与去年赛题相似的采样报告的方法。因为时间仓促,为了保证赛题稳定,我们在选手解题环境和系统验证环境使用了相同的报告样本和度量值,这就给选手们提供了取巧的余地。选手们只要复制题目运行过程中正确示例的输出,在解题时直接对比这些输出就可以完成解题了。这个是我们赛题设计的不完善之处,并且采用这种方法解题的同学也算是了解了可信度量的基本原理,因此我们认可采用这种方式解题的选手团队,但仅限于这一次,下一次再有类似赛题时,就没有绕路的方法了。

4.未来的计划

在这几次可信赛题出题的过程中,我们总有束手束脚的感觉。因为很多可信机制都需要底层安全机制的支持,而现有的赛题平台在这些方面有所限制。传统的docker模式难以支持底层安全机制,而虚拟机模式虽然可以支持底层安全机制,但是资源消耗较大,大型比赛环境难以使用。为此,我们基于可信3.0的理念,设计了安全可信实训平台,以为可信赛题提供一个具有完整可信链的实训环境。
我们已经制作了安全可信实训平台的样品,有x86版,龙芯版,飞腾版三个版本,未来还可以支持更多的架构。目前,赛题环境适配和赛题开发移植工作正在紧张进行中。新的平台不但可以独立运行,也可以与传统赛题平台对接,提供可信环境下的可信赛题。同时,我们还在设计面向AI、物联网、工控、大数据等场景的大型综合性可信计算赛题。今后,我们希望与同行合作,为大家构建便捷、完整、与实际结合的安全可信实训竞赛环境,为安全可信生态发展和人才培养贡献自己的力量。


“用户信息访问控制”选手解法

作者:浙江工业大学Stinger 黄宇鑫

操作内容:

  1. 修改 instance/server 目录下策略文件 record.list,补全表1中所有记录项对应的客体安全属性。
  2. 修改 src/record_acl/record_acl.cexcept_rule 函数,以在数据读取行为符合例外规则时返回1。

任务一:补全 record.list

首先看 record.list 文件,题目已经给了我们部分记录项的策略,我们需要补充的是 cell  和 email  这两个字段的策略。
仔细阅读题目描述中关于这两个字段的访问控制要求,cell 字段要求 “员工管理权限内同级别、高级别或低一级别员工可查询”,email  字段要求 “员工管理权限内同级别、高级别、低一级别或低两个级别员工可查询”。
结合题目中提到的 “变形BLP访问控制方案” 和 “客体标记” 的计算方式,结合题目提示根据已有的六条策略去编写最后两条策略。
设定对 cellemail  字段的访问控制要求:
  • cell: 员工管理权限内同级别、高级别或低一级别员工可查询。
  • email: 员工管理权限内同级别、高级别、低一级别或低两个级别员工可查询。
我们需要在 record.list 文件末尾添加以下两项:
{
 "name":"cell",
 "isleveladjust":1,
 "isselfdefine":0,
 "class":0,
 "level_fix":0,
 "level_adjust":0 
},
{
 "name":"email",
 "isleveladjust":1,
 "isselfdefine":0,
 "class":0,
 "level_fix":0,
 "level_adjust":-1
}
经过测试通过,六条查询仅剩查询工资失败。

任务二:实现 except_rule 函数

题目要求实现一个例外规则:当读取内容为薪水时,本人可以作为可信对象,读取自己的薪水。
根据题目提示,我们需要修改 src/record_acl/record_acl.c 中的 except_rule 函数。观察函数及其被调用位置的提示信息.
打开 record_acl.c 文件,找到 except_rule 函数,发现这个函数的输入参数包含了记录项名称 (record_name)、读取用户 (read_user) 和记录所属用户 (record_user)。
根据题目要求,我们需要在这个函数中判断:
  1. 记录项名称是否为 “salary”
  2. 读取用户是否与记录所属用户相同
如果两个条件都满足,则符合例外规则,函数返回1。
int except_rule(char * record_name,char * read_user,char * record_user)
{
 int ret;
 // add except rule check here
 if (strcmp(record_name, "salary") == 0 && strcmp(read_user, record_user) == 0) {
        return 1;
    }
 return 0;
}
这段代码首先检查 record_name 是否为 “salary”,如果是,则继续检查读取用户 (read_user) 是否与记录所属用户 (record_user) 相同。如果两个条件都满足,则说明符合例外规则,函数返回1。否则,函数返回0。

编译与测试

完成上述修改后,我们需要在/home/player/cube-userinfo-access/src目录下使用 make 命令编译代码,然后执行 sh record_access.sh 进行测试。观察脚本输出结果,确认不同用户读取数据时,实际获取的数据内容符合题目要求的访问控制策略。
在进行第一次编译时,同时经过排查,直接使用make会出现头文件丢失问题。
[player@engine-1 record_acl]$ make
gcc -g -c -fPIC -DUSER_MODE -I/root/centoscloud/cube-1.3/proc/include -I/root/centoscloud/cube-1.3/include -I/home/player/cube-userinfo-acces/include record_acl.c
record_acl.c:13:25: fatal error: user_define.h: No such file or directory
 #include "user_define.h"
compilation terminated.
make: *** [record_acl.o] Error 1
[player@engine-1 record_acl]$ 
此时确认include文件夹中存在对应的头文件,但无法读取。
打开Makefile文件阅读后猜测与环境变量有关。
FLAGS= -g -shared -o 
INCLUDE= -I$(CUBESYSPATH)/include -I$(CUBE_PATH)/include -I$(CUBEAPPPATH)/include
CFLAGS= -g -c -fPIC -DUSER_MODE $(INCLUDE)
CC=gcc
CCP=g++
PLUGIN=record_acl
PLUGIN_OBJ=
TEST_LIB= -L$(CUBELIBPATH)/lib -lmessage -lmemdb -lconnector -lstruct -lcrypto_func -lpthread
LOCALLIB=-L$(CUBEAPPPATH)/locallib/bin -lstring_func
 
main: lib$(PLUGIN).so
lib$(PLUGIN).so:  $(PLUGIN).o $(PLUGIN_PROC_OBJ) $(INIT_DB_OBJ)
        $(CC) $(FLAGS) lib$(PLUGIN).so $(PLUGIN).o $(PLUGIN_OBJ) $(TEST_LIB)
        mv lib$(PLUGIN).so $(CUBEAPPPATH)/plugin
        cp $(PLUGIN).cfg $(CUBEAPPPATH)/plugin
$(PLUGIN).o: $(PLUGIN).c $(PLUGIN).h
        $(CC) $(CFLAGS) $(PLUGIN).c
clean:
        rm -f lib$(PLUGIN).so
        rm  *.o *~
这里有两种配置环境变量的方式,后来通过浏览~/cube-userinfo-access发现
[player@engine-1 cube-userinfo-access]$ ls
define  exec_def  include  instance  player.sh  plugin  record_access.sh  run_cube.sh  set_env.sh  src
所以可以
1.
export CUBEAPPPATH=/home/player/cube-userinfo-access

2.
cd ~/cube-userinfo-access
sh run_cube.sh
sh set_env.sh
修改之后进行编译,成功。然后执行 sh record_access.sh 进行测试,符合预期。
{
"return_code":"SUCCEED","return_info":"login succeed!
"
}
enter user attach proc!
find user addr!
{
"name":"zhou","ID":"1005","department":"M","position":"CMO","YOF":3,"salary":0,"
cell"
:"**********","email":""}
enter user attach proc!
find user addr!
{
"name":"wang","ID":"1008","department":"R","position":"DM","YOF":4,"salary":2000
0,"cell":"**********","email":""}
exit the proc! 
{
"return_code":"SUCCEED","return_info":"login succeed!
"
}
enter user attach proc!
find user addr!
{
"name":"zhou","ID":"1005","department":"M","position":"CMO","YOF":3,"salary":350
00,"cell":"1350000000","email":"[email protected]"}
enter user attach proc!
find user addr!
{
"name":"wang","ID":"1008","department":"R","position":"DM","YOF":4,"salary":0,"c
ell"
:"**********","email":""}
exit the proc! 
{
"return_code":"SUCCEED","return_info":"login succeed!
"
}
enter user attach proc!
find user addr!
{
"name":"zhou","ID":"1005","department":"M","position":"CMO","YOF":3,"salary":0,"
cell"
:"**********","email":"[email protected]"}
enter user attach proc!
find user addr!
{
"name":"wang","ID":"1008","department":"R","position":"DM","YOF":4,"salary":0,"c
ell"
:"**********","email":""}
exit the proc! 

提交答案

执行 sh player.sh后得到正确答案。


“平台可信认证”选手解法

作者:cameudis

直接编译运行发现没有输出预期内容,所以找到了instance/crypt_hub/cube_err.log文件,查看其中报错:
[player@engine-1 src]$ cat ../instance/crypt_hub/cube_err.log
time: 0.078772 :warninfo: read aspect policy failed -1!time: 0.079465 :errinfo: tcm dev /dev/vtcm1 can't access!time: 0.079473 :errinfo: read plugin 2 error 14267620
time: 0.079508 :errinfo: can'
t find plugin libkey_manage.so!
time: 0.079513 :errinfo: read plugin 3 error 61
time: 0.079543 :errinfo: can't find plugin libkey_manage_server_emu.so!
time: 0.079546 :errinfo: read plugin 4 error 72
time: 0.079575 :errinfo: can'
t find plugin libkey_server_return.so!
time: 0.079579 :errinfo: read plugin 5 error 68
time: 8.091854 :errinfo: proc_router_send_msg: can't find local message target key_manage_server_emutime: 12.121621 :errinfo: proc_router_send_msg: can't find local message target key_manage_server_emutime: 16.161873 :errinfo: proc_router_send_msg: can't find local message target key_manage_server_emu
经过不断搜索字符串和查看编译流程发现,这一题同样需要修复环境变量的问题,包括TCM_PATH, TCM_PLUGINAPPPATH 三个环境变量,同时需要在 src 目录的 Makefile 中加入以上三个模块的编译。
此外,最重要的一点就是修改一些配置文件的 PLUGIN 目录设置。具体是哪些文件可以通过搜索 PLUGIN 字符串搜到。下面介绍我如何摸索出正确的配置。

弯路

本来我以为是把编译后的 PLUGIN 移动到程序会读取的那个目录下即可。crypt_hub 中的 plugin 配置如下:
instance/crypt_hub/plugin_config.cfg
{
        "name":"virtual_node",
        "libname":"virtual_node",
    "init_para":{
        "node_type":1,
        "node_name":"server",
        "domain":"center"
    }
}
{
        "name":"tcm_init",
        "libname":"tcm_libinit"
    "init_para":{
        "tcm_type":1,
        "node_name":"server",
        "dev_name":"/dev/vtcm1"
    }
}
{
        "name":"key_manage",
        "libname":"key_manage"
}
{
        "name":"key_manage_server_emu",
        "libname":"key_manage_server_emu"
}
{
        "name":"key_server_return",
        "libname":"key_server_return"
}
...
搜索其中能够正常加载的模块,可以搜到下面的目录:
[player@engine-1 platform_verify]$ find / -name "*pikcert_verify*" 2>/dev/null
/root/centoscloud/cube_tcmplugin/src/pikcert_verify
/root/centoscloud/cube_tcmplugin/src/pikcert_verify/pikcert_verify.o
/root/centoscloud/cube_tcmplugin/src/pikcert_verify/pikcert_verify.cfg
/root/centoscloud/cube_tcmplugin/src/pikcert_verify/pikcert_verify.c
/root/centoscloud/cube_tcmplugin/src/pikcert_verify/pikcert_verify.h
/root/centoscloud/cube_tcmplugin/plugin/pikcert_verify.cfg
/root/centoscloud/cube_tcmplugin/plugin/libpikcert_verify.so
[player@engine-1 platform_verify]$ ls /root/centoscloud/cube_tcmplugin/plugin/
README                  key_certify.cfg         libexpandstruct_store.so  libpik_casign.so      libremotekey_gen.so      localkey_gen.cfg  pikcert_store.cfg    sessionkey_switch.cfg
create_key.cfg          key_check.cfg           libkey_certify.so         libpik_caverify.so    libremotekey_send.so     pcr_multirw.cfg   pikcert_verify.cfg   tcm_libinit.cfg
ekpub_expandsend.cfg    libcreate_key.so        libkey_check.so           libpik_client.so      libremotekey_store.so    pcr_rw.cfg        quote_report.cfg     uuid_symm_crypt.cfg
ekpub_send.cfg          libekpub_expandsend.so  liblocalkey_gen.so        libpikcert_store.so   libsessionkey_switch.so  pik_casign.cfg    remotekey_gen.cfg
ekpub_store.cfg         libekpub_send.so        libpcr_multirw.so         libpikcert_verify.so  libtcm_libinit.so        pik_caverify.cfg  remotekey_send.cfg
expandstruct_store.cfg  libekpub_store.so       libpcr_rw.so              libquote_report.so    libuuid_symm_crypt.so    pik_client.cfg    remotekey_store.cfg
[player@engine-1 platform_verify]$ cd src/
[player@engine-1 src]$ ls
Makefile   key_event_user  key_manage_hack    key_manage_server_emu  key_server_return  login_user  quote_report_emu
key_event  key_manage      key_manage_server  key_manage_user        login_server       policy_rw   user_label
[player@engine-1 src]$
但我发现这个目录不可写,所以找裁判询问了本题是否有误,得到了否定的回应。于是我开始思考:APP从哪拿到的plugin目录地址?Plugin 目录地址总不会硬编码在可执行文件里,所以一定有一个配置文件或环境变量描述了 APP 会从哪里读取 so 插件。
于是终于找到上面提到的正确做法,也就是在/home/player目录下搜索字符串PLUGIN,并将其中配置不正确的全都改成/home/player/platform_verify/plugin

代码编写

根据文档,我们需要判断三个寄存器的值是否与预期相同,因此首先需要知道预期的值是什么。一种方法是参考去年wp,使用API查询各个policy的值;另一种方法是在下面这个文件中拿到硬编码的值:
database/pcr/policy.list
{
        "type":"GENERAL_RETURN",
        "subtype":"UUID"
}
{
        "name":"trust_boot",
        "return_value":"1b483aa95573a38b95f9f866ff7586ade43a686f165fd7875125583cf4a73de4",
}
{
        "name":"linux_kernel",
        "return_value":"7a4d7b56552b0d20c1f7566eacdfb5232e627c537aba89143a17fc7a92007f6a",
}
{
        "name":"secure_mechanism",
        "return_value":"660ca5ea8b7b7f4256d2bdf30a829da85820376020c1167ee232cc74ed6a126f",
}
{
        "name":"secure_policy",
        "return_value":"8b4877c3ffbda4dfe506785e8cbeedeb7364b50b2b8b4a0fc4c0d53a1bae0fc7",
}
但这些值不论是其本身还是 sm3 hash 过后,都和测试样例中传入的值不符。于是我决定暂时假设测试样例中的数据就是正确答案(下面的第二条样例):
geIbwkh8Ghef/NvTifbD8aMCzSaPDJN40IOfxqCP1eosLcVz3BGsZrMsM344R92dfm2TJf2Lfxu2ti/P9qYOWwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
81 e2 1b c2 48 7c 1a 17 9f fc db d3 89 f6 c3 f1 a3 02 cd 26 8f 0c 93 78 d0 83 9f c6 a0 8f d5 ea
2c 2d c5 73 dc 11 ac 66 b3 2c 33 7e 38 47 dd 9d 7e 6d 93 25 fd 8b 7f 1b b6 b6 2f cf f6 a6 0e 5b
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

geIbwkh8Ghef/NvTifbD8aMCzSaPDJN40IOfxqCP1eosLcVz3BGsZrMsM344R92dfm2TJf2Lfxu2ti/P9qYOW2LICP2RTORHe8PF5iKWi11fvq2kRX6RH6ANNEq6q4Bw
81 e2 1b c2 48 7c 1a 17 9f fc db d3 89 f6 c3 f1 a3 02 cd 26 8f 0c 93 78 d0 83 9f c6 a0 8f d5 ea
2c 2d c5 73 dc 11 ac 66 b3 2c 33 7e 38 47 dd 9d 7e 6d 93 25 fd 8b 7f 1b b6 b6 2f cf f6 a6 0e 5b
62 c8 08 fd 91 4c e4 47 7b c3 c5 e6 22 96 8b 5d 5f be ad a4 45 7e 91 1f a0 0d 34 4a ba ab 80 70
将拿到的这三个结果硬编码进代码,然后使用 Memcmp 将报告中的PCR值与其比较,根据结果判断是否完成验证。代码如下:
BYTE pcr7[]  = {0x81,0xe2,0x1b,0xc2,0x48,0x7c,0x1a,0x17,0x9f,0xfc,0xdb,0xd3,0x89,0xf6,0xc3,0xf1,0xa3,0x02,0xcd,0x26,0x8f,0x0c,0x93,0x78,0xd0,0x83,0x9f,0xc6,0xa0,0x8f,0xd5,0xea};
BYTE pcr11[] = {0x2c,0x2d,0xc5,0x73,0xdc,0x11,0xac,0x66,0xb3,0x2c,0x33,0x7e,0x38,0x47,0xdd,0x9d,0x7e,0x6d,0x93,0x25,0xfd,0x8b,0x7f,0x1b,0xb6,0xb6,0x2f,0xcf,0xf6,0xa6,0x0e,0x5b};
BYTE pcr14[] = {0x62,0xc8,0x08,0xfd,0x91,0x4c,0xe4,0x47,0x7b,0xc3,0xc5,0xe6,0x22,0x96,0x8b,0x5d,0x5f,0xbe,0xad,0xa4,0x45,0x7e,0x91,0x1f,0xa0,0x0d,0x34,0x4a,0xba,0xab,0x80,0x70};

RECORD(GENERAL_RETURN,UUID) * verify_output(RECORD(TCM_KEY_DESC,VERIFY_DESC) * verify_desc,
        RECORD(TCM_PIK_DESC,PCRQUOTE) * quote_report)
{
        RECORD(GENERAL_RETURN,UUID) * verify_result;//待输出的验证结果
        RECORD(GENERAL_RETURN,UUID) *policy_digest;
        TCM_PCR_COMPOSITE * pcr_result;   // 待计算的PCR值
        TCM_PCR_COMPOSITE * pcr_report;   // 报告中的PCR值
        DB_RECORD * db_record;
        UINT32 result;
        pcr_result=Talloc0(sizeof(*pcr_result));
        result = TCM_ExInitPcrComposite(pcr_result); //对PCR值进行初始化
        if(result!=0)
                return -EINVAL;
        NAME2VALUE trust_policy[5] = {
                {"trust_boot",7},
                {"linux_kernel",11},
                {"secure_mechanism",11},
                {"secure_policy",14},
                {NULL,0},
        };

        int i;
        verify_result = Talloc0(sizeof(*verify_result));
        if(verify_result == NULL)
                return -ENOMEM;

        Memcpy(verify_result->return_value,verify_desc->object_uuid,DIGEST_SIZE);
        if(verify_desc->result!=0)
        {
                verify_result->name=dup_str("sign verify fail",0);
        }
        else
        {
                // 从报告中获取pcr值
                pcr_report=&(quote_report->pcrComp);
                printf("yy: size: %dn", pcr_report->valueSize);

                // 与硬编码的三个值进行比较
                if (!Memcmp(pcr_report->pcrValue, pcr7, 32) && !Memcmp((char*)(pcr_report->pcrValue)+32, pcr11, 32) && !Memcmp((char*)pcr_report->pcrValue+64, pcr14, 32)) {
                        verify_result->name=dup_str("trust verify succeed"0);
                } else {
                        verify_result->name=dup_str("trust verify fail"0);
                }

                // Debug
                int a=0, b=0, c=0;
                if (!Memcmp(pcr_report->pcrValue, pcr7, 32)) {
                        printf("pcr7 passn");
                }
                if (!Memcmp(pcr_report->pcrValue+32, pcr11, 32)) {
                        printf("pcr11 passn");
                }
                if (!Memcmp(pcr_report->pcrValue+64, pcr14, 32)) {
                        printf("pcr14 passn");
                }
        }
        return verify_result;
}
直接编译该插件,就通过了本题!也算是偷了一个小懒。




相关阅读



官方WP | 关于“可信度量”赛题的设计与思考
赛前热身|「第十六届全国大学生信息安全竞赛」安全可信赛题介绍

赛前热身第2期|「第十六届全国大学生信息安全竞赛」安全可信赛题

赛前热身第3期|「第十六届全国大学生信息安全竞赛」安全可信赛题


+ + + + + + + + + + + 


官方WP | 可信赛题的创新与线上赛题目解说

原文始发于微信公众号(春秋伽玛):官方WP | 可信赛题的创新与线上赛题目解说

版权声明:admin 发表于 2024年6月12日 下午2:54。
转载请注明:官方WP | 可信赛题的创新与线上赛题目解说 | CTF导航

相关文章