0xcafebabe 发布的文章

nSMC

嵌套分支SMC
网页的两分钟限制可以把js reset去掉,然后10分钟手动续一次容器,手撕。
手撕方法:Ctrl+N手动设置RIP寄存器,然后走解密函数,递归地走解密函数。
然后通过xref反向查找到最顶层,拿到每一层的if条件。
gy5r64K3RxrZWkXJ7P6XVo93KxDmbrRI
发现这个是Correct!
然后开一个新的页面,把challenge-id改成最开始的id,提交,就过了

R3CTF{AU7OMATE_EVeRy7hInG_In_It_6714e11d6406}

baby_rop

在主函数read后,栈被整个换掉了,可以清楚看到栈上的逻辑,我们可以定位到strlen函数,发现它的返回进入了一个My_Cmp函数,这个函数生成随机数,并和另一个magic异或,这个值再异或strlen的值,最后看结果是不是0,然后会操纵跳转,我们可以知道,这两个数异或的值就是正确值,得到flag长度32,然后,我们再经过调试,发现它把flag的每8位 先异或 0x343230324E494448 再加上 0x343230324E494448 ,最后的值还是走My_Cmp函数进行正确性判断,我们就可以写出z3脚本

from z3 import *
from Crypto.Util.number import *
x = [BitVec(f"x{i}", 64) for i in range(4)]
s = Solver()
magic = 0x343230324E494448 
s.add((x[0] ^ magic) + magic == 0x0000000011DB2A3F^0x9A7BA6984AB8636B)
s.add((x[1] ^ magic) + magic == 0x0000000030836D0F^0x8F739F7345DC15CF)
s.add((x[2] ^ magic) + magic == 0x000000000AD48145^0x399F7938C150EA1A)
s.add((x[3] ^ magic) + magic == 0x000000001ECB02BB^0x7D454145674F5DD5)

print(s.check())
m = s.model()
result = b""
for i in range(4):
    result += long_to_bytes(m[x[i]].as_long())[::-1]

print(result)
# b'DASCTF{R0p_is_so_cr34y_1n_re!!!}'

FinalEncrypt

进去后发现是ChaCha加密,然后发现时间戳决定密钥,我们先根据这个rand自己写一个根据时间戳生成key的程序

#include <iostream>
#include <ios>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
        int a;
        std::cin >> a;
        srand(a);
        uint32_t mykey[32];
        for(int i = 0; i < 32; ++i){
                mykey[i] = rand();
        }
        char* cb = (char*)mykey;
        for(int i = 0;i < 64;i++)
        {
                printf("%02x", (int)cb[i] & 0xff);
        }
        return 0;
}

这个程序必须在linux下才能正常运行(rand和windows下的不一样),然后我们注意到,*.enc的两个文件,它们可以在属性中看到修改时间,精确到秒,我们就可以直接获取key了,解密这两个文件
2024-06-02T10:31:47.png
2024-06-02T10:31:54.png
然后,分析exe,发现exe里面也是一个根据时间决定一个码表的,而加密结果就是加密文本对于码表的索引值的数据,我们就可以根据上面的时间戳,对于这个时间戳附近进行爆破(生成box的算法直接从ida扣出来用)。
Exp


#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctime>
#include <iostream>

__int64 __fastcall __ROR1__(unsigned __int8 a1, char a2)
{
        return (unsigned __int8)(((int)a1 >> a2) | (a1 << (8 - a2)));
}

