• REVERSE-COMPETITION-DSCTF-2022


    REVERSE-COMPETITION-DSCTF-2022

    catchme

    安卓逆向,java层传递输入,调用native层的check方法
    ida打开.so文件,没有直接找到check方法,JNI_OnLoad也看不出什么
    Findcrypt查到AES的S盒,通过对S盒查找交叉引用,来到sub_B2A4函数
    catchme-main
    输入经过AES加密,再进行变表base64,最后与true_cipher进行比较
    在AES解密前,AES_key和true_cipher都需要进行异或变换
    catchme-key
    catchme-cipher

    from Crypto.Cipher import AES
    import base64
    
    key=[0x24, 0x3C, 0x3D, 0x37, 0x36, 0x21, 0x35, 0x26, 0x3F, 0x37, 
      0x32, 0x2A, 0x72, 0x72, 0x72, 0x72]
    for i in range(len(key)):
        key[i]^=0x53
    print(bytes(key))
    # wonderfulday!!!!
    
    enc=[0x4F, 0x1C, 0x36, 0x49, 0x09, 0x3A, 0x3F, 0x07, 0x4D, 0x3D, 
      0x22, 0x39, 0x00, 0x0A, 0x22, 0x25, 0x06, 0x09, 0x01, 0x20, 
      0x4A, 0x1B, 0x51, 0x51]
    for i in range(len(enc)):
        enc[i]^=0x6C
    print(bytes(enc))
    # #pZ%eVSk!QNUlfNIjemL&w==
    
    ori_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    cur_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*()+/"
    
    cipher=base64.b64decode(bytes(enc).decode().translate(str.maketrans(cur_table,ori_table)))
    
    aes=AES.new(bytes(key),AES.MODE_ECB)
    print(aes.decrypt(cipher))
    # flag{weu/.,iopl}
    
    • 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

    FFunction

    ida打开my_plugin.dll,函数窗口第一个函数f,最后调用了memcmp函数,猜测这个f就是校验函数
    在f函数的第一行代码处下断点,通过尝试,当输入的长度为30时,程序会断下来
    function-f
    观察此时的input,发现程序在调用f函数前,对原本的输入进行了位置变换和标准base64变换

    s="flag{abcdefghijklmnopqrstuvwx}"
    # 1
    # f}lxawgv{uatbscrdqepfognhmiljk
    # Zn1seGF3Z3Z7dWF0YnNjcmRxZXBmb2duaG1pbGpr
    
    • 1
    • 2
    • 3
    • 4

    第32到第45行代码,是将input倒置

    # 2
    # rpGbp1Gaud2bmBXZxRmcjNnY0FWd7Z3Z3FGes1nZ
    
    • 1
    • 2

    然后是将倒置后的input,每个字符的高四位和低四位拆分成两个字节
    function-f

    # 3
    # ord("r")==0x72 -> 0x70 0x02
    # ord("p")==0x70 -> 0x70 0x00
    
    • 1
    • 2
    • 3

    最后就是TEA加密,delta已知,key已知,密文(a2)已知
    function-tea
    于是,先解密TEA

    #include 
    #include 
    
    //加密函数
    void encrypt(unsigned int num_rounds, uint32_t* v, uint32_t* k) {
    	uint32_t v0 = v[0], v1 = v[1], sum = 0, i;
    	uint32_t delta = 0x79B99E37;
    	uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
    	for (i = 0; i < num_rounds; i++) {
    		sum += delta;
    		v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
    		v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
    	}
    	v[0] = v0; v[1] = v1;
    }
    
    //解密函数
    void decrypt(unsigned int num_rounds, uint32_t* v, uint32_t* k) {
    	uint32_t v0 = v[0], v1 = v[1], i;
    	uint32_t delta = 0x79B99E37,sum = delta*num_rounds;
    	uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
    	for (i = 0; i<num_rounds; i++) {
    		v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
    		v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
    		sum -= delta;
    	}
    	v[0] = v0; v[1] = v1;
    }
    
    //打印数据 hex_or_chr: 1-hex 0-chr
    void dump_data(uint32_t * v,int n,bool hex_or_chr)
    {
    	if(hex_or_chr)
    	{
    		for(int i=0;i<n;i++)
    		{
    			printf("0x%x,",v[i]);
    		}
    	}
    	else
    	{
    		for (int i = 0; i < n; i++)
    		{
    			for (int j = 0; j < sizeof(uint32_t)/sizeof(uint8_t); j++)
    			{
    				printf("0x%02x,", (v[i] >> (j * 8)) & 0xFF);
    			}
    		}
    	}
    	printf("\n");
    	return;
    }
    
    int main()
    {
    	// v为要加解密的数据
    	uint32_t v[] = { 0x5c15754c,0xd1d781e7,0x501bf173,0xcb4db222,0x215d61f5,0x3fca9ee7,0x7c76b5c7,0xc7dd8cb9,0x990d23fa,0xbab1ad3,0x8e12c932,0xd307baf2,0xe52dd123,0xfbb68f2c,0xbdd853e3,0x892e1e4e,0x39dd66fa,0x87feec65,0x307c5e60,0x340c6c00 };
    	// k为加解密密钥,4个32位无符号整数,密钥长度为128位
    	uint32_t k[4] = { 0x0BABEC0FE,0x0DEADBEEF,0x0FACEB00C,0x0DEADC0DE };
    	// num_rounds,建议取值为32
    	unsigned int r = 32;
    
    	int n = sizeof(v) / sizeof(uint32_t);
        /*
    	printf("加密前明文数据:");
    	dump_data(v,n,1);
    
    	for(int i=0;i
    	for(int i=0;i<n/2;i++)
    	{
    		decrypt(r,&v[i*2], k);
    	}
    
    	printf("解密后明文数据:");
    	dump_data(v,n,1);
    
    	printf("解密后明文字符:");
    	dump_data(v,n,0);
    
    	return 0;
    }
    // 解密后明文数据:0x6400130,0x4600440,0x2500740,0x8500330,0xa400c60,0x3600e60,0x9300c60,0x4600130,0x2400330,0xd400450,0x2500770,0x2600850,0x6500f60,0x8500030,0xe400730,0xa500030,0x5400860,0x9400750,0x1300370,0xa500e60,
    // 解密后明文字符:0x30,0x01,0x40,0x06,0x40,0x04,0x60,0x04,0x40,0x07,0x50,0x02,0x30,0x03,0x50,0x08,0x60,0x0c,0x40,0x0a,0x60,0x0e,0x60,0x03,0x60,0x0c,0x30,0x09,0x30,0x01,0x60,0x04,0x30,0x03,0x40,0x02,0x50,0x04,0x40,0x0d,0x70,0x07,0x50,0x02,0x50,0x08,0x60,0x02,0x60,0x0f,0x50,0x06,0x30,0x00,0x50,0x08,0x30,0x07,0x40,0x0e,0x30,0x00,0x50,0x0a,0x60,0x08,0x40,0x05,0x50,0x07,0x40,0x09,0x70,0x03,0x30,0x01,0x60,0x0e,0x50,0x0a,
    
    • 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
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    再按照3、2、1的顺序将解TEA得到的明文转换成flag即可

    import base64
    s="flag{abcdefghijklmnopqrstuvwx}"
    # 1
    # f}lxawgv{uatbscrdqepfognhmiljk
    # Zn1seGF3Z3Z7dWF0YnNjcmRxZXBmb2duaG1pbGpr
    
    # 2
    # rpGbp1Gaud2bmBXZxRmcjNnY0FWd7Z3Z3FGes1nZ
    
    # 3
    # ord("r")==0x72 -> 0x70 0x02
    # ord("p")==0x70 -> 0x70 0x00
    
    # 4
    # TEA
    
    tea_plain=[0x30,0x01,0x40,0x06,0x40,0x04,0x60,0x04,0x40,0x07,0x50,0x02,0x30,0x03,0x50,0x08,0x60,0x0c,0x40,0x0a,0x60,0x0e,0x60,0x03,0x60,0x0c,0x30,0x09,0x30,0x01,0x60,0x04,0x30,0x03,0x40,0x02,0x50,0x04,0x40,0x0d,0x70,0x07,0x50,0x02,0x50,0x08,0x60,0x02,0x60,0x0f,0x50,0x06,0x30,0x00,0x50,0x08,0x30,0x07,0x40,0x0e,0x30,0x00,0x50,0x0a,0x60,0x08,0x40,0x05,0x50,0x07,0x40,0x09,0x70,0x03,0x30,0x01,0x60,0x0e,0x50,0x0a]
    cipher=""
    for i in range(0,len(tea_plain),2):
        cipher+=chr(tea_plain[i]+tea_plain[i+1])
    cipher=cipher[::-1]
    cipher=base64.b64decode(cipher)
    
    flag=""
    for i in range(0,len(cipher),2):
        flag+=chr(cipher[i])
    for i in range(len(cipher)-1,0,-2):
        flag+=chr(cipher[i])
    print(flag)
    # flag{Emp0wer_F1utter_w1th_C!!}
    
    • 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

    nothing

    出题人,richar师傅的wp:ISC-Nothing出题思路及WriteUp
    FallW1nd师傅的wp:nothing

    bad_apple

    附件是1个.elf文件和1张电路图,电路图里是树莓派连接ST7789
    根据字符串"frame: %d\n"的交叉引用,来到sub_100003A4函数,猜测是画图函数
    frame_data是每一帧填充的像素,总共2192帧,每帧的大小为宽240*高180
    apple-main
    dump出byte_100068CC数据

    data=get_bytes(0x100068CC,1343128)
    with open("D:\\CTFFiles\\ZMatches\\202208\\20220801-360DSCTF-Final\\bad_apple\\data","wb") as f:
        f.write(data)
    
    • 1
    • 2
    • 3

    直接复制ida反编译出来的伪代码,把每帧的frame_data输出到文件里

    #include
    #include"defs.h"
    
    int32 frame_id=0;
    
    int32 dword_20000FC8=0;
    
    char byte_100068CC[1343128];
    
    int __fastcall sub_1000035C(int *a1)
    {
      int v1; // r1
      _BYTE *i; // r3
      int v3; // r4
      int v4; // r6
      char *v5; // r7
    
      while ( 1 )
      {
        v1 = a1[2];
        if ( v1 )
          break;
        v4 = *a1;
        v5 = (char *)&byte_100068CC + *a1;
        v3 = 0;
        for ( i = (_BYTE *)v5; ; ++i )
        {
          v3 |= (*i & 0x7F) << v1;
          if ( (char)*i >= 0 )
            break;
          LOBYTE(v1) = v1 + 7;
        }
        a1[2] = v3;
        *a1 = v4 + i + 1 - (_BYTE *)v5;
        *((_WORD *)a1 + 2) = ~*((_WORD *)a1 + 2);
      }
      a1[2] = v1 - 1;
      return *((unsigned __int16 *)a1 + 2);
    }
    
    void sub_100003A4(FILE *fp)
    {
        int i; // r4
        _WORD frame_data[43204]; // [sp+0h] [bp-15188h] BYREF
    
        printf("frame: %d\n", frame_id);
        for ( i = 0; i <= 43199; ++i )
            frame_data[i] = sub_1000035C(&dword_20000FC8);
        for(int y=0;y<180;y++)
        {
            for(int x=0;x<240;x++)
            {
                if(frame_data[y*240+x])
                    fwrite("*",1,1,fp);
                else
                    fwrite("0",1,1,fp);
            }
            fwrite("\n",1,1,fp);
        }
        frame_id++;
        return;
    }
    
    int main()
    {
        FILE *fp = NULL;
        fp = fopen("D:\\CTFFiles\\ZMatches\\202208\\20220801-360DSCTF-Final\\bad_apple\\data", "rb");
        fseek(fp, 0, SEEK_SET);
        fread(byte_100068CC, 1, 1343128, (FILE*)fp);
        fclose(fp);
    
        fp = fopen("D:\\CTFFiles\\ZMatches\\202208\\20220801-360DSCTF-Final\\bad_apple\\flag", "wb");
        for(int i = 0; i < 2192; i++) {
            sub_100003A4(fp);
        }
        fclose(fp);
        return 0;
    }
    
    • 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
    • 77
    • 78

    在最后的地方看到flag
    apple-flag

    fantastic_cpu

    verilog写的vm,flag的4个int,4选2,选4组做加法,和data比较
    通过运行.v,发现data是已知的8个int的第0、2、4、6个
    cpu-data
    用claripy求解即可得到flag

    import claripy
    
    flag=[claripy.BVS(f"flag_{i}",64) for i in range(4)]
    
    data=[0x90771cb9,0xe3520b8,0x65dfd405,0x74c00bcc,0x64b1ca23,0x74942df9,0xb7385ab6,0xec36f96c]
    
    cons=[[0,1],[1,3],[2,3],[0,3]]
    
    s=claripy.Solver()
    for i in range(len(cons)):
        s.add(flag[cons[i][0]]+flag[cons[i][1]]==data[i*2])
    
    for i in s.batch_eval(flag,1):
        for c in i:
            print(hex(c)[2:].zfill(8),end="")
    # 70e7d1b51f8f4b041e61412246508901
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    里氏代换原则
    OpenCV图像处理——获取穿过圆的直线与圆相交的两个点
    “拳头”重拳出击,Valorant监控来袭,网络环境改善?隐私安全?
    Nginx原理以及基础知识详解
    Linux下awk命令的使用
    深度解读《深度探索C++对象模型》之C++虚函数实现分析(一)
    【gitlab】我的gitlab经历--20220901
    YOLO算法
    企业应用级自动化运维的建设思路
    散装问答-总结(更新中)
  • 原文地址:https://blog.csdn.net/weixin_45582916/article/details/126142464