RCTF babyRe

RCTF babyRe

复习中太无聊,忙里偷闲看看题

拿到后,为64位elf文件
image_1dbd1fo978gt1ambd8a1da81qfk9.png-50.4kB
简单运行输入下
image_1dbd1h5jluli1et59ok1f56vgjm.png-39.5kB
提示了校验成功的话会输出Bingo!(当时没注意,被小坑了一下),直接拖入ida分析
image_1dbd6umbsd49q0l11bq1kod1a5r8e.png-5.7kB
首先可以看到先检验了长度是否为16位,然后进入了一个转输入为hex的函数,这个在调试过程发现得出
image_1dbd2b59m17frvulkr16di55s2f.png-157.1kB
在r13指向的内存中可以观察到目标hex,在转换结束后,就进入了xxtea解密过程
说一下算法识别的过程
image_1dbd2vnfcgds1o8b39t17101mb32s.png-42.8kB
看上去贼长。。但是实际上真正运行的部分只有截图的部分,这就减少了很大的工作量,然后就是在f5中频繁出现了一个数字0x9E3779B9以及0x61C88647,这两个数值是tea系列算法的delta值,然后就是对比加密过程
image_1dbd347701fba1gffa9sl93cj139.png-19.5kB

#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))

可以对着找出key和密文,最后一步就是判断是加密还是解密过程

void btea(uint32_t *v, int n, uint32_t const key[4])
{
    uint32_t y, z, sum;
    unsigned p, rounds, e;
    if (n > 1)            /* Coding Part */
    {
        rounds = 6 + 52 / n;
        sum = 0;
        z = v[n - 1];
        do
        {
            sum += DELTA;
            e = (sum >> 2) & 3;
            for (p = 0; p<n - 1; p++)
            {
                y = v[p + 1];
                z = v[p] += MX;
            }
            y = v[0];
            z = v[n - 1] += MX;
        } while (--rounds);
    }
    else if (n < -1)      /* Decoding Part */
    {
        n = -n;
        rounds = 6 + 52 / n;
        sum = rounds * DELTA;
        y = v[0];
        do
        {
            e = (sum >> 2) & 3;
            for (p = n - 1; p>0; p--)
            {
                z = v[p - 1];
                y = v[p] -= MX;
            }
            z = v[n - 1];
            y = v[0] -= MX;
            sum -= DELTA;
        } while (--rounds);
    }
}

可以清楚的看出来,加密的过程中是每一次加上MX,解密过程中是减去,因此这里直接判断为xxtea算法的解密即可,编译一份自己测试下,其中key是
image_1dbd3a32vjv51tpd1nttmt4tg63m.png-2.8kB

还挺有意思的哈,直接用Bingo!!!测试下

int main()
{
    //42 69 6e 67 6f 21
    //676e6942 2121216f
    uint32_t v[2] = { 0x676e6942,0x2121216f };
    uint32_t const k[4] = { 0xE0C7E0C7,0xC6F1D3D7,0xC6D3C6D3,0xC4D0D2CE };
    int n = 2; //n的绝对值表示v的长度,取正表示加密,取负表示解密
               // v为要加密的数据是两个32位无符号整数
               // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
    printf("加密前原始数据:%x %x\n", v[0], v[1]);
    btea(v, n, k);
    printf("加密后的数据:%x %x\n", v[0], v[1]);
    //btea(v, -n, k);
    //printf("解密后的数据:%x %x\n", v[0], v[1]);
    getchar();
    return 0;
}

别忘了端序哈,这里转来转去还是有点观察下结果
image_1dbd3e34dr4qk0scf9fh81cna43.png-356.5kB
验证成功,可以知道这一串就是xxtea的解密函数,看下校验点
image_1dbd3fmc818foqkvtn01e02vu4g.png-12.1kB
可以看到,这里取出了密文的最后一位并且进行了校验,最后一字节必需小于等于4,重新构造密文最后一字节为00,过了第二个函数校验
image_1dbd3olu6pjr1st01kaucuo14394t.png-64.6kB
从这里我们可以推断出,由于要输出bingo,并且每一位都是和0x17异或过的,
image_1dbd9a968o4b1c0jep7h9j1fhfa2.png-53.6kB
第三个校验函数一开始发现里面全是大量的逻辑运算,本来想逆推来着。。结果跟着跟着头就晕了,只好重新想办法
image_1dbd3reb4ok2mnargk1ncr1e725a.png-40.2kB
看到校验是把这个byte的明文压缩成了一16位的密文,再加上直接去谷歌搜索0x1021
image_1dbd3vvgov621jtk16da1f1f9n56n.png-62.8kB
可以发现是Crc16中似乎要用到的数字,并且加上校验的密文为0x69E2,刚好为16位,直接盲猜Crc16,然后去了解了发现crc16有很多种。。但是这里是哪种呢?
image_1dbd45pjg11t51omd1rek1bfbfj87k.png-144.4kB
总之先让这个函数运行结束,跑完了发现这里的crc16值是0xEC4F,直接去这个网站把我们的Bingo!!去crc计算下得到校验码,找到合适的即可 https://crccalc.com/
image_1dbd495vp71gtl71svg1m1h1l4n81.png-81.6kB
再次验证几组,结果都是一样的,也就是说,这个算法就是CRC16 Kermit,然后就是要碰撞这个crc值了,算法大概就分析到这里了,剩下的事情就是爆破了。。吧?先写一段程序生成全部可能的输入,由于java操作字符串比较习惯,我用java

