buu练题记录9-[2019红帽杯]xx

0x00 查壳

image-20210425191240165

无壳,发现是64位程序,用IDA64打开

ox01 IDA分析

搜索字符串,发现了可疑字符串,从you win开始分析

image-20210425191608716

找到关键函数:

__int64 __fastcall sub_1400011A0(__int64 a1, __int64 a2)
{
  unsigned __int64 v2; // rbx
  signed __int64 v3; // rax
  __int128 *v4; // rax
  __int64 v5; // r11
  __int128 *v6; // r14
  int v7; // edi
  __int128 *v8; // rsi
  char v9; // r10
  int v10; // edx
  __int64 v11; // r8
  unsigned __int64 v12; // rcx
  signed __int64 v13; // rcx
  unsigned __int64 v14; // rax
  unsigned __int64 i; // rax
  _BYTE *v16; // rax
  size_t v17; // rsi
  _BYTE *v18; // rbx
  _BYTE *v19; // r9
  signed int v20; // er11
  char *v21; // r8
  signed __int64 v22; // rcx
  char v23; // al
  signed __int64 v24; // r9
  signed __int64 v25; // rdx
  _QWORD *v26; // rax
  size_t Size; // [rsp+20h] [rbp-48h]
  __int128 v29; // [rsp+28h] [rbp-40h]
  int v30; // [rsp+38h] [rbp-30h]
  int v31; // [rsp+3Ch] [rbp-2Ch]
  int code[4]; // [rsp+40h] [rbp-28h]
  int v33; // [rsp+50h] [rbp-18h]

  *code = 0i64;
  v33 = 0;
  sub_1400018C0(std::cin, a2, code);            //和v5取值的code不是同一code,重命名即可看到
  v2 = -1i64;
  v3 = -1i64;
  do
    ++v3;
  while ( *(code + v3) );
  if ( v3 != 19 )                               // length == 19
  {
    sub_140001620(std::cout, "error\n");
    _exit(code);
  }
  v4 = sub_140001E5C(5ui64);
  v5 = *&Code;                                  // qwertyuiopasdfghjklzxcvbnm1234567890
  v6 = v4;
  v7 = 0;
  v8 = v4;
  do
  {
    v9 = *(v8 + code - v4);
    v10 = 0;
    *v8 = v9;
    v11 = 0i64;
    v12 = -1i64;
    do
      ++v12;
    while ( *(v5 + v12) );                      // v12 = len(Code) = 36
    if ( v12 )
    {
      do
      {
        if ( v9 == *(v5 + v11) )
          break;                                // 判断输入字符是否在Code字符集中
        ++v10;
        ++v11;
      }
      while ( v10 < v12 );
    }
    v13 = -1i64;
    do
      ++v13;
    while ( *(v5 + v13) );                      // v13 = len(Code) = 36
    if ( v10 == v13 )
      _exit(v5);
    v8 = (v8 + 1);
  }
  while ( v8 - v4 < 4 );
  *(v4 + 4) = 0;                                // v4保存前4个字符   flag?
  do
    ++v2;
  while ( *(code + v2) );                       // v2 = len(input)
  v14 = 0i64;
  v29 = *v6;
  while ( *(&v29 + v14) )
  {
    if ( !*(&v29 + v14 + 1) )
    {
      ++v14;
      break;
    }
    if ( !*(&v29 + v14 + 2) )
    {
      v14 += 2i64;
      break;
    }
    if ( !*(&v29 + v14 + 3) )
    {
      v14 += 3i64;
      break;
    }
    v14 += 4i64;
    if ( v14 >= 0x10 )
      break;
  }
  for ( i = v14 + 1; i < 16; ++i )
    *(&v29 + i) = 0;                            // 将key拓展为16位
  v16 = sub_140001AB0(code, v2, &v29, &Size);   // xxtea加密
  v17 = Size;
  v18 = v16;
  v19 = sub_140001E5C(Size);
  v20 = 1;
  *v19 = v18[2];                                // box替换
  v21 = v19 + 1;
  v19[1] = *v18;
  v19[2] = v18[3];
  v19[3] = v18[1];
  v19[4] = v18[6];
  v19[5] = v18[4];
  v19[6] = v18[7];
  v19[7] = v18[5];
  v19[8] = v18[10];
  v19[9] = v18[8];
  v19[10] = v18[11];
  v19[11] = v18[9];
  v19[12] = v18[14];
  v19[13] = v18[12];
  v19[14] = v18[15];
  v19[15] = v18[13];
  v19[16] = v18[18];
  v19[17] = v18[16];
  v19[18] = v18[19];
  v19[19] = v18[17];
  v19[20] = v18[22];
  v19[21] = v18[20];
  v19[22] = v18[23];
  for ( v19[23] = v18[21]; v20 < v17; ++v21 )   // v20 = 1,v21 = &v19[1]
  {
    v22 = 0i64;
    if ( v20 / 3 > 0 )
    {
      v23 = *v21;
      do
      {
        v23 ^= v19[v22++];                      // 循环异或
        *v21 = v23;
      }
      while ( v22 < v20 / 3 );                  // 三个一组
    }
    ++v20;
  }
  *&v29 = 0xC0953A7C6B40BCCEi64;
  v24 = v19 - &v29;
  *(&v29 + 1) = 0x3502F79120209BEFi64;
  v25 = 0i64;
  v30 = 0xC8021823;
  v31 = 0xFA5656E7;
  do
  {
    if ( *(&v29 + v25) != *(&v29 + v25 + v24) ) // &29+v24=v19
      _exit(v7 * v7);
    ++v7;
    ++v25;
  }
  while ( v25 < 24 );
  v26 = sub_140001620(std::cout, "You win!");
  std::basic_ostream<char,std::char_traits<char>>::operator<<(v26, sub_1400017F0);
  return 0i64;
}

