-
-
KCTF2020秋季赛 第八题 惊天阴谋
-
2020-12-6 20:47 5710
-
处理逻辑
# 用户名+序列号形式, 序列号格式为16进制小写, # 用户名记为user, 序列号分两部分记为sn1, sn2, sn1=hex2bin(sn1), len(sn1)==32 sn2=hex2bin(sn2), len(sn2)==0xC0 md=md5(user) md1=md5(md[0:8]) md2=md5(md[8:16]) # >>>> 处理sn1 # u32 v[8] # 注意tlscallback中的初始化 # .text:004054B0 mov dword_6E2771, 0F496B3AFh for i in range(8): v[i]=sub_402EE0(v[i]) # 这个只有位移与异或操作, 用z3来解就行了, 注意右移操作要用LShR就行了 # sub_00404010, Crypt系列API, 这里求kernel32基址的shellcode有问题, 所以不能在win7上正常运行 aes_key=sha256('1_L0V3_BXS_F0REVER!') aes_iv='\x00'*16 aes_cbc_encrypt(aes_key, aes_iv, v) # u8 v[32] # u8 buf[16] for i in range(16): buf[i] = v[2*i] assert v[2*i]+0x7F == v[2*i+1] # sub_004033B0 # .data:006ECD70 aes_sbox 与标准的不一样 aes_key='Wo YongYuan XiHuan KanXun LunTan' assert aes_encrypt(aes_key, buf) == md1 # # >>>> 处理sn2 # sub_4041A0, 输入0xC0字节, 输出为32字节 s = to_binary_string(s) buf = [] for i in range(0x200): # 每次取3bit buf[i] = s[3*i:3*i+3] buf[i] = (buf[i]-2)<<1 A=[ [-1, -1, -1, 1, 1, -1, 1, 1], [-1, -1, 1, -1, 1, 1, 1, -1], [-1, 1, -1, 1, 1, 1, -1, -1], [-1, 1, -1, -1, -1, -1, 1, -1], ] # buf为64个8*1的矩阵, 每个矩阵记为X, A*X=B # B(4*1)可以确定结果中的4个bit # 因为A矩阵不存在逆矩阵, 所以(已知A,B)求X存在很多解(8个变量, 4个方程) # 但是如果用伪逆矩阵求解的话, 最终得到的序列号会与题目提供的相一致 # sub_404860, 解 模N-16元1次 方程, 输入32字节, 输出16字节 # sub_404D90, 与md2计算后==固定值
脚本
import hashlib import struct from Crypto.Cipher import AES from z3 import * import gmpy2 as gp import numpy as np g_005D0810 = None def hex2bin(s): return s.decode('hex') def bin2hex(s): return s.encode('hex') def load_file(filename): f = open(filename, 'rb') s = f.read() f.close() return s def save_file(filename, s): f = open(filename, 'wb') f.write(s) f.close() return def sha256(s): md = hashlib.sha256() md.update(s) return md.digest() def md5(s): md = hashlib.md5() md.update(s) return md.digest() def aes_cbc_encrypt(key, iv, s): c = AES.new(key, AES.MODE_CBC, iv) return c.encrypt(s) def aes_cbc_decrypt(key, iv, s): c = AES.new(key, AES.MODE_CBC, iv) return c.decrypt(s) def aes_decrypt(s): # sbox: 006ECD70 if s == hex2bin('510b3d82cb5577b5dc1a908233c12a36'): # KCTF return hex2bin('1F93C53327F92AD79198AF2EF597CA4A') if s == hex2bin('99f3546a852db6b344f2eb399160887a'): return hex2bin('60E94A7359AF5293E7C7553F805FE48A') s = bin2hex(s) # print s p = os.popen("aes.exe decrypt %s" % s) s = p.readline() # print s return hex2bin(s) def ror8(v, shift): shift &= 7 if shift == 0: return v return ((v >> shift) | (v << (8 - shift))) & 0xFF def rol8(v, shift): shift &= 7 if shift == 0: return v return ((v << shift) | (v >> (8 - shift))) & 0xFF def get_bit(v, i): return (v >> i) & 1 def isbitset(v, i): return get_bit(v, i) == 1 def high4(v): return (v >> 4) & 0x0F def low4(v): return v & 0x0F def high8(v): return (v >> 8) & 0xFF def low8(v): return v & 0xFF def make16(h, l): return (h << 8) | l def get_u8(ary, offset): if type(ary) == str: return ord(ary[offset]) return ary[offset] def get_u32(ary, offset): v = 0 v |= get_u8(ary, offset) v |= get_u8(ary, offset + 1) << 8 v |= get_u8(ary, offset + 2) << 16 v |= get_u8(ary, offset + 3) << 24 return v def va2fileoffset(v): return v - 0x005CF000 + 0x001CD400 def x_404d90_rev(md): v3 = [ 0x1A, 0x1C, 0x11, 0x18, 0x08, 0x0C, 0x19, 0x01, 0x20, 0x0B, 0x07, 0x10, 0x17, 0x02, 0x1D, 0x15, 0x14, 0x1B, 0x16, 0x12, 0x05, 0x1E, 0x0A, 0x00, 0x09, 0x03, 0x13, 0x0D, 0x04, 0x06, 0x0E, 0x1F, ] v2 = [ 0x15, 0x17, 0x16, 0x14, 0x13, 0x0C, 0x04, 0x12, 0x03, 0x06, 0x10, 0x0E, 0x0A, 0x18, 0x1C, 0x0F, 0x1F, 0x00, 0x0B, 0x05, 0x08, 0x1A, 0x0D, 0x20, 0x1E, 0x1D, 0x11, 0x09, 0x19, 0x02, 0x01, 0x1B, ] v1 = [ 0x03, 0xEE, 0xEC, 0x11, 0x14, 0x0E, 0x05, 0x0C, 0x03, 0xED, 0xF7, 0x05, 0x00, 0xF6, 0x00, 0xE7, 0x00, 0xE8, 0xEF, 0x0B, 0xF5, 0x03, 0x04, 0xFF, 0x00, 0x16, 0x06, 0xF4, 0xEF, 0x18, 0x09, 0xF9, ] r = [ 0x15, 0x09, 0x0C, 0x1F, 0x1C, 0x13, 0x16, 0x19, 0x1D, 0x03, 0x10, 0x0F, 0x01, 0x02, 0x1E, 0x06, ] s = '' for i in range(16): s += chr(rol8((r[i] + ord(md[i]) - v1[i]) & 0xFF, v3[i]) ^ v2[i]) return s def x_4041a0_rev(dst): results = [-8, 8] A = np.matrix([ [-1, -1, -1, 1, 1, -1, 1, 1], [-1, -1, 1, -1, 1, 1, 1, -1], [-1, 1, -1, 1, 1, 1, -1, -1], [-1, 1, -1, -1, -1, -1, 1, -1], ], dtype=long) # pseudo-inverse A_INV = np.linalg.pinv(A) r_bits = '' for i in range(8): for j in range(7, -1, -1): B = np.matrix([ [results[get_bit(ord(dst[i]), j)]], [results[get_bit(ord(dst[i + 8]), j)]], [results[get_bit(ord(dst[i + 16]), j)]], [results[get_bit(ord(dst[i + 24]), j)]], ], dtype=long) X = (A_INV * B).tolist() for x in X: v = x[0] if v < 0: v = int(v - 0.5) else: v = int(v + 0.5) r_bits += bin(v / 2 + 2)[2:].rjust(3, '0') s = '' for i in range(0, len(r_bits), 8): s += chr(int(r_bits[i:i + 8], 2)) return s def x_402ee0_init(): global g_005D0810 offset = va2fileoffset(0x005D0810) g_005D0810 = bytearray(load_file('KCTF-KeyME.exe')[offset:]) offset = va2fileoffset(0x006E2771) - offset val = 0xF496B3AF g_005D0810[offset] = val & 0xFF g_005D0810[offset + 1] = (val >> 8) & 0xFF g_005D0810[offset + 2] = (val >> 16) & 0xFF g_005D0810[offset + 3] = (val >> 24) & 0xFF return def x_402ee0_rev(dst): global g_005D0810 solver = Solver() src = BitVec('src', 32) state = [0] * 16 state[15] = src ary = [0x0123, 0x4567, 0x89AB, 0xCDEF, 0x0F1E, 0x2D3C, 0x4B5A, 0x6978] i = 0 while True: v0 = get_u32(g_005D0810, i) # u32 v0 # u8 v1 # u8 pad[pad_len] # u8 v2 # u8 v3 ary_idx = (get_bit(v0, 0x1B) << 2) | (get_bit(v0, 0x13) << 1) | get_bit(v0, 8) pad_len = (get_bit(v0, 0x10) << 1) | get_bit(v0, 7) v1 = get_u8(g_005D0810, i + 4) v2 = get_u8(g_005D0810, i + 5 + pad_len) v3 = get_u8(g_005D0810, i + 6 + pad_len) t = high8(ary[ary_idx]) ^ v1 dst_idx = high4(t) op_idx = low4(t) op = low8(ary[ary_idx]) ^ v2 ary = ary[1:] ary.append(make16(v1, v2)) i += 7 + pad_len if isbitset(op, 6): state[dst_idx] &= v0 elif isbitset(op, 5): # DO NOT USE state[dst_idx] >>= v3 state[dst_idx] = LShR(state[dst_idx], v3) elif isbitset(op, 4): state[dst_idx] <<= v3 elif isbitset(op, 3): state[dst_idx] ^= state[op_idx] elif isbitset(op, 2): state[dst_idx] = state[op_idx] elif isbitset(op, 1): state[dst_idx] <<= 1 if i >= 0x111F71: break solver.add(simplify(state[14] == dst)) if solver.check() == unsat: raise RuntimeError('unsat') m = solver.model() return m[src].as_long() def x_404860_rev(dst): src = '' base = [ 0xE9, 0x88, 0xBD, 0x84, 0x9D, 0x64, 0xC4, 0xB9, 0x8A, 0xDE, 0x5A, 0x65, 0x73, 0xE5, 0xA1, 0x61, ] var = [ord(_) for _ in dst] modulus = 0xFF8F for i in range(16): co = [0] * 16 for k in range(16): co[k] = gp.powmod(base[i], 15 - k, modulus) v = 0 for k in range(16): v += co[k] * var[k] v %= modulus src += struct.pack('H', v) return src def test(): x_402ee0_init() user = '141E8F96636898EF' user = 'KCTF' md = md5(user) md1 = md5(md[0:8]) md2 = md5(md[8:16]) s = aes_decrypt(md1) s = ''.join([chr(ord(ch)) + chr((ord(ch)+0x7F) & 0xFF) for ch in s]) s = aes_cbc_decrypt(sha256('1_L0V3_BXS_F0REVER!'), '\x00'*16, s) if user == '141E8F96636898EF': r1 = hex2bin('dd8c5dd5bff047cb86c51fc808254c0950ebd2d9c7e6b34679a6cda7f96ea0f4') elif user == 'KCTF': r1 = hex2bin('83bde72e2806ce3c8f424e242559a66314bb37008d62a69bfd1a960f8e4102c8') else: r1 = '' for i in range(0, len(s), 4): v = struct.unpack('I', s[i:i + 4])[0] v = x_402ee0_rev(v) r1 += struct.pack('I', v) r = '' r += bin2hex(r1) s = x_404d90_rev(md2) s = x_404860_rev(s) s = x_4041a0_rev(s) r2 = bin2hex(s) r += r2 print r # 83bde72e2806ce3c8f424e242559a66314bb37008d62a69bfd1a960f8e4102c850a28948c68b49a70989a28b89a28b6614d24982996614d249a7096d34c26d10522c345241a69b6d105208a69949a70950a28949829941a69b48a21b50a28925146289a28b48c68b50a2896614d241a69b89a28b49829948c68b49829989a28b89a28b41a69b48a21b25146248c68b48c68b25146249a7092538d241a69b2c34522538d241a69b65345489a28b48a21b6534542538d248c68b6614d26d105250a2896d105249a70948c68b6d105208a69941a69b89a28b50a28941a69b2d14d0 return test()
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2020-12-6 21:32
被风间仁编辑
,原因:
赞赏
他的文章
KCTF2022春季赛 第三题 石像病毒
8276
KCTF2022春季赛 第二题 末日邀请
15399
KCTF2021秋季赛 第二题 迷失丛林
17936
KCTF2020秋季赛 第十题 终焉之战
8107
KCTF2020秋季赛 第九题 命悬一线
5831
看原图