buu三月春季挑战赛Crypto部分wp

2022DASCTF X SU 三月春季挑战赛

Crypto

FlowerCipher

题目

# python3
from secret import flag
import random

flag = b'flag{%s}' % md5(something).hexdigest()
# note that md5 only have characters 'abcdef' and digits

def Flower(x, key):
    flower = random.randint(0, 4096)
    return x * (key ** 3 + flower)

flag = flag[5:-1]
rounds = len(flag)

L, R = 1, 0
for i in range(rounds):
    print(flag[i])
    L, R = R + Flower(L, flag[i]), L

print(L, R)

# L = 15720197268945348388429429351303006925387388927292304717594511259390194100850889852747653387197205392431053069043632340374252629529419776874410817927770922310808632581666181899
# R = 139721425176294317602347104909475448503147767726747922243703132013053043430193232376860554749633894589164137720010858254771905261753520854314908256431590570426632742469003

思路

L , R R + F l o w e r ( L , f l a g 1 ) , L 已 知 R + F l o w e r ( L , f l a g 1 ) , L 则 R = R + F l o w e r ( L , f l a g 1 ) − F l o w e r ( L , f l a g 1 ) ∵   F l o w e r ( L , f l a g 1 ) = L   ∗   ( f l a g 1 3   +   r a n d i n t ( 0 , 4096 ) ) , 且 f l a g 1 和 r a n d i n t ( 0 , 4096 ) 未 知 , 但 可 以 爆 破 ∴   当 R + F l o w e r ( L , f l a g 1 )   −   L   ∗   ( f l a g 1 3   +   r a n d i n t ( 0 , 4096 ) ) 恰 好 大 于 0 时 , 则 爆 出 R ,   和 低 位 f l a g 同 理 可 以 求 出 整 个 f l a g L, R\\ R + Flower(L, flag_1), L\\ 已知R + Flower(L, flag_1), L\\ 则 R = R + Flower(L, flag_1) - Flower(L, flag_1)\\ ∵\ Flower(L, flag_1) = L\ *\ (flag_1^3\ +\ randint(0, 4096)),且flag_1和randint(0,4096)未知,但可以爆破\\ ∴\ 当R + Flower(L, flag_1)\ -\ L\ *\ (flag_1^3\ +\ randint(0, 4096))恰好大于0时,则爆出R,\ 和低位flag\\ 同理可以求出整个flag L,RR+Flower(L,flag1),LR+Flower(L,flag1),LR=R+Flower(L,flag1)Flower(L,flag1) Flower(L,flag1)=L  (flag13 + randint(0,4096))flag1randint(0,4096) R+Flower(L,flag1)  L  (flag13 + randint(0,4096))0R, flagflag

EXP

L = 15720197268945348388429429351303006925387388927292304717594511259390194100850889852747653387197205392431053069043632340374252629529419776874410817927770922310808632581666181899
R = 139721425176294317602347104909475448503147767726747922243703132013053043430193232376860554749633894589164137720010858254771905261753520854314908256431590570426632742469003
s = ''
for k in range(32):
    f = 0
    for i in b'0123456789abcdef':
        if f:break
        for j in range(4096):
            if (L - R * (i ** 3 + j) < 0):
                f = 1
                if i != 0:
                    l = L - R * (i ** 3 + j - 1)
                    s = chr(i) + s
                else:
                    l = L - R * ((i - 1) ** 3 + 4095)
                    s = chr(i - 1) + s
                break
    L, R = R, l

print('flag{' + s + '}')
# flag{3e807b66ef26d38e671ddcbb9c108250}

meet me in the middle

题目

from Crypto.Util.number import *
from hashlib import sha256
import socketserver
import signal
import string
from Crypto.Random import random
from Crypto.PublicKey import DSA

