强网拟态MISC&Crypto
MISC
Find way to read video
题目
amily0721 has put her email template on a public platform.
有些东西在public平台上被公开了!
分析
amily0721 has put her email template on a public platform.
去公开的平台上寻找amily0721,最终在gitcode上找到邮件模板,
分析邮件,有好多邮件组成,里面还有有详细的法条This mail is being sent in compliance with Senate bill 2716 , Title 4 ; Section 306 . ,尝试搜索Dear后面的名字,无果;在尝试搜法案,发现是垃圾邮件,有专门加减密的网站,去在线网站解密
得到
BV1FD2EYyEWo eyJ2IjozLCJuIjoiZmxhZyIsInMiOiIiLCJoIjoiMDI1NTVlZiIsIm0iOjkwLCJrIjo4MSwibWciOjIwMCwia2ciOjEzMCwibCI6NDMsInNsIjoxLCJmaGwiOlsiMjUyZjEwYyIsImFjYWM4NmMiLCJjYTk3ODExIiwiY2QwYWE5OCIsIjAyMWZiNTkiLCI0ZTA3NDA4IiwiNWZlY2ViNiIsIjNlMjNlODEiLCIzZTIzZTgxIiwiMTk1ODFlMiIsIjE4YWMzZTciLCI2Yjg2YjI3IiwiMThhYzNlNyIsIjM5NzNlMDIiLCIxOGFjM2U3IiwiMThhYzNlNyIsImU3ZjZjMDEiLCI0ZTA3NDA4IiwiMzk3M2UwMiIsIjRiMjI3NzciLCJkNDczNWUzIiwiNmI4NmIyNyIsIjRlMDc0MDgiLCIzOTczZTAyIiwiY2E5NzgxMSIsIjRlMDc0MDgiLCI2Yjg2YjI3IiwiZTdmNmMwMSIsIjM5NzNlMDIiLCJjYTk3ODExIiwiMThhYzNlNyIsIjE4YWMzZTciLCI0YjIyNzc3IiwiNGIyMjc3NyIsIjRiMjI3NzciLCJlZjJkMTI3IiwiMTk1ODFlMiIsIjZiODZiMjciLCI0YjIyNzc3IiwiNzkwMjY5OSIsIjJjNjI0MjMiLCJkMTBiMzZhIiwiMDFiYTQ3MSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNmUzNDBiOSIsIjZlMzQwYjkiLCI2ZTM0MGI5IiwiNzliZWM3ZiIsImU3N2I5YTkiLCJhYjg5N2ZiIiwiNGFlODE1NyIsImNiZTVjZmQiLCI4OGFhM2UzIiwiMTQ4ZGU5YyIsIjVkNWM3ZDIiLCI5NDlmOTRkIl19
base64解码
]EaÈE¨{"v":3,"n":"flag","s":"","h":"02555ef","m":90,"k":81,"mg":200,"kg":130,"l":43,"sl":1,"fhl":["252f10c","acac86c","ca97811","cd0aa98","021fb59","4e07408","5feceb6","3e23e81","3e23e81","19581e2","18ac3e7","6b86b27","18ac3e7","3973e02","18ac3e7","18ac3e7","e7f6c01","4e07408","3973e02","4b22777","d4735e3","6b86b27","4e07408","3973e02","ca97811","4e07408","6b86b27","e7f6c01","3973e02","ca97811","18ac3e7","18ac3e7","4b22777","4b22777","4b22777","ef2d127","19581e2","6b86b27","4b22777","7902699","2c62423","d10b36a","01ba471","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","6e340b9","79bec7f","e77b9a9","ab897fb","4ae8157","cbe5cfd","88aa3e3","148de9c","5d5c7d2","949f94d"]}
发现开头BV1FD2EYyEWo没解码出来,题目提示信息是要找video,去b站上搜BV1FD2EYyEWo,发现有90个flag视频,
仔细分析视频,里面每秒出现一个由.-组成的电码,手搓一点,发现类里面的-长短不一样,不像是莫斯,,先把视频下载出来,然后提取出图片,
让chat帮忙写一下提取图片的脚本,分离出图片
import cv2
import os
from PIL import Image
FREQUENCY = 1 # 提取频率(每秒提取一帧)
def extract_frames(video_path, dst_folder, index=1):
"""从视频中提取帧并保存为图片。"""
video = cv2.VideoCapture(video_path)
if not video.isOpened():
print(f"无法打开视频:{video_path}")
return
count = 0
while True:
success, frame = video.read()
if not success:
break # 视频读取结束
if count % FREQUENCY == 0:
save_path = f"{dst_folder}/{index:03d}.jpg"
cv2.imwrite(save_path, frame) # 保存图片
index += 1
count += 1
video.release()
print(f"从 {video_path} 提取了 {index - 1} 张图片")
# 批量处理视频
filePath = "./flag" # 视频文件夹路径
dst_folder = "./pic" # 图片保存的总目录
for i, file in enumerate(os.listdir(filePath)):
if file.endswith(".mp4"): # 只处理 .mp4 文件
video_path = os.path.join(filePath, file)
pic_path = os.path.join(dst_folder, f"pic{i}") # 创建对应的图片目录
os.makedirs(pic_path, exist_ok=True)
extract_frames(video_path, pic_path)
{"v":3,"n":"flag","s":"","h":"02555ef","m":90,"k":81,"mg":200,"kg":130,"l":43,"sl":1,"fhl":很好奇这段信息是否有帮助,是否代表位置信息。先分析每个视频中第一个白点出现的地方,看他们的位置是否相同,仔细对比,发现每个视频的起始位置并不是一样的,第一个视频切出的第五张图,出现的是-- -- ,前面分析了不是莫斯,那就就可能是0,1二进制表示,后面的图片像极了01数据自增,尝试提取图片像素
from PIL import Image
pic_path = "./pic/pic0"
pic_img_path = os.path.join(pic_path, "005.jpg")
image = Image.open(pic_img_path)
flag = ['0'] * 8
for x in range(32, 32 + 8):
pixel_value = image.getpixel((x, 0))
if pixel_value >= (10, 10, 10):
flag[x - 32] = '1'
m = int.to_bytes(int(''.join(flag), 2), 1, 'big')
print(m)
刚好得到了f
,猜测flag在后面图片中,尝试后发现后面基本上确实是二进制自增
分析取后面视频的第5张图片,发现每张都不一样像极了flag,尝试提得后到flag
from PIL import Image
m = b""
for i in range(90):
pic_path = "./pic/pic"+str(i)
pic_img_path = os.path.join(pic_path, "005.jpg")
image = Image.open(pic_img_path)
flag = ['0'] * 8
for x in range(32, 32 + 8):
pixel_value = image.getpixel((x, 0))
if pixel_value >= (10, 10, 10):
flag[x - 32] = '1'
m += int.to_bytes(int(''.join(flag), 2), 1, 'big')
print(m)
Crypto
xor
题目
mimic is a keyword.
0b050c0e180e585f5c52555c5544545c0a0f44535f0f5e445658595844050f5d0f0f55590c555e5a0914
分析
简单循环异或
CFBchall
题目
遭遇过几次拖库之后,我们直接删除了数据库!请你保存好生成的token,不要篡改哦~
from flask import Flask, render_template, request, jsonify
from Crypto.Cipher import AES
import os
from string import printable
app = Flask(__name__)
# 初始化全局变量
def initialize_globals():
global key, iv,register_open, login_attempts
key = os.urandom(16)
iv = os.urandom(16)
register_open = True
login_attempts = 500
initialize_globals()
def encrypt(data, key):
#iv = os.urandom(16)
cipher = AES.new(key, AES.MODE_CFB, iv=iv)
ct_bytes = cipher.encrypt(data.encode('utf-8'))
return ct_bytes.hex()
def decrypt(ct, key):
ct_bytes = bytes.fromhex(ct)
#iv = ct_bytes[:16]
cipher = AES.new(key, AES.MODE_CFB, iv=iv)
data = cipher.decrypt(ct_bytes[:])
#print("data:",data)
return data
@app.route('/', methods=['GET', 'POST'])
def index():
global register_open, login_attempts
message = ""
if request.method in ['POST']:
if request.is_json:
data = request.get_json()
action = data.get('action')
if action == 'register':
if not register_open:
message = "Registration function is closed"
else:
username = data.get('username')
password = data.get('password')
if len(password)<8:
message = "Registration failed, password too short"
elif not set(password+username)<=set(printable):
message = "Registration failed, illegal character"
elif 'admin' in username:
message = "Registration failed, you are not an admin"
else:
token = encrypt(f"{username}\x00{password}\x01\x02\x03", key)
register_open = False
message = f"Please save your token: {token}"
elif action == 'login':
if login_attempts <= 0:
message = "Too many attempts"
else:
username = data.get('username').encode()
password = data.get('password').encode()
token = data.get('token')
try:
decrypted = decrypt(token, key)
#print(decrypted)
token_username, *_, token_password = decrypted.split(b'\x00')
#print(token_username,",",token_password)
assert(token_password[-3:]==b"\x01\x02\x03")
token_password=token_password[:-3]
if username == token_username and password == token_password:
if username == b'admin':
#print(token_password)
if password == b'123456':
f=open("./flag","r")
flag=f.read()
#print(flag)
f.close()
message = "You have logged in with admin privileges, here is your flag: "+flag
else:
message = "Admin login failed, please try again"
else:
message = "You have logged in as a regular user"
else:
message = "Login failed, please try again"
except:
message = "Login wrong, please try again"
finally:
login_attempts -= 1
elif action == 'restart':
initialize_globals()
message = "System has been restarted. AES key and function counts have been reset."
else:
message = "Unsupported Media Type: Content-Type must be application/json"
return jsonify({'message': message})
return render_template('index.html', message=message)
if __name__ == '__main__':
app.run(host="0.0.0.0")
分析
考察CFB模式特性
CFB模式是一种将AES的块加密算法转化为流加密算法的方式,适用于连续数据流的加密,不需要对数据进行填充。
在CFB模式中,如果某一块密文发生错误,错误只会影响当前块和后续一块,限制了错误的扩散。
比特翻转:CFB模式中,明文和密文的关系如下
可以对密文中的某一比特位进行翻转,进而改变解密后的明文内容,如将admim
伪造成admin
hex(int(token[8:10], 16) ^ ord('m') ^ ord('n'))[2:].zfill(2)
本题使用了\x00
进行截断,因翻转了m
的密文,所以确定后面一块密文受到影响,可以爆破出\x00
与原有\x00
进行组合截断,从而只保留翻转出来的admin
。
注册时password要大于等于8,但登录时admin所对应的密码为123456,又需要\x00
进行截断伪造。可以构造17个字节加123456
,改变第一个字节对应的密文,后面16个字节的密文块受到影响,且最后一个字节有概率出现\x00
与原有的\x00
组合截断从而丢弃中间的17个字节只保留123456
。
import requests
def login(token, password):
data = {"action": "login", "username": "admin", "password": password, "token": token}
return requests.post(url, json=data).json()["message"]
def initialize_globals():
requests.post(url, json={"action": "restart"})
def register():
data = {"action": "register", "username": username, "password": password}
token = requests.post(url, json=data).json()["message"]
return token.split(': ')[1]
def get_admin(token, token0):
for i in range(256):
ct = token0 + hex(i)[2:].zfill(2) + token[12:]
decrypted = login(ct, password)
print(decrypted)
if "Admin login failed" in decrypted:
return i
return None
url = "http://web-549638574d.challenge.xctf.org.cn:80/"
username = "admim" + "2" * 17
password = "1" * 17 + "123456"
data = f"{username}\x00{password}\x01\x02\x03"
while True:
initialize_globals()
token = register()
signal = 0
token0 = token[:8] + hex(int(token[8:10], 16) ^ ord('m') ^ ord('n'))[2:].zfill(2)
k = get_admin(token, token0)
if k is None: continue
ct0 = token0 + hex(k)[2:].zfill(2)
for i in range(256):
ct = ct0 + token[12:12 + 44] + hex(i)[2:].zfill(2) + token[-50:]
# decrypted = decrypt(ct, key)
decrypted = login(ct, "123456")
print(decrypted)
if "flag" in decrypted:
print(decrypted)
signal = 1
break
if signal == 1:
break
watermarking
计算太贵了!想跟我讲话,首先得买我的水印!
题目
from Crypto.Util.number import *
from Crypto.Cipher import AES
from hashlib import sha256
import socketserver
import signal
import os
import string
import random
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from Crypto.Util.number import getPrime,getStrongPrime
from Crypto.Random import get_random_bytes
from sympy import nextprime
class Task(socketserver.BaseRequestHandler):
def _recvall(self):
BUFF_SIZE = 4096
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 handle(self):
e=3
maxlens=4096
RSAparameter=None
signal.alarm(60)
watermark=os.urandom(512)
self.send(b"welcome to my proxy encryption program with watermarking")
messages=[]
while 1:
self.send(b"1 for free encrypt with time limit")
self.send(b"2 for check your watermarking ")
self.send(b"plz input function code")
try:
mode=int(self.recv())
except:
self.send(b"plz input right function code")
continue
if mode==1:
if maxlens<=0:
self.send(b"sorry, no free chance, try last time~")
continue
self.send(b"now choose your n bitlens")
self.send(b"1. 1024 2. 2048 3. 4096")
try:
mode=int(self.recv())
except:
self.send(b"plz input right function code")
continue
if mode==1:
newparameter=1024
if mode==2:
newparameter=2048
if mode==3:
newparameter=4096
if newparameter!= RSAparameter:
RSAparameter=newparameter
p=getStrongPrime(RSAparameter//2)
q=getStrongPrime(RSAparameter//2)
n=p*q
phi=(p-1)*(q-1)
self.send(b"your n is changed to")
self.send(hex(n).encode())
try:
rsa_key = RSA.construct((n, e))
public_key = rsa_key.publickey().export_key()
cipher = PKCS1_v1_5.new(RSA.import_key(public_key))
self.send(b"plz input your message with hex")
message=self.recv().decode()
#print(message,len(message))
messages.append(message)
message=watermark[:RSAparameter//16]+bytes.fromhex(message)
#print(message)
c = (cipher.encrypt(message)).hex().encode()
#print(c)
self.send(c)
e=nextprime(e)
maxlens-=RSAparameter
except:
self.send(b"wrong~ try again")
continue
elif mode==2:
if maxlens>0:
self.send(b"sorry, not even yet~")
continue
self.send(b"now give me your message without free chance")
e=65537
d=pow(e,-1,phi)
rsa_key = RSA.construct((n, e,d))
public_key = rsa_key.publickey().export_key()
cipher = PKCS1_v1_5.new(rsa_key)
cts=self.recv().decode()
cts=bytes.fromhex(cts)
try:
p = (cipher.decrypt(cts,b"bad cipertext"))
print(p)
except Exception as e:
print(e)
self.send(b"wrong~ try again")
continue
if p[:RSAparameter//16]!=watermark[:RSAparameter//16]:
self.send(b"not used the watermark!")
continue
if p[RSAparameter//16:].hex() in messages:
self.send(b"not cost!")
continue
f=open("./flag","rb")
flag=f.read()
f.close()
self.send(b"cong! your flag is "+flag)
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', 9999
print("HOST:POST " + HOST+":" + str(PORT))
server = ForkedServer((HOST, PORT), Task)
server.allow_reuse_address = True
server.serve_forever()
分析
加密:
watermark=os.urandom(512)
maxlens=4096
n的bit 可以选择 1024,2048,4096,生成p,q,n
如果n的bit 等于上一轮nbit,那么不再重新生成p,q,n不变
e=3,给出message,m=watermark[:nbit//16]+mmessage
对m进行pkcs#1 v1.5填充加密,输出c
每经过一轮,e=nextprime,maxlens-nbit
直到maxlens=0结束
1024 1024 1024 1024 e--11
1024 1024 2048 e--7
1024 2048 1024 e--7
2028 1024 1024 e--7
2048 2048 e--5
4096 e--3
解密:
n就是最后一轮加密的n
e=65537
p=decrypt(m,e,n)
如果pkcs#1 v1.5解填充成功,并且p中含有watermark[:nbit//16],但不含你给出的message
查看PKCS#1 v1.5 encryption padding源码
def encrypt(self, message):
"""Produce the PKCS#1 v1.5 encryption of a message.This function is named ``RSAES-PKCS1-V1_5-ENCRYPT``, and it is specified in
`section 7.2.1 of RFC8017
<https://tools.ietf.org/html/rfc8017#page-28>`_.
:param message:
The message to encrypt, also known as plaintext. It can be of
variable length, but not longer than the RSA modulus (in bytes) minus 11.
:type message: bytes/bytearray/memoryview
:Returns: A byte string, the ciphertext in which the message is encrypted.
It is as long as the RSA modulus (in bytes).
:Raises ValueError:
If the RSA key length is not sufficiently long to deal with the given
message.
"""
# See 7.2.1 in RFC8017
k = self._key.size_in_bytes()
mLen = len(message)
# Step 1
if mLen > k - 11:
raise ValueError("Plaintext is too long.")
# Step 2a
ps = []
while len(ps) != k - mLen - 3:
new_byte = self._randfunc(1)
if bord(new_byte[0]) == 0x00:
continue
ps.append(new_byte)
ps = b"".join(ps)
# Step 2b
em = b'\x00\x02' + ps + b'\x00' + _copy_bytes(None, None, message)
# Step 3a (OS2IP)
em_int = bytes_to_long(em)
# Step 3b (RSAEP)
m_int = self._key._encrypt(em_int)
# Step 3c (I2OSP)
c = long_to_bytes(m_int, k)
return c
EM = 0x00 || 0x02 || PS || 0x00 || M
EM是最终要被加密的明文,PS是随机生成的不小于8字节的内容不含0x00的数据,更准确的说PS的长度应该为k - mLen - 3
题目中
em=0x00 || 0x02 || PS || 0x00 || watermark[:nbit//16]+m
求出watermark[:nbit//16],
构造
"\x00\x02" + urandom(8) + b"\x00" + watermark + urandom(117),即可获得flag
求watermark,Coppersmith’s short-pad attack
在Sage中有通用的方法来进行消元从而化归到单变量的形式
结式(resultant): f.resultant(g, q)
EG.g = f1.resultant(f2, q)
消去了变量q
f = N - p*q
g = p+q - p_plus_q
h = f.resultant(g, q)
print([f, g])
# [-p*q + 91, p + q - 20]
print([h, factor(h)])
# [-p^2 + 20*p - 91, (-1) * (p - 13) * (p - 7)]
Sage内置的resultant实现不能满足计例如在Zmod(n)下,或很大的有限域下。这时可以先转化为
Sylvester矩阵,再计算矩阵的行列式
from sage.matrix.matrix2 import Matrix
Matrix.determinant(f1.sylvester_matrix(f2, var))
消去m1变成只有a存在的单变量的形式
a=(ps1-ps2) 八字节 8*8 64bit copper攻击得到a,
gcd(f1,f2)==M1
from http.client import responses
from os import urandom
from Crypto.Util.number import long_to_bytes, bytes_to_long
from pwn import *
from sage.all import *
# context.log_level='debug'
re=remote("124.223.10.170",12000)
c=[]
re.recvuntil(b'>')
re.sendline(b'1')
re.recvuntil(b'>')
re.sendline(b'2')
re.recvline()
n=int(re.recvline().decode().strip(),16)
print(f'{n=}')
message=urandom(245-2048 // 16)
print(f'{message=}')
re.recvuntil(b'>')
re.sendline(message.hex().encode())
c1=re.recvline().decode().strip()
print(f'{c1=}')
c1=int(c1,16)
re.recvuntil(b'>')
re.sendline(b'1')
re.recvuntil(b'>')
re.sendline(b'2')
re.recvuntil(b'>')
re.sendline(message.hex().encode())
c2=re.recvline().decode().strip()
print(f'{c2=}')
c2=int(c2,16)
PR.<a,x>= PolynomialRing(Zmod(n))
f1=x^3-c1
f2=(2^(8*246)*a+x)^5-c2
t=f1.sylvester_matrix(f2, x)
res=t.det()
PR1.<a> = PolynomialRing(Zmod(n))
res=eval(str(res).replace("^","**"))
res=res.monic()
a=res.small_roots(X=2**64,beta=0.5)[0]
PR.<x> = PolynomialRing(Zmod(n))
f1 = (x)^3 - c1
f2=(2^(8*246)*a+x)^5-c2
def gcd(g1, g2):
while g2:
g1, g2 = g2, g1 % g2
return g1.monic()
m = -gcd(f1, f2)[0]
watermark = long_to_bytes(int(m), 256)
print(f'{watermark=}')
re.recvuntil(b'>')
re.sendline(b'2')
re.recvline()
msg = b"\x00\x02" + urandom(8) + b"\x00" + watermark[11:11+128] + urandom(117)
ct = int(pow(bytes_to_long(msg), 65537, n))
print(f'{ct=}')
wei_message=long_to_bytes(ct).hex()
re.sendline(wei_message.encode())
re.recvuntil(b"cong! your flag is ")
flag=re.recvline()
print(flag)
re.interactive()
# b'welcome to my proxy encryption program with watermarking\n1 for free encrypt with time limit\n2 for check your watermarking \nplz input function code\n>'
# b' now choose your n bitlens\n1. 1024 2. 2048 3. 4096\n>'
# b' your n is changed to\n'
# n=22871499096953256526645322468035980618391980741781388630105510538793939947971570404996508522120309579475680627998610224649437434209180471832337705699590355261709013176067318230976515679362020967103987323487802455521315803979431734938044979900759431421068276974811022252784244587782605744072334661693985297627667054459757071053197161966966183983814888410381801898238412103796536046427828878821813388194184321987289585405673030004645604375989176226593489792938377601445540913328958268822094842351261659871799818449471352500906779537457881423439640521337291721708013586197731869596357254279708231125543898273798218499183
# message=b'\r\xd7\x8c\xf7\xfd\x98\xe2\xf8\x88 \xba\xef\xf3\x86\x1f4}5\x94\x97\xd3RC\x00z\xce\xd4\xb8\x9b\xbf\xb2a\xd7\x0b?\x1c\xc8\x88\x0e\xbau\x94T\xbb\x8es\xb2\xbd\xcd\x93\xe7\x90\xd1\x11\xf3{\xeb\x1f2\xeb9\xd6HLp`\xb6\xf0\x03\x1f8\xd4u\xca\xc7\x04\x1b0\xee\xc9\xc2L\xb2\x9e(ou)L\x1cd\x8d\xd7\x82\x9e\x84(\xa4y\xda\x01\xa3\xae\x90l\xe6>#\x00:\xba\x1a\t\xfbI\xcd\x9b'
# b'plz input your message with hex\n>'
# c1='1fc500ee133a462ada0c4b4867ab6a4c3948eb40877a00c51de6ababe2f8b030540acb4ec7b17a430b064cb43c8719d26e229b9737e0e846fb70de751575c72dd54a6236781d1299f22f799c9e749a3646b2218a42cca6938b7dc7ecaacabde345d40dbc5a437e3e6d7250b9082ec1d6232360c5d6d52510c51524fa1a93a3c002767dc861c799cf902497887ac530f08452b4692981b4d98a077c6f6fdc9a680563160ab4a362d147e2ff4bb027092bf4ade93d9c369d821f5df06ae24bf7acf4dfd1250058ec93bcd39497b0d5a5da42d3d4ce055951669525dc39f4871a924d14ccfd3bfc704de53ea9a058b3ee8b44a6cf5f0651b0a898d01cd4b3bd1e6a'
# b'1 for free encrypt with time limit\n2 for check your watermarking \nplz input function code\n>'
# b' now choose your n bitlens\n1. 1024 2. 2048 3. 4096\n>'
# b' plz input your message with hex\n>'
# c2='049110ccc39fdf7e5aa93f81aef4bf396f19d02e256a34e2175acdc9e0f4dfdf2a0c4e3c939ed09c7a8efc6a2b39f424a4dcec0dcf42b78ac9f3bad5e8a96b33b80782e2103c48a5e282228dc3accedc477b52c2d4d81dd287159a2a226e10c0f9f70f72cabc7ba1c568bad685d46e87373400409b32bfc46185db0bd664d6fa4fb50419f62ec0d864a5de033c938b0652c0c6ded001422f9ffd9b2da2b87074c62677c5da5d4abc4a931c809a2acaecb189903dfd1a2e83425ae4474e65bc06c7732446bda2cb992f29e3b9913ff3b7eeaf739606e0f60d474b8b558655a88d352d68cfb5988d38761a430812a7fbe054fa37a0005f7d51219223e35bb8a381'
# watermark=b'\x00\x02\xa1\x85\xc2\xc3\xa7Wo\xf1\x00}\xcd;4\x1c\x00\x0fS\x80Y\xd6\xae!>\xda\x0c\x156@\xb8\x9a\x98\x1av\xe1&\xa7\xa3\xe2\xce\x8a\xfb\x12<\x97i\xbe\xd5\xffp\xf9_\x0c\xad\x1f-P~:\xad\xbeN\xcd\x12L\x9c\xf2\xf6\xea\x9e\xb1\xd2%\xf0\xf2\xda\xe6D\x17nrY\x13\xb6V\x99\x0e\xc2\x1a\xfa\x97\x11\x9f\xf9j\xba$\xa6\r\x81^Y\x87\xa6\xc5R\xac9\xd7\xf8\xcb\xf3R\xcf\xc3\x96\x12\xf1\xb4B\xb9\x98\x06\xc6@\xac\x04\xc7\x8f#3\x0f=$\x7f\xa8\xf9\xca\r\xd7\x8c\xf7\xfd\x98\xe2\xf8\x88 \xba\xef\xf3\x86\x1f4}5\x94\x97\xd3RC\x00z\xce\xd4\xb8\x9b\xbf\xb2a\xd7\x0b?\x1c\xc8\x88\x0e\xbau\x94T\xbb\x8es\xb2\xbd\xcd\x93\xe7\x90\xd1\x11\xf3{\xeb\x1f2\xeb9\xd6HLp`\xb6\xf0\x03\x1f8\xd4u\xca\xc7\x04\x1b0\xee\xc9\xc2L\xb2\x9e(ou)L\x1cd\x8d\xd7\x82\x9e\x84(\xa4y\xda\x01\xa3\xae\x90l\xe6>#\x00:\xba\x1a\t\xfbI\xcd\x9b'
# b'1 for free encrypt with time limit\n2 for check your watermarking \nplz input function code\n>'
# b' now give me your message without free chance\n'
# ct=18171392056130170632697136167604589419783459492941622078742468727438054056511102954874107953620159726318555962194750406962982292144393445739154357451154199065754554227294501940966941096717019896290021398107395456084444256105059891122866745412055763116060302808295733386539517171737166287647962228852764769174454759581866828730527326411011394836523660721315720673175771770948102506963262060772853992314886180435992251579581358314191345719324465523727827783355931417983246074156222835742308842076172637675327038261140455782213034848993172703115605638695738698462742273403842605153516440401127947916904669810050953813381
# b'> cong! your flag is '
# b'flag{bda0dae2-1e60-4e04-a6ed-50857b102743}\n'
总结:
1.CFB模式特性:在CFB模式中,如果某一块密文发生错误,错误只会影响当前块和后续一块,限制了错误的扩散。
2.利用结式将多变量的多项式方程转化成单变量方程
3.Coppersmith’s Short-pad Attack和Related Message Attack(Franklin-Reiter攻击)
当padding 过短也有可能被很容易地攻击, padding 过短,其实就是对应的多项式的根会过小,是可以考虑copper attack 出padding内容