陇原战疫crypto
一个月前的比赛,当时只会简单的RSA,现在回过来复现一下
1.mostlycommon
from Crypto.Util.number import bytes_to_long, getPrime
f = open('flag.txt', 'rb')
flag = f.read()
f.close()
m = bytes_to_long(flag)
p = getPrime(512)
q = getPrime(512)
n = p * q
e1 = 65536
e2 = 270270
c1 = pow(m, e1, n)
c2 = pow(m, e2, n)
f = open('message.txt', 'w')
f.write('n=' + str(n) + '\n')
f.write('c1=' + str(c1) + '\n')
f.write('c2=' + str(c2) + '\n')
f.close()
简单的共模攻击注意此处的e1,e2不互素,得到的m不能直接转字节(需要开根)
代码如下:
import gmpy2
n=122031686138696619599914690767764286094562842112088225311503826014006886039069083192974599712685027825111684852235230039182216245029714786480541087105081895339251403738703369399551593882931896392500832061070414483233029067117410952499655482160104027730462740497347212752269589526267504100262707367020244613503
c1=39449016403735405892343507200740098477581039605979603484774347714381635211925585924812727991400278031892391996192354880233130336052873275920425836986816735715003772614138146640312241166362203750473990403841789871473337067450727600486330723461100602952736232306602481565348834811292749547240619400084712149673
c2=43941404835820273964142098782061043522125350280729366116311943171108689108114444447295511969090107129530187119024651382804933594308335681000311125969011096172605146903018110328309963467134604392943061014968838406604211996322468276744714063735786505249416708394394169324315945145477883438003569372460172268277
e1 = 65536
e2 = 270270
def exgcd(a,b):
if b==0:return 1,0
else:
x,y=exgcd(b,a%b)
return y,x-(a//b)*y
def attack(e1,e2,c1,c2,n):
x,y=exgcd(e1,e2)
i=gmpy2.gcd(e1,e2)
print(i)
m=pow(c1,x,n)*pow(c2,y,n)%n
print(m)
if __name__ == '__main__':
attack(e1,e2,c1,c2,n)
2.easytask
import random
import hashlib
from Crypto.Util.number import *
from Crypto.Cipher import AES
from secret import flag,V
def get_random_U(n):
def get_U1():
A = Matrix(ZZ, n, n)
for i in range(0,n):
for j in range(0,n):
if i<j:
A[i,j] = random.randint(1,1000)
if i==j:
A[i,j] = 1
return A
def get_U2():
A = Matrix(ZZ, n, n)
for i in range(0,n):
for j in range(0,n):
if i>j:
A[i,j] = random.randint(1,1000)
if i==j:
A[i,j] = 1
return A
return get_U1()*get_U2()
def get_public_key():
U = get_random_U(9) #U为上三角与下三角的乘积
V = matrix(V) #V是给定矩阵(出题者导入)
W = V*U
return W #返回UV乘积
def get_random_r(): #随机的9维向量(|坐标|不超过3)
n = 9
delta = 4
r = random_vector(ZZ, n, x=-delta+1, y=delta)
r = matrix(r)
return r
def encrypt():
M = [getPrime(10)for i in range(9)]
m = matrix(M) #九维向量坐标为2^9~2^10的素数
W = get_public_key() #矩阵W
r = get_random_r() #9维向量
e = m*W+r
print("e =",e)
print("W =",W)
return M
def new_encrypt():
M = encrypt()
key = hashlib.sha256(str(M).encode()).digest()
cipher = AES.new(key, AES.MODE_ECB)
c = cipher.encrypt(flag).hex()
print("c =",c)
new_encrypt()
#e = [151991736758354 115130361237591 58905390613532 130965235357066 74614897867998 48099459442369 45894485782943 7933340009592 25794185638]
#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]
#c=1070260d8986d5e3c4b7e672a6f1ef2c185c7fff682f99cc4a8e49cfce168aa0
还是太菜了,刚开始做的时候以为是个可以把才学的线代运用到实践,可以直接爆破的题目,写完跑了半小时没出,放弃了(果断学习wp)
考的是格的一种加密体制GGH,1999年被Nguyen证明是不安全的
而这题本质上是求CVP问题,在查阅资料后了解到babai算法和embedding technique(嵌入式技术,属于是十分形象了)可以解决此类问题
babai算法考虑的是在优质的基(哈达玛比率接近1)下CVP可以利用四舍五入求解
但是实际可能还需调整,我直接对W格基规约后进行这个操作还是不能出结果,一个可能的原因是哈达玛比率还不够高(然后wp的算法写的我有点看不太懂)
于是我们采用嵌入式技术来解决,嵌入式技术的原理是通过对格的一个升维将CVP转换为SVP(可行的原因是加密算法所选取的扰动向量相对于基太小了,所以我们可以认为通过升维求得的最短向量就是扰动向量)
把相关的资料贴这:hxp | VolgaCTF 2016 Quals: crypto300 "XXY" writeup
代码如下:
1.求解扰动向量
from sage.modules.free_module_integer import IntegerLattice
e=Matrix([[151991736758354,115130361237591,58905390613532,130965235357066,74614897867998,48099459442369,45894485782943,7933340009592,25794185638]])
W=Matrix([[-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]])
B = W.stack(e).augment(vector([0] * W.ncols() + [1]))
r=IntegerLattice(B).shortest_vector()
r=matrix(r[:-1])
V=W.solve_left(e-r)
print(V)
2.aes解密
from Crypto.Util.number import *
from Crypto.Cipher import AES
c ='1070260d8986d5e3c4b7e672a6f1ef2c185c7fff682f99cc4a8e49cfce168aa0'
M=[ 877 , 619 , 919 , 977, 541 , 941 , 947 ,1031 ,821]
key = hashlib.sha256(str(M).encode()).digest()
aes = AES.new(key, AES.MODE_ECB)
m=aes.decrypt(long_to_bytes(int(c,16)))
print(m)
3.Civet cat for Prince
from Crypto.Cipher import AES
import os
from hashlib import sha256
import socketserver
import signal
import string
import random
table = string.ascii_letters + string.digits
BANNER = br'''
.d8888b. d8b 888 888
d88P Y88b Y8P 888 888
888 888 888 888
888 888 888 888 .d88b. 888888 .d8888b 8888b. 888888
888 888 888 888 d8P Y8b 888 d88P" "88b 888
888 888 888 Y88 88P 88888888 888 888 .d888888 888
Y88b d88P 888 Y8bd8P Y8b. Y88b. Y88b. 888 888 Y88b.
"Y8888P" 888 Y88P "Y8888 "Y888 "Y8888P "Y888888 "Y888
.d888 8888888b. d8b
d88P" 888 Y88b Y8P
888 888 888
888888 .d88b. 888d888 888 d88P 888d888 888 88888b. .d8888b .d88b.
888 d88""88b 888P" 8888888P" 888P" 888 888 "88b d88P" d8P Y8b
888 888 888 888 888 888 888 888 888 888 88888888
888 Y88..88P 888 888 888 888 888 888 Y88b. Y8b.
888 "Y88P" 888 888 888 888 888 888 "Y8888P "Y8888
'''
guard_menu = br'''
1.Tell the guard my name
2.Go away
'''
cat_menu = br'''1.getpermission
2.getmessage
3.say Goodbye
'''
def Pad(msg):
return msg + os.urandom((16 - len(msg) % 16) % 16)
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'[+] Give Me XXXX :')
if len(XXXX) != 4 or sha256(XXXX + proof[4:]).hexdigest().encode() != sha:
return False
return True
def register(self):
self.send(b'')
username = self.recv()
return username
def getpermission(self, name, iv, key):
aes = AES.new(key, AES.MODE_CBC, iv)
plain = Pad(name)+b"a_cat_permission"
return aes.encrypt(plain)
def getmessage(self, iv, key, permission):
aes = AES.new(key, AES.MODE_CBC, iv)
return aes.decrypt(permission)
def handle(self):
signal.alarm(50)
if not self.proof_of_work():
return
self.send(BANNER, newline=False)
self.key = os.urandom(16)
self.iv = os.urandom(16)
self.send(b"I'm the guard, responsible for protecting the prince's safety.")
self.send(b"You shall not pass, unless you have the permission of the prince.")
self.send(b"You have two choices now. Tell me who you are or leave now!")
self.send(guard_menu, newline=False)
option = self.recv()
if option == b'1':
try:
self.name = self.register()
self.send(b"Hello " + self.name)
self.send(b"Nice to meet you. But I can't let you pass. I can give you a cat. She will play with you")
self.send(b'Miao~ ' + self.iv)
for i in range(3):
self.send(b"I'm a magic cat. What can I help you")
self.send(cat_menu, newline=False)
op = self.recv()
if op == b'1':
self.send(b"Looks like you want permission. Here you are~")
permission = self.getpermission(self.name, self.iv, self.key)
self.send(b"Permission:" + permission)
elif op == b'2':
self.send(b"Looks like you want to know something. Give me your permission:")
permission = self.recv()
self.send(b"Miao~ ")
iv = self.recv()
plain = self.getmessage(iv, self.key, permission)
self.send(b"The message is " + plain)
elif op == b'3':
self.send(b"I'm leaving. Bye~")
break
self.send(b"Oh, you're here again. Let me check your permission.")
self.send(b"Give me your permission:")
cipher = self.recv()
self.send(b"What's the cat tell you?")
iv = self.recv()
plain = self.getmessage(iv, self.key, cipher)
prs, uid = plain[16:],plain[:16]
if prs != b'Princepermission' or uid != self.name:
self.send(b"You don't have the Prince Permission. Go away!")
return
else:
self.send(b"Unbelievable! How did you get it!")
self.send(b"The prince asked me to tell you this:")
f = open('flag.txt', 'rb')
flag = f.read()
f.close()
self.send(flag)
except:
self.request.close()
if option == b'2':
self.send(b"Stay away from here!")
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', 10005
print("HOST:POST " + HOST + ":" + str(PORT))
server = ForkedServer((HOST, PORT), Task)
server.allow_reuse_address = True
server.serve_forever()
题目不难,但是代码有点长,熟悉一下流程接着逐个理清函数的作用即可
此题采用的是ECB模式的AES加密(考的还是通过修改数据来达到绕过检测的目的)与CBC翻转类似,但是多了一步对前面的iv的修改
代码如下:
import hashlib
from pwn import *
from itertools import product
import string
from Crypto.Util.number import *
p=remote('node4.buuoj.cn',26813)
#context.log_level = 'debug'
table = string.ascii_letters + string.digits
def proof_of_work():
proof = p.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:
p.recvuntil(b'[+] Give Me XXXX :')
p.sendline(head.encode())
break
proof_of_work()
p.recvuntil('[-]')
p.sendline('1')
p.recvuntil('[-]')
p.sendline('hashhashhashhash')
p.recvuntil('Miao~ ')
iv=p.recvuntil('\n')[:-1]
iv1=hex(bytes_to_long(iv))[2:]
p.recvuntil('[-]')
p.sendline('1')
p.recvuntil('Permission:')
c=p.recvuntil('\n')[:-1]
c1=hex(bytes_to_long(c))[2:]
SUB1=str(c1)
sub1=hex(int(SUB1[:12],16)^bytes_to_long(b'a_cat_')^bytes_to_long(b'Prince'))[2:]
c1=int(str(sub1)+SUB1[12:],16)
print(hex(c1))
c=long_to_bytes(c1)
p.recvuntil('[-]')
p.sendline('2')
p.recvuntil('[-]')
p.sendline(c)
p.recvuntil('[-]')
p.sendline(iv)
p.recvuntil('The message is ')
temp=hex(bytes_to_long(p.recvuntil('\n')[:-1]))[2:]
print(temp)
SUB2=str(iv1)
sub2=hex(int(SUB2,16)^int(str(temp)[:32],16)^bytes_to_long(b'hashhashhashhash'))[2:]
iv1=int(str(sub2),16)
print(hex(iv1))
iv=long_to_bytes(iv1)
p.recvuntil('[-]')
p.sendline('3')
p.recvuntil('[-]')
p.sendline(c)
p.recvuntil('[-]')
p.sendline(iv)
p.interactive()

浙公网安备 33010602011771号