table = string.ascii_letters + string.digits
BANNER = br'''

888b     d888                   888          888b     d888                                             
8888b   d8888                   888          8888b   d8888                                             
88888b.d88888                   888          88888b.d88888                                             
888Y88888P888  .d88b.   .d88b.  888888       888Y88888P888  .d88b.                                     
888 Y888P 888 d8P  Y8b d8P  Y8b 888          888 Y888P 888 d8P  Y8b                                    
888  Y8P  888 88888888 88888888 888          888  Y8P  888 88888888                                    
888   "   888 Y8b.     Y8b.     Y88b.        888   "   888 Y8b.                                        
888       888  "Y8888   "Y8888   "Y888       888       888  "Y8888                                     
                                                                                                       
                                                                                                       
                                                                                                       
8888888                888    888                     888b     d888 d8b      888      888 888          
  888                  888    888                     8888b   d8888 Y8P      888      888 888          
  888                  888    888                     88888b.d88888          888      888 888          
  888   88888b.        888888 88888b.   .d88b.        888Y88888P888 888  .d88888  .d88888 888  .d88b.  
  888   888 "88b       888    888 "88b d8P  Y8b       888 Y888P 888 888 d88" 888 d88" 888 888 d8P  Y8b 
  888   888  888       888    888  888 88888888       888  Y8P  888 888 888  888 888  888 888 88888888 
  888   888  888       Y88b.  888  888 Y8b.           888   "   888 888 Y88b 888 Y88b 888 888 Y8b.     
8888888 888  888        "Y888 888  888  "Y8888        888       888 888  "Y88888  "Y88888 888  "Y8888  

'''


class DigitalSignatureAlgorithm:
    def __init__(self, key):
        self.p = key.p
        self.q = key.q
        self.g = key.g
        self.y = key.y
        self.x = key.x
        self.k = []

    def sign(self, m):
        k = random.StrongRandom().randint(1, self.q - 1)
        self.k.append(k)
        h = bytes_to_long(sha256(m).digest())
        r = pow(self.g, k, self.p) % self.q
        s = inverse(k, self.q) * (h + self.x * r) % self.q
        return r, s

    def verify(self, m, signature):
        r, s = signature
        if (not (1 <= r <= self.q - 1)) or (not (1 <= s <= self.q - 1)):
            return False
        z = bytes_to_long(sha256(m).digest())
        w = inverse(s, self.q)
        u1 = (z * w) % self.q
        u2 = (r * w) % self.q
        v = (pow(self.g, u1, self.p) * pow(self.y, u2, self.p)) % self.p % self.q
        return r == v


myDSA = DigitalSignatureAlgorithm(DSA.generate(1024))
MENU = br'''
[1] Sign.
[2] Verify.
[3] Get_public_key.
[4] Get_sth_in_the_middle
[5] Exit.
'''


