import argparse import importlib.util import math from pathlib import Path
try: import numpy as np from PIL import Image, ImageOps except Exception as e: raise SystemExit("请先安装依赖: pip install numpy pillow") from e
THIS_DIR = Path(__file__).resolve().parent
defload_data(): data_file = THIS_DIR / "grayscale_matrix.txt" withopen(data_file, "r") as f: content = f.read() flat = [int(x) for x in content.split()] return flat
defdivisors(n): d = [] for i inrange(1, int(math.sqrt(n)) + 1): if n % i == 0: d.append((i, n // i)) return d
deffilter_shapes(shapes): # 过滤出看起来合理的形状(最小边 >= 10,且长宽比在 0.2 - 5 之间) out = [] for w, h in shapes: if w < 10or h < 10: continue ar = w / h if0.2 <= ar <= 5: out.append((w, h)) return out
flat = load_data() n = len(flat) print(f"已加载灰度数据,共 {n} 像素")
if args.width: w = args.width if n % w != 0: raise SystemExit(f"指定宽度 {w} 不整除长度 {n}") h = n // w out = THIS_DIR / f"gray_{w}x{h}.png" save_image_from_flat(flat, w, h, out) print(f"已保存: {out}") return
cand = divisors(n) cand = cand + [(h, w) for w, h in cand] # 试两种方向 # 去重 cand = list({(w, h) for w, h in cand}) cand = filter_shapes(cand) # 按接近正方形排序(越接近平方越优先) cand.sort(key=lambda wh: abs(wh[0] - wh[1]))
from Crypto.Util.number import * from secret import flag p = getPrime(512) q = getPrime(512) n = p * q e = 65537 leak = p >> 230 m = bytes_to_long(flag) c = pow(m,e,n) print("n=",n) print("leak=",leak) print("c=",c) ''' n= 103581608824736882681702548494306557458428217716535853516637603198588994047254920265300207713666564839896694140347335581147943392868972670366375164657970346843271269181099927135708348654216625303445930822821038674590817017773788412711991032701431127674068750986033616138121464799190131518444610260228947206957 leak= 6614588561261434084424582030267010885893931492438594708489233399180372535747474192128 c= 38164947954316044802514640871285562707869793354907165622336840432488893861610651450862702262363481097538127040490478908756416851240578677195459996252755566510786486707340107057971217557295217072867673485369358370289506549932119879791474279677563080377456592139035501163534305008864900509896586230830001710243 '''
铜匠coppersmith先利用高位p求出p,在解RSA
py
from Crypto.Util.number import long_to_bytes
n = 103581608824736882681702548494306557458428217716535853516637603198588994047254920265300207713666564839896694140347335581147943392868972670366375164657970346843271269181099927135708348654216625303445930822821038674590817017773788412711991032701431127674068750986033616138121464799190131518444610260228947206957 leak = 6614588561261434084424582030267010885893931492438594708489233399180372535747474192128 c = 38164947954316044802514640871285562707869793354907165622336840432488893861610651450862702262363481097538127040490478908756416851240578677195459996252755566510786486707340107057971217557295217072867673485369358370289506549932119879791474279677563080377456592139035501163534305008864900509896586230830001710243 e = 65537
# 1. 恢复高位 p_high = leak << 230
# 2. 定义多项式环 PR.<x> = PolynomialRing(Zmod(n)) f = x + p_high
from Crypto.Util.number import * from gmpy2 import * from random import * import string k = randint(30, 40) str = string.digits + string.ascii_letters + "_@" flag = b"VIDAR{" + "".join([choice(str) for i inrange(k)]).encode() + b"}" p = getPrime(120) q = getPrime(120) n = p * q e = 65537 m = bytes_to_long(flag) c = pow(m, e, n) print(f'c = {c}') print(f'p = {p}') print(f'q = {q}')
''' c = 451420045234442273941376910979916645887835448913611695130061067762180161 p = 722243413239346736518453990676052563 q = 777452004761824304315754169245494387 '''
n太小,导致RSA求解的数据变为 c % n 。 因为已知c前缀 “Vidar{” 和后缀 “}” ,可构建一个lll格约束爆破寻找flag。
py
import string from Crypto.Util.number import bytes_to_long, long_to_bytes
defsolve_flag(): # 按照题目 randint(30, 40) for k inrange(30, 41): print(f"\n[+] Testing length k = {k}...") # 1. 建立基础偏移 # Flag = prefix << (8k + 8) + unknown << 8 + suffix # unknown = sum(y_i * 256^(k-1-i)) target = (m1 - suffix - (prefix << (8*k + 8))) % n # A 是 unknown 整体相对于 n 的系数,这里是 2^8 A_total = pow(2, 8, n) # 计算每一位字符 y_i 对应的权重 coeffs_i # y = y_0*256^(k-1) + y_1*256^(k-2) + ... + y_{k-1}*256^0 coeffs = [(A_total * pow(256, k - 1 - i, n)) % n for i inrange(k)] # 2. 尝试不同的中心点(因为字符集分布并不均匀) # 典型的 ASCII 集中在 48-122,中心点 85 附近 for center inrange(60, 101, 2): const_sum = sum(center * c for c in coeffs) % n new_target = (target - const_sum) % n # 3. 构造格 M # 我们要寻找 delta_i 使得 sum(delta_i * coeffs_i) - X*n = new_target W = 2^256# 强化同余约束 dim = k M = Matrix(ZZ, dim + 2, dim + 2) for i inrange(dim): M[i, i] = 1 M[i, dim] = coeffs[i] * W M[dim, dim] = n * W M[dim + 1, dim] = new_target * W M[dim + 1, dim + 1] = 1 # 4. LLL 约化 M_red = M.LLL() for row in M_red: if row[dim + 1] in [1, -1]: s = -int(row[dim + 1]) deltas = [row[i] * s for i inrange(dim)] actual_y = [center + d for d in deltas] # 验证并打分 try: res = bytes([int(round(x)) for x in actual_y]) score = sum(1for c in res if c in charset) if score > k - 5: # 容错门槛 print(f" [Center {center}] Score: {score}/{k} | {res}") if score == k: print(f"\n{'-'*20}") print(f"FOUND FLAG: {prefix_str.decode()}{res.decode()}}}") print(f"{'-'*20}") return except: continue