D3CTF复现(MangoFeng)
Misc
BadW3ter
下载附件后,看到是一个wav
文件,缺少文件头无法播放,然后加一下文件头后可正常播放
依据题目提示,用deepsound
打开去解密,发现需要密码
用了john
爆了很久之后也没爆出来
然后发现原来覆盖的文件头后是一串ascii
CUY1nw31lai
得到flag.png
是一个二维码
然后一扫
各种Never gonna ...
看一下图片的内容,有ps
的字样
改一下后缀名然后用ps
将其打开发现有两个图层,修改一下背景色,得到一个新的二维码
D3CTF{M1r@9e_T@nK_1s_Om0sh1roiii1111!!!!!Isn't_1t?}
Crypto
D3factor
from Crypto.Util.number import bytes_to_long, getPrime
from secret import msg
from sympy import nextprime
from gmpy2 import invert
from hashlib import md5
flag = 'd3ctf{'+md5(msg).hexdigest()+'}'
p = getPrime(256)
q = getPrime(256)
assert p > q
n = p * q
e = 0x10001
m = bytes_to_long(msg)
c = pow(m, e, n)
N = pow(p, 7) * q
phi = pow(p, 6) * (p - 1) * (q - 1)
d1 = getPrime(2000)
d2 = nextprime(d1 + getPrime(1000))
e1 = invert(d1, phi)
e2 = invert(d2, phi)
print(f'c = {c}')
print(f'N = {N}')
print(f'e1 = {e1}')
print(f'e2 = {e2}')
'''
c = 2420624631315473673388732074340410215657378096737020976722603529598864338532404224879219059105950005655100728361198499550862405660043591919681568611707967
N = 1476751427633071977599571983301151063258376731102955975364111147037204614220376883752032253407881568290520059515340434632858734689439268479399482315506043425541162646523388437842149125178447800616137044219916586942207838674001004007237861470176454543718752182312318068466051713087927370670177514666860822341380494154077020472814706123209865769048722380888175401791873273850281384147394075054950169002165357490796510950852631287689747360436384163758289159710264469722036320819123313773301072777844457895388797742631541101152819089150281489897683508400098693808473542212963868834485233858128220055727804326451310080791
e1 = 425735006018518321920113858371691046233291394270779139216531379266829453665704656868245884309574741300746121946724344532456337490492263690989727904837374279175606623404025598533405400677329916633307585813849635071097268989906426771864410852556381279117588496262787146588414873723983855041415476840445850171457530977221981125006107741100779529209163446405585696682186452013669643507275620439492021019544922913941472624874102604249376990616323884331293660116156782891935217575308895791623826306100692059131945495084654854521834016181452508329430102813663713333608459898915361745215871305547069325129687311358338082029
e2 = 1004512650658647383814190582513307789549094672255033373245432814519573537648997991452158231923692387604945039180687417026069655569594454408690445879849410118502279459189421806132654131287284719070037134752526923855821229397612868419416851456578505341237256609343187666849045678291935806441844686439591365338539029504178066823886051731466788474438373839803448380498800384597878814991008672054436093542513518012957106825842251155935855375353004898840663429274565622024673235081082222394015174831078190299524112112571718817712276118850981261489528540025810396786605197437842655180663611669918785635193552649262904644919
'''
分析一下题目可知信息有:e1,e2,N,c
四个已知信息
其中 N = p 7 ⋅ q , p h i = p 6 ⋅ ( p − 1 ) ⋅ ( q − 1 ) 以 及 { e 1 ⋅ d 1 ≡ 1 ( m o d p h i ) ( 1 ) e 2 ⋅ d 2 ≡ 1 ( m o d p h i ) ( 2 ) d 2 = d 1 + x ( 3 ) N=p^7\cdot q,phi=p^6\cdot (p-1)\cdot(q-1)以及\begin {cases}e_1\cdot d_1\equiv 1\pmod{phi}(1)\\e_2\cdot d_2\equiv1\pmod{phi}(2)\\d_2=d_1+x(3)\end{cases} N=p7⋅q,phi=p6⋅(p−1)⋅(q−1)以及⎩⎪⎨⎪⎧e1⋅d1≡1(modphi)(1)e2⋅d2≡1(modphi)(2)d2=d1+x(3)
d1 = getPrime(2000)
d2 = nextprime(d1 + getPrime(1000))
可将 d 2 与 d 1 间 的 跨 度 记 为 x 即 d 2 = d 1 + x d_2与d_1间的跨度记为x即d_2=d_1+x d2与d1间的跨度记为x即d2=d1+x
由(1)乘以e2和(2)乘以e1再相减可以得出
e 1 e 2 ( d 1 − d 2 ) + e 1 − e 2 ≡ 0 ( m o d p h i ) e_1e_2(d_1-d_2)+e_1-e_2\equiv0\pmod{phi} e1e2(d1−d2)+e1−e2≡0(modphi)
将(3)代入可得: e 1 e 2 x + e 1 − e 2 ≡ 0 ( m o d p h i ) e_1e_2x+e_1-e_2\equiv0\pmod{phi} e1e2x+e1−e2≡0(modphi)ps:此处x可正可负不影响
再由这篇文章:
得到 φ ( N ) = p r − 1 ( p − 1 ) ( q − 1 ) ⇒ e 1 e 2 x + e 1 − e 2 ≡ 0 ( m o d p r − 1 ) φ(N) = p^{r-1}(p−1)(q-1)\Rightarrow e_1e_2x+e_1-e_2\equiv0\pmod{p^{r-1}} φ(N)=pr−1(p−1)(q−1)⇒e1e2x+e1−e2≡0(modpr−1)
以及 g ( x ) = x − a ≡ 0 ( m o d p r − 1 ) w h e r e g(x)=x-a\equiv0\pmod{p^{r-1}} where g(x)=x−a≡0(modpr−1)where a ≡ ( e 2 − e 1 ) ( e 1 e 2 ) − 1 ( m o d N ) ( a s s e r t ( a < N ) ) a\equiv(e_2-e_1)(e_1e_2)^{-1}\pmod{N}(assert (a<N)) a≡(e2−e1)(e1e2)−1(modN)(assert(a<N))
给了一个Applying [Lenstra–Lenstra–Lovász lattice basis reduction algorithm] 其中就包含了Coppersmith method
接下来可计算a的大小(由题初分析已知e1,e2,N),然后未知数只有一个x,即采用一元coppersmith.其中 p r − 1 是 N 的 因 数 , 可 找 到 一 个 β 使 得 p r − 1 ≥ N β p^{r-1}是N的因数,可找到一个\beta使得p^{r-1} \geq N^{\beta} pr−1是N的因数,可找到一个β使得pr−1≥Nβ
从 而 解 出 x 然 后 就 能 通 过 g ( x ) 来 表 达 出 p r − 1 从而解出x然后就能通过g(x)来表达出p^{r-1} 从而解出x然后就能通过g(x)来表达出pr−1
即 x − a = k ⋅ p r − 1 ⇒ g c d ( x − a , N ) = p r − 1 ⇒ p ( 在 本 题 中 r = 7 ) x-a=k\cdot p^{r-1}\Rightarrow gcd(x-a,N)=p^{r-1}\Rightarrow p(在本题中r=7) x−a=k⋅pr−1⇒gcd(x−a,N)=pr−1⇒p(在本题中r=7)
from Crypto.Util.number import *
from gmpy2 import *
from hashlib import *
e = 65537
r = 7
c = 2420624631315473673388732074340410215657378096737020976722603529598864338532404224879219059105950005655100728361198499550862405660043591919681568611707967
N = 1476751427633071977599571983301151063258376731102955975364111147037204614220376883752032253407881568290520059515340434632858734689439268479399482315506043425541162646523388437842149125178447800616137044219916586942207838674001004007237861470176454543718752182312318068466051713087927370670177514666860822341380494154077020472814706123209865769048722380888175401791873273850281384147394075054950169002165357490796510950852631287689747360436384163758289159710264469722036320819123313773301072777844457895388797742631541101152819089150281489897683508400098693808473542212963868834485233858128220055727804326451310080791
e1 = 425735006018518321920113858371691046233291394270779139216531379266829453665704656868245884309574741300746121946724344532456337490492263690989727904837374279175606623404025598533405400677329916633307585813849635071097268989906426771864410852556381279117588496262787146588414873723983855041415476840445850171457530977221981125006107741100779529209163446405585696682186452013669643507275620439492021019544922913941472624874102604249376990616323884331293660116156782891935217575308895791623826306100692059131945495084654854521834016181452508329430102813663713333608459898915361745215871305547069325129687311358338082029
e2 = 1004512650658647383814190582513307789549094672255033373245432814519573537648997991452158231923692387604945039180687417026069655569594454408690445879849410118502279459189421806132654131287284719070037134752526923855821229397612868419416851456578505341237256609343187666849045678291935806441844686439591365338539029504178066823886051731466788474438373839803448380498800384597878814991008672054436093542513518012957106825842251155935855375353004898840663429274565622024673235081082222394015174831078190299524112112571718817712276118850981261489528540025810396786605197437842655180663611669918785635193552649262904644919
a = pow((e2-e1)*invert(e1*e2,N),1,N)
P.<x> = PolynomialRing(Zmod(N))
f = x-a
x = f.small_roots(X = 2^1000,beta = 0.4)
x = x[0]
kmultpr1 = x-a
pr1=gcd(mpz(kmultpr1),mpz(N))
p = iroot(int(pr1),(r-1))[0]
print(p)
#81911394167511996830305370213894554209992159667974516868378702592733037962549
q = N//(p**r)
#59689394622751323780317475130818337618980301243859922297121750335804594909859
print(q)
n = p*q
phi_n=(p-1)*(q-1)
d = invert(e,phi_n)
m = pow(c,d,n)
print(long_to_bytes(m))
# MM is still working on Valentine's Day.You can't be like him.
m = bytes.decode(long_to_bytes(m))
msg = md5(m.encode()).hexdigest()
print("d3ctf{"+msg+"}")
#d3ctf{42f79e777e622aef5344b04ad6233130}
babyqcg
from Crypto.Util.number import *
import random
from random import randint
from gmpy2 import *
from secret import flag
import hashlib
assert b'd3ctf' in flag
Bits = 512
UnKnownBits = 146
class QCG():
def __init__(self,bit_length):
p = getPrime(bit_length)
a = randint(0,p)
c = randint(0,p)
self._key = {'a':a,'c':c,'p':p}
self.secret = randint(0,p)
self.high = []
def Qnext(self,num):
return ((self._key['a'])*num**2+self._key['c'])%self._key['p']
def hint(self):
num = self.secret
for i in range(2):
num = self.Qnext(num)
self.high.append(num>>UnKnownBits)
def get_key(self):
return self._key
def get_hint(self):
return self.high
Q1 = QCG(Bits)
print(Q1.get_key())
#{'a': 3591518680290719943596137190796366296374484536382380061852237064647969442581391967815457547858969187198898670115651116598727939742165753798804458359397101, 'c': 6996824752943994631802515921125382520044917095172009220000813718617441355767447428067985103926211738826304567400243131010272198095205381950589038817395833, 'p': 7386537185240346459857715381835501419533088465984777861268951891482072249822526223542514664598394978163933836402581547418821954407062640385756448408431347}
Q1.hint()
print(Q1.get_hint())
#[67523583999102391286646648674827012089888650576715333147417362919706349137337570430286202361838682309142789833, 70007105679729967877791601360700732661124470473944792680253826569739619391572400148455527621676313801799318422]
enc = bytes_to_long(hashlib.sha512(b'%d'%(secret)).digest())^bytes_to_long(flag)
print(enc)
# 6176615302812247165125832378994890837952704874849571780971393318502417187945089718911116370840334873574762045429920150244413817389304969294624001945527125
分析一下:
首先Q1先用Bits=512然后构造了一些属性a,c,p,secret,然后我们通过get_key方法得到了a,c,p。
之后调用hint()函数在self.high里append了两个num>>UnkonwBits后的值,其中num是通过Qnext函数生成的,具体生成方法为:
{ n u m 1 ≡ a ⋅ ( s e l f . s e c r e t ) 2 + c ( m o d p ) ( 1 ) n u m 2 ≡ a ⋅ n u m 1 2 + c ( m o d p ) ( 2 ) \begin{cases}num_1\equiv a\cdot(self.secret)^2+c\pmod{p}(1)\\num_2\equiv a\cdot num_1^2 +c\pmod{p}(2)\end{cases} {num1≡a⋅(self.secret)2+c(modp)(1)num2≡a⋅num12+c(modp)(2)
随后调用了get_hint()函数返回了self.high即num1和num2的高位
最后算的是self.secret与flag的异或值
整 理 一 下 目 前 已 知 : a , c , p , n u m 1 高 位 = h 1 , n u m 2 高 位 = h 2 整理一下目前已知:a,c,p,num_1高位=h1,num_2高位=h2 整理一下目前已知:a,c,p,num1高位=h1,num2高位=h2
因为UnKnownBits=146已知即可设出num1低位=l1,num2低位=l2
由 ( 2 ) 可 得 h 2 + l 2 ≡ a ⋅ ( h 1 + l 1 ) + c ( m o d p ) 即 a ⋅ ( h 1 + l 1 ) 2 + c − h 2 − l 2 ≡ 0 ( m o d p ) 由(2)可得h2+l2\equiv a\cdot (h1+l1)+c\pmod{p}\\即a\cdot(h1+l1)^2+c-h2-l2\equiv 0\pmod{p} 由(2)可得h2+l2≡a⋅(h1+l1)+c(modp)即a⋅(h1+l1)2+c−h2−l2≡0(modp)
已知高位求低位可用coppersmith method
此时是一个2阶的多项式f,在模p下,快速求出
p
1
2
p^\frac{1}{2}
p21的根,测试一下:
import gmpy2
p = 7386537185240346459857715381835501419533088465984777861268951891482072249822526223542514664598394978163933836402581547418821954407062640385756448408431347
e = 2
print(bool(2 ** 146 < gmpy2.iroot(p,e)[0]))
True
在sagemath
中small_roots()
适用Univariate
,而本题中需要适用 bivariate
Usage
See examples.sage for confirmed use cases. For general use, the arguments of small_roots
are:
f
- Multivariate polynomial with small roots. Its base ring should be some sort of integers moduloN
.bounds
- Tuple of bounds for each variable inf.variables()
. This is used to optimize the lattice and does not strictly determine the size of roots returned.m
- Determines how many higher powers off
andN
to use. Defaults to 1.d
- Determines how many variable shifts to use. Defaults tof.degree()
.
Sage by default handles univariate polynomials with a special class. On the other hand, small_roots
requires that the polynomial ring be implemented as multivariate. In order to do that for a single variable, you must explicitly pass in 1 like so:
sage: P.<x> = PolynomialRing(ZZ); P
Univariate Polynomial Ring in x over Integer Ring
sage: P.<x> = PolynomialRing(ZZ, 1); P
Multivariate Polynomial Ring in x over Integer Ring
解出num1和num2(用脚本的时候记得把每一个缩进改一下 自动将github上下来的代码Tab解析成了四个space)
import itertools
def small_roots(f, bounds, m=1, d=None):
if not d:
d = f.degree()
R = f.base_ring()
N = R.cardinality()
f /= f.coefficients().pop(0)
f = f.change_ring(ZZ)
G = Sequence([], f.parent())
for i in range(m+1):
base = N^(m-i) * f^i
for shifts in itertools.product(range(d), repeat=f.nvariables()):
g = base * prod(map(power, f.variables(), shifts))
G.append(g)
B, monomials = G.coefficient_matrix()
monomials = vector(monomials)
factors = [monomial(*bounds) for monomial in monomials]
for i, factor in enumerate(factors):
B.rescale_col(i, factor)
B = B.dense_matrix().LLL()
B = B.change_ring(QQ)
for i, factor in enumerate(factors):
B.rescale_col(i, 1/factor)
H = Sequence([], f.parent().change_ring(QQ))
for h in filter(None, B*monomials):
H.append(h)
I = H.ideal()
if I.dimension() == -1:
H.pop()
elif I.dimension() == 0:
roots = []
for root in I.variety(ring=ZZ):
root = tuple(R(root[var]) for var in f.variables())
roots.append(root)
return roots
return []
##bivariate
a = 3591518680290719943596137190796366296374484536382380061852237064647969442581391967815457547858969187198898670115651116598727939742165753798804458359397101
c = 6996824752943994631802515921125382520044917095172009220000813718617441355767447428067985103926211738826304567400243131010272198095205381950589038817395833
p = 7386537185240346459857715381835501419533088465984777861268951891482072249822526223542514664598394978163933836402581547418821954407062640385756448408431347
h1 = 67523583999102391286646648674827012089888650576715333147417362919706349137337570430286202361838682309142789833
h2 = 70007105679729967877791601360700732661124470473944792680253826569739619391572400148455527621676313801799318422
UnKnownBits = 146
h1 = h1<<UnKnownBits
h2 = h2<<UnKnownBits
P.<l1,l2> = PolynomialRing(Zmod(p))
f = a*(h1 + l1)^2 + c - h2 - l2
l1,l2 = small_roots(f,[2^146,2^146],m=4,d=4)[0]
num1=h1+l1
print(num1)
#6023304966622247460261427847144394818572943247946434323275721792843243938440324294324349326166203828252327046668948034768905493329350113405677812338671880
num2=h2+l2
print(num2)
#6244842503401055989731826584817504999004136293095105898911723541081898139712912492313195038595586857514845849858518208403631165050143225465588755092954391
让我们再回到(1)
n u m 1 ≡ a ⋅ ( s e l f . s e c r e t ) 2 + c ( m o d p ) ( 1 ) num_1\equiv a\cdot(self.secret)^2+c\pmod{p}(1) num1≡a⋅(self.secret)2+c(modp)(1)
现在已经求出$num_1,已知a,c,p,可求self.secret\(self.secret)^2 \equiv(num_1-c)\cdot a^{-1}\pmod{p}\$
就是一个求二次剩余的问题:使用Tonelli_Shanks
方法求解关于p的二次剩余
代码来自:https://blog.csdn.net/weixin_44617902/article/details/112785051
def tonelli(n, p):
# 勒让德符号
def legendre(a, p):
return pow(a, (p - 1) // 2, p)
assert legendre(n, p) == 1, "不是二次剩余"
q = p - 1
s = 0
while q % 2 == 0:
q //= 2
s += 1
if s == 1:
return pow(n, (p + 1) // 4, p)
for z in range(2, p):
if p - 1 == legendre(z, p):
break
c = pow(z, q, p)
r = pow(n, (q + 1) // 2, p)
t = pow(n, q, p)
m = s
t2 = 0
while (t - 1) % p != 0:
t2 = (t * t) % p
for i in range(1, m):
if (t2 - 1) % p == 0:
break
t2 = (t2 * t2) % p
b = pow(c, 1 << (m - i - 1), p)
r = (r * b) % p
c = (b * b) % p
t = (t * c) % p
m = i
return r
完整代码:
import itertools
def small_roots(f, bounds, m=1, d=None):
if not d:
d = f.degree()
R = f.base_ring()
N = R.cardinality()
f /= f.coefficients().pop(0)
f = f.change_ring(ZZ)
G = Sequence([], f.parent())
for i in range(m+1):
base = N^(m-i) * f^i
for shifts in itertools.product(range(d), repeat=f.nvariables()):
g = base * prod(map(power, f.variables(), shifts))
G.append(g)
B, monomials = G.coefficient_matrix()
monomials = vector(monomials)
factors = [monomial(*bounds) for monomial in monomials]
for i, factor in enumerate(factors):
B.rescale_col(i, factor)
B = B.dense_matrix().LLL()
B = B.change_ring(QQ)
for i, factor in enumerate(factors):
B.rescale_col(i, 1/factor)
H = Sequence([], f.parent().change_ring(QQ))
for h in filter(None, B*monomials):
H.append(h)
I = H.ideal()
if I.dimension() == -1:
H.pop()
elif I.dimension() == 0:
roots = []
for root in I.variety(ring=ZZ):
root = tuple(R(root[var]) for var in f.variables())
roots.append(root)
return roots
return []
##bivariate
a = 3591518680290719943596137190796366296374484536382380061852237064647969442581391967815457547858969187198898670115651116598727939742165753798804458359397101
c = 6996824752943994631802515921125382520044917095172009220000813718617441355767447428067985103926211738826304567400243131010272198095205381950589038817395833
p = 7386537185240346459857715381835501419533088465984777861268951891482072249822526223542514664598394978163933836402581547418821954407062640385756448408431347
h1 = 67523583999102391286646648674827012089888650576715333147417362919706349137337570430286202361838682309142789833
h2 = 70007105679729967877791601360700732661124470473944792680253826569739619391572400148455527621676313801799318422
UnKnownBits = 146
h1 = h1<<UnKnownBits
h2 = h2<<UnKnownBits
P.<l1,l2> = PolynomialRing(Zmod(p))
f = a*(h1 + l1)^2 + c - h2 - l2
l1,l2 = small_roots(f,[2^146,2^146],m=4,d=4)[0]
num1=h1+l1
print(num1)
#6023304966622247460261427847144394818572943247946434323275721792843243938440324294324349326166203828252327046668948034768905493329350113405677812338671880
num2=h2+l2
print(num2)
#6244842503401055989731826584817504999004136293095105898911723541081898139712912492313195038595586857514845849858518208403631165050143225465588755092954391
from Crypto.Util.number import *
from gmpy2 import *
from hashlib import *
a = 3591518680290719943596137190796366296374484536382380061852237064647969442581391967815457547858969187198898670115651116598727939742165753798804458359397101
c = 6996824752943994631802515921125382520044917095172009220000813718617441355767447428067985103926211738826304567400243131010272198095205381950589038817395833
p = 7386537185240346459857715381835501419533088465984777861268951891482072249822526223542514664598394978163933836402581547418821954407062640385756448408431347
num1 = 6023304966622247460261427847144394818572943247946434323275721792843243938440324294324349326166203828252327046668948034768905493329350113405677812338671880
num2 = 6244842503401055989731826584817504999004136293095105898911723541081898139712912492313195038595586857514845849858518208403631165050143225465588755092954391
def tonelli(n, p):
# 勒让德符号
def legendre(a, p):
return pow(a, (p - 1) // 2, p)
assert legendre(n, p) == 1, "不是二次剩余"
q = p - 1
s = 0
while q % 2 == 0:
q //= 2
s += 1
if s == 1:
return pow(n, (p + 1) // 4, p)
for z in range(2, p):
if p - 1 == legendre(z, p):
break
c = pow(z, q, p)
r = pow(n, (q + 1) // 2, p)
t = pow(n, q, p)
m = s
t2 = 0
while (t - 1) % p != 0:
t2 = (t * t) % p
for i in range(1, m):
if (t2 - 1) % p == 0:
break
t2 = (t2 * t2) % p
b = pow(c, 1 << (m - i - 1), p)
r = (r * b) % p
c = (b * b) % p
t = (t * c) % p
m = i
return r
ainverse = invert(a,p)
n = (num1-c)*ainverse
secret=tonelli(n,p)
print(secret)
#3345361405203462981041847914374453868599106060665812229784462734764742247048957655005612474587555839753748604882708741687926147536458567411789178129398205
enc = 6176615302812247165125832378994890837952704874849571780971393318502417187945089718911116370840334873574762045429920150244413817389304969294624001945527125
flag = bytes_to_long(sha512(b'%d'%(secret)).digest()) ^ enc
print(flag)
#3791700680078480258027873468537531067118876164954753982985956765389562142392757389958861632856601451782594082216264379268786284864363029391282749962086269
print(long_to_bytes(flag))
#Here_is_ur_flag!:)d3ctf{th3_c0oppbpbpbp3rsM1th_i5_s0_1ntr35ting}
二元coppersmith+二次剩余