# 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),L已知R+Flower(L,flag1),L则R=R+Flower(L,flag1)−Flower(L,flag1)∵ Flower(L,flag1)=L ∗ (flag13 + randint(0,4096)),且flag1和randint(0,4096)未知,但可以爆破∴ 当R+Flower(L,flag1) − L ∗ (flag13 + randint(0,4096))恰好大于0时,则爆出R, 和低位flag同理可以求出整个flag
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}
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()
根据这篇paper,实现攻击
其中 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 LLL或者BKZ,解完后如论文所言就是解线性方程组,有手就行。
解完就得到了两个 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+x∗r)%q, ∴x=(s∗k−h)∗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+x∗r)
代码丑不拉几,要用 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()