int main() {
        unsigned int v3; // eax
        char Str[8]; // [rsp+20h] [rbp-60h] BYREF
        char v6[56]; // [rsp+28h] [rbp-58h] BYREF
        int v7; // [rsp+60h] [rbp-20h]
        char v8[260]; // [rsp+70h] [rbp-10h] BYREF
        int v9; // [rsp+174h] [rbp+F4h]
        int v10; // [rsp+178h] [rbp+F8h]
        int v11; // [rsp+17Ch] [rbp+FCh]
        int v12; // [rsp+180h] [rbp+100h]
        int v13; // [rsp+184h] [rbp+104h]
        int v14; // [rsp+188h] [rbp+108h]
        int v15; // [rsp+18Ch] [rbp+10Ch]
        int v16; // [rsp+190h] [rbp+110h]
        char v17; // [rsp+195h] [rbp+115h]
        char v18; // [rsp+196h] [rbp+116h]
        char v19; // [rsp+197h] [rbp+117h]
        int i; // [rsp+198h] [rbp+118h]
        unsigned __int8 v21; // [rsp+19Ch] [rbp+11Ch]
        char v22; // [rsp+19Dh] [rbp+11Dh]
        char v23; // [rsp+19Eh] [rbp+11Eh]
        char v24; // [rsp+19Fh] [rbp+11Fh]

        //e07816e1dba1da61536634bef2c3b6346d533cc3b6b834e3beb634c80264143c34e36400bb4daa6902ff643414e3b8344dff6634b8b66db6bbc33834143461ab147e04

        for (int i = 1715097600; i < 1717309574; i++)
        {
                srand(i);
                do
                        v19 = rand();
                while (!v19);
                memset(v8, 0, 0x100ui64);
                v8[0] = v19;
                v22 = 1;
                v21 = 1;
                do
                {
                        if (v22 < 0)
                                v24 = 27;
                        else
                                v24 = 0;
                        v22 ^= v24 ^ (2 * v22);
                        v18 = (2 * v21) ^ (4 * ((2 * v21) ^ v21)) ^ v21;
                        v17 = v18 ^ (16 * v18);
                        if (v17 < 0)
                                v23 = 9;
                        else
                                v23 = 0;
                        v21 = v23 ^ v17;
                        v16 = (unsigned __int8)(v23 ^ v17);
                        v16 = __ROR1__(v23 ^ v17, 7);
                        v15 = v16 ^ (unsigned __int8)(v21 ^ v8[0]);
                        v14 = v21;
                        v14 = __ROR1__(v21, 6);
                        v13 = v15 ^ v14;
                        v12 = v21;
                        v12 = __ROR1__(v21, 5);
                        v11 = v13 ^ v12;
                        v10 = v21;
                        v10 = __ROR1__(v21, 4);
                        v9 = v11 ^ v10;
                        v8[v22] = v11 ^ v10;
                } while (v22 != 1);
                unsigned char hexData[67] = {
                        0xE0, 0x78, 0x16, 0xE1, 0xDB, 0xA1, 0xDA, 0x61, 0x53, 0x66, 0x34, 0xBE, 0xF2, 0xC3, 0xB6, 0x34,
                        0x6D, 0x53, 0x3C, 0xC3, 0xB6, 0xB8, 0x34, 0xE3, 0xBE, 0xB6, 0x34, 0xC8, 0x02, 0x64, 0x14, 0x3C,
                        0x34, 0xE3, 0x64, 0x00, 0xBB, 0x4D, 0xAA, 0x69, 0x02, 0xFF, 0x64, 0x34, 0x14, 0xE3, 0xB8, 0x34,
                        0x4D, 0xFF, 0x66, 0x34, 0xB8, 0xB6, 0x6D, 0xB6, 0xBB, 0xC3, 0x38, 0x34, 0x14, 0x34, 0x61, 0xAB,
                        0x14, 0x7E, 0x04
                };

                unsigned char result[67] = {};
                bool flag = true;
                for (int j = 0; j < 67; j++)
                {
                        bool notFound = true;
                        for (int k = 0; k < 0x90; k++)
                        {
                                if ((unsigned char)v8[k] == (unsigned char)hexData[j])
                                {
                                        result[j] = k;
                                        notFound = false;
                                        break;
                                }
                        }
                        if (notFound)
                        {
                                flag = false;
                                break;
                        }
                }
                
                if (flag)
                {
                        std::cout << i << std::endl;
                }
                if (flag && result[0] == 'D' && result[1] == 'A' && result[2] == 'S' && result[3] == 'C' && result[4] == 'T')
                {
                        flag = true;
                        std::cout << result << std::endl;
                }
                else
                {
                        flag = false;
                }
                if (flag)
                {
                        std::cout << "ok" << std::endl;
                }

        }

        return 0;
}
DASCTF{7ou_h@ve_5o1ved_4he_fina1_4ncrypti0n_a4d_y0u_de5erv3_a_7lag}