class Task(socketserver.BaseRequestHandler):
    def _recvall(self):
        BUFF_SIZE = 2048
        data = b''
        while True:
            part = self.request.recv(BUFF_SIZE)
            data += part
            if len(part) < BUFF_SIZE:
                break
        return data.strip()

    def send(self, msg, newline=True):
        try:
            if newline:
                msg += b'\n'
            self.request.sendall(msg)
        except:
            pass

    def recv(self, prompt=b'[-] '):
        self.send(prompt, newline=False)
        return self._recvall()

    def proof_of_work(self):
        proof = (''.join([random.choice(table) for _ in range(12)])).encode()
        sha = sha256(proof).hexdigest().encode()
        self.send(b"[+] sha256(XXXX+" + proof[4:] + b") == " + sha)
        XXXX = self.recv(prompt=b'[+] Plz Tell Me XXXX :')
        if len(XXXX) != 4 or sha256(XXXX + proof[4:]).hexdigest().encode() != sha:
            return False
        return True

    def sign(self):
        m1 = b'What you want to know'
        m2 = b'My dear lone warrior'
        signature1 = myDSA.sign(m1)
        signature2 = myDSA.sign(m2)
        self.send(b'Your signature1 is:' + str(signature1).encode())
        self.send(b'Your signature2 is:' + str(signature2).encode())

    def verify(self):
        m = self.recv(b'message:')
        r = int(self.recv(b'r:'))
        s = int(self.recv(b's:'))
        signature = (r, s)
        if m == b"I'm Admin.I want flag.":
            if myDSA.verify(m, signature):
                self.send(b'Hello there.This is what you want.')
                flag = open('flag').read()
                self.send(flag.encode())
            else:
                self.send(b'Who are U?Get out!')
                return False
        else:
            self.send(b'Who are U?Get out!')

    def get_public_key(self):
        self.send(b'p = ' + str(myDSA.p).encode())
        self.send(b'q = ' + str(myDSA.q).encode())
        self.send(b'g = ' + str(myDSA.g).encode())
        self.send(b'y = ' + str(myDSA.y).encode())

    def sth_in_the_middle(self):
        if len(myDSA.k) == 2:
            middle_k0 = int(bin(myDSA.k[0])[2:][30:-30], 2) << 30
            middle_k1 = int(bin(myDSA.k[1])[2:][30:-30], 2) << 30
            self.send(b'middle_k0' + str(middle_k0).encode())
            self.send(b'middle_k1' + str(middle_k1).encode())
        else:
            self.send(b"The time has not come.")

    def handle(self):
        signal.alarm(60)
        self.send(BANNER)
        if not self.proof_of_work():
            self.send(b'Oops,you are wrong. Bye~')
            self.request.close()
        while 1:
            self.send(MENU)
            option = int(self.recv(prompt=b'Give me your option:'))
            if option == 1:
                self.sign()
            elif option == 2:
                self.verify()
                break
            elif option == 3:
                self.get_public_key()
            elif option == 4:
                self.sth_in_the_middle()
            else:
                break
        self.request.close()


class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass

class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
    pass

if __name__ == "__main__":
    HOST, PORT = '0.0.0.0', 5000

    print("HOST:POST " + HOST + ":" + str(PORT))
    server = ForkedServer((HOST, PORT), Task)
    server.allow_reuse_address = True
    server.serve_forever()

思路

  • dsa的nonce的中间部分泄露,恢复nonce,伪造签名

根据这篇paper,实现攻击

buu三月春季挑战赛Crypto部分wp_第1张图片

其中 K K K表示 n o n c e nonce nonce泄露的位数(我在这里卡了好久,以为是 n o n c e nonce nonce的总位数), n n n E C D S A ECDSA ECDSA为阶数 o r d e r order order,在 D S A DSA DSA中为模数 q q q(本题为 q q q),矩阵 B B B的空白表示 0 0 0,其余的参数论文里都有明显表示不再赘述,但不要像我一样搞错了。

矩阵 B B B有了之后,在 S a g e M a t h SageMath SageMath里解 L L L 或 者 B K Z LLL或者BKZ LLLBKZ,解完后如论文所言就是解线性方程组,有手就行

解完就得到了两个 n o n c e nonce nonce(一个就够),之后求私钥 x x x

∵   s = i n v e r s e ( k , q ) ∗ ( h + x ∗ r ) % q ,   ∴ x = ( s ∗ k − h ) ∗ i n v e r s e ( r , q ) % q ∵\ s = inverse(k, q) * (h + x * r) \% q,\ ∴x = (s*k-h)*inverse(r,q)\%q  s=inverse(k,q)(h+xr)%q, x=(skh)inverse(r,q)%q

伪造签名: r = p o w m o d ( g , K , p ) % q s = i n v e r s e ( K , q ) ∗ ( h + x ∗ r ) r = powmod(g,K,p)\%q\\s = inverse(K, q) * (h + x * r) % q r=powmod(g,K,p)%qs=inverse(K,q)(h+xr)

EXP

代码丑不拉几,要用 S a g e M a t h SageMath SageMath跑,但是load(“exp.py”)不好使(我的会报错),只能打开Ubuntu里的sage,复制进去。

可是呢,里面的换行奇奇怪怪,所以我的for循环代码也奇奇怪怪。

from pwn import *
import string
from Crypto.Util.number import *
from hashlib import *
from gmpy2 import  powmod

