ACTF2023 Cypto

ACTF2023 Cypto

也是稍微花了一点时间给队里面的密码签到一下

EasyRSA

E ∗ D − k 1 ∗ n 1 = A E ∗ D − a ∗ n 2 = B E ∗ D − d ∗ n 3 = C E*D-k_1*n_1=A\\E*D-a*n_2=B\\E*D-d*n_3=C EDk1n1=AEDan2=BEDdn3=C

存在这三个等式关系,其中D,A,B,C均为小于E的较小数直接造格就好

M = Matrix(ZZ,[[e,e,e,2^767],
               [n1,0,0,0],
               [0,n2,0,0],
               [0,0,n3,0]])
# e_*d_-k1*n1,n1
d=abs(M.LLL()[0][3]//2^767)
long_to_bytes(ZZ(pow(c,d,n1)))
#ACTF{5FFC427B-F14F-DCA0-C425-675B149890C2}ACTF{5FFC427B-F14F-DCA0-C425-675B149890C2}

MidRSA

手动测一下这里相比于上面卡了4-6bits的界,所以爆破一下高位就行

E ∗ ( h d + d 0 ) − k 1 ∗ n 1 = h a + A 0 E ∗ ( h d + d 0 ) − a ∗ n 2 = h b + B 0 E ∗ ( h d + d 0 ) − d ∗ n 3 = h c + C 0 E*(h_d+d_0)-k_1*n_1=h_a+A_0\\E*(h_d+d_0)-a*n_2=h_b+B_0\\E*(h_d+d_0)-d*n_3=h_c+C_0 E(hd+d0)k1n1=ha+A0E(hd+d0)an2=hb+B0E(hd+d0)dn3=hc+C0

for i in tqdm(range(70000,2^20)):
    t1 = bin(i)[2:].zfill(21)
    h = int('1'+t1[:3],2) << 0x23c
    h1 = int(t1[3:9],2) << 1338
    h2 = int(t1[9:15],2) << 1338
    h3 = int(t1[15:21],2) << 1338
    M = Matrix(QQ,[[-e,-e,-e,2^766,0,0,0,0],
                   [n1,0,0,0,0,0,0,0],
                   [0,n2,0,0,0,0,0,0],
                   [0,0,n3,0,0,0,0,0],
                   [-h*e,-h*e,-h*e,0,2^(1338),0,0,0],
                   [-h1,0,0,0,0,2^1338,0,0],
                   [0,-h2,0,0,0,0,2^1338,0],
                   [0,0,-h3,0,0,0,0,2^1338]])
    # e_*d_-k1*n1,n1
    res = M.LLL()
    d = int(res[0][3]//2^766) + h
    if b'ACTF' in long_to_bytes(ZZ(pow(c,d,n1))):
        print(long_to_bytes(ZZ(pow(c,d,n1))))

CRCRC

以前有类似的题,这里应该就改了一下,去年的hackergame 不可加密的异世界。当时一点不会做。

在crc128中有一个初始值,经过调试可以得到头尾固定时的状态转移过程

s t a t e 1 − > s t a t e 2 − > s t a t e 3 − > s t a t e 4 state_1->state_2->state_3->state_4 state1>state2>state3>state4

由1到2是前一段base64可正向推得,由4->3反推可以使用上面的re_crc128函数

def re_crc128(data, crc, poly = 0x883ddfe55bba9af41f47bd6e0b0d8f8f):
    crc = crc ^ ((1 << 128) - 1)
    for b in data[::-1]:
        for _ in range(8):
            if crc.bit_length() < 128:
                crc = crc << 1
            else :
                crc = ((crc ^ poly) << 1) + 1
        crc ^= b
    return crc

所以最终要解决就是已知状态2和状态3,求一个在base64表中的的data值

c r c ( Δ ⊕ a ) ⊕ c r c ( Δ ⊕ b ) = const ∀ Δ crc(\Delta \oplus a)\oplus crc(\Delta \oplus b) = \textrm{const}\quad \forall \Delta crc(Δa)crc(Δb)=const∀Δ

由这个式子可以转换成mod2加法,由于需要可见字符,所以考虑更多bytes的data,测试考虑30位的data,这样base64decode可以满足flag条件

如何对于矩阵来说

则矩阵形式为 128 × ( 30 ∗ 8 ) × X = 128 ∗ 1 128\times (30*8)\times X=128*1 128×(308)×X=1281

所以可以固定 24 × 3 < 30 ∗ 8 − 128 24\times 3<30*8-128 24×3<308128解空间,直接固定每个字符前3位为010,在再解空间爆破。

改一下之前hacker game的脚本就好,具体矩阵推导看hacker game,这里不多写了

def crc128(data, poly=0x883ddfe55bba9af41f47bd6e0b0d8f8f):
    crc = 0x9aefa6cb65b524cf97abaa31b3c757e3 #状态2通过前缀得来的,就不说了
    for b in data:
        crc ^^= b
        for _ in range(8):
            crc = (crc >> 1) ^^ (poly & -(crc & 1))
    return crc ^^ ((1 << 128) - 1)

def equivalent_affine_crc(crc = crc128, crc_bits = 128, target_bytes = 30):
    zero_crc = crc(target_bytes*b"\x00")
    target_bits = 8 * target_bytes
    v2n = lambda v: int(''.join(map(str, v)), 2)
    n2v = lambda n: vector(GF(2), bin(n)[2:].zfill(crc_bits))
    # n2v_t = lambda n: vector(GF(2), bin(n)[2:].zfill(target_bits))
    Affine_Matrix = []
    for i in range(target_bits):
        v = vector(GF(2), (j == i for j in range(target_bits)))
        value = crc(long_to_bytes(v2n(v),target_bytes)) ^^ zero_crc
        Affine_Matrix.append(n2v(value))
    Affine_Matrix=matrix(GF(2),Affine_Matrix).transpose()
    for i in range(target_bytes):
        v,w,k = [0]*target_bits,[0]*target_bits,[0]*target_bits
        v[i*8],w[i*8+1],k[i*8+2]=1,1,1
        v = vector(GF(2), v)
        w = vector(GF(2), w)
        k = vector(GF(2), k)
        Affine_Matrix = Affine_Matrix.stack(v)
        Affine_Matrix = Affine_Matrix.stack(w)
        Affine_Matrix = Affine_Matrix.stack(k)
    # crc affine function: crc_128(x) = M*x+ C
    return Affine_Matrix, n2v(zero_crc)

def crc_128_reverse(crc_value):
    M , C = equivalent_affine_crc()
    # crc affine function: crc_128(x) = M*x+ C
    v2n = lambda v: int(''.join(map(str, v)), 2)
    n2v = lambda n: vector(GF(2), bin(n)[2:].zfill(128))
    temp = n2v(crc_value)+C
    temp = vector(GF(2),list(temp)+[0,1,0]*30)
    print(M.ncols(),M.nrows(),len(temp))
    res = M.solve_right(temp)
    bas = M.right_kernel()
    K = len(bas.basis())
    for i in range(2<<K):
        tr = res+bas[i]
        s = long_to_bytes(v2n(tr))
#         print(s)
        if re.fullmatch(b'[A-Za-z0-9+/]*={0,2}', s):
            print(s)
            break
#     return long_to_bytes(v2n(res))
crc_128_reverse(0x1bff942435a8f7d5b2f76fc4735f168b ^^ ((1 << 128) - 1))
#HTSUZATLBQWGHRQPUFXZVYBPLCPOMB
#得到RGVhciBndWVzdCwgd2VsY29tZSB0byBDUkNSQyBNYWdpYyBIb3VzZSwgSWYgeW91IGlucHV0IAHTSUZATLBQWGHRQPUFXZVYBPLCPOMBLCB5b3Ugd2lsbCBnZXQgMHg5YzZhMTFmYmMwZTk3YjFmZmY1ODQ0ZmE4OGIxZWUyZA==
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值