2023一月份赛事题目总结
强网拟态决赛密码题
决赛唯一的一道crypto,侥幸拿了个二血...
题目给了\(\small g_1\),而由于费马小定理容易得到\(\small g^{(p-1)\cdot {r_1}} \;mod\;p=1\),那么容易推导模\(\small N\)也是一样的等于1,所以求\(\small g_1\)和\(\small N\)的最大公因子就能分解\(\small N\)了,而后面的\(\small c_1\)解密又是利用了费马小定理,具体地,\(\small {g_1}^{s_1}\;mod\;p=1\),所以直接把\(\small c_1\)模p就是第一部分\(\small m\)了。\(\small c_2\)的解密首先需要直接开\(\small e\)次方求出关于$\small A B C $的二次方程,用sage的roots()求解即可,最后的exp:
from Crypto.Util.number import *
from gmpy2 import *
c1= 19024563955839349902897822692180949371550067644378624199902067434708278125346234824900117853598997270022872667319428613147809325929092749312310446754419305096891122211944442338664613779595641268298482084259741784281927857614814220279055840825157115551456554287395502655358453270843601870807174309121367449335110327991187235786798374254470758957844690258594070043388827157981964323699747450405814713722613265012947852856714100237325256114904705539465145676960232769502207049858752573601516773952294218843901330100257234517481221811887136295727396712894842769582824157206825592614684804626241036297918244781918275524254
c2= 11387447548457075057390997630590504043679006922775566653728699416828036980076318372839900947303061300878930517069527835771992393657157069014534366482903388936689298175411163666849237525549902527846826224853407226289495201341719277080550962118551001246017511651688883675152554449310329664415179464488725227120033786305900106544217117526923607211746947511746335071162308591288281572603417532523345271340113176743703809868369623401559713179927002634217140206608963086656140258643119596968929437114459557916757824682496866029297120246221557017875892921591955181714167913310050483382235498906247018171409256534124073270350
N1= 21831630625212912450058787218272832615084640356500740162478776482071876178684642739065105728423872548532056206845637492058465613779973193354996353323494373418215019445325632104575415991984764454753263189235376127871742444636236132111097548997063091478794422370043984009615893441148901566420508196170556189546911391716595983110030778046242014896752388438535131806524968952947016059907135882390507706966746973544598457963945671064540465259211834751973065197550500334726779434679470160463944292619173904064826217284899341554269864669620477774678605962276256707036721407638013951236957603286867871199275024050690034901963
g1= 20303501619435729000675510820217420636246553663472832286487504757515586157679361170332171306491820918722752848685645096611030558245362578422584797889428493611704976472409942840368080016946977234874471779189922713887914075985648876516896823599078349725871578446532134614410886658001724864915073768678394238725788245439086601955497248593286832679485832319756671985505398841701463782272300202981842733576006152153012355980197830911700112001441621619417349747262257225469106511527467526286661082010163334100555372381681421874165851063816598907314117035131618062582953512203870615406642787786668571083042463072230605649134
S= 234626762558445335519229319778735528295
N2= 28053749721930780797243137464055357921262616541619976645795810707701031602793034889886420385567169222962145128498131170577184276590698976531070900776293344109534005057067680663813430093397821366071365221453788763262381958185404224319153945950416725302184077952893435265051402645871699132910860011753502307815457636525137171681463817731190311682277171396235160056504317959832747279317829283601814707551094074778796108136141845755357784361312469124392408642823375413433759572121658646203123677327551421440655322226192031542368496829102050186550793124020718643243789525477209493783347317576783265671566724068427349961101
e= 5
Cs= [1693447496400753735762426750097282582203894511485112615865753001679557182840033040705025720548835476996498244081423052953952745813186793687790496086492136043098444304128963237489862776988389256298142843070384268907160020751319313970887199939345096232529143204442168808703063568295924663998456534264361495136412078324133263733409362366768460625508816378362979251599475109499727808021609000751360638976, 2240772849203381534975484679127982642973364801722576637731411892969654368457130801503103210570803728830063876118483596474389109772469014349453490395147031665061733965097301661933389406031214242680246638201663845183194937353509302694926811282026475913703306789097162693368337210584494881249909346643289510493724709324540062077619696056842225526183938442535866325407085768724148771697260859350213678910949, 5082341111246153817896279104775187112534431783418388292800705085458704665057344175657566751627976149342406406594179073777431676597641200321859622633948317181914562670909686170531929552301852027606377778515019377168677204310642500744387041601260593120417053741977533047412729373182842984761689443959266049421034949822673159561609487404082536872314636928727833394518122974630386280495027169465342976]
p1 = gcd(g1-1,N1)
q1 = N1//p1
print(long_to_bytes(c1%p1))
cnt = 3
A = [(i + 128) ** 2 for i in range(cnt)]
B = [(i + 1024) for i in range(cnt)]
C = [(i + 512) for i in range(cnt)]
C_ = []
for i in Cs:
C_.append(iroot(i,5)[0])
P1.<m1>=Zmod()[]
P2.<m2>=Zmod()[]
P3.<m3>=Zmod()[]
f1 = A[0] * m1^2 + B[0] * m1 + C[0] - int(C_[0])
f2 = A[1] * m2^2 + B[1] * m2 + C[1] - int(C_[1])
f3 = A[2] * m3^2 + B[2] * m3 + C[2] - int(C_[2])
v1 = f1.roots()
v2 = f2.roots()
v3 = f3.roots()
print(long_to_bytes(v1[0][0])+long_to_bytes(v2[0][0])+long_to_bytes(v3[0][0]))
# flag{f561fafb-32ce-9d16-18fa-ec795fc1d208}
某安全管理员决赛-ecbBlock
本质上就是把用同一个key异或得到的密文按照每个字节进行s盒替换,那么解密只需要先把s盒的这部分变换逆过来,再看作一个mtp解密即可。完整exp:
from Crypto.Util.number import *
import binascii
_sbox = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16]
f = open('secret.encrypted','rb')
c = f.read()
print(len(c))
# 272
c = str(binascii.b2a_hex(c))[2:-1]
print(c)
_sbox = _sbox
_index = []
for i in range(0,len(c),2):
tmp = c[i] + c[i+1]
num = int(tmp,16)
t = hex(_sbox.index(num))[2:]
if len(t) != 2:
t = '0' + t
_index.append(t)
print(_index)
print(''.join(_index))
ff = open('c.txt','w')
for i in range(0,272,16):
tmp = ''.join(_index[i:i+16])
print(tmp)
ff.write(tmp+'\n')
ff.close()
import Crypto.Util.strxor as xo
import libnum, codecs, numpy as np
def isChr(x):
if ord('a') <= x and x <= ord('z'): return True
if ord('A') <= x and x <= ord('Z'): return True
return False
def infer(index, pos):
if msg[index, pos] != 0:
return
msg[index, pos] = ord(' ')
for x in range(len(c)):
if x != index:
msg[x][pos] = xo.strxor(c[x], c[index])[pos] ^ ord(' ')
dat = []
def getSpace():
for index, x in enumerate(c):
res = [xo.strxor(x, y) for y in c if x!=y]
f = lambda pos: len(list(filter(isChr, [s[pos] for s in res])))
cnt = [f(pos) for pos in range(len(x))]
for pos in range(len(x)):
dat.append((f(pos), index, pos))
c = [codecs.decode(x.strip().encode(), 'hex') for x in open('c.txt', 'r').readlines()]
msg = np.zeros([len(c), len(c[0])], dtype=int)
getSpace()
dat = sorted(dat)[::-1]
for w, index, pos in dat:
infer(index, pos)
print('\n'.join([''.join([chr(c) for c in x]) for x in msg]))
key = xo.strxor(c[13], b't?Of course,you ')
print(key)
for i in c:
print(str(xo.strxor(key,i))[2:-1])
#Take_c0n7ro1@f-Y0ur_o#n_Des7ing
idekctf-ecrsa
ecc上的rsa,这也算是个高频考点了,这题很多参数未知所以求解要多几步。
首先是不知道n,但已知三个点坐标在椭圆曲线上,那么可以通过椭圆曲线表达式在ZZ上建立三个方程,然后用groebner_basis()简化就能求出kn,利用类似已知e d n分解n的方式把n求出来(其实不一定能成功,但这题刚好),拿到n之后同样的方法把n分解。有了n建立groebner_basis()就可以在zmod(n)下进行,这样就能把a和b求出来。至此,我们需要的所有参数都获得了。后边分别在p和q的域下求椭圆曲线的阶,\(\small \phi=ordp\cdot ordq\),这个值是椭圆曲线上rsa群的\(\small \phi\),那么可以把该群的d求出,用d解密即可。
from Crypto.Util.number import *
import random
import gmpy2
kn = 294083687600221251201409868487487774730104718594174639451489296553988461457888664494965737668534028932375540759444253985369035140435426103376392803373291107990254324121343661627606657756209541077058412828914792557915308132794597460035750960251320361249634360168796582817207238622129685127196642701524591289688431172826681240478404297490554942948610335154446277992177135540657855247480017928950445034504977425351189727678787577107257969296310533999013146187505034782165402643428345958918990605418030685665683648903295005014128332738023682099376785225329771156480666855623057103132268793419419849833457113303802099706767188373406168131963972896250547601204695567741002753130335714759102236952616180273701580818213684279073626251840378342056839579453193984485296265105723222074065254838706629389396645465885020439830310629816159070027993583365711212981703969683454455093980514681083231184773656453095914113782636424164330440922498622425743787175906404265042857217651283657729781463669061153632675781809175399766620798664026614325497262113654557865684344992175613200193631698425834024429010930209521079458884339887727998370269939666379411323609957926928180845333227663821684067262179287393272966111675810742839119753406604065147069
e = 3
d = 99193023581616109152177764300040037859521925088272985981669959946817746109531909713425474710564402873765914926441545005839662821744603138460681680285655317684469203777533871394260260583839662628325884473084768835902143240687542429953968760669321064892423877370896609497584167478711224462305776836476437268587
def getpq(n,e,d):
while True:
k = e * d - 1
g = random.randint(0, n)
while k%2==0:
k=k//2
temp=gmpy2.powmod(g,k,n)-1
if gmpy2.gcd(temp,n)>1 and temp!=0:
return gmpy2.gcd(temp,n)
#n = getpq(kn,e,d)
n = 148789535372424163728266646450060056789282887632409478972504939920226619164297864570138212065846604310648872389662317508759494232616904707691022520428483000923260778669946008689451863137527523684502948570798504215922534787506491833325381174139925947167122783344470619692746866285435276907642606269209931602317
# p = getpq(n,e,d)
# print(p)
p = 12106285759457603837646209698473787447139576157605716627376889077738609086595516271990595704705464336024969899141833853372028724555298162959385807206566981
print(isPrime(p))
print(p.bit_length())
q = n//p
d1 = inverse(e, (p-1)*(q-1))
print(d1)
from sage.all import *
d = 99193023581616109152177764300040037859521925088272985981669959946817746109531909713425474710564402873765914926441545005839662821744603138460681680285655317684469203777533871394260260583839662628325884473084768835902143240687542429953968760669321064892423877370896609497584167478711224462305776836476437268587
c = (115076663389968253954821343472300155800654332223208277786605760890770425514748910251950393842983935903563187546008731344369976804796963863865102277460894378910744413097852034635455187460730497479244094103353376650220792908529826147612199680141743585684118885745149209575053969106545841997245139943766220688789 , 74232642959425795109854140949498935461683632963630260034964643066394703345139733396470958836932831941672213466233486926122670098721687149917605871805886006479766670309639660332339984667770417687192717160061980507220617662938436637445370463397769213554349920956877041619061811087875024276435043752581073552318)
test = (79615329406682121028641446306520032869660130854153788352536429332441749473394735222836513266191300847548366008281109415002581029448905418880962931523411475044527689429201653146200630804486870653795937020571749192405439450656659472253086567149309166068212312829071678837253421625687772396105149376211148834937 , 114576105009077728778286635566905404081211824310970349548035698466418670695753458926421098950418414701335730404414509232776047250916535638430446206810902182305851611221604003509735478943147034397832291215478617613443375140890349118302843641726392253137668650493281241262406250679891685430326869028996183320982)
n = 148789535372424163728266646450060056789282887632409478972504939920226619164297864570138212065846604310648872389662317508759494232616904707691022520428483000923260778669946008689451863137527523684502948570798504215922534787506491833325381174139925947167122783344470619692746866285435276907642606269209931602317
t = ZZ(int.from_bytes(b"ECRSA offers added security by elliptic entropy.", 'big'))
yt = 2
P.<a,b>=PolynomialRing(Zmod(n))
#P.<a,b>=PolynomialRing(ZZ)
F=[]
f1 = t^3 + a*t + b - yt^2
f2 = test[0]^3 + a*test[0] + b - test[1]^2
f3 = c[0]^3 + a*c[0] + b - c[1]^2
F.append(f1)
F.append(f2)
F.append(f3)
Ideal = Ideal(F)
I = Ideal.groebner_basis()
print(I)
res=[x.constant_coefficient() for x in I]
a = -res[0]%n
b = -res[1]%n
E = EllipticCurve(Zmod(n), [a, b])
C = E(c)
p = 12106285759457603837646209698473787447139576157605716627376889077738609086595516271990595704705464336024969899141833853372028724555298162959385807206566981
q = n/p
Ep = EllipticCurve(Zmod(p), [a, b])
Eq = EllipticCurve(Zmod(q), [a, b])
# ordp = Ep.order()
# ordq = Eq.order()
# phi = ordp*ordq
# print(phi)
phi = 148789535372424163728266646450060056789282887632409478972504939920226619164296671910830162422173521086104260442096339694304886999126003562791358712412416317442287195786906697615489065379945573862193455179868067475036156124279466870451072060581891741234837916854904063588317305400955406105882208744056825746850
d = inverse_mod(3,phi)
from Crypto.Util.number import *
m = (C*d)[0]
print(long_to_bytes(int(m)))
realworld体验赛—babycurve
这题改编自hxpctf2018的curve12833227,考点几乎一模一样。题目并没有给椭圆曲线的a和b,所以第一步是求a和b,利用点加法add的形式做一些变化就能求a,得到a再求b只需要代入解方程。
具体地,当椭圆曲线上两个点相同时,\(\small \lambda=\frac{3x^2+a}{2y}\),但这题给的是\(\small \frac{3x^2+4x+1}{2y}=\frac{3(x+\frac{2}{3})^2-\frac{1}{3}}{2y}\)。结合椭圆曲线的几何意义,这里可以看作是整个曲线左移了\(\small F_p(2/3)\),而a就是\(\small F_p(-1/3)\)。而b的求解只需要带入a和某个点坐标即可,但是要注意椭圆曲线的表达式为\(\small y^2=(x+k)^3+a(x+k)+b\;mod\;p\),即平移过后的表达式。带入a b 计算判别式,\(\small -16(4a^3+27b^2)\;mod\;p=0\),这说明平移并不会改变光滑曲线的性质,平移之后仍然是光滑的。该椭圆曲线的形式展开为\(\small x^3 + 2x^2 + x=(x+1)^2x\),参考stackexchange,可以令\(\small x=x-1\)化成该形式,再转成乘法群的dlp求解。这里要注意exp中的u并不是原根,所以求出来的dlp虽然满足题意但是不一定就是key,正确的操作是需要找到u对应子群的阶order,对求出的dlp加上k倍order去解密,最终得到flag。给出exp:
p = 193387944202565886198256260591909756041
Q = (65639504587209705872811542111125696405,125330437930804525313353306745824609665)
G = (4,10)
Fp = GF(p)
P1 = Fp(G[1])
P0 = Fp(G[0])
a = Fp(-1/3)
k = Fp(2/3)
R.<b> = Zmod(p)[]
# 用Q求也是这个a和b
f = P1^2 - (P0+k)^3 - a*(P0+k) - b
r = f.roots()
b = r[0][0]
# 验证脆弱性
print((f'Delta:{(4*a^3 + 27*b^2)%p}'))
P.<x> = GF(p)[]
f = (x+k)^3 + a*(x+k) + b
print(f)
# 验证点的坐标
yQ = Q[0]^3 + 2*Q[0]^2 + Q[0] - Q[1]^2
print(yQ%p)
f_ = f.subs(x = x-1)
print(f_)
print(f_.factor())
t = GF(p)(193387944202565886198256260591909756040).square_root()
P_ = (G[0] +1, G[1])
Q_ = (Q[0] +1, Q[1])
u = Fp((P_[1] + t*P_[0])/(P_[1] - t*P_[0]))
v = Fp((Q_[1] + t*Q_[0])/(Q_[1] - t*Q_[0]))
#print(v.log(u))
dlp = 4470735776084208177429085432176719338
assert u^dlp == v
order = u.multiplicative_order()
print(order)
print(dlp)
from Crypto.Cipher import AES
import binascii
x = 4470735776084208177429085432176719338
c = binascii.a2b_hex(b'b3669dc657cef9dc17db4de5287cd1a1e8a48184ed9746f4c52d3b9f8186ec046d6fb1b8ed1b45111c35b546204b68e0')
for i in range(1,5):
key = x + i * order
aes = AES.new(int(key).to_bytes(16, 'big'), AES.MODE_CBC, bytes(16))
m = aes.decrypt(c)
if b'rwctf' in m:
print(m)
break
这个题目原本挺好的,但是并非原创,而是来源于"搬运国外赛题",看来国内CTF赛题质量的提升还有很长的路要走。