[置顶]【WP】 Writeup for SJTU-CTF ,被同级大佬和学长联合虐爆
大概就是比赛的开始一天(被友好欢迎了一下)、中间一天(颓了下mc)和结束三四天做了一下题目
开题顺序:
welcome
corrupt save
KOH
卑鄙baby square
baba RSA
卑鄙baby guess
卑鄙baby pack
卑鄙baby HASH (赛后一定)
cool dog(赛后一定)
最后几天在学长的建议下选择了能啃啃信竞老本的 crypto
然后边学边做,大概就是一天一道题的样子(甚至 ddl 之前敲了高数线代做题)
Welcome
被签到题干碎
flag 里面有不可见字符,对不懂套路的萌新来说很不友好
手打一遍flag就好了
或者用手机选择 flag 的时候看到有两个字符之间蓝色的颜色较深,想办法把那个不可见字符去掉(居然有人在手机上开题) 重新看了一下貌似不行,不可见字符好像不止一个,手机上只有一个地方是深蓝,那个可能只能算个小提示
corrupt
捣鼓了半天,发现这存档进去了之后卡的要死,以为真的要修存档,但是之前准备比赛刷题的时候有前辈(外校)在介绍CTF的时候无意间说了几句:
- “CTF 题很杂,水很深,你把握不住,快逃!”
- “CTF 就是拼的脑洞,题目很杂的,那个misc尤其杂,比如有时候就会有 MC 的题目出来”
- 我:MC 能怎么出?难道 flag 用砖块堆出来么?
- “对啊,就是用砖块堆出来,然后让你满地图跑,去找flag”
然后就真遇到这种东西了,真·一语成谶(离谱
所幸没真让我满地图找,如果顺带让打几条末影龙什么的就好完玩了
想到这里,在看看眼前好像确实有五彩缤纷的砖块,于是就想着开创造模式飞起来 让我康康(虽说没怎么玩过 MC 但这些东西倒是晓得的)
然后就控制台开 mod 1 按两下空格,发现...不知道为什么飞不起来,而且因为卡成了 PPT 所以每次都要等一会儿才能看效果(大草
然后想着应该是哪个数据(八成是地图)太大了所以卡成狗,然后就去翻了一下save 里面的文件,果然发现有个...多少 K 的 region ,明显比别的大,修改后缀让他失效
重新进游戏,果然不卡了!连拼成 flag 的砖块都没了!(笑死
然后开个创造模式上天,退出游戏
把文件后缀改回来,替换掉新出现的文件
再次进入游戏,走一走,转一转,能看到 flag 了,截个图然后手打 flag 就好了
顺嘴提一句:用银河一号开这个存档会卡么【逃
Square
提示是开根。
看到 DLP 的时候有点懵,萌新表示只看得懂开根【菜
chall.py:
from Crypto.Util import number
import os
from flag import *
assert len(flag) == 60
flags = [flag[i:i+20] for i in range(0, len(flag), 20)]
LEN_P = 110
def generate_prime(LEN):
while True:
p = number.getPrime(LEN)
if p % 4 == 3:
return p
N = generate_prime(LEN_P)*generate_prime(LEN_P)
print(N)
seeds = [number.bytes_to_long(os.urandom(27 - len(flag)) + flag)
for flag in flags]
output = [pow(seed, 2**495495, N) for seed in seeds]
print(output)
看到这里把 flag 分成了三份,然而用的同一种算法各自加密,所以只是 flag 太长了拆一下,并不是分组加密
观察下代码,N 是两个 110 长度且模 4 = 3 的素数的乘积,然后 flag 是转数字之后做了 \(2^{495495}\) 次幂模 N,也就是说我们只需要对 seed 开 495495 次根就可以得到 flag 了,然后感觉一下,这个 p 和 q 模 4 = 3 很有猫腻,但是记忆力下降的 OI 生涯并没有告诉我什么相关的性质
查询CTF-wiki 得知 这是典型的公钥指数攻击,所以可以用 Rabin 算法开根
然后发现我们要求 \(m_p=\sqrt c ~ mod ~p\) 和 \(m_q=\sqrt c ~ mod ~q\) 也就是说要去求 c 关于 p 和 q 的二次剩余(???OI 生涯记忆力恢复)
可以套个网上现成的模板抄抄(毕竟 AFO 的菜鸡早就不会敲 二次剩余了),但是继续翻翻 CTF-wiki 的话就会发现 p%4=3 且 q%4=3 的时候 m_p , m_q 可以直接求,
然后 ex_gcd 求出 p q 关于彼此的逆元(或者直接用库函数求逆更方便)
之后可以根据如下公式得到四个明文:
那么我们只需要求 495495 次根,然后把这 \(4^{495495}\) 个解都搞出来,看看哪个转成 bytes 之后又 0ops 就好了【doge
其实进一步分析一下(看代码),把 (p+1)/4 和 (q+1)/4 都求出来看看就会发现他们是偶数,也就是说我们开根后下次运算会内含一次平方,又因为这四个根的平方是一个值,也就是说这四个根在运算过程中是等价的,只有最后一次开根的结果需要判断哪一个是 flag
下附代码:
from Crypto.Util.number import *
import os
from random import randint
import gmpy2
#
#assert len(flag) == 60
#flags = [flag[i:i+20] for i in range(0, len(flag), 20)]
#
# https://blog.csdn.net/jcbx_/article/details/105303760 开方
N = 511490398280089896829556698249976719621998231130077313967635052153
p=688686416134306346667836523178879
q=742704351787795374036583643200007
PHI=(p-1)*(q-1)
'''
def Ex_gcd(a , b):
if b==0:
return 1,0,a
x,y,gcd=Ex_gcd(b,a%b)
return y,x-a//b*y,gcd
def Sqrt(a , mod):
if a==0:
return 0
b=( randint(1,1<<14)<<14^randind(1,1<<14) ) %mod
while pow(b,(mod-1)>>1,mod)!=mod-1:
b=( randint(1,1<<14)<<14^randind(1,1<<14) ) %mod
s=mod-1
t=0
int=pow(a,mod-2,mod)
f=1
while ~(s&1):
t=t+1
s=s>>1
f=f<<1
t=t-1
x=pow(a,(s+1)>>1,mod)
f=f>>1
while t:
f=f>>1
if pow(inv*x%mod*x%mod,f,mod)!=1:
x=x*pow(b,s,mod)%mod
t=t-1
s=s<<1
return min(x,mod-x)
'''
def Calc(c):
# Mp=Sqrt(x,p)
# Mq=sqrt(c,q)
Mp=pow(c,(p+1)>>2,p)
Mq=pow(c,(q+1)>>2,q)
'''
Yp, Yq , _gcd=Ex_gcd(p,q)
'''
Yp = gmpy2.invert(p,q)
Yq = gmpy2.invert(q,p)
a=(Yp*p*Mq + Yq*q*Mp) % N
b=N-int(a)
c=(Yp*p*Mq - Yq*q*Mp) % N
d=N-int(c)
return c,d
'''
def Calc(c):
# Mp=Sqrt(x,p)
# Mq=sqrt(c,q)
Mp=pow(c,(p+1)>>2,p)
Mq=pow(c,(q+1)>>2,q)
Yp = gmpy2.invert(p,q)
Yq = gmpy2.invert(q,p)
a=(Yp*p*Mq + Yq*q*Mp) % N
b=N-int(a)
c=(Yp*p*Mq - Yq*q*Mp) % N
d=N-int(c)
return a,b
'''
def Solt(x):
for i in range(0,495495):
if i%50000 ==0:
print (int(100*i/495495),'% Done!')
x,y=Calc(x)
return x,y
print('\n\n\n')
seeds=[202689292044494708585874083576035994532608494187960264651647194100, 349155488012675015373790008764956465654572687491071388513744087680, 428897998593573900719023336137030299789691435960087064073891777555]
for seed in seeds:
print(seed)
s1,s2=Solt(seed)
for SSR in (s1,s2):
flag = (long_to_bytes(SSR))
print (flag)
print('\n\n')
print('\n\n\n\n\n All above is the flags\n')
'''
flag= 你猜
'''
################################################################################
RSA
chall.py:
from Crypto.Util.number import *
from secret import FLAG, E1, E2, p, q, P, Q1, Q2
assert len(FLAG) == 45
assert FLAG[:5] == b'0ops{' and FLAG[-1:] == b'}'
assert E1 * E2 == 91091
flag = FLAG[5:-1]
part_1 = flag[:20]
part_2 = flag[20:]
n = p * q
m_1 = bytes_to_long(part_1)
c_1 = pow(m_1, E1, n)
c_2 = pow(m_1, E2, n)
print(f"n = {n}")
print(f"c_1 = {c_1}")
print(f"c_2 = {c_2}")
N1 = P * Q1
N2 = P * Q2
m_2 = bytes_to_long(part_2)
C1 = pow(m_2, E1, N1)
C2 = pow(m_2, E2, N2)
print(f"N1 = {N1}")
print(f"N2 = {N2}")
print(f"C1 = {C1}")
print(f"C2 = {C2}")
首先发现题目是两部分,一个是共模,一个是同质
第一部分考虑扩欧求出 r 和 s 使得 r e1+s e2=1
然后让 c1 c2 分别求 r 和 s 次幂相乘模 N
原理:
至于 e1 e2 枚举即可,但此时 e1 和 e2 会有公共因子,那么我们需要让它们都除去公共因子然后用以上算法,求出来 \(m^k\) ,其中 k=(e1,e2)
发现 e1 和 e2 的 gcd 最大是 7*13 ,乘上flag 的最大位数后量级直接爆碾 N , 虽然gcd的上确界很大,但是抱着试一试的心态(毕竟e1 e2 不一定这么大),考虑爆破,幸运的得到了 e1 和 e2
于是得到 part_1 的flag
from Crypto.Util.number import *
import os
from random import randint
from gmpy2 import *
#
#assert len(flag) == 60
#flags = [flag[i:i+20] for i in range(0, len(flag), 20)]
#
n = 29804855461219525809483226171447400629054389411209928077733989086881407915697629574489862366943916433250380893845064051868447277146099723344108491318363736970130552687834175107316389356412081460597193385122564402544028293223141492637593387849516866281975532921702211359695794328959577714933066037464530475666958327048553653419004959786993380324876416891277797557889764943496430192224333962685452521203739217690948634546711914576041274275163862103467979109605926625310456477531660479434029125982482536551716944635048867063664853033414244047680463959733088567306956910621629259157404014322615778420395527009203665234867
e1e2=91091
c1 = 5805095971678736984233000257363705474400067573877379489049985451548586015729865485401200776437838394198594585786343444459382200303815426682300448702522397881557890770612504121957727906722849594625449208276498609219751732566474462125536972773644340327444476197887130505371470377495914017368699538534837536176389392229200333966690024777471983110285970000300684529729020451726310805556702655635580572575780846261852351293127833450690228377612400667883011221729243458077813653341722084133814126490975005112494340624873677319889784913354136031024566601570503586765086626702335528524669391680719956518671680032189187461583
c2 = 21040659170349076453328467809948878673572171477318129739316066117735587948963653486187835499247011612045049391015510265991153140472441727276218607631308900484368761970475768636953012359580586420610631486203848852367959193105899777086215804465399028311023336963278518552534784547932293795144438455992648413615511086648016811737274059845135214768805826810071158903970180682144080655355798409467691413144904546864765174157620547051276031561862364699186343648454585389662948079658497134567099056607884232610902466499222078050836227886397513672844551857719675763870934510296811497925280493382213367370947889133310986454378
def Ex_gcd(a , b):
if b==0:
return 1,0,a
x,y,gcd=Ex_gcd(b,a%b)
return y,x-a//b*y,gcd
'''
failed: (e1,e2)!=1
for e1,e2 in DIV:
r,s,gg=Ex_gcd(e1,e2)
if r<0:
r=-r
c1=invert(c1,n)
if s<0:
s=-s
c2=invert(c2,n)
m=powmod(c1,r,n)*powmod(c2,s,n)%n
print(long_to_bytes(m),'???\n\n')
'''
def RSA_sameN(e1,e2,c1,c2,n):
e1,e2,c1,c2,n=int(e1),int(e2),int(c1),int(c2),int(n)
print ('now e1,e2 is :',e1,e2,'\n')
s=gcdext(e1,e2)
s1=s[1]
s2=s[2]
if s1<0:
s1=-s1
c1=invert(c1, n)
if s2<0:
s2=- s2
c2=invert(c2, n)
m = (powmod(c1,s1,n) * powmod(c2 ,s2 ,n)) % n
return int(m)
def Sqr(c,e,n):
k=0
while k<100000:
mk= c+n*k
res,flg=iroot(mk,e)
if flg:
return res
k+=1
for e1 in range(7,e1e2):
if e1e2%e1==0:
e2=e1e2//e1
c=RSA_sameN(e1,e2,c1,c2,n)
e=gcd(e1,e2)
m1=Sqr(c,e,n)
if m1 and m1<100000000000000000000000000000000000000000000000000000000:
print('\n!!!!!\n\n',long_to_bytes(m1),'\n\n')
part_1=???
# R4b1nP3rmUt4T10n&Qu4
'''
g=b'R4b1nP3rmUt4T10n&Qu4'
print (bytes_to_long(g))
print(len('469305435782367231774394752793149699305669489972'))
'''
print(48*13)
print(48*13*7)
print(len('29804855461219525809483226171447400629054389411209928077733989086881407915697629574489862366943916433250380893845064051868447277146099723344108491318363736970130552687834175107316389356412081460597193385122564402544028293223141492637593387849516866281975532921702211359695794328959577714933066037464530475666958327048553653419004959786993380324876416891277797557889764943496430192224333962685452521203739217690948634546711914576041274275163862103467979109605926625310456477531660479434029125982482536551716944635048867063664853033414244047680463959733088567306956910621629259157404014322615778420395527009203665234867'))
################################################################################
part2 就需要共模攻击了,查了挺多资料的,但其实后来发现还是应该多想想乱搞做法(于是查来查去可能半天时间没了)
首先可以得到:
然后同网上教程:
然后就和网上教程不一样了,因为这里 e1 和 e2 不等并且没有和 phi(n1),phi(n2) 互质的因子(
那么考虑让 c1 乘上 \(\frac{e2}{(e1,e2)}\) ,c2 乘上\(\frac{e1}{(e1,e2)}\) ,然后再去 exCRT,得到 \(m^{lcm(e1,e2)} mod ~q1*q2\) ,然后求出 lcm(e1,e2) 和phi(q1*q2) 的最大互质的因子,再对其求逆元得到 inv_e,然后 给 $m^{lcm(e1,e2)} $ 求 inv_e 次幂,发现得到了 \(m^{13}\)
最后考虑开根,由第一部分启发,爆破求根号 13 即可
from Crypto.Util.number import *
import os
from random import randint
from gmpy2 import *
flag=你猜
part_1=???
e1=637 #7*13*7
e2=143 #11*13
N1 = 23856531468494932149158441279820221958733289687773214618360631023639907666631842545905826981022303999372141536515664962572660333114705490759250473286009293699454647317879579025075566583806455097268718041921834867122485011733298510226500451055470196912593247387546086922711505115426494084990070127271386149429960015040523207707095022175791723355255220370148663763032661323574976034775111107349052228469623523116005281025845395926631135671525884567122075565201487212817882002280480094997037293811556559370512778068536953110782636849476781964874518787775692837445758246149554411534111215550916625175873859169243317579407
N2 = 14606287383905271238806377619804856612083129638676099657937596149668964790411259516998628489875777098012837723411528028560339150159251289662770952015064936056758393351189302501715603151778335754305216539038383959294601526795938955362080269385901797474569435837982428469925650098098675487739267330383962231557639357322897568627351841841132206246299271168118626199242374082288576888824800197863106837653332469780763796998340372002149895175132269852640010475366027170831575897710482343290609781790387651962085985923227948868747619585474280105551399868460679867700120661506274697531489033825706936840037802131181849482559
P=gcd(N1,N2)
Q1=N1//P
Q2=N2//P
C1 = 5877629942479289087438535033547827711087229704908716162059499524711223130411102111708773074330036146638697814946699080019024111586962929510031079156763405901264074181029433045256186431235495384554320192788781413841482196856657154871739291807048641104929480241225303362367778928184670347591353147815417999734889749518303591532111513321144121333943703263142977664147844817319769626822680276144800554448964968769635962769213967477351533652774308419270548225709627437411051087204712593155649572140816198920586228499694672216132229637256298116341165444322206726584155610100630743276125749470111666776263352129445361964183
C2 = 9203048878408485237617264525956866029329713008215567013906351951412434780481561849345481908214839165094745473923395779916000135713734276141868766445712002360713986231354004103713662338717540147922285092772947320775321460599896232941315105368178311809025918441734894203754208723533494837586895534761750243223540003867711472075686724657919338559153833790730589708778006367530730882489981285402968272745115097555875175964189478697413421529059664309370906039084106004869208846628860803318444264404597887629118809581987337162026906805016910578244987259596966439415670145344766250895302216409092529491772816211776554135510
def ECRT(c1,c2,n1,n2):
M = n1*n2
x = 0
x= ( x + invert(n2,n1)*n2*c1)%M
x= ( x + invert(n1,n2)*n1*c2)%M
return int(M+x%M)%M
Mt=ECRT(powmod(C1,e2//13,Q1),powmod(C2,e1//13,Q2),Q1,Q2)
N_phi=((Q1-1)*(Q2-1))
INV_E=invert(e1*e2//13//13,N_phi)
m_13=powmod(Mt,INV_E,Q1*Q2)
def Sqr(c,e,n):
k=0
while k<100000:
mk= c+n*k
res,flg=iroot(mk,e)
if flg:
return res
k+=1
TrM=Sqr(m_13,13,Q1*Q2)
part_2=long_to_bytes(TrM)
print(part_2)
part_2=???
# gcd(e1,phi_1)=7*13
# gcd(e2,phi_2)=11*13
# gcd(e1*e2,P-1)=7*11
# gcd(e1*e2, Q1-1 or Q2-1)=13
################################################################################
guess
看名字,啥也看不出
chall.py:
#!/usr/bin/env python3
import random
from Crypto.Util.number import *
from os import urandom
from secret import flag
assert type(flag)==str
assert len(flag)==45
assert flag[:5]=='0ops{' and flag[-1]=='}'
from secret import g1,g2
while True:
Prim=getPrime(511)
if isPrime((p:=2*Pim+1)):
break
while True:
Prim=getPrime(511)
if isPrime((q:=2*Prim+1)):
break
n=p*q
flag1=flag[:20].encode()
cip1=[pow(g1,v,n) for v in flag1]
print(f'{n=}')
print(f'{cip1=}')
while True:
q=getPrime(127)
if isPrime((p:=2*q+1)):
break
flag2=flag[20:].encode()
cip2=[pow(g2,v,p) for v in flag2]
print(f'{p=}')
print(f'{cip2=}')
又是熟悉的两部分解题...但思路其实是一样的
查阅 CTF-wiki,发现应该是离散对数类型,但是不知道根就很烦(还能知道根直接送分么,笑
但是发现这里出题人没有把 0ops{} 取走,那么我们就可以通过部分明文和公钥结合的方式得到根了
其中第一部分有5个明文可以用,我是直接用了 '0' ,因为 其ascii 码是 \(48=2*2*2*2*3\) ,都是小质数,开根时考虑直接爆破就可以得到 g1,
第二部分的话只有一个 '}' 可以用,发现ascii 码值是 \(125=5*5*5\) ,显然和 p-1 互质,直接求 p-1 下的逆然后给最后一个密文做个幂 g2 就出来了
from Crypto.Util.number import *
import os
from random import randint
from gmpy2 import *
#
#assert len(flag) == 60
#flags = [flag[i:i+20] for i in range(0, len(flag), 20)]
#
n=87414845868213216800195042371401565199834805052305564497085079194350340828874748331888471116447396526866899450154108200117559601244413937910691691245269342652855198926707584214922470532052069822588939463619870093353386083227545651734856915698079889875822511915508821155124294059245675336481733350641303079301
cip1=[2611396359632038309920140297384020814524968901192209023591293135966980553481371169873319899200012745596151624350037953010415696033477908848470409788889937184541228819097132172328321, 66873308155019585020403155683810317762807764877073017866260523282330055579570110225189339791779029968908064713041090279025800794345180391127774103337221847172089787654410513191904250622224443583130256640786043864036137405051406383567512860249990357231658833441205153927349327793002075525214183005026588558950, 75825215627763942797058232309724908353022530251086485527294565918233302891326681584631126465118971733612471440508148655167626897811544347924889661399861665550498882960234646874885125057150454898015981825543678340662159577448102714269133171020122662917545166941260852517691216482883911671921957223500650723362, 84900166775312790491728504753841340131896794811139934535003135380479081880171622442680957693630025671566682395350350590404722125710104415781427737285835146149215473799781916140216350212380825680932431613119499979272086234998458996580835508408057142840821453572662224456363132016254679539363986812938940995520, 1647176792149195911381593013884425360615196615143732300058809017953371302787348963423211509453155403532599223727495154686094082624213744499745867022761711799356388925897956481450408466404220980380673902594525923659037223328773140021840772002419920030369558797884038713911312242523404629091016350221316913056, 26226083581075551310482272556543809460225198423891052895241181887364977820928168244065670384008497481000616118937129736619368708240277278599440280247401502930650090428569500609879105154758685438094390008092475715842458081889058004109006481405906868038516946506851882349977638279276682428617, 14981580915209003784011844886092127412929746586139703168343248721042567435322626401563236261710473121485121868896167736420754848144062763063674740958861569627713029735160247272647577577, 4844937477252728345154881808695858028321340421194353125346169294054303141822113795302654052920943825115630784049887162284760522175385972238708505118012239283092960350978923847354129250282880766854039784134672881222293093013444383928277928845162869484656886479133512032531072746870687425693580871355452678601, 84532468461873665629151132408704695831546166599140306701453337207261180695892969115445513623163470637129497098634468753152455047051512081493655073138241242781656243517581115850428467547928747252305427931627707005660606089737599333702765873003264924456179790857445692702528149055392485879861158513016011587576, 10589685229440730757441130990965626321681358631392169555601316082764416151602183970881449949551931189548308748144663359908264280247245048216662530049075158792603950784021678900356541724906686569832138984316198781188674356137866417844157500593020337844767582205853089402607587522823600363355141605603647493939, 66399543206668155386566473374623427377528408818643663486088345499682166875995836476867518140883397528075956576682520646479856141404542896744829769065107072971231734311105665730133483857874823076829599149274481751366883224977246569617166905314324987522314872083824926567143827080173261530076491483618867560831, 14981580915209003784011844886092127412929746586139703168343248721042567435322626401563236261710473121485121868896167736420754848144062763063674740958861569627713029735160247272647577577, 2611396359632038309920140297384020814524968901192209023591293135966980553481371169873319899200012745596151624350037953010415696033477908848470409788889937184541228819097132172328321, 66399543206668155386566473374623427377528408818643663486088345499682166875995836476867518140883397528075956576682520646479856141404542896744829769065107072971231734311105665730133483857874823076829599149274481751366883224977246569617166905314324987522314872083824926567143827080173261530076491483618867560831, 84900166775312790491728504753841340131896794811139934535003135380479081880171622442680957693630025671566682395350350590404722125710104415781427737285835146149215473799781916140216350212380825680932431613119499979272086234998458996580835508408057142840821453572662224456363132016254679539363986812938940995520, 3628346761837129338125006527663815756417795967221751174534516319238436791934372604955083728255983321536400675244443369528469142645665083108582721581475386983478127345670765696472452405413512087872491036693590204515102968378523087869199984528358177161872546877830593274588846784829152354698500156234429091761, 796826449044622573732789831223599570744014300898556832836156916016351321895748423497769855707558803620539125811225583796545653450759399029593299880889667686835323892043622436049202832907359526458676464976449873782814960233366103522544622834887362807225185350789280799730273261723193, 2611396359632038309920140297384020814524968901192209023591293135966980553481371169873319899200012745596151624350037953010415696033477908848470409788889937184541228819097132172328321, 74798467119668989701159595404377524086463886314303589990624033996916187590975962566722690996448587413729563521467023505471284983608465050993217231386068300513162221131781427561190441126517596847906186038387898118790520637829454550857204829546329956280016526000278430803029350578241452411926299739277726788588, 4445632465714670676987477860512753318967184248753354067721460444280683150911996143420731119867172985756872198833516921128331121623927076228540884827559804873479684970424667512590960985785144982038785365270031068682215702915159001401152322699737012081418164511217408420789353128644499494237650093784494646093]
p=259857352472449638618155305618331063003
cip2=[80833917735370598592609231815725893292, 238404049829097626542744528611695020438, 161467596452810611494236771133341580897, 93691884183185633153774260016261051275, 245947978361781919904294101538961596874, 8343491577773366952613485421016488772, 55124189736851599938752214661539436857, 253723011008980879592676450737645422214, 78223947027734784360769773019760135866, 55124189736851599938752214661539436857, 80833917735370598592609231815725893292, 2186545696042314769550394051584231354, 36499282799347011599568839855936449048, 36499282799347011599568839855936449048, 93691884183185633153774260016261051275, 112298636568884361475324669480674883235, 19926409228584300368881795626614701445, 80833917735370598592609231815725893292, 30274608690261343742696197681032611359, 30274608690261343742696197681032611359, 112298636568884361475324669480674883235, 112298636568884361475324669480674883235, 236507571730032799225317901923605096983, 236507571730032799225317901923605096983, 103861429441219903910672984593680544330]
def Sqr(c,e,n):
k=0
while k<100000:
mk= c+n*k
res,flg=iroot(mk,e)
if flg:
print(k,'\n',res,'\n',powmod(res,e,n),'\n',c,'!!!\n\n')
return res
k+=1
gg='0ops{}'.encode()
for v in gg:
print(v)
cp_0=48
cp_9=125
g1=cip1[0]
g1=Sqr(g1,48,n)
print(g1)
print('\n\n',powmod(g1,48,n))
print(cip1[0],'!!!\n\n')
inv_125=invert(125,p-1)
g2=cip2[-1]
g2=powmod(g2,inv_125,p)
print('\n\n',powmod(g2,125,p))
print(cip2[-1],'!!!\n\n')
print(g2)
def Vio(y,g,n):
for x in range(0,1000):
if powmod(g,x,n)==y:
return x
part1=b''
part2=b''
for v in cip1:
part1+=long_to_bytes(Vio(v,g1,n))
for v in cip2:
part2+=long_to_bytes(Vio(v,g2,p))
print (part1)
print (part2)
print(part1+part2)
flag=你猜
#############################################################################
Pack
看名字,背包加密
做到 nc 交互了,头大,痛苦面具
虽说也多学了些知识就是了
server:
#!/usr/bin/env python3
import random
import signal
import socketserver
import string
from Crypto.Util.number import *
from hashlib import sha256
from os import urandom
from secret import flag
class Task(socketserver.BaseRequestHandler):
def __init__(self, *args, **kargs):
super().__init__(*args, **kargs)
def proof_of_work(self):
random.seed(urandom(8))
proof = ''.join([random.choice(string.ascii_letters + string.digits) for _ in range(20)])
digest = sha256(proof.encode()).hexdigest()
self.dosend('sha256(XXXX + {}) == {}'.format(proof[4: ], digest))
self.dosend('Give me XXXX:')
x = self.request.recv(10)
x = (x.strip()).decode('utf-8')
if len(x) != 4 or sha256((x + proof[4: ]).encode()).hexdigest() != digest:
return False
return True
def dosend(self, msg):
try:
self.request.sendall(msg.encode('latin-1') + b'\n')
except:
pass
def recvint(self,length):
buf=b''
while len(buf)<length:
buf+=self.request.recv(length-len(buf))
return bytes_to_long(buf)
def timeout_handler(self, signum, frame):
raise TimeoutError
def challenge(self):
base=[getRandomNBitInteger(i) for i in range(10,74,2)]
p=getPrime(76)
k=getRandomRange(2**10,p)
msg=bytes_to_long(urandom(4))
binmsg=[int(c) for c in bin(msg)[2:].zfill(32)]
cip=sum([b*v*k for b,v in zip(binmsg,base)])%p
self.dosend('p = %d'%p)
self.dosend('Here is your cipher:')
self.dosend(str(cip))
self.dosend('Here is your base:')
self.dosend(str([v*k%p for v in base]))
self.dosend('Give me the messsage (in hex):')
inpt=self.request.recv(10).strip()
inpt=int(inpt.decode(),16)
if inpt==msg:
self.dosend(flag)
else:
self.dosend('Good luck')
def handle(self):
try:
signal.signal(signal.SIGALRM, self.timeout_handler)
signal.alarm(40)
if not self.proof_of_work():
self.dosend('You must pass the PoW!')
return
signal.alarm(60)
self.challenge()
except TimeoutError:
self.dosend('Timeout!')
self.request.close()
except Exception as e:
print(e)
self.dosend('Wtf?')
self.request.close()
class ThreadedServer(socketserver.ForkingMixIn, socketserver.TCPServer):
pass
if __name__ == "__main__":
HOST, PORT = '0.0.0.0', 8888
server = ThreadedServer((HOST, PORT), Task)
server.allow_reuse_address = True
server.serve_forever()
main 函数不用看,就是调用 self 处理 request
这里用到了些新函数,还有蛮多新词,总之看不懂就查(
开头很不友好的让你先破解 sha256 ,给了几乎所有的明文,剩下四个让你填
查了半天sha256 原理(天真了)想要往前推
后来发现直接爆破更爽( ,虽说原理看不懂,想要倒推就更是吃人说梦就是了
#!/usr/bin/env python3
import re
import random
import signal
import socketserver
import string
from Crypto.Util.number import *
from hashlib import sha256
from os import urandom
import binascii
#from secret import flag
'''
base=[13701240101585076805514, 3116626158905841884772, 34151638535881787490312, 22781502956445774582910, 28650851919276777165924, 13116847465273562375850, 21928403294520149417174, 30417107148587595200979, 37727781098164932123126, 6324019069314836876363, 38076151552493819138974, 5018328691974162247600, 19175293726351567674444, 25848160220958945374851, 13722380935426049287042, 4261542243572700618457, 31954857031243842726422, 14718574679347422125513, 10897848595553451508706, 21654524100209294221816, 35508473507918652307400, 20282445062838165378501, 17288679757000429841732, 3907841862024515013070, 3403717398644584712739, 34962843745514575382168, 1111814940376603389993, 11870994191383641377636, 21389101094332931620378, 29503734986081658221205, 33200668995634435440336, 15507001113707628155330]
p=39339855220898420642837
msg=bytes_to_long(urandom(4))
binmsg=[int(c) for c in bin(msg)[2:].zfill(32)]
cip=sum([b*v for b,v in zip(binmsg,base)])%p
print(p)
print('cip=',cip)
print(msg)
print(binmsg)
'''
'''
0ops{MAKE_LLL_g2eat_aga1n!!!}
'''
Pr='R1R5xxUjtSLu7OZp'
Sha='f4d0995cccd9751f729d81a8498c251dfcc3ae4a37972749081b6b549194cd2c'
msg=bytes_to_long(urandom(4))
binmsg=[int(c) for c in bin(msg)[2:].zfill(32)]
Cr=[chr(48+i) for i in range(0,10)]
Cr+=[chr(65+j) for j in range(0,26)]
Cr+=[chr(97+k) for k in range(0,26)]
def func():
for c1 in Cr:
for c2 in Cr:
for c3 in Cr:
for c4 in Cr:
Tmp=c1+c2+c3+c4
# print(Tmp+Pr)
if sha256((Tmp+Pr).encode()).hexdigest()==Sha:
print(Tmp)
return 1
print('\n',func(),'\n\n')
'''
p = 59267452524397511819137
cip=694155088198386291006
Bases=[42860889044181729862314, 20726556765866476467818, 40306730958550293556689, 52649981869959719341768, 26811984082486624629901, 5217798987937332626232, 55996171131724985367534, 30935747149022804185987, 19028505298276979480328, 44087472283440022738107, 46322196289345692514695, 41928686556308463551125, 52815112131886006151742, 38105566727830585460464, 58795617951689234287304, 36447394952318004428521, 6493101890855617031493, 40693008400744204269739, 4788165385355475460720, 3594191199862822306657, 24873500075269720617109, 188630576775169859308, 46518808952004621011615, 15079840394115080584377, 27295185816536722461209, 33301101753552184132410, 53059380573466699339324, 45377740115951318622562, 26238666700520551604519, 14053835680239538162485, 40153574945790852959977, 10881357065799705827245]
def Solv():
for S in range(0,0x100000000):
if S&((1<<20)-1)==0:
print('!!!')
for i in range(0,32):
tmp=0
if (S>>i)&1:
tmp=(tmp+Bases[i])%p
if tmp==cip:
return S
return 0
res=Solv()
if res:
msg=str(hex(res))
print(msg)
print (msg)
else:
print ('error')
'''
################################################################################
然后做 背包解密,由 CTF-wiki 得知原来这个 pack 套用一下 LLL 算法就好了?大喜过望,然后 sage 弄了一个下午(痛苦面具
查 sage 资料到大概六点了?发现还没能正常使用,然后厚着脸皮问前辈 sage 函数库怎么导进 python ,得知是要把 py 文件改成 sage 文件然后放进 shell 里去跑,然后用了 LLL 算法,坐等答案
然后就发现跑不出答案,原来是这里有取膜, LLL 自带函数没法处理取膜运算,真是妙呢
然后想了一会儿,试了下直接爆破明文,复杂度大概是 1e32*32,也就是说大概也就 3e33 吧,试着跑了一下,好像是跑不出来(起码这个 60s之内跑不出来,更别提我还要复制粘贴数据耗费亿点时间了)
然后发现直接爆破取模的次数就好了啊,因为 base 总共就 32 个,都是模了 p 输出的,那么也就是说 没有模 p 的 密文 cip 最多也就 + 32*p,而且很极限,实在不行就多 重连几次(
然后爆破未取模的 cip ,放进 LLL 里面跑,以为终于得到答案了(毕竟跑完这 32 次也就刚好出来那么 1 个解)
然后被server 告知 good luck
mdmdmdmdmdmdmd
后来自己设置明文,跑了一下,发现确实有问题,但是得到的背包二进制竟然是没问题的,只有输出的十六进制代码出锅了,后来发现 CTF-wiki 上的模板的锅,人代码直接把十六进制最后一位丢掉了
......
......
......
这波啊,这波,这波是 rnm ,退网!
然后修正一下就可以得到 flag 了
import binascii
# open the public key and strip the spaces so we have a decent array
fileKey = open("pubKey.txt", 'rb')
PubKey = fileKey.read().replace(b' ', b'').replace(b'L', b'').strip(b'[]').split(b',')
nbit = len(PubKey)
# open the encoded message
fileEnc = open("enc.txt", 'rb')
PP,Encoded = fileEnc.read().replace(b'L', b'').split(b',')
print ("start")
pubKey=[]
for num in PubKey:
pubKey.append(int(num))
p=int(PP)
encoded=int(Encoded)
# create a large matrix of 0's (dimensions are public key length +1)
def Calc(enco):
A = Matrix(ZZ, nbit + 1, nbit + 1)
# fill in the identity matrix
for i in range(0,nbit):
A[i, i] = 1
# replace the bottom row with your public key
for i in range(0,nbit):
A[i, nbit] = pubKey[i]
# last element is the encoded message
A[nbit, nbit] = -int(enco)
res = A.LLL()
for i in range(0, nbit + 1):
# print solution
M = res.row(i).list()
flag = True
for m in M:
if m != 0 and m != 1:
flag = False
break
if flag:
print (i, M)
M = ''.join(str(j) for j in M)
# remove the last bitW
print(M)
M = M[:-1]
print(hex(int(M, 2)))
M = hex(int(M, 2))[2:]
print (M)
return
return
k=0
while k<35:
Calc(k*p+encoded)
k+=1
################################################################################
顺便提一嘴,弄 sage 环境的话其实没必要下虚拟机,按照CTF-wiki给的网址找到 github 原主的wp(才发现 github 好像要柯学上网才能进了),然后在wp里面找到sageMath 下载链接,然后下载这个软件就好了,之后用 shell(相当于是 sage环境下的命令行?)加载上述文件就可以轻轻松松得到 msg (马杀鸡)了(
forest
做了,但没完全做,或者,完全没做(
大概意思就是让你去一个地图吃鸡,你不知道自己会出生在哪个位置(但其实可以根据一些反馈信息比对地图得到自己位置),然后在地图上捡装备和 Flag ,尽量能杀掉看到的敌人就杀掉,防止对面杀自己,其实就算对面很弱也要干掉,防止突然技术爆炸(doge),详情参考 《三体·黑暗森林》,然后捡多少 flag 加多少分( ,活到最后获得的分才算入成绩,另外,别人捡到的 flag 死了会掉出来的,所以更加没有理由不杀对面达成共赢了
离谱的就是这地图里面有 AK47 和地雷等武器就算了,居然还有二向箔、水滴和智子,智子还有挂...三体快降临把,地球人已经疯了(
大概用了两天时间?一分没拿,调了好久代码才勉强做到个交互,人家已经在地图里面杀疯了,我的小人连路都不会走
server:http://111.186.57.85:40560/
学长杀疯了的证据:
至于自己的代码就不放出来了,还有 bug 来着,估计也不会修了(反正 程序员节也过去了)
HASH
下次一定
dog
下次也不一定
总体评价
这次比赛,怎么说呢...
Fuck, it's darking fuck.
译:md,真是黑暗他妈
总而言之,黑暗他妈给黑暗开门,黑暗到家