所以获取算法核心:

  1. 获取输入input,判断输入是否为19位;
  2. 检验输入的各个字符是否在字符集“qwertyuiopasdfghjklzxcvbnm1234567890”内;
  3. 将input的前四位保存在v4中,然后拓展为16位(用 ‘\0’ 填充)作为key;
  4. 用key对input进行xxtea加密,保存在v18中;
  5. 对v18进行乱序(box替换),保存在v19中;
  6. 对v19进行分组、循环异或;
  7. 与明文对比。

所以我们就可以从明文出发,所以在上面的核心中看到,只有4,5,6步是对数据进行了加密,所以也就只有三步而已。

这里的明文是小端存储的,所以应该逆序过来(hex数据格式,两个表示一位)

0x02 exp

exp1

v29 = "FA5656E7C80218233502F79120209BEFC0953A7C6B40BCCE"
crypt = []
for i in range(len(v29)-1,-1,-2):
    crypt.append(int(v29[i-1]+v29[i],16))
    #小端存储是逆序,先倒叙,因为是hex,两个一组。

print(crypt)
for i in crypt:
    print(str(hex(i).upper())[2:],end='')
print('')#输出逆序后的v29

for i in range(len(crypt)-1,-1,-1):
    d = int(i / 3)
    if d > 0:
        for j in range(d-1,-1,-1):
            crypt[i] ^= crypt[j]
    #逆分组循环异或

for i in crypt:
    print(str(hex(i))[2:],end='')
print('')#输出逆异或后的结果

box = [2,0,3,1,6,4,7,5,10,8,11,9,14,12,15,13,18,16,19,17,22,20,23,21]
res = [0]*24
for i in range(24):
    res[box[i]] = crypt[i]
    #box替换,得到xxtea加密后的结果
res1 = ''
for i in res:
    res1 += str(hex(i))[2:].zfill(2)
    #字符处理,将res里的数转为hex再转str用切片方式删去'0x',用zfill()方法将一位的数前面补0
print(res1)
image-20210425193846839

这里运行之后可以得到xxtea加密后的数据,只需要解码(“bca5ce40f4b2b2e7a9129d12ae10c85b3dd7061ddc70f8dc”)就好。

这里的解码就出现问题了……py是含有xxtea库的,但是用的时候……会报错我是用了错误的key……

exp2

没有办法只好找找其他的不用库的实现办法

dec = 'bca5ce40f4b2b2e7a9129d12ae10c85b3dd7061ddc70f8dc'
dec1 = ''

for i in range(0,len(dec),2):
    dec1 += chr(int(dec[i]+dec[i+1],16))
    #将hex转为字符

import struct
 
_DELTA = 0x9E3779B9  
 
def _long2str(v, w):  
    n = (len(v) - 1) << 2  
    if w:  
        m = v[-1]  
        if (m < n - 3) or (m > n): return ''  
        n = m  
    s = struct.pack('<%iL' % len(v), *v)  
    return s[0:n] if w else s  
 
def _str2long(s, w):  
    n = len(s)  
    m = (4 - (n & 3) & 3) + n  
    s = s.ljust(m, "\0")  
    v = list(struct.unpack('<%iL' % (m >> 2), s))  
    if w: v.append(n)  
    return v  
 
def encrypt(str, key):  
    if str == '': return str  
    v = _str2long(str, True)  
    k = _str2long(key.ljust(16, "\0"), False)  
    n = len(v) - 1  
    z = v[n]  
    y = v[0]  
    sum = 0  
    q = 6 + 52 // (n + 1)  
    while q > 0:  
        sum = (sum + _DELTA) & 0xffffffff  
        e = sum >> 2 & 3  
        for p in xrange(n):  
            y = v[p + 1]  
            v[p] = (v[p] + ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z))) & 0xffffffff  
            z = v[p]  
        y = v[0]  
        v[n] = (v[n] + ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[n & 3 ^ e] ^ z))) & 0xffffffff  
        z = v[n]  
        q -= 1  
    return _long2str(v, False)  
 
def decrypt(str, key):  
    if str == '': return str  
    v = _str2long(str, False)  
    k = _str2long(key.ljust(16, "\0"), False)  
    n = len(v) - 1  
    z = v[n]  
    y = v[0]  
    q = 6 + 52 // (n + 1)  
    sum = (q * _DELTA) & 0xffffffff  
    while (sum != 0):  
        e = sum >> 2 & 3  
        for p in xrange(n, 0, -1):  
            z = v[p - 1]  
            v[p] = (v[p] - ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z))) & 0xffffffff  
            y = v[p]  
        z = v[n]  
        v[0] = (v[0] - ((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4) ^ (sum ^ y) + (k[0 & 3 ^ e] ^ z))) & 0xffffffff  
        y = v[0]  
        sum = (sum - _DELTA) & 0xffffffff  
    return _long2str(v, True)  
 
key = 'flag'
dec2 = decrypt(dec1, key)
print (len(dec2))
print (dec2)

这里的第二个脚本需要在py2的环境下跑。然后得到了flag:

image-20210425195450671

0x03 求解

拿到flag之后,我就试着用xxtea的库来加密之后和字符串dec对比,结果发现真的不一样。但是为什么出现这种问题?不应该啊

image-20210425200029666

这个结果和dec里的值完全不一致,甚至连字符串长度都不一样。希望有大佬可以解惑 。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值