20211107 陇原战疫Crypto方向WP

原文地址
https://4xwi11.github.io/posts/a1174b3b/

陇原战"疫"2021网络安全大赛

Crypto

mostlycommon

共模再开个方

import gmpy2
from Crypto.Util.number import *

e1 = 65536 // 2
e2 = 270270 // 2

n = 122031686138696619599914690767764286094562842112088225311503826014006886039069083192974599712685027825111684852235230039182216245029714786480541087105081895339251403738703369399551593882931896392500832061070414483233029067117410952499655482160104027730462740497347212752269589526267504100262707367020244613503
c1 = 39449016403735405892343507200740098477581039605979603484774347714381635211925585924812727991400278031892391996192354880233130336052873275920425836986816735715003772614138146640312241166362203750473990403841789871473337067450727600486330723461100602952736232306602481565348834811292749547240619400084712149673
c2 = 43941404835820273964142098782061043522125350280729366116311943171108689108114444447295511969090107129530187119024651382804933594308335681000311125969011096172605146903018110328309963467134604392943061014968838406604211996322468276744714063735786505249416708394394169324315945145477883438003569372460172268277

get_tuple = gmpy2.gcdext(e1, e2)        # return (g,s,t)   g = gcd(e1,e2) and g = e1*s + e2*t

r = -get_tuple[1]
s = get_tuple[2]

a = gmpy2.powmod(gmpy2.invert(c1, n), r, n)
b = gmpy2.powmod(c2, s, n)

m = gmpy2.f_mod(gmpy2.mul(a,b),n)
print(gmpy2.iroot(m, 2))
print(long_to_bytes(gmpy2.iroot(m, 2)[0]))

easytask(recuring)

