今年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
运行结果