今年frank因为种种原因未能参加,虽然成绩不如往年但还是挺满意的 今年py的越来越多了我* 
 
目录 
Web和Pwn都没做出来(
 
Misc 火锅链观光打卡 正常做几道题集齐7种食材即可
flag: flag{y0u_ar3 hotpot_K1ng}
神秘文件 这题有点。。。
Part1: 点开属性,发现一段密文QFCfpPQ6ZymuM3gq和密钥lanjing,提示是Bifid加密。
Part2: 第二页左上角展开之后,点击“这里”会打开一个doc文件,后面的文字被隐藏了,于是用Word删除文字格式还原,得到密文mQPinNS6Xtm1JGJs。文字提示Caeser,即用ROT解密,key为16。
Part3: 打开ppt的时候提示有宏,打开VB脚本,阅读脚本可知是RC4加密,无密钥,base64解码RC4解码再base64解码
Part4: 第三页荧光笔手写的密文UGF5dDQ6NmYtNDA=是base64
Part5: 第五页Notes有密文和提示N轮base64解密
Part6: 第五页缩小后,左上角有缩小的密文UGFyVDY6ZC0y base64解密
Part7: 打开窗体,第四页有密文HRSFIQp9ZwWvZj==,提示ROT13并勾选所有,base64解密
Part8: 点开模版,找到第三张删除背景后,根据提示得到密文,base64解密
Part9: binwalk 提取,找到一堆照片,其中有一张PPT没有的furry图,左下角有密文base64,用解码
Part10: 第4页的Comments有一段对话,给出了密文ZYWJbIYnFhq9密钥furry,用Vigenere加密
拼接10个part得到flag。
flag: flag{e675efb3-346f-405f-90dd-2622b387edee9}
通风机 
找了一小时mwp打开方法然后摸鱼的时候发现不用打开…
 
拿到1通风机监控.mwp,没见过的文件格式。先用binwalk提取,然后strings提取字符串,得到一串可疑字符ZmxhZ3syNDY3Y2UyNi1mZmY5LTQwMDgtOGQ1NS0xN2RmODNlY2JmYzJ9, 用base64解码后即获得flag。
flag: flag{2467ce26-fff9-4008-8d55-17df83ecbfc2}
Power Trajectory Diagram 该题目给出了index,input和对应的trace,trace是5000个点取样功耗。对每个index,将40种input对应的trace功耗曲线计算平均后,找到偏差值最大的input,该input即为当前index的密钥。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 import  numpy as  npimport  matplotlib.pyplot as  pltdata = np.load('data.npz' ) index = data['index' ] input_data = data['input' ] trace = data['trace' ] key = ['' ] * 13  for  i in  range (13 ):         idx = np.where(index == i)[0 ]     traces = trace[idx]     inputs = input_data[idx]          unique_inputs = np.unique(inputs)     avg_traces = []     for  ui in  unique_inputs:         ui_traces = traces[inputs == ui]         avg_trace = np.mean(ui_traces, axis=0 )         avg_traces.append(avg_trace)     avg_traces = np.array(avg_traces)               max_diff = 0      best_input = ''      for  j in  range (len (unique_inputs)):         for  k in  range (j+1 , len (unique_inputs)):             diff = np.linalg.norm(avg_traces[j] - avg_traces[k])             if  diff > max_diff:                 max_diff = diff                 best_input = unique_inputs[j]          key[i] = best_input print ("Recovered Key:" , '' .join(key))
 
该脚本不能完全解析,需要部分人工观察(例如ciscm应该为ciscn
Crypto 古典密码 密文AnU7NnR4NassOGp3BDJgAGonMaJayTwrBqZ3ODMoMWxgMnFdNqtdMTM9
一开始Cyberchef提示是base64,尝试后无果。于是尝试所有常见古典密码,最后发现atbash密码解密后再base64解密的结果和可能是flag。格式非常像uuid且开头flag错位,显然是栅栏密码。
flag: flag{b2bb0873-8cae-4977-a6de-0e298f0744c3}
hash 在python2.7中,阅读python可知,hash的加密符合以下函数
1 2 3 4 5 6 7 long  long  hash (unsigned  char  k[], len) {     unsigned  long  long  x = k[0 ] << 7 ;     for  (int  i = 0 ; i < len; i++)         x = (x * 1000003 ) ^ k[i];     return  (long  long )(x ^ len); } 
 
根据提供的 hash(key) 的值,通过以下代码预处理后两个byte的所有可能:
1 2 3 4 5 6 7 8 9 10 11 12 for  (int  p7 = 0 ; p7 < 256 ; p7++){     a[p7] = 7457312583301101236llu  ^ p7;     a[p7] *= 16109806864799210091llu ; } for  (int  p7 = 0 ; p7 < 256 ; p7++)    for  (int  p6 = 0 ; p6 < 256 ; p6++)     {         unsigned  long  long  t = a[p7] ^ p6;         t *= 16109806864799210091llu ;         b[t / 1000 ] = p6;     } 
 
之后通过以下代码暴力前四个byte:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 for  (int  i = 0 ; i < 256 ; i++, printf ("%d\n" , i))    for  (int  j = 0 ; j < 256 ; j++)         for  (int  k = 0 ; k < 256 ; k++)             for  (int  l = 0 ; l < 256 ; l++)             {                 unsigned  long  long  x = i << 7 ;                 x = (x * 1000003 ) ^ i;                 x = (x * 1000003 ) ^ j;                 x = (x * 1000003 ) ^ k;                 x = (x * 1000003 ) ^ l;                 x = (x * 1000003 );                 if  (b.count (x/1000 ) > 0 )                 {                     printf ("%02x %02x %02x %02x\n" , i, j, k, l);                 }             } 
 
最后暴力后三个byte:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 for  (int  p1 = 0 ; p1 < 256 ; p1++)    for  (int  p2 = 0 ; p2 < 256 ; p2++)         for  (int  p3 = 0 ; p3 < 256 ; p3++)         {             unsigned  long  long  x = 0x5d  << 7 ;             x = (x * 1000003 ) ^ 0x5d ;             x = (x * 1000003 ) ^ 0x8c ;             x = (x * 1000003 ) ^ 0xf0 ;             x = (x * 1000003 ) ^ 0x3f ;             x = (x * 1000003 ) ^ p1;             x = (x * 1000003 ) ^ p2;             x = (x * 1000003 ) ^ p3;             x ^= 7 ;             if  ((long  long )x == 7457312583301101235ll )                 printf ("%02x %02x %02x\n" , p1, p2, p3);         } 
 
得到key为\x5d\x8c\xf0\x3f\x5a\x08\x52,之后按题目解密即可。
用户信息访问控制 阅读理解题,按照文档实现即可。
record.list
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 { 	"name":"cell", 	"isleveladjust":1, 	"isselfdefine":0, 	"class":0, 	"level_fix":0, 	"level_adjust":-1 } { 	"name":"email", 	"isleveladjust":1, 	"isselfdefine":0, 	"class":0, 	"level_fix":0, 	"level_adjust":-2 } 
 
record_acl.c
1 2 3 4 5 if  (strcmp (record_name, "salary" ) == 0 ) {	if  (strcmp (read_user, record_user) == 0 ) { 		return  1 ; 	} } 
 
平台可信认证 代码拉下来发现是个git仓库。 需要补全的是key_server_return.c中的verify_output()。 查找git changes,发现有一个删除了的event_judge.c,内容和需要补全的代码几乎完全一致。 修改代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 else { 	 	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  NULL ; 		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_report=&(quote_report->pcrComp); 	 	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 ); 	} } 
 