差点以为是和省赛NTRU那样的题目(其实就是

虽然r是完全可以爆破的,但是要3个小时才能跑完(再买个内存条

所以可还行,emmmm,写了个脚本但比赛中没有出(做不进去,组里还一直催项目,我tm,到底知不知道实验室是什么撑起来的,还非得比赛的时候催,瞬间不想做了


有能力出,但没出,总结一下几点

  1. 遍历所有的r不慢,但是不精明的操作(在循环中生成AES解密)会导致空间复杂度很大,导致程序非常慢
  2. 赛后问尚师傅,其实真正的r开头是-3 -2(应该是刻意为之),所以尽管空间复杂度很大,但是比赛中还是遍历到了,判断机制写得不对(马虎,还有别的原因
  3. 综上,判断机制不是非得是flag.starswith(b'flag'),求出来的m很有特征的;可以学尚师傅,先自己定个r,然后用脚本跑一遍(处理大数据,阳哥的样本方法
  4. 比赛中先算出r保存在内存里,再开始遍历

调整后的脚本快多了

#!/usr/bin/env sage
# -*- coding: utf-8 -*-
import hashlib
from Crypto.Cipher import AES
import re
from itertools import product

c = '1070260d8986d5e3c4b7e672a6f1ef2c185c7fff682f99cc4a8e49cfce168aa0'
c = bytes.fromhex(c)
ct_e = '[151991736758354 115130361237591  58905390613532 130965235357066  74614897867998  48099459442369  45894485782943   7933340009592     25794185638]'
ct_W = '''[-10150241248 -11679953514  -8802490385 -12260198788 -10290571893   -334269043 -11669932300  -2158827458     -7021995]
[ 52255960212  48054224859  28230779201  43264260760  20836572799   8191198018  14000400181   4370731005     14251110]
[  2274129180  -1678741826  -1009050115   1858488045    978763435   4717368685   -561197285  -1999440633     -6540190]
[ 45454841384  34351838833  19058600591  39744104894  21481706222  14785555279  13193105539   2306952916      7501297]
[-16804706629 -13041485360  -8292982763 -16801260566  -9211427035  -4808377155  -6530124040  -2572433293     -8393737]
[ 28223439540  19293284310   5217202426  27179839904  23182044384  10788207024  18495479452   4007452688     13046387]
[   968256091  -1507028552   1677187853   8685590653   9696793863   2942265602  10534454095   2668834317      8694828]
[ 33556338459  26577210571  16558795385  28327066095  10684900266   9113388576   2446282316   -173705548      -577070]
[ 35404775180  32321129676  15071970630  24947264815  14402999486   5857384379  10620159241   2408185012      7841686]'''

e = []
for i in re.findall(r"d+", ct_e):
    e.append(int(i))
e = matrix(e)

W = [[0 for _ in range(9)] for j in range(9)]
ct_W = re.findall(r'-?d+', ct_W)
for i in range(len(ct_W)):
    W[i // 9][i % 9] = int(ct_W[i])
W = matrix(W)
inv_W = W.inverse()

table = [_ for _ in range(-3, 4)]
r = product(table, repeat=9)

for ri in r:
    rx = matrix(ri)
    m = (e - rx) * inv_W
    if 0 < m[0][0] < 1024:
        M = list(m[0])
        key = hashlib.sha256(str(M).encode()).digest()
        cipher = AES.new(key, AES.MODE_ECB)
        flag = cipher.decrypt(c)
        if flag.startswith(b'flag') or flag.startswith(b'SET'):
            print(r)
            print(flag)
            break

让我看看之前的脚本为啥不能出

我们自己写一个r,就[-3,-3,-3,-3,-3,-3]吧,然后走一遍,我知道了,是这个问题

M = list(m[0])

sage矩阵转列表的时候要多取一个,差不多是这么一个意思吧

image-20211108072631010

Civet cat for Prince(recuring)

代码小饶


目的,已知IV,可以获得输入name+'a_cat_permission'的密文,可以有最多两次自己输入IV和密文进行解密,求输入name+'Princepermission'的密文,注意最后这里我们可以自己定义IV

重点是最后一句话,这就是利用点,复现的时候我一个上午都没注意到,以为是要用它的IV;然后下午看到,那就比较简单了

一个小思路,假设获取的name_cipher

c

c

c分成前半段

c

1

,

 

c

2

c_1, c_2

c1, c2,密文构造成

c

1

a

_

c

a

t

_

p

e

r

m

i

s

s

i

o

n

 

P

r

i

n

c

e

p

e

r

m

i

s

s

i

o

n

+

c

2

c_1oplus a_cat_permission oplus Princepermission + c_2

c1a_cat_permission Princepermission+c2
这样第二段密文解密出来就是Princepermission

然后利用一次解密的机会,将上面这个密文的前半段和系统的IV丢进去,得到的结果记为

m

1

m_1

m1,求

m

1

I

V

P

r

i

n

c

e

p

e

r

m

i

s

s

i

o

n

m_1oplus IV oplus Princepermission

m1IVPrincepermission
这样解密出来的第一段就是Princepermission,其实name无所谓什么都可以

到此这道题已经被我们攻破,可能有点绕,但是海星

写了个jo本,源文件改过了?打本地可以,远程有时候可以,可能是有些结果有换行

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import hashlib
from pwn import *
from itertools import product
import string

context.log_level = 'debug'
table = string.ascii_letters + string.digits


class Solve:
    def __init__(self):
        # self.sh = remote('node4.buuoj.cn', 28743)
        self.sh = remote('node4.buuoj.cn', 29129)
        self._Princepermission = b'Princepermission'
        self._a_cat_permission = b'a_cat_permission'
        self.iv = b''
        self.cipher_name = b''
        self.payload_cipher = b''
        self.payload_iv = b''

    def proof_of_work(self):
        """
        [+] sha256(XXXX+Q3kqSv2c) == e9ded46c9d0dbcf14d8c36852678fe59daec43b1025c282738a81e7ea9f395f9
        [+] Give Me XXXX :
        """
        proof = self.sh.recvline()
        tail = proof[16:24].decode()
        HASH = proof[29:93].decode()
        for i in product(table, repeat=4):
            head = ''.join(i)
            t = hashlib.sha256((head + tail).encode()).hexdigest()
            if t == HASH:
                self.sh.recvuntil(b'[+] Give Me XXXX :')
                self.sh.sendline(head.encode())
                break

    def solve_BANNER(self, _name):
        self.sh.sendlineafter(b'[-]', b'1')
        self.sh.sendlineafter(b'[-]', _name)
        self.sh.recvline()
        self.sh.recvline()
        self.sh.recvuntil(b'Miao~ ')
        self.iv = self.sh.recvuntil(b"I'm a")[:-6]
        print(len(self.iv))

    def solve_NAME(self):
        self.sh.sendlineafter(b'[-]', b'1')
        self.sh.recvuntil(b'Permission:')
        self.cipher_name = self.sh.recvuntil(b"I'm a")[:-6]
        self.cipher_name = self.cipher_name
        self.payload_cipher = xor(xor(self.cipher_name[:16], self._a_cat_permission),
                                  self._Princepermission) + self.cipher_name[16:32]

    def solve_Princepermission(self):
        self.sh.sendlineafter(b'[-]', b'2')
        self.sh.sendlineafter(b'[-]', self.payload_cipher[:16])
        self.sh.sendlineafter(b'[-]', self.iv)
        self.sh.recvuntil(b'The message is ')
        self.payload_iv = xor(xor(self.sh.recvuntil(b'1.getpermission')[:16], self.iv), self._Princepermission)

    def solve_flag(self):
        self.sh.sendlineafter(b'[-]', self.payload_cipher)
        self.sh.sendlineafter(b'[-]', self.payload_iv)
        self.sh.recvuntil(b'The prince asked me to tell you this:n')
        flag = self.sh.recvline()
        print(flag)

    def solve(self):
        self.proof_of_work()
        self.solve_BANNER(self._Princepermission)

        # get cipher_name
        # chance ====> 2
        self.solve_NAME()

        # get cipher_Princepermission
        # chance ====> 1
        self.solve_Princepermission()

        # chance ====> 0
        self.sh.sendlineafter(b'[-]', b'3')
        # get flag
        self.solve_flag()


if __name__ == '__main__':
    solution = Solve()
    solution.solve()

image-20211108161217066

好一个狸猫换太子

Re

EasyRe

反编译失败,查了好久,尝试平衡栈,手动修无果,然后想起一开始看到一串32位的字符串没用到,随便搜了下竟然是hello world的md5,抱着试一试的心态丢进去就对了

image-20211107141510771
xs


还是太容易被别人影响了

努力很廉价,也很昂贵,对自己来说廉价,对别人来说昂贵

你在楼上看到的风景,我选择贴地接近

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>