re = remote('node4.buuoj.cn', 30000)
re.recvuntil(b'[+] sha256(XXXX+')
x = re.recv(8).decode()
re.recvuntil(b') == ')
y = re.recv(64).decode()

s = string.ascii_letters + string.digits
flag = 0
for a in s:
    if flag: break
for b in s:
                    if flag: break
for c in s:
                if flag: break
for d in s:
                z = a+b+c+d
if sha256((z+x).encode()).hexdigest() == y:
flag = 1
break


re.recv()
re.sendline(z.encode())
print(re.recv().decode())
re.send(b'1')
re.recvuntil(b'Your signature1 is:')
signature1 = eval(re.recvuntil(b'\n')[:-1])
re.recvuntil(b'Your signature2 is:')
signature2 = eval(re.recvuntil(b'\n').decode()[:-1])
print(re.recv().decode())
re.send(b'3')
re.recvuntil(b'p = ')
p = int(re.recvuntil(b'\n').decode()[:-1])
re.recvuntil(b'q = ')
q = int(re.recvuntil(b'\n').decode()[:-1])
re.recvuntil(b'g = ')
g = int(re.recvuntil(b'\n').decode()[:-1])
re.recvuntil(b'y = ')
y = int(re.recvuntil(b'\n').decode()[:-1])
print(re.recv().decode())
re.send(b'4')
re.recvuntil(b'middle_k0')
mk1 = int(re.recvuntil(b'\n').decode()[:-1])
re.recvuntil(b'middle_k1')
mk2 = int(re.recvuntil(b'\n').decode()[:-1])
re.recv()
r1, s1 = signature2
r2, s2 = signature2
27
m1 = b'What you want to know'
m2 = b'My dear lone warrior'
h1 = bytes_to_long(sha256(m1).digest())
h2 = bytes_to_long(sha256(m2).digest())


K = 2 ** 30
t = -inverse(s1, q) * s2 * r1 * inverse(r2, q)
u = inverse(s1,q) * r1 * h2 * inverse(r2, q) - inverse(s1, q) * h1
uu = mk1 + t * mk2 + u


matrix = [[K, K * 2**130, K * t, K * t * 2**130, uu],
          [0, K * q, 0, 0, 0],
          [0, 0, K * q, 0, 0],
          [0, 0, 0, K * q, 0],
          [0, 0, 0, 0, q]]
matrix = Matrix(matrix)
l = matrix.BKZ()
s = []

for i in range(0,4):
    s.append(list(l[i]))


for i in range(4):
    for j in range(4):
        if s[i][j] % K == 0:
            s[i][j] = s[i][j] // K


a = [s[0][:4], s[1][:4], s[2][:4], s[3][:4]]
b = [-s[0][4], -s[1][4], -s[2][4], -s[3][4]]
A = Matrix(a)
B = vector(b)
ll = A \ B
K1 = mk1 + ll[0] + ll[1] * 2**130
K2 = mk2 + ll[2] + ll[3] * 2**130

x =( (s1 * K1 - h1) * inverse(r1,q)) % q
re.send(b'2')
re.recvuntil(b'message:')
re.send(b"I'm Admin.I want flag.")
re.recvuntil(b'r:')
r = powmod(g,int(K1),p)%q
re.send(str(r).encode())
re.recvuntil(b's:')
h = bytes_to_long(sha256(b"I'm Admin.I want flag.").digest())
s = inverse(int(K1), q) * (h + x * r) % q
re.send(str(s).encode())

re.interactive()
2 + ll[2] + ll[3] * 2**130

x =( (s1 * K1 - h1) * inverse(r1,q)) % q
re.send(b'2')
re.recvuntil(b'message:')
re.send(b"I'm Admin.I want flag.")
re.recvuntil(b'r:')
r = powmod(g,int(K1),p)%q
re.send(str(r).encode())
re.recvuntil(b's:')
h = bytes_to_long(sha256(b"I'm Admin.I want flag.").digest())
s = inverse(int(K1), q) * (h + x * r) % q
re.send(str(s).encode())

re.interactive()

你可能感兴趣的:(CTF,python)