第一届长城杯信息安全铁人三项赛初赛

LoginToMe #

main 函数核心逻辑,s 为长度 20 的字符串

    if ( *(unsigned __int16 *)s * *(unsigned __int16 *)&s[2] == 342772773
      && *(unsigned __int16 *)s + *(unsigned __int16 *)&s[2] == 39526
      && *(_DWORD *)&s[4] - *(_DWORD *)&s[8] == 1005712381
      && *(unsigned __int16 *)&s[4] + *(unsigned __int16 *)&s[6] == 56269
      && *(unsigned __int16 *)&s[8] - *(unsigned __int16 *)&s[10] == 15092
      && s[4] * s[8] == 10710
      && s[6] * s[10] == 12051
      && s[7] + s[11] == 172
      && *(unsigned __int16 *)&s[12] * *(unsigned __int16 *)&s[14] == 171593250
      && *(unsigned __int16 *)&s[12] + *(unsigned __int16 *)&s[14] == 26219
      && *(unsigned __int16 *)&s[16] * *(unsigned __int16 *)&s[18] == 376306868
      && *(unsigned __int16 *)&s[16] + *(unsigned __int16 *)&s[18] == 0x9D95 )
    {
      puts("check ok~!");
    }

实际上就是解方程,可以直接用 z3 去解,拼接 flag 时要注意 z3 使用的是大端

这题是有特别多解的,可以再套一个多解脚本

from z3 import *

flag_bytes = [BitVec("x%d" % i, 8) for i in range(20)]

s = Solver()
for i in range(4 * 5):
    s.add(flag_bytes[i] < 127)
    s.add(flag_bytes[i] > 32)

flag_words = [Concat(flag_bytes[i+1], flag_bytes[i]) for i in range(0, 20, 2)]

flag_dwords = [Concat(flag_bytes[i+3], flag_bytes[i+2], flag_bytes[i+1], flag_bytes[i]) for i in range(0, 20, 4)]

conds = [
    flag_words[0] * flag_words[1] == 342772773,
    flag_words[0] + flag_words[1] == 39526,
    flag_dwords[1] - flag_dwords[2] == 1005712381,
    flag_words[2]  + flag_words[3] == 56269,
    flag_words[4] - flag_words[5] == 15092,
    flag_bytes[4] * flag_bytes[8] == 10710,
    flag_bytes[6] * flag_bytes[10] == 12051,
    flag_bytes[7] + flag_bytes[11] == 172,
    flag_words[6] * flag_words[7] == 171593250,
    flag_words[6] + flag_words[7] == 26219,
    flag_words[8] * flag_words[9] == 376306868,
    flag_words[8] + flag_words[9] == 40341
]

s.add(conds)
result=s.check()
while result==z3.sat:
    m=s.model()
    flag = ''.join(chr(m.eval(x).as_long()) for x in flag_bytes)
    print(flag)
    # exclude the previous result by 'AND' a 'NOT'
	# 'NOT AND' is implemented by 'OR NEQ'
    extra=[var()!=m[var] for var in m]
    s.add(z3.Or(extra))
    result=s.check()

#125hfggtisu8219549ad
#125hfggtisu82195ad49
#125hfggtisu89521ad49
#125hfggtisu8952149ad
#...

babypy #

Cython 原生 DLL,test1.py 提示有三个导出函数 encrypt_AES_CBC, changtable 和 myBase64Encode

在 IDA 里定位这几个字符串,找在 .data 节的引用,就可以找到函数表

框架都是一样的,应该是做一些参数检查,然后再调用真正的函数

很容易就可以找到真正的函数,因为三个函数只有这一处是不一样的

先看最简单的 changtable,实际上就是 s=s[31:64]+s[:31]

在 .rdata 节可以找到 base64 的初始码表和两个 bytes 常量,32 位的那个显然是 key,16 位的是 iv

from base64 import b64decode as b64d, b64encode as b64e
from Crypto.Cipher import AES

b64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

change = lambda x: x[31:64] + x[0:31]

new_b64_table = change(b64_table)

encoded = 'hFHKBrfErYqSzpLZ/WD35J9+xNEt0uEZs/cNJeT7onH='

trans = str.maketrans(new_b64_table, b64_table)

encoded = encoded.translate(trans)

ct = b64d(encoded)
print(ct)


iv = b'\x00\x01\\{\x8c\xaa\xdf\xbc\xe9,OF\xa4\xda\x1e\xc6'
key = b'GU,\x8b\x0cSI\xe1\x92\x08\x97\xa3\xd0\xa1X-\xc3\x11\xd6U\xef\xca\xf9#g\x7f\xae\xd3x\xe2n\xd5'


aes = AES.new(key, AES.MODE_CBC, iv=iv)

pt = aes.decrypt(ct)
print(pt)
#flag{pYth0n_1ts_S0_CO0L}

square #

脱一个梆梆加固壳

WIP