解析2025古剑山CTF Crypto - 四次方程求解挑战详解
文章探讨了一道密码学数学题,通过分析四次多项式方程y = x⁴ + a*x² + b*x + c的数量级差异,利用y的四次方根近似求解x,并结合暴力搜索与素性测试等方法成功求解出系数a。 2025-12-2 07:28:27 Author: www.freebuf.com(查看原文) 阅读量:9 收藏

题目概述

本题是一道经典的密码学数学题目,题目给出了一个四次多项式方程的计算结果,要求我们反向求解出方程中的某个系数,并以此生成flag。题目描述:"区区二元方程,肯定能解出来",看似简单,实则需要深刻理解数学性质和密码学原理。

题目分析

加密方案

查看题目源码task.sage,我们可以看到加密的核心逻辑:

p,x,a,b,c=getPrime(2025), getPrime(1024),getPrime(512),getPrime(1024),getPrime(1500)
y=x**4+a*x**2+b*x+c

题目生成了五个素数:

  • p: 2025位素数(题目中给出但未使用)

  • x: 1024位素数

  • a: 512位素数(这是我们的目标,需要求解出来)

  • b: 1024位素数

  • c: 1500位素数

然后计算四次多项式:

y = x^4 + a*x^2 + b*x + c

题目给出了y、b、c三个值,隐藏了x和a,要求我们求出a。

flag的生成方式是:

flag = b'flag{' + hashlib.md5(str(a).encode()).hexdigest().encode() + b'}'

已知信息

题目提供给我们的数据:

  • y: 一个非常大的整数(约4096位)

  • b: 1024位素数

  • c: 1500位素数

未知信息

我们需要求解:

  • x: 1024位素数

  • a: 512位素数(最终目标)

数学分析

方程结构

原方程为:

y = x^4 + a*x^2 + b*x + c

整理后得到:

a*x^2 = y - x^4 - b*x - c

因此:

a = (y - x^4 - b*x - c) / x^2

关键观察

这道题的关键突破点在于:y约等于x^4

为什么?我们来分析各项的数量级:

  1. x^4的规模:x是1024位素数,x^4约为4096位

  2. a*x^2的规模:a是512位,x^2是2048位,乘积约为2560位

  3. b*x的规模:b是1024位,x是1024位,乘积约为2048位

  4. c的规模:c是1500位

从上述分析可以看出:

  • y的主导项是x^4(4096位)

  • 其他项相比x^4都小得多(最大也只有2560位)

这意味着:y的高位部分主要由x^4决定

近似求解策略

既然y ≈ x^4,我们可以通过计算y的四次方根来近似得到x:

x_approx, exact = gmpy2.iroot(y, 4)

这里gmpy2.iroot函数返回两个值:

  • x_approx: y的整数四次方根

  • exact: 布尔值,表示是否为精确根

由于y = x^4 + (较小的项),所以:

  • 如果较小项之和为正,则x_approx略小于真实的x

  • 如果较小项之和为负(不可能,因为都是素数),则x_approx略大于真实的x

在本题中,ax^2 + bx + c必然为正,所以x_approx <= 真实的x,且差值很小。

解题思路

第一步:计算x的近似值

x_approx, exact = gmpy2.iroot(y, 4)

运行后得到x_approx的位长为1024位,与题目中x的位长完全匹配,这验证了我们的分析。

第二步:暴力搜索精确值

虽然x_approx非常接近真实的x,但我们需要找到精确的x值才能计算出正确的a。

我们知道x必须满足以下条件:

  1. x是素数

  2. x是1024位整数

  3. x是奇数(除了2以外所有素数都是奇数)

  4. x与x_approx非常接近

因此采用如下搜索策略:

for dx in range(-10000, 10000):
    xc = x_approx + dx

在x_approx周围±10000的范围内搜索。

第三步:验证候选值

对于每个候选值xc,我们需要验证多个条件:

条件1:奇数检查

if xc % 2 == 0:
    continue

素数(除了2)都是奇数,可以快速排除偶数。

条件2:素性检查

if not is_prime(xc):
    continue

使用gmpy2的素性测试,验证xc是否为素数。

条件3:位长检查

if xc.bit_length() != 1024:
    continue

x必须是1024位整数。

条件4:方程验证

如果x是正确的,那么a必须满足:

a = (y - x^4 - b*x - c) / x^2

这要求:

  1. 分子必须能被x^2整除(否则a不是整数)

  2. a必须是正数

  3. a必须是512位素数

代码实现:

x2 = xc * xc
x4 = x2 * x2
num = y - x4 - b * xc - c

# 检查能否整除
if num % x2 != 0:
    continue

a = num // x2

# 验证a的性质
if a > 0 and a.bit_length() == 512 and is_prime(a):
    print("找到正确的x和a!")
    break

第四步:生成flag

找到a后,按照题目要求生成flag:

flag = b'flag{' + hashlib.md5(str(a).encode()).hexdigest().encode() + b'}'

完整解题代码

import gmpy2
from gmpy2 import mpz, is_prime, isqrt
import hashlib