Reverse asm_re 阅读源码可知,是对flag,进行乘0x50、加0x14、异或0x4D、加0x1E,最后与unk_100003F10比对。该数组使用小端序,将四字节合并为一个int后,逆向解密可得flag。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 const  int  merged_array[] = {    0x00001FD7 ,      0x000021B7 ,      0x00001E47 ,      0x00002027 ,      0x000026E7 ,      0x000010D7 ,      0x00001127 ,      0x00002007 ,      0x000011C7 ,      0x00001E47 ,      0x00001017 ,      0x00001017 ,      0x000011F7 ,      0x00002007 ,      0x00001037 ,      0x00001107 ,      0x00001F17 ,      0x000010D7 ,      0x00001017 ,      0x00001017 ,      0x00001F67 ,      0x00001017 ,      0x000011C7 ,      0x000011C7 ,      0x00001017 ,      0x00001FD7 ,      0x00001F17 ,      0x00001107 ,      0x00000F47 ,      0x00001127 ,      0x00001037 ,      0x00001E47 ,      0x00001037 ,      0x00001FD7 ,      0x00001107 ,      0x00001FD7 ,      0x00001107 ,      0x00002787    }; int  main () {     for  (int  i = 0 ; i < 38 ; i++)         printf ("%c" , (((merged_array[i]-0x1e )^0x4d )-0x14 )/0x50 ); } 
 
