[可信计算] 刷题记录
写在开头
0.重要
先打非预期cat /root/cube-shell/instance/flag_server/flag.list
如果没有这个文件找一下find / -name *flag* 2> /dev/null
1.如何连接题目?
题目类似于下面的样子
连接方案:ssh -p 32325 player@39.106.48.123
然后输入密码就连上了
2.如何找到代码?
一般在~/题目名/src
下面有几个模块,根据题目给的文档找就行了。
3.如何验证答案?
根据题目给的文档,一般是在/题目名
文件夹下有player.sh
,我们采用sh player.sh
即可运行他给的脚本。
4.如何改写代码?
使用服务器自带的vim编辑器进行修改,也可以先cat出来,复制到本地再粘贴上去。
5.vim粘贴事项?
首先你要清空文本,然后输入i
打开input mode,然后输入:set paste
打开粘贴模式,最后Ctrl+Shift+V
进行粘贴。当然要关闭粘贴模式输入:set nopaste
,之所以要打开粘贴模式,是因为粘贴进去会有缩进,导致代码全乱,粘贴模式打开后重新进入vim后自动关闭,需要再次打开。
6.为什么sftp和scp用不了?
因为服务器不支持,这是我觉得最匪夷所思的地方。
必看!!!黑手办法!!!!
经过我的测试,我们发现只要可信计算不是下面这种题
我是有通杀方案的!我们下来来讨论一下通杀(理论让你运行sh player.sh
的题都行)。
首先我们知道,存flag的地方是固定的,因为所有可信计算题目都是一个模子( 本题目为“兵棋“模式新型可信计算赛题,示例在docker环境下运行,基于可信软件基原型Cube-1.3搭建,通过分布式消息驱动机制模拟应用流程与攻防行为。
)cat /root/cube-shell/instance/flag_server/flag.list
这是flag的地方,如果能cat出来直接交flag,cat不出来(没权限的话)就接着看。
1.进入题目的文件夹
2.输入touch /tmp/flag
来在tmp文件夹里面创建flag空文件,便于后续写入,因为代码跑在root下,所以直接mv过来会导致权限还是root
的,无法读取。
3.输入source set_env.sh
来设置编译的环境(这个一般都在doc中有)。
4.cd src/xxxxx
进入xxxx文件夹(题目需要你补全的代码文件夹)
5.vim xxxxxx.c
来进入要修改的c文件
6.找到这个文件里面的init函数,如下图
7.写入system("cat /root/cube-shell/instance/flag_server/flag.list > /tmp/flag");
如下图
8.保存退出:wq
然后当前文件夹下执行make
。
9.cd ../../
来返回到主文件夹
10.sh player.sh
来开启评测,静候评测结束(10秒内不输出东西的时候)。
11.cat /tmp/flag
拿下。
基于挑战码的双向认证1 & 2
详细阅读给的文档,发现是一个让你完成代码片段类的题目。
国密SM1/SCB2,SM4/SMS4,SM7是对称加密,对标 DES, IDEA, AES, RC5, RC6
国密SM2,SM9是基于离散对数的非对称加密,对标ECC, ECDH, DAS, DH
国密SM3是杂凑(哈希)对标SHA256, MD5, SHA512, SHA-1, SHA-2
所以可以理解为让你补一个哈希处理的函数。
接着读题,让你补一个特定的函数,就去找这个函数。
这是函数最初的样子
int proc_login_response(void * sub_proc,void * recv_msg)
{
int ret;
RECORD(USER_DEFINE,CLIENT_STATE) * client_state;
RECORD(USER_DEFINE,LOGIN) * login_info;
RECORD(USER_DEFINE,RETURN) * return_info;
void * new_msg;
// get the store data in first step
client_state = proc_share_data_getpointer();
if(client_state==NULL)
return -EINVAL;
// get server return login data and copy nonce B
ret=message_get_record(recv_msg,&login_info,0);
if(ret<0)
return ret;
Memcpy(client_state->nonceB,login_info->nonce,DIGEST_SIZE);
// compute Mb‘ value
// add your code here!
// compare Mb and Mb'
if( Memcmp(Buf+DIGEST_SIZE*3,login_info->passwd,DIGEST_SIZE) != 0)
{
// server verify failed, build a server verify failed message
client_state->curr_state=ERROR;
proc_share_data_setpointer(client_state);
return_info=Talloc0(sizeof(*return_info));
if(return_info==NULL)
return -ENOMEM;
return_info->return_code=SERVERERR;
return_info->return_info=dup_str("server verify failed!\n",0);
new_msg=message_create(TYPE_PAIR(USER_DEFINE,RETURN),recv_msg);
if(new_msg==NULL)
return -EINVAL;
ret=message_add_record(new_msg,return_info);
if(ret<0)
return ret;
ret=ex_module_sendmsg(sub_proc,new_msg);
return ret;
}
// server verify succeed, now prepare to compute the response data
// reponse phrase: compute the Ma value start
// add your code here!
// compute Ma value end
Memset(login_info->nonce,0,DIGEST_SIZE);
// compute the response data end
// add the login info in message and send it
new_msg=message_create(TYPE_PAIR(USER_DEFINE,LOGIN),NULL);
if(new_msg==NULL)
return -EINVAL;
ret=message_add_record(new_msg,login_info);
if(ret<0)
return ret;
ret=ex_module_sendmsg(sub_proc,new_msg);
// challenge client_state value and store it
if(ret >=0)
client_state->curr_state=RESPONSE;
proc_share_data_setpointer(client_state);
return ret;
}
我们先补第一块
// compute Mb‘ value
// add your code here!
由于Mb' = SM3(key, rA||rB)
我们还不知道右边的形式是啥样,我们可以参考login_server的源码,搜索sm3,找到如下结果
Memset(Buf,0,DIGEST_SIZE*4);
Strncpy(Buf,user_state->passwd,DIGEST_SIZE);
Memcpy(Buf+DIGEST_SIZE,user_state->nonceA,DIGEST_SIZE);
Memcpy(Buf+DIGEST_SIZE*2,user_state->nonceB,DIGEST_SIZE);
calculate_context_sm3(Buf,DIGEST_SIZE*3,login_info->passwd);
Memcpy(login_info->nonce,user_state->nonceB,DIGEST_SIZE);
我们先找calculate_context_sm3
的函数原型,先在根目录find头文件然后进去grep即可。
[player@engine-1 root]$ cat ./centoscloud/cube-1.3/include/crypto_func.h | grep calculate_context_sm3
int calculate_context_sm3(BYTE* context, int context_size, BYTE *SM3_hash);
显然第一个是输入,第二个是输入的长度,第三个是返回值,第三个应该传入返回指针。
分析login_server的代码,DIGEST_SIZE可以认为是一组数据的长度,Buf是缓冲区,用来拼凑数据的,这块经过对比后显然是服务端用来计算Mb的,我们就知道了,SM3(key, rA||rB)
的意思其实就是把三个成一个整体,从左到右按顺序,我们就可以把这个复制过来,改一改,作为我们补写的代码:
Memset(Buf,0,DIGEST_SIZE*4);
Strncpy(Buf,client_state->key,DIGEST_SIZE);
Memcpy(Buf+DIGEST_SIZE,client_state->nonceA,DIGEST_SIZE);
Memcpy(Buf+DIGEST_SIZE*2,client_state->nonceB,DIGEST_SIZE);
calculate_context_sm3(Buf,DIGEST_SIZE*3,Buf+DIGEST_SIZE*3);
注意第二行不是client_state->passwd
,因为passwd其实是SM3(key, rA||rB)的结果,而key才是原始key
,在客户端代码区找key就知道它在client_state
我们接着看第二块
// reponse phrase: compute the Ma value start
// add your code here!
显然是让我们补充Ma的计算,计算方法是MA=SM3(key,rB)
我们参考服务端的Ma'的计算验证
Memset(Buf,0,DIGEST_SIZE*2);
Strncpy(Buf,user_state->passwd,DIGEST_SIZE);
Memcpy(Buf+DIGEST_SIZE,user_state->nonceB,DIGEST_SIZE);
calculate_context_sm3(Buf,DIGEST_SIZE*2,Buf+DIGEST_SIZE*2);
然后改成客户端的
Memset(Buf,0,DIGEST_SIZE*2);
Strncpy(Buf,client_status->passwd,DIGEST_SIZE);
Memcpy(Buf+DIGEST_SIZE,user_state->nonceB,DIGEST_SIZE);
calculate_context_sm3(Buf,DIGEST_SIZE*2, login_info->passwd);
为什么把结果放在login_info->passwd
呢?因为可以注意到服务端代码,login_info是互相传递的。
完整函数代码
int proc_login_response(void * sub_proc,void * recv_msg)
{
int ret;
RECORD(USER_DEFINE,CLIENT_STATE) * client_state;
RECORD(USER_DEFINE,LOGIN) * login_info;
RECORD(USER_DEFINE,RETURN) * return_info;
void * new_msg;
// get the store data in first step
client_state = proc_share_data_getpointer();
if(client_state==NULL)
return -EINVAL;
// get server return login data and copy nonce B
ret=message_get_record(recv_msg,&login_info,0);
if(ret<0)
return ret;
Memcpy(client_state->nonceB,login_info->nonce,DIGEST_SIZE);
// compute Mb‘ value
// add your code here!
Memset(Buf,0,DIGEST_SIZE*4);
Strncpy(Buf,client_state->key,DIGEST_SIZE);
Memcpy(Buf+DIGEST_SIZE,client_state->nonceA,DIGEST_SIZE);
Memcpy(Buf+DIGEST_SIZE*2,client_state->nonceB,DIGEST_SIZE);
calculate_context_sm3(Buf, DIGEST_SIZE*3, Buf+DIGEST_SIZE*3);
// compare Mb and Mb'
if( Memcmp(Buf+DIGEST_SIZE*3,login_info->passwd,DIGEST_SIZE) != 0)
{
// server verify failed, build a server verify failed message
client_state->curr_state=ERROR;
proc_share_data_setpointer(client_state);
return_info=Talloc0(sizeof(*return_info));
if(return_info==NULL)
return -ENOMEM;
return_info->return_code=SERVERERR;
return_info->return_info=dup_str("server verify failed!\n",0);
new_msg=message_create(TYPE_PAIR(USER_DEFINE,RETURN),recv_msg);
if(new_msg==NULL)
return -EINVAL;
ret=message_add_record(new_msg,return_info);
if(ret<0)
return ret;
ret=ex_module_sendmsg(sub_proc,new_msg);
return ret;
}
// server verify succeed, now prepare to compute the response data
// reponse phrase: compute the Ma value start
// add your code here!
Memset(Buf,0,DIGEST_SIZE*3);
Strncpy(Buf,client_state->key,DIGEST_SIZE);
Memcpy(Buf+DIGEST_SIZE,client_state->nonceB,DIGEST_SIZE);
calculate_context_sm3(Buf,DIGEST_SIZE*2, login_info->passwd);
// compute Ma value end
Memset(login_info->nonce,0,DIGEST_SIZE);
// compute the response data end
// add the login info in message and send it
new_msg=message_create(TYPE_PAIR(USER_DEFINE,LOGIN),NULL);
if(new_msg==NULL)
return -EINVAL;
ret=message_add_record(new_msg,login_info);
if(ret<0)
return ret;
ret=ex_module_sendmsg(sub_proc,new_msg);
// challenge client_state value and store it
if(ret >=0)
client_state->curr_state=RESPONSE;
proc_share_data_setpointer(client_state);
return ret;
}
最后,别忘了在代码文件夹下make
,然后返回主目录,执行sh player.sh
就拿到了flag。
Biba
非预期
userdefine 1 & 2
ez
代码补全后
int proc_access_write(void * sub_proc,void * recv_msg)
{
int ret;
RECORD(RECORD_DEFINE,WRITE) * record_write;
RECORD(LABEL_DEFINE,USER) * user_label;
MSG_EXPAND * msg_expand;
void * new_msg;
ret=message_get_record(recv_msg,&record_write,0);
if(ret<0)
return ret;
ret=message_remove_expand(recv_msg,TYPE_PAIR(LABEL_DEFINE,USER),&msg_expand);
if(ret<0)
return ret;
if(msg_expand==NULL)
{
print_cubeerr("can't find user attached!\n");
return -EINVAL;
}
user_label=msg_expand->expand;
if(user_label->role == 1)
{
//admin
}else
{
if(strcmp(record_write->segment, "admin_info") == 0)
{
new_msg=message_create(TYPE_PAIR(USER_DEFINE,RETURN),recv_msg);
RECORD(USER_DEFINE,RETURN) * err_return = Talloc0(sizeof(*err_return));
if(err_return==NULL)
return -ENOMEM;
err_return->return_info=dup_str("write permission denied!",0);
err_return->return_code=NOACCESS;
message_add_record(new_msg,err_return);
ret=ex_module_sendmsg(sub_proc,new_msg);
return ret;
}
}
ret=ex_module_sendmsg(sub_proc,recv_msg);
return ret;
}
int proc_access_read(void * sub_proc,void * recv_msg)
{
int ret;
RECORD(RECORD_DEFINE,RECORD) * record_data;
RECORD(LABEL_DEFINE,USER) * user_label;
MSG_EXPAND * msg_expand;
void * new_msg;
ret=message_get_record(recv_msg,&record_data,0);
if(ret<0)
return ret;
ret=message_remove_expand(recv_msg,TYPE_PAIR(LABEL_DEFINE,USER),&msg_expand);
if(ret<0)
return ret;
if(msg_expand==NULL)
{
print_cubeerr("can't find user attached!\n");
return -EINVAL;
}
user_label=msg_expand->expand;
// add read access control code here
// filter the non_access data in record_data
// if you want to erase an elem in record_data, just let
// record_data->xxx = NULL
if(user_label->role == 1)
{
//admin
}else
{
record_data->admin_info = NULL;
}
new_msg=message_create(TYPE_PAIR(RECORD_DEFINE,RECORD),recv_msg);
if(new_msg==NULL)
return -EINVAL;
message_add_record(new_msg,record_data);
ret=ex_module_sendmsg(sub_proc,new_msg);
return ret;
}
写在最后
结果今年国赛是有人检查+不给你shell的😂
评论已关闭