public class xxtea {

  public final static int[] KEY = new int[]{//加密解密所用的KEY
          0xE0C7E0C7, 0xC6F1D3D7,
          0xC6D3C6D3, 0xC4D0D2CE
 };
     /* Encrypt data with key.
     *
     * @param data
     * @param key
     * @return
     */
     public static byte[] encrypt(byte[] data, byte[] key) {
         if (data.length == 0) {
             return data;
         }
             return toByteArray(
                     encrypt(toIntArray(data, false),
                             toIntArray(key, false)), false);
     } /**
     * Decrypt data with key.
     *
     * @param data
     * @param key
     * @return
     */ public static byte[] decrypt(byte[] data, byte[] key) {
         if (data.length == 0) {
             return data;
         }
         return toByteArray( decrypt(toIntArray(data, false),
                 toIntArray(key, false)), false); } /**
     * Encrypt data with key.
     *
     * @param v
     * @param k
     * @return
     *
     *
     */ public static int[] encrypt(int[] v, int[] k) {
         int n = v.length;
         int y;
         int p;
         int rounds = 6 + 52/n;
         int sum = 0;
         int z = v[n-1];
         int delta = 0x9E3779B9;
         do {
             sum += delta; int e = (sum >>> 2) & 3;
             for (p=0; p<n-1; p++) {
                 y = v[p+1];
                 z = v[p] += (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
             }
                 y = v[0]; z = v[n-1] += (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z); }
                 while (--rounds > 0);
         return v;
     } /**
     * Decrypt data with key.
     *
     * @param v
     * @param k
     * @return
     */ public static int[] decrypt(int[] v, int[] k) {
         int n = v.length;
         int z = v[n - 1],
                 y = v[0],
                 delta = 0x9E3779B9, sum, e;
         int p; int rounds = 6 + 52/n;
         sum = rounds*delta;
        y = v[0];
        do {
            e = (sum >>> 2) & 3;
        for (p=n-1; p>0; p--) {
            z = v[p-1]; y = v[p] -= (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
        }
        z = v[n-1]; y = v[0] -= (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
        }
        while ((sum -= delta) != 0);
        return v;
     } /**
     * Convert byte array to int array.
     *
     * @param data
     * @param includeLength
     * @return
     */ private static int[] toIntArray(byte[] data, boolean includeLength) {
         int n = (((data.length & 3) == 0) ? (data.length >>> 2) : ((data.length >>> 2) + 1));
         int[] result; if (includeLength) {
             result = new int[n + 1];
             result[n] = data.length;
         }
         else {
             result = new int[n];
         } n = data.length; for (int i = 0; i < n; i++) {
             result[i >>> 2] |= (0x000000ff & data[i]) << ((i & 3) << 3);
         }
         return result;
     } /**
     * Convert int array to byte array.
     *
     *
     * @param data
     * @param includeLength
     * @return
     */ private static byte[] toByteArray(int[] data, boolean includeLength) {
         int n = data.length << 2; ;
         if (includeLength) {
             int m = data[data.length - 1];
             if (m > n) {
                 return null; } else {
                 n = m; }
         }
                 byte[] result = new byte[n];
         for (int i = 0; i < n; i++) {
             result[i] = (byte) ((data[i >>> 2] >>> ((i & 3) << 3)) & 0xff); }
             return result; }


    public static void main(String[] args) {
        int[] v=new int[2];
        for(int i=33;i<126;i++){
            v[1]=0x02213678;
            v[0]=0x70797e55;
            String  s=Integer.toHexString(i);
            String a="02"+s+"3678";
            //System.out.println(a);
            int valueTen2 = Integer.parseInt(a,16);
            //System.out.println(valueTen2);
            v[1]=valueTen2;
            //System.out.println(v[1]);
            //System.out.println(m+" "+n);
            encrypt(v,KEY);
            String s1=String.format("%08x", v[0]);
            String s2=String.format("%08x", v[1]);//此时是全部可能的字符串
            String xiao1=s1.substring(0,2);
            String xiao2=s1.substring(2,4);
            String xiao3=s1.substring(4,6);
            String xiao4=s1.substring(6,8);
            String final1=xiao4+xiao3+xiao2+xiao1;
            String da1=s2.substring(0,2);
            String da2=s2.substring(2,4);
            String da3=s2.substring(4,6);
            String da4=s2.substring(6,8);
            String final2=da4+da3+da2+da1;
            System.out.println(final1+final2);
        }
    }
}

代码十分丑。。完全就是瞎写的,
image_1dbd9t1aq8i0h64bd411r2ionaf.png-31.5kB
全部字符串,保存至txt中使用subprocess爆破即可,结果第一个就输出了bingo,后面爆破md5的部分就不用多说了,这题当时没看到bingo这个提示。。。然后考虑到7位碰撞空间太大了,不大现实,就去复习了,赛后听他们说有bingo。。就重看了下这题。
image_1dbda2bg0s6im1raj419pt1n2cce.png-26.1kB