2851 words
14 minutes
2025鹏城杯wp
2025-12-13
统计加载中...

前言#

lj比赛,lj题目,场景题不会出就别出,出的跟musc脑电波一样,只写几题wp

题目#

babyrsa#

task.py

from Crypto.Util.number import *
import decimal
m=long_to_bytes("?????")
p=getPrime(1024)
while True:
q=getPrime(1024)
if p>q:
break
n=p*q
e="?????"
d=inverse(e,(p-1)*(q-1))
c=pow(m,e,n)
decimal.getcontext().prec = 1024
P=decimal.Decimal(p)
Q=decimal.Decimal(q)
leak=decimal.Decimal((3*P*P-1)/(3*P*Q))
print("c =",c)
print("leak =",leak)
print("d =",d)

和basectf2024的题差不多,连分数展开就行

exp.py

c = 7908369000608075306226552240713890041649799894903074579356627811865842237315201153498579205223600526520994811661608630888045462921547166872107507948062717836952855804806976414887413729060431265217539895710936669089248515746191716161194996469977577048602427553584286064475300979649416171469313168995504717602670924606819204605601860560767900702512753735554900344201907921239415885901489708576066483012272256175573658509614344875077232108364134161997767814675830320630271209201503987787921279932886374846298269125068817280777403718279754392091441050281244934594776307137448975055247018414699621410668188864774860026941
leak = 1.396995694831414203476063690838730308815841662737318558906107823553922718340982125801595368449608188770051881765292978548960520326036779130167518285237817101541807766017642530065080930654694948943506714268685400709580398894902693407016988670394423892586264077247263710263220932577837642377245651448838665854362532801659965471421937839336237670710012298796758992931116659292915200628873553198226185187089027680973673618973869464164460226697625936493428822424637497370197316811245879504779934098600596822159243994319583651080005054538419168988020562590543262648544970376255020489363894055887067948343768399654357738592577280906555896933717091837896978973488220368081406433117367524537063718421897982643644320078600517763936883820416362057895941185749296170109172249907094176821124345672294602380784325702476105763209165109703429326132417850746805701054961710623030742187505484821961670922386999933202645522248608323217011522889282323071281405301772218220381951540118124201599862330377374571641729649420917168701463539034702411
d = 16306054997613721520756151430779642117683661431522665108784419231044104572118893098180652730976905729602478591047033305251624752030036736271198006715513694904231940253554804069707679445942892410812386221633728427239116007373836662495075237456279818311659331982404534490546781763464409713789636372508503902598331950861474527128323735250673137355260113147338636761737748874105625008482750923429512271416511835596944209137554445130949731646669691366003832655082535985891463876904334888009751956386994969339847254470145428608062575606120441725590059524749595027078238962391188809496875025237129899849787699468205026040721
from Crypto.Util.number import *
cf = continued_fraction(leak)
convers = cf.convergents()
for pkd in convers:
# possible k, d
pp, pq = pkd.as_integer_ratio()
pp=int(pp)
if pp.bit_length()==1024 and isPrime(pp):
flag=long_to_bytes(int(pow(c,d,pp)))
if b'flag' in flag:
print(flag)
break

peco#

task.py