Logo: 2024

len(ROIS_LOGO) * .2024 = 449.5304
default_guarded_getitem # No restrictions可以getattr

也就是把代码长度限制在449以下,可以考虑对 logo 这样加密:

  1. 除去所有换行符,这样就只有空格和#了
  2. 把所有连续的同种字符的个数记录,变成列表。这样的话,列表中第1个数是#的,第2个数是空格的,第3个数是#的,依次类推。
  3. 把这个列表中每个数和96(0x60)异或,变成bytes,这样大部分都是可见字符,减少长度

这样得到下面的l(为了使得l的长度是偶数,最后加上了一个x60,异或回去表示0个字符,不会有影响),解密即可。

l=b'\xe0aaa)cbgkababjkshmjcbkiojsfrgchghezdmdldfckefdkcndldvdmdedkdmdldvdncddmcmcmdvdndcdmdlcnetdndccoclcofrdncdcoclcqfpdmddcockdtfmdldecockdvelddkfcndkdxejddihdmdkdzdididicmcldzdidjdhdkcmdzdidkdhdidmdmdididlciefclgoedejcnakilrikma\x7fbNd\x10\x60'
a=''
i=0
c=0
while i<len(l):
    a=a+'#'*(l[i]^96)+' '*(l[i+1]^96)
    i=i+2
i=100
while i<len(a):
    a=a[:i]+'\n'+a[i:]
    i=i+101
logo=a

2024-05-30T11:11:07.png

s1ayth3sp1re

Score>3000 to obtain a flag
找到关键部分
2024-05-30T11:11:27.png
写出解密脚本

public class Main {
    public static void main(String[] args) {
        int[] iArr = {164, 158, 95, 107, 4, 215, 108, 115, 5, 8, 25, 57, 41, 236, 231, 17, 85};
        int[] iArr2 = {246, 221, 11, 45, 127, 148, 45, 36, 70, 73, 78, 8, 98, 141, 140, 112, 40};
        String str = "";
        for (int i = 0; i < iArr.length; i++) {
            str = str + String.valueOf((char) (iArr[i] ^ iArr2[i]));
        }
        System.out.println(str);
        // RCTF{CAWCAW1Kaka}
    }
}

Find a Hacker

翻了一堆东西(扫文件,剪贴板,浏览器balabala)然后走投无路跑了下进程,发现一个idaq64.exe和一个poner.exe,给ida的进程memdump下来放进gimp里一通爆查
idaq64.exe:
2024-05-30T11:12:18.png
2024-05-30T11:12:26.png
poner.exe
2024-05-30T11:12:35.png

0x7e577070        \Users\Administrator\Desktop\enc.til        216
0x7e578330        \Users\Administrator\Desktop\enc.i64        216

拿到了一个二进制,打开ida稍微分析一下,即可写出exp

>>> a = bytes.fromhex("0C0F2B486F5D46536459594B5F475B5B6B5F15165D12766B071B334A67071100")
>>> b = bytes.fromhex("353F4E2B566B746A5D6D6F736C773868596E20213C714F09367D557251322766")
>>> for i in a:
...     print()
KeyboardInterrupt
>>> for i in range(32):
...     print(chr(a[i] ^ b[i]),end='')
...
90ec9629946830c32157ac9b1ff8656f
# 题目没说加RCTF前缀,加上后对了
RCTF{90ec9629946830c32157ac9b1ff8656f}