androidso_re 用jadex反编译,点开flag验证函数,发现是DES加密后base64,密文在inspect函数,密钥key和初始化向量IV从Secret_entrance.so中的函数getiv()和getkey()获得。于是逆向Secret_entrance.so。
get_fixediv()阅读反编译代码后得知,将密文F2IjBoh1mRW= ROT16后再base64解密,得到iv Wf3DLups
getkey() 则是将密文TFSecret用RC4解密,密钥为YourRC4Key(密钥提示了加密算法),解密后再跟038933b8540c206a异或,得到keyA8UdWaeq
最后DES解密,获得flag
flag: flag{188cba3a5c0fbb2250b5a2e590c391ce}
whereThel1b 经过观察,不难发现,只改变输入的某一位的情况下,输出也只会有其中的一两位发生变化:
1 2 3 4 5 6 7 >>>  whereThel1b.trytry(b'123456789' )[75 , 88 , 79 , 122 , 74 , 76 , 82 , 52 , 66 , 126 , 96 , 48 ] >>>  whereThel1b.trytry(b'12345a789' )[75 , 88 , 79 , 122 , 74 , 76 , 81 , 110 , 66 , 126 , 96 , 48 ] >>>  whereThel1b.trytry(b'12a45a789' )[75 , 88 , 76 , 104 , 74 , 76 , 81 , 110 , 66 , 126 , 96 , 48 ] >>> 
 
所以我们可以有理有据地猜测,在输入长度一定的情况下,输入中的每一位是互不影响的。并且可以注意到:
1 2 3 4 5 >>>  whereThel1b.trytry(b'12a45a789fsdjkvjklsjeoru203uflksdj' )[85 , 100 , 80 , 106 , 94 , 100 , 73 , 113 , 93 , 100 , 113 , 16 , 87 , 78 , 70 , 121 , 105 , 93 , 114 , 21 , 113 , 79 , 89 , 85 , 106 , 33 , 118 , 66 , 102 , 24 , 95 , 47 , 110 , 108 , 87 , 97 , 112 , 112 , 114 , 126 , 66 , 45 , 82 , 74 , 11  3 , 100 , 30 , 61 ]>>>  bytes (_)b'UdPj^dIq]dq\x10WNFyi]r\x15qOYUj!vBf\x18_/nlWappr~B-RJqd\x1e=' 
 
就是说,输入会经过 base64 转换,长度会变成原来的 4/3 倍。所以 flag 的长度就是 len(encry) / 4 * 3,即 42。
既然每个字符之间互不影响,我们可以考虑用模拟退火来做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 import  randomimport  mathimport  whereThel1bdef  shared (lhs, rhs ):    return  sum ([ x == y for  x, y in  zip (lhs, rhs) ]) encry = [108 , 117 , 72 , 80 , 64 , 49 , 99 , 19 , 69 , 115 , 94 , 93 , 94 , 115 , 71 , 95 , 84 , 89 , 56 , 101 , 70 , 2 , 84 , 75 , 127 , 68 , 103 , 85 , 105 , 113 , 80 , 103 , 95 , 67 , 81 , 7 , 113 , 70 , 47 , 73 , 92 , 124 , 93 , 120 , 104 , 108 , 106 , 17 , 80 , 102 , 101 , 75 , 93 , 68 , 121 , 26 ] flag = [ 0  ] * 42  ALPHABET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&()*+,-./:;<=>?@[]^_`{|}~'  t = 0.7  i = 0  flag_val = 0  while  True :    t *= 0.99998      i += 1      if  i & 511  == 0 :         print (bytes (flag), flag_val, t)     current = flag[:]     j = random.randrange(0 , len (current))     current[j] = ord (random.choice(ALPHABET))     seed = random.randrange(0 , 1  << 64 )     current_val = shared(whereThel1b.trytry(bytes (current)), encry)     random.seed(seed)     delta = current_val - flag_val     if  math.exp(delta / t) > random.random():         flag_val = current_val         flag = current 
 
运行结果