-
-
[原创]第三题 七十二疑冢
-
2018-12-6 23:38 4043
-
题目逻辑比较清晰,不需要太多逆向工作,main函数逻辑如下:
int __cdecl main(int argc, const char **argv, const char **envp) { unsigned int basekey_len; // kr00_4 char *data_; // edx signed int i; // esi char *pp; // eax char *data_1; // ecx signed int ctr_4; // edi char basekey[139]; // [esp+10h] [ebp-A0h] char v11; // [esp+9Bh] [ebp-15h] char plaintext[16]; // [esp+9Ch] [ebp-14h] strcpy( basekey, "“Perfection is achieved not when you have nothing more to add, but when you have nothing left to take away.”--Antoin" "e de Saint - Exupery"); v11 = 0; basekey_len = strlen(basekey); printf("请输入序列号!"); printf("////当且仅当回显“序列号输入正确”时才算破解成功\n"); printf("----------------------------------------------------\n"); printf("序列号:"); if ( getinput() ) { printf("\n\nInput invalid!\n\n"); exit(0); } data_ = &d1[1]; i = 0; do { // genkey if ( (unsigned __int8)(1 << (7 - (i & 7))) & (unsigned __int8)unhex[(unsigned int)i >> 3] )// by bit { pp = &basekey[i + 1]; data_1 = data_; ctr_4 = 4; do { *(pp - 1) ^= *(data_1 - 1); *pp ^= *data_1; pp[1] ^= data_1[1]; pp[2] ^= data_1[2]; data_1 += 4; pp += 4; --ctr_4; } // xor 16 while ( ctr_4 ); } ++i; // bit = 0, nothing; // bit = 1, xor 16 byte; data_ += 16; } while ( i < 72 ); // 9*8 = 72 bit *(_DWORD *)plaintext = 0x7AB392EC; *(_DWORD *)&plaintext[4] = 0x565BFB02; *(_DWORD *)&plaintext[8] = 0xBF433269; *(_DWORD *)&plaintext[12] = 0xE27C8D52; encrypt(plaintext, basekey, basekey_len); if ( plaintext[14] || plaintext[15] ) printf("\n\n不对哦~~~\n\n"); else printf("\n\n%s\n\n", plaintext); getc(); getc(); return 0; }
逻辑很清晰,拿到9字节的输入后,根据对应的72bit生成key,然后加密已知明文,要求所得密文是“序列号输入正确”。同时可以看到,key虽然长度是138,但在生成的过程中最多只改变前87个字节。
加密函数流程也很简单,
void __cdecl encrypt(char *dst, char *src, unsigned int len) { char *p; // eax unsigned int i; // edx int xor; // edi _BYTE *next; // eax int idx; // edi char *item; // ecx signed int v9; // esi char v10; // bl char v11; // bl p = dst; i = 0; if ( len ) { do { xor = (unsigned __int8)*p ^ (unsigned __int8)src[i]; next = p + 1; idx = 16 * xor; item = &d2[idx + 1]; v9 = 3; do { v10 = *next ^ *(item - 1); item += 5; *(next - 1) = v10; v11 = next[1] ^ *(item - 5); next += 5; *(next - 5) = v11; *(next - 4) = *(next - 3) ^ *(item - 4); *(next - 3) = *(next - 2) ^ *(item - 3); --v9; *(next - 2) = *(next - 1) ^ *(item - 2); } while ( v9 ); p = dst; ++i; dst[15] = d2[idx + 15]; } while ( i < len ); } }
138轮的操作,实际上后面138-87=51轮是固定的。
可以用python模拟一下这key生成和加密两步操作,
def genkey(x): ret = [] for i in wtf[:87]: ret.append(i) bb = x for i in range(len(bb)): for j in range(16): ret[i+j] ^= x[i]*d1[i*16+j] return ret def enc(plain, y, round=138): assert len(y) == 138 ret = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16] for i in range(16): ret[i] = plain[i] for i in y[:round]: idx = ret[0] ^ i idx *= 16 for j in range(15): ret[j] = ret[j+1] ^ d2[idx+j] ret[15] = d2[idx+15] v12 = [236, 146, 179, 122, 2, 251, 91, 86, 105, 50, 67, 191, 82, 141, 124, 226] plain = [236, 146, 179, 122, 2, 251, 91, 86, 105, 50, 67, 191, 82, 141, 124, 226] wtf = [161, 176, 80, 101, 114, 102, 101, 99, 116, 105, 111, 110, 32, 105, 115, 32, 97, 99, 104, 105, 101, 118, 101, 100, 32, 110, 111, 116, 32, 119, 104, 101, 110, 32, 121, 111, 117, 32, 104, 97, 118, 101, 32, 110, 111, 116, 104, 105, 110, 103, 32, 109, 111, 114, 101, 32, 116, 111, 32, 97, 100, 100, 44, 32, 98, 117, 116, 32, 119, 104, 101, 110, 32, 121, 111, 117, 32, 104, 97, 118, 101, 32, 110, 111, 116, 104, 105, 110, 103, 32, 108, 101, 102, 116, 32, 116, 111, 32, 116, 97, 107, 101, 32, 97, 119, 97, 121, 46, 161, 177, 45, 45, 65, 110, 116, 111, 105, 110, 101, 32, 100, 101, 32, 83, 97, 105, 110, 116, 32, 45, 32, 69, 120, 117, 112, 101, 114, 121] tail = [110, 103, 32, 108, 101, 102, 116, 32, 116, 111, 32, 116, 97, 107, 101, 32, 97, 119, 97, 121, 46, 161, 177, 45, 45, 65, 110, 116, 111, 105, 110, 101, 32, 100, 101, 32, 83, 97, 105, 110, 116, 32, 45, 32, 69, 120, 117, 112, 101, 114, 121] def dec(xx): g = [-1]*87 + tail idx = -1 tmp = [] for i in xx: tmp.append(i) for i in range(len(g)): tt = tmp[15] for j in range(len(d2)): if j % 16 == 15 and d2[j] == tt: idx = j - 15 assert idx != -1 for k in range(15): tmp[15-k] = tmp[15-k-1] ^ d2[idx+15-k-1] tmp[0] = (idx/16) ^ g[137-i] return tmp
其中dec
可以把后面51轮固定操作倒推掉。
要求输出中文,也就是,
In [795]: u'序列号输入正确'.encode('gbk') Out[795]: '\xd0\xf2\xc1\xd0\xba\xc5\xca\xe4\xc8\xeb\xd5\xfd\xc8\xb7' In [796]: ans = map(ord, u'序列号输入正确'.encode('gbk')) + [0,0,] In [797]: ans Out[797]: [208, 242, 193, 208, 186, 197, 202, 228, 200, 235, 213, 253, 200, 183, 0, 0]
这里有两张表,d1和d2,d1用来生成key,d2用于加密过程。观察d2,其中几列明显有规律,第10、11两列看起来不规律。
整体流程中只有异或操作,不妨看看d2[:,10]
是否在GF(2)上线性。
sage: a = [] sage: b = [] sage: c = [] sage: for i in range(256): ....: tmp = [1&(d2[i*16+10]>>j) for j in range(8)] ....: a.append([1&(i>>j) for j in range(8)]) ....: c.append(tmp) ....: sage: aa = matrix(GF(2), a) sage: cc = matrix(GF(2), c) sage: bb = aa.solve_right(cc) sage: bb [0 0 1 0 1 0 0 0] [0 0 0 1 0 1 0 0] [0 0 0 0 1 0 1 0] [0 0 0 0 0 1 0 1] [0 0 0 0 0 0 1 0] [1 0 0 0 0 0 0 1] [0 1 0 0 0 0 0 0] [0 0 1 0 0 0 0 0]
果然是线性的,11列同理。
所以整个流程都是线性的,严格来说明文到密文是线性的,但题目中明文是固定的,这里可以试试看key到密文是不是线性的。只修改key中的固定位置pos的一个bit,看结果中的bit如何变化,如果这种变化跟pos之外的位置上是0是1无关,那么我们就可以得到key和密文的线性关系。
In [718]: b00 = [bits(i) for i in en2(v12, en1([0]*71+[0]), 87)] In [719]: b01 = [bits(i) for i in en2(v12, en1([0]*71+[1]), 87)] In [720]: b10 = [bits(i) for i in en2(v12, en1([1]*71+[0]), 87)] In [721]: b11 = [bits(i) for i in en2(v12, en1([1]*71+[1]), 87)] ... In [725]: for i in range(16): ...: for j in range(8): ...: if b00[i][j] != b01[i][j]: ...: print (i,j), ...: ...: (0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (0, 5) (1, 2) (1, 3) (2, 0) (2, 2) (2, 3) (2, 4) (2, 6) (2, 7) (3, 0) (3, 2) (3, 5) (3, 7) (4, 0) (4, 2) (4, 3) (4, 5) (4, 7) (5, 0) (5, 2) (5, 3) (5, 4) ( 5, 5) (6, 2) (6, 3) (6, 7) (7, 0) (7, 3) (7, 5) (7, 6) (8, 0) (8, 1) (8, 3) (8, 4) (8, 6) (8, 7) (9, 0) (9, 3) (9, 4) (10, 1) (10, 5) (11, 2) (11, 3) (11, 6) (12, 0) (12, 2) (12, 3) (12, 5) (12, 6) (13, 1) (13, 3) (13, 5) (13, 7) (14, 0) (14, 1) (14, 2) (14, 3) (14, 6) (15, 1) (15, 6) In [726]: for i in range(16): ...: for j in range(8): ...: if b10[i][j] != b11[i][j]: ...: print (i,j), ...: ...: (0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (0, 5) (1, 2) (1, 3) (2, 0) (2, 2) (2, 3) (2, 4) (2, 6) (2, 7) (3, 0) (3, 2) (3, 5) (3, 7) (4, 0) (4, 2) (4, 3) (4, 5) (4, 7) (5, 0) (5, 2) (5, 3) (5, 4) ( 5, 5) (6, 2) (6, 3) (6, 7) (7, 0) (7, 3) (7, 5) (7, 6) (8, 0) (8, 1) (8, 3) (8, 4) (8, 6) (8, 7) (9, 0) (9, 3) (9, 4) (10, 1) (10, 5) (11, 2) (11, 3) (11, 6) (12, 0) (12, 2) (12, 3) (12, 5) (12, 6) (13, 1) (13, 3) (13, 5) (13, 7) (14, 0) (14, 1) (14, 2) (14, 3) (14, 6) (15, 1) (15, 6)
可以看到,虽然前面71个bit不同,但最后一位的bit变化带来的结果变化是一致的。
所以现在的加密过程等效于方程AX+B=Y。其中X是key,B是key全为0时的Y,A就是关系阵,dec(ans)
可以拿到题目要求的Y,之后解线性方程就可以拿到我们要的X。
先拿Y和B,
In [767]: for i in b00: ...: for j in i: ...: print j,',' , ...: ...: ...: 1 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 1 , 0 , 1 , # B In [770]: ma = de2(ans) In [771]: mab = [bits(i) for i in ma] In [772]: mab Out[772]: [[0, 1, 0, 0, 0, 1, 1, 1], [0, 1, 0, 0, 1, 1, 0, 1], [1, 1, 0, 1, 1, 1, 0, 1], [0, 1, 0, 0, 0, 1, 0, 0], [0, 1, 1, 1, 1, 1, 0, 0], [1, 1, 1, 0, 1, 0, 1, 0], [0, 1, 0, 0, 0, 1, 0, 0], [0, 0, 1, 0, 1, 1, 0, 0], [1, 0, 0, 1, 1, 1, 1, 0], [1, 1, 1, 0, 1, 1, 0, 0], [1, 0, 1, 0, 0, 1, 1, 0], [0, 0, 0, 1, 1, 0, 0, 1], [0, 0, 1, 1, 1, 0, 1, 0], [0, 1, 1, 0, 1, 0, 0, 1], [0, 0, 1, 1, 0, 0, 1, 1], [0, 0, 1, 0, 1, 0, 1, 1]] In [773]: for i in mab: ...: for j in i: ...: print j,',' , ...: ...: ...: ...: 0 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 0 , 1 , 1 , # Y
再遍历key的每一个bit,拿到A,
tbl = [0]*72 for pos in range(72): tmp = [0]*72 tmp[pos] = 1 tbl[pos] = [] b01 = [bits(i) for i in enc(v12, genkey(tmp), 87)] for i in range(16): for j in range(8): if b00[i][j] != b01[i][j]: tbl[pos].append(i*8+j) tt = [0]*128 for i in range(72): for j in tbl[i]: if tt[j] == 0: tt[j] = [] tt[j].append(i) y = [0]*128 ttt = [0]*128 for i in range(128): ttt[i] = [0]*128 for j in tt[i]: ttt[i][j] = 1 print ttt
注意这里搞错了矩阵列数,实际上只需要72列,这里弄了成了128*128的,当然其实是无所谓的,多余的都是0。
现在就可以算答案了,
sage: b = matrix(GF(2), [1 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 0 , 1 , 0 ....: , 0 , 1 , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 1 ....: , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 1 , 0 , 1 ,]) sage: sage: mt = matrix(GF(2), ttt) sage: mt 128 x 128 dense matrix over Finite Field of size 2 (use the '.str()' method to see the entries) sage: y = matrix(GF(2), [0 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 1 , 1 ....: , 1 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 ....: , 0 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 0 , 1 , 1 ]) sage: y-b 1 x 128 dense matrix over Finite Field of size 2 (use the '.str()' method to see the entries) sage: mt.solve_right(((y-b).T)) 128 x 1 dense matrix over Finite Field of size 2 (use the '.str()' method to see the entries) sage: print mt.solve_right(((y-b).T)).T.str() [1 1 1 0 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 0 1 0 0 1 0 1 1 0 1 1 1 0 0 1 0 0 1 0 1 0 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] In [777]: unbits('1 1 1 0 0 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 0 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 0 1 0 0 1 0 1 1 0 1 1 1 0 0 1 0 0 1 0 1 0 1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ...: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0'.replace(' ','')).encode('hex').upper() Out[777]: 'E7DFE373BFF25B92B600000000000000'
故答案为E7DFE373BFF25B92B6。
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。