# 题目给定的值
y = mpz(198522960435841482189432265177909868426431703074708363449219028697324701510160286719731988116839697036160581630187160949885168801231636762705713983033164840216512010109089390010468198557792366011939222563881564708155342114969230636341034212421633874868858789397938243061335664034978831542864101231007091988193863118052712382091154270467198016237288512835005671248249864343182623298497353279333896185090300689372993251851698985725825619040354352099701531339567909888327001736937441117830890673409609636796619930226667955511073115983145641056494143455805357766933615911269415380543240132925744315363193308341329870002528062545716167903459438493154302274735882612908825416096548207130441684370171413794313131775960498691561791175984389699661776179746486882233034632979256741127422204726199986374102650551713456275685579171314911783130052174900534533297618292233601037654694611306838303066884626125878765611689352475739052132349596965687310082111652949904102268706219733830038063864703811394198182986558883397487207721093367621647038297033723455527107418011037322197091733780060565430632034276705456268207898108856563488519654411483838153783153351440293627133844440601677480833571012370843618968387929873540183054860492446381685034534436)
b = mpz(174037789483961573123221843591212086149338262121485604600830887974881925500571571986993457692950300053374733237615433793104052491813933671943903946487842930332507742237430616633825365722075237337670353892075697891908329460336348924680104502864021820883975695834115061923434753902679746280494899854826747016131)
c = mpz(33472511251772997775575923606329341691183359500908766818057589728522254242596438955590397842265158831677351198820346034459567637818737702918129437591421137895764213815168420429024803177742927091662422333575499875132388315943460516679655107714170719351306979285358080183600281172752401859701765071852769889627868633217209348758684870450300228084878260106253395883903968044935866937201968348531962567937222914516096107266208665856669507873113157476771707)

# 第一步:计算x的近似值
x_approx, exact = gmpy2.iroot(y, 4)
print("x_approx bit length:", x_approx.bit_length())

# 第二步:在近似值附近搜索精确的x
for dx in range(-10000, 10000):
    xc = x_approx + dx

    # 过滤条件1:必须是奇数
    if xc % 2 == 0:
        continue

    # 过滤条件2:必须是素数
    if not is_prime(xc):
        continue

    # 过滤条件3:必须是1024位
    if xc.bit_length() != 1024:
        continue

    # 第三步:验证方程并求解a
    x2 = xc * xc
    x4 = x2 * x2
    num = y - x4 - b * xc - c

    # 检查是否能整除
    if num % x2 != 0:
        continue

    a = num // x2

    # 验证a的性质
    if a > 0 and a.bit_length() == 512 and is_prime(a):
        print("x =", xc)
        print("a =", a)

        # 第四步:生成flag
        flag = b'flag{' + hashlib.md5(str(a).encode()).hexdigest().encode() + b'}'
        print("Flag:", flag.decode())
        break

运行结果

x_approx bit length: 1024
x = 118700537553211954550048004781775080401932332850570944095711624501897463083367644971859743574498196302011104420378652302813269169958574688007916893192307716154983803917438654233114797758373432605029710562957895322045205200076731671875204306942502853158331545499699193323983441371137557474651068912166123556729
a = 13342456772038855071856564172638324854222892143136347332583734986658804976828540066543494761438193576738170423487795386855661438330715380522711135350044589
Flag: flag{01a6eb898468abbd352300a7a072495c}

核心技术点总结

1. 数量级分析

在密码学问题中,分析各项的数量级至关重要。本题的突破口就是认识到y ≈ x^4这一关键性质。

2. 整数方根计算

gmpy2库的iroot函数可以高效计算大整数的整数方根,这是Python标准库所不具备的能力。

3. 素性测试优化

搜索过程中使用多重过滤条件:

  • 首先检查奇偶性(最快)

  • 然后检查位长(较快)

  • 最后才进行素性测试(较慢)

这样可以大幅减少昂贵的素性测试次数。

4. 整除性验证

在计算a之前,先验证(y - x^4 - b*x - c)能否被x^2整除,避免进行无效的除法运算。

5. 搜索范围估算

本题中搜索范围设为±10000,这是基于对误差范围的估计:

  • y - x^4的最大值约为ax^2 + bx + c

  • 其中a*x^2是主导项,约为2560位

  • 相比x^4(4096位),误差占比约为2^(2560-4096) ≈ 2^(-1536)

  • 因此x_approx与真实x的相对误差极小,绝对误差也很小

实际上在本题中,x_approx就等于真实的x(dx=0时找到),说明误差项之和小于1。

思考与延伸

为什么不能直接解方程?

这是一个关于x的四次方程,理论上可以通过Ferrari方法求解,但:

  1. 方程系数过大,符号计算极其复杂

  2. 涉及复杂的根式运算,数值精度难以保证

  3. 还需要验证哪个根是符合条件的素数

因此,利用数量级差异进行近似+暴力搜索反而是最有效的方法。

如果搜索范围不够怎么办?

如果±10000的范围内没找到,可以:

  1. 扩大搜索范围到±100000或更大

  2. 使用二分搜索等更高效的算法

  3. 利用更多约束条件(如模运算性质)缩小搜索空间

安全性分析

这个加密方案在密码学上是不安全的,原因在于:

  1. 高次项的数量级差异泄露了信息

  2. 可以通过数学分析大幅减小搜索空间

  3. 没有使用陷门函数,缺乏单向性保证

在实际密码系统中,应该使用经过严格安全性证明的方案,如RSA、ECC等。

总结

本题是一道优秀的CTF密码学题目,考察了以下知识点:

  1. 多项式方程的数学性质

  2. 大整数运算和数量级分析

  3. 素数的基本性质

  4. 暴力搜索与剪枝优化

  5. Python密码学库的使用

解题的核心思想是:通过数学分析将看似困难的问题转化为可控范围内的搜索问题。这种思维方式在密码学分析中极为重要,也是CTF竞赛的魅力所在。


文章来源: https://www.freebuf.com/articles/others-articles/459990.html
如有侵权请联系:admin#unsafe.sh