from Crypto.Util.number import *
from secret import FLAG,x,y
f0= bytes_to_long(FLAG[:len(FLAG)//2].encode())
f1= bytes_to_long(FLAG[len(FLAG)//2:].encode())
n= int()
c= int()
gift1= int()
gift2= int()
m=getPrime(1876)
p=getPrime(1024)
q=getPrime(1024)
print(p,q)
n=p*q
e=65537
c=pow(m,e,n)
print('n=',n)
print('c=',c)
print('gift1=',1293023064232431070902426583269468463*x**2-105279230912868770223946474836383391725923*y**2)
print('gift2=',(p**7+q**13)&(2**777-1))
assert (x*f0+y*f1)%m <2**99

前面gift1是个pell方程,sagemath有个函数可以写,都是感觉有点慢,还得自己筛选正数解,ai更是手搓一堆,这里推荐用from sympy.solvers.diophantine.diophantine import diop_DN,包好的。

pq可以通过copper出来,但是我是捡的(),看这个

然后打个格就行了

exp.py

from Crypto.Util.number import *
from gmpy2 import *
from sage.all import *
from sympy.core.intfunc import iroot
from sympy.solvers.diophantine.diophantine import diop_DN
n= int(18443962106578943927922829208562388331564422618353954662348987125496135728205879853444693999188714508145409575298801277623433658530589571956301880815632542860363148763704636874275223979061507756787642735086825973011622866458454405794279633717255674221895468734500735123736684346340314680683830866884050311047424068122453972745273167956795195575475691048908906061023817574695902603984554911326264947716547564759877947888574515784489778380086664649338093680740990860192640619047071160362288611331225632270531304525264824445326394068892806774552310748255977040249822464839809344521107040968321810533993659358229305320413)
c= int(8176283809770578639445916571748890916863681496488338436815389781344271720445865752568007651231910205530735296305471880971422173915403956857863330698931559658909826642456860761540607878553228782799635976463090037022164739976302533892173751687781100980039065722082091714141141136171701360981540040678479802206949078162548124224838019262997441233919136963696523351831737708850863538007579105976954619102728135600542584651031405327214877358323388674864043740117718200022790892542634633918493245432384562983429810936975869853596007429259749282607844407676244954057886824475948603911174707176467261179324130051317766768127)
gift1= int(1293023064232431070902426583269468463)
gift2= int(26161714402997656593966327522661504448812191236385246127313450633226841096347099194721417620572738092514050785292503472019045698167235604357096118735431692892202119807587271344465029467089266358735895706496467947787464475365718387614)
x = diop_DN(105279230912868770223946474836383391725923//1293023064232431070902426583269468463,gift1//1293023064232431070902426583269468463)[0][0]
yy=(1293023064232431070902426583269468463*x**2-gift1)//105279230912868770223946474836383391725923
y=iroot(yy,2)[0]
print(x)
print(y)
x=int(x)
y=int(y)
p = 110321094976129707319520600986374898031772388334195419291797204096276942296698733990367680023948047820442401228783658911134388494335281166694315709721180388295015528680094263090624783953349710316927409137594927749594230788983109047830897067234559148509079478238626283574442539878131266374870841191635047394681
q = 167184364065364685056497190415155636144720644950725295920271367595483444357416641085807605674441141156570389367370149531967480290218274897524375212202875627325755457975276196034582673268786547482587150378645612877166485244134843695743056623756823734183252667243967918491196265305063449882555425959453836272773
m=pow(c,inverse(65537,(p-1)*(q-1)),n)
W=2**100
M = Matrix(ZZ, [
[1, 0, x * W],
[0, 1, y * W],
[0, 0, m * W]
])
L=M.LLL()
for row in L:
try:
r0 = abs(row[0])
r1 = abs(row[1])
r2 = abs(row[2])
p1 = long_to_bytes(r0)
p2 = long_to_bytes(r1)
p3=long_to_bytes(r2)
print(p1)
print(p2)
print(p3)
except Exception:
continue

比较懒直接全输出出来了

pem#

给了残缺的公钥和私钥,比较抽象的是给了ne,哎,你需要通过公钥和私钥文件把n给拼出来,这个n才是对的,哥们是没想到的,大ne,d拿boneh_durfee打

exp.py

from __future__ import print_function
import time
############################################
# Config
##########################################
"""
Setting debug to true will display more informations
about the lattice, the bounds, the vectors...
"""
debug = True
"""
Setting strict to true will stop the algorithm (and
return (-1, -1)) if we don't have a correct
upperbound on the determinant. Note that this
doesn't necesseraly mean that no solutions
will be found since the theoretical upperbound is
usualy far away from actual results. That is why
you should probably use `strict = False`
"""
strict = False
"""
This is experimental, but has provided remarkable results
so far. It tries to reduce the lattice as much as it can
while keeping its efficiency. I see no reason not to use
this option, but if things don't work, you should try
disabling it
"""
helpful_only = True
dimension_min = 7 # stop removing if lattice reaches that dimension
############################################
# Functions
##########################################
# display stats on helpful vectors
def helpful_vectors(BB, modulus):
nothelpful = 0
for ii in range(BB.dimensions()[0]):
if BB[ii,ii] >= modulus:
nothelpful += 1
print(nothelpful, "/", BB.dimensions()[0], " vectors are not helpful")
# display matrix picture with 0 and X
def matrix_overview(BB, bound):
for ii in range(BB.dimensions()[0]):
a = ('%02d ' % ii)
for jj in range(BB.dimensions()[1]):
a += '0' if BB[ii,jj] == 0 else 'X'
if BB.dimensions()[0] < 60:
a += ' '
if BB[ii, ii] >= bound:
a += '~'
print(a)
# tries to remove unhelpful vectors
# we start at current = n-1 (last vector)
def remove_unhelpful(BB, monomials, bound, current):
# end of our recursive function
if current == -1 or BB.dimensions()[0] <= dimension_min:
return BB
# we start by checking from the end
for ii in range(current, -1, -1):
# if it is unhelpful:
if BB[ii, ii] >= bound:
affected_vectors = 0
affected_vector_index = 0
# let's check if it affects other vectors
for jj in range(ii + 1, BB.dimensions()[0]):
# if another vector is affected:
# we increase the count
if BB[jj, ii] != 0:
affected_vectors += 1
affected_vector_index = jj
# level:0
# if no other vectors end up affected
# we remove it
if affected_vectors == 0:
print("* removing unhelpful vector", ii)
BB = BB.delete_columns([ii])
BB = BB.delete_rows([ii])
monomials.pop(ii)
BB = remove_unhelpful(BB, monomials, bound, ii-1)
return BB
# level:1
# if just one was affected we check
# if it is affecting someone else
elif affected_vectors == 1:
affected_deeper = True
for kk in range(affected_vector_index + 1, BB.dimensions()[0]):
# if it is affecting even one vector
# we give up on this one
if BB[kk, affected_vector_index] != 0:
affected_deeper = False
# remove both it if no other vector was affected and
# this helpful vector is not helpful enough
# compared to our unhelpful one
if affected_deeper and abs(bound - BB[affected_vector_index, affected_vector_index]) < abs(bound - BB[ii, ii]):
print("* removing unhelpful vectors", ii, "and", affected_vector_index)
BB = BB.delete_columns([affected_vector_index, ii])
BB = BB.delete_rows([affected_vector_index, ii])
monomials.pop(affected_vector_index)
monomials.pop(ii)
BB = remove_unhelpful(BB, monomials, bound, ii-1)
return BB
# nothing happened
return BB
"""
Returns:
* 0,0 if it fails
* -1,-1 if `strict=true`, and determinant doesn't bound
* x0,y0 the solutions of `pol`
"""
def boneh_durfee(pol, modulus, mm, tt, XX, YY):
"""
Boneh and Durfee revisited by Herrmann and May
finds a solution if:
* d < N^delta
* |x| < e^delta
* |y| < e^0.5
whenever delta < 1 - sqrt(2)/2 ~ 0.292
"""
# substitution (Herrman and May)
PR.<u, x, y> = PolynomialRing(ZZ)
Q = PR.quotient(x*y + 1 - u) # u = xy + 1
polZ = Q(pol).lift()
UU = XX*YY + 1
# x-shifts
gg = []
for kk in range(mm + 1):
for ii in range(mm - kk + 1):
xshift = x^ii * modulus^(mm - kk) * polZ(u, x, y)^kk
gg.append(xshift)
gg.sort()
# x-shifts list of monomials
monomials = []
for polynomial in gg:
for monomial in polynomial.monomials():
if monomial not in monomials:
monomials.append(monomial)
monomials.sort()
# y-shifts (selected by Herrman and May)
for jj in range(1, tt + 1):
for kk in range(floor(mm/tt) * jj, mm + 1):
yshift = y^jj * polZ(u, x, y)^kk * modulus^(mm - kk)
yshift = Q(yshift).lift()
gg.append(yshift) # substitution
# y-shifts list of monomials
for jj in range(1, tt + 1):
for kk in range(floor(mm/tt) * jj, mm + 1):
monomials.append(u^kk * y^jj)
# construct lattice B
nn = len(monomials)
BB = Matrix(ZZ, nn)
for ii in range(nn):
BB[ii, 0] = gg[ii](0, 0, 0)
for jj in range(1, ii + 1):
if monomials[jj] in gg[ii].monomials():
BB[ii, jj] = gg[ii].monomial_coefficient(monomials[jj]) * monomials[jj](UU,XX,YY)
# Prototype to reduce the lattice
if helpful_only:
# automatically remove
BB = remove_unhelpful(BB, monomials, modulus^mm, nn-1)
# reset dimension
nn = BB.dimensions()[0]
if nn == 0:
print("failure")
return 0,0
# check if vectors are helpful
if debug:
helpful_vectors(BB, modulus^mm)
# check if determinant is correctly bounded
det = BB.det()
bound = modulus^(mm*nn)
if det >= bound:
print("We do not have det < bound. Solutions might not be found.")
print("Try with highers m and t.")
if debug:
diff = (log(det) - log(bound)) / log(2)
print("size det(L) - size e^(m*n) = ", floor(diff))
if strict:
return -1, -1
else:
print("det(L) < e^(m*n) (good! If a solution exists < N^delta, it will be found)")
# display the lattice basis
if debug:
matrix_overview(BB, modulus^mm)
# LLL
if debug:
print("optimizing basis of the lattice via LLL, this can take a long time")
BB = BB.LLL()
if debug:
print("LLL is done!")
# transform vector i & j -> polynomials 1 & 2
if debug:
print("looking for independent vectors in the lattice")
found_polynomials = False
for pol1_idx in range(nn - 1):
for pol2_idx in range(pol1_idx + 1, nn):
# for i and j, create the two polynomials
PR.<w,z> = PolynomialRing(ZZ)
pol1 = pol2 = 0
for jj in range(nn):
pol1 += monomials[jj](w*z+1,w,z) * BB[pol1_idx, jj] / monomials[jj](UU,XX,YY)
pol2 += monomials[jj](w*z+1,w,z) * BB[pol2_idx, jj] / monomials[jj](UU,XX,YY)
# resultant
PR.<q> = PolynomialRing(ZZ)
rr = pol1.resultant(pol2)
# are these good polynomials?
if rr.is_zero() or rr.monomials() == [1]:
continue
else:
print("found them, using vectors", pol1_idx, "and", pol2_idx)
found_polynomials = True
break
if found_polynomials:
break
if not found_polynomials:
print("no independant vectors could be found. This should very rarely happen...")
return 0, 0
rr = rr(q, q)
# solutions
soly = rr.roots()
if len(soly) == 0:
print("Your prediction (delta) is too small")
return 0, 0
soly = soly[0][0]
ss = pol1(q, soly)
solx = ss.roots()[0][0]
#
return solx, soly
def example():
############################################
# How To Use This Script
##########################################
#
# The problem to solve (edit the following values)
#
# the modulus
N =
# the public exponent
e =
# the hypothesis on the private exponent (the theoretical maximum is 0.292)
delta = .28 # this means that d < N^delta
#
# Lattice (tweak those values)
#
# you should tweak this (after a first run), (e.g. increment it until a solution is found)
m = 8 # size of the lattice (bigger the better/slower)
# you need to be a lattice master to tweak these
t = int((1-2*delta) * m) # optimization from Herrmann and May
X = 2*floor(N^delta) # this _might_ be too much
Y = floor(N^(1/2)) # correct if p, q are ~ same size
#
# Don't touch anything below
#
# Problem put in equation
P.<x,y> = PolynomialRing(ZZ)
A = int((N+1)/2)
pol = 1 + x * (A + y)
#
# Find the solutions!
#
# Checking bounds
if debug:
print("=== checking values ===")
print("* delta:", delta)
print("* delta < 0.292", delta < 0.292)
print("* size of e:", int(log(e)/log(2)))
print("* size of N:", int(log(N)/log(2)))
print("* m:", m, ", t:", t)
# boneh_durfee
if debug:
print("=== running algorithm ===")
start_time = time.time()
solx, soly = boneh_durfee(pol, e, m, t, X, Y)
# found a solution?
if solx > 0:
print("=== solution found ===")
if False:
print("x:", solx)
print("y:", soly)
d = int(pol(solx, soly) / e)
print("private key found:", d)
else:
print("=== no solution was found ===")
if debug:
print(("=== %s seconds ===" % (time.time() - start_time)))
if __name__ == "__main__":
example()
# e="70 55 09 ec 28 3d c9 4e 3b be 85 ca 1e 36 85 85 86 72 1f 3d 1a 8d 67 81 34 51 e1 60 72 8c c8 7e 73 a5 f1 6a 3c 4e d3 ef b5 53 ed e1 5d 54 01 de 32 c2 65 cc 49 02 a6 66 6a 3b 7d 8e 98 44 b9 cb 2a 1f fc 44 79 df 0d 0f 1e e9 92 71 84 93 ad 47 cb 28 9d f2 06 33 7a 06 3a 0f b0 d7 5f 66 a0 99 81 20 a0 22 7b 4a c0 10 00 ee e0 e8 e6 00 12 aa 6a b6 13 fb 92 b3 73 92 2e e3 28 5b 6c bd 42 9a 3b f8 a6 31 72 09 0e 14 6b 19 cf 19 0a f1 5a be 65 73 e9 9a bb fd 01 69 5f 80 0c 2c f4 70 63 ef 7f ec 9e 69 60 f9 19 68 24 3b 67 32 ae 43 1a 3e f4 08 ea 02 7e 3e 7c d4 46 e3 3d 43 0f 18 ed ba d8 c6 5f 75 4b 06 4a 83 cc 0f f8 1d 79 47 26 c5 c1 f7 d3 9f f9 1a 79 cd 3a 7e 18 fe 26 f3 cf a2 3d e3 34 9f cb 44 d7 08 4a 05 e7 9a ed 98 90 ad ea e9 32 d3 e7 78 9d 02 08 32 43 23 62 b1 e1 25"
# n="00 d8 1d b1 95 02 4c 9b d0 3d d8 56 65 6a d1 19 fa 19 a0 a7 71 20 bf 10 d9 c4 02 f4 eb 3d c7 98 b6 11 fd d9 c2 09 c1 7d 87 93 9f a9 2f b0 e8 c1 14 73 23 22 7d d2 ed d8 1b 40 f6 82 a5 4d e1 03 5f 0a f0 3a 66 0e c1 b3 4d b6 88 84 d0 38 e2 e1 af aa b7 95 46 d4 72 50 fd 30 d2 a7 0a 7f fd 83 f1 13 8f 35 3e c9 4f 58 bf 2b 34 48 f8 c4 d3 32 41 9e 3e 1a 32 cf 73 1d ce db 66 ec 1f c4 0a fd fe 3a 05 ad 2d 1c f4 f7 66 a6 42 cb 64 69 0b 45 e2 b6 46 56 3a fb 6d fd f5 99 df 84 83 8b 71 1f 1b 0a 79 b5 f7 bd f1 08 8a 4f 77 a1 0b 13 ad 8a 36 71 db ff 92 00 13 13 7f c5 e2 97 5a 58 1c d8 7b cc 85 15 d8 73 bf ae c4 33 4c b1 c3 1b 16 20 63 16 f9 2c be 44 9f ae 81 15 74 11 3e 5e b2 ed 01 53 d1 fc cb 80 a0 21 0e 80 76 e1 c5 fb f6 af ab be a7 3a d1 80 5c 0a 1b 20 c7 0c f2 c1 3b fe 03"
# w=0
# nlow=""
# for i in e.split(" "):
# w+=1
# nlow+=i
# print(int(nlow,16))
n=
e=
c=open("/Users/zsm/Downloads/crypto/pem/enc","rb").read()
from Crypto.Util.number import *
c=bytes_to_long(c)
d=
m=pow(c,d,n)
print(long_to_bytes(m))

RandomAudit#

最重量级的

题目描述

某内部审计系统号称“全部采用自研高强度密码模块”,为了节省日志空间,他们把敏感日志 AES 加密后上传,又用 RSA 对关键密钥做了“备份加密”,最后还用“秘密分享”来保护真正的 FLAG。不幸的是,开发同学对“随机数”和“密码学”理解似乎有点……偏差。你从审计服务器上拿到了以下文件你的任务是:从这些文件中还原出最终的 flag。

给了四个文件aes_ct.txt,这个是aes相关的。rsa_pub.txt给了ne。session_ids.txt给了四个随机数。shares.enc给了三个加密后的数。

这玩意你得语文阅读能力好一点。

我们先进行对话,对话之后按照系统来说就是要对日志进行加密了,加密的时候采用的key和iv继续用这个LCG生成。

第三个第四个64-bit拼接起来刚好是iv,第一个第二个64-bit是key,但是CBC模式下解密是乱码。那么我们尝试其他的方法,CTR下拿到106141198856029082317733263764736461207

这玩意是seed,当成LCG新的种子,往后爆破可以分解N。

然后去解密那三个数,得到一个等差数列[a, b, c] —> c - b == b - a(diff),uuid是32位,diff转16进制之后刚好是32位,然后用”-“连上。

神了,脚本就不放了()

总结#

感觉出题风格越来越奇怪了?感觉都想往实际环境的方向走,但是都很怪,要么是出的不太实际,要么是沾点脑洞。

那就得想怎么出的实际了。实际生活的密码学其实是比较安全的,如果想贴近实际,可能只有侧信道比较多?比如vctf的哪一题,强网拟态决赛的那个侧信道misc?感觉需要多方向结合起来,比如web中有dh或者是其他的东西泄露,也有可能像那个misc一样简单的侧信道之后再misc工具求解?

其实有个大胆的想法,如果webshell弹了之后需要解密码提权怎么样(,或者是域管理的密钥、凭证需要密码学的东西?说不定下次tkkctf就有了()

2025鹏城杯wp
https://www.zhuangsanmeng.xyz/posts/pcb2025/
Author
zsm
Published at
2025-12-13
License
MIT

Some information may be outdated