Loading

2022 美团MTCTF Re wp

小A一个
pwn爷爷带到第一名了

small

看汇编即可

通过

mov rax 1

call syscall

来实现exit等各种系统调用

loc_10068:                              ; CODE XREF: LOAD:0000000000010062↑j
LOAD:0000000000010068                 add     ebx, 67452301h  ; Add
LOAD:000000000001006E                 shl     ecx, 4          ; Shift Logical Left
LOAD:0000000000010071                 inc     ecx             ; Increment by 1
LOAD:0000000000010073                 shr     eax, 5          ; Shift Logical Right
LOAD:0000000000010076                 add     eax, 23h ; '#'  ; Add
LOAD:0000000000010079                 xor     ecx, eax        ; Logical Exclusive OR
LOAD:000000000001007B                 mov     eax, edi
LOAD:000000000001007D                 add     eax, ebx        ; Add
LOAD:000000000001007F                 xor     ecx, eax        ; Logical Exclusive OR
LOAD:0000000000010081                 add     ebp, ecx        ; Add
LOAD:0000000000010083                 mov     ecx, ebp
LOAD:0000000000010085                 shr     ecx, 5          ; Shift Logical Right
LOAD:0000000000010088                 add     ecx, 67h ; 'g'  ; Add
LOAD:000000000001008B                 mov     eax, ebp
LOAD:000000000001008D                 shl     eax, 4          ; Shift Logical Left
LOAD:0000000000010090                 add     eax, 45h ; 'E'  ; Add
LOAD:0000000000010093                 xor     ecx, eax        ; Logical Exclusive OR
LOAD:0000000000010095                 mov     eax, ebp
LOAD:0000000000010097                 add     eax, ebx        ; Add
LOAD:0000000000010099                 xor     ecx, eax        ; Logical Exclusive OR
LOAD:000000000001009B                 add     edi, ecx        ; Add
LOAD:000000000001009D                 inc     edx             ; Increment by 1
LOAD:000000000001009F                 cmp     edx, 35         ; Compare Two Operands
LOAD:00000000000100A2                 jl      short loc_10052 ; Jump if Less (SF!=OF)
LOAD:00000000000100A4                 mov     [rsi-8], ebp
LOAD:00000000000100A7                 mov     [rsi-4], edi
LOAD:00000000000100AA                 mov     ecx, [rsp+10h]
LOAD:00000000000100AE                 add     ecx, 20h ; ' '  ; Add
LOAD:00000000000100B1                 cmp     esi, ecx        ; Compare Two Operands
LOAD:00000000000100B3                 jl      loc_1000B       ; Jump if Less (SF!=OF)
LOAD:00000000000100B9                 xchg    rax, rsi        ; Exchange Register/Memory with Register
LOAD:00000000000100BB                 mov     esi, 20h ; ' '
LOAD:00000000000100C0
LOAD:00000000000100C0 loc_100C0:                              ; CODE XREF: LOAD:00000000000100D3↓j
LOAD:00000000000100C0                 mov     cl, [rax]
LOAD:00000000000100C2                 cmp     byte ptr dword_100F7[esi], cl ; Compare Two Operands
LOAD:00000000000100C9                 jnz     short exit_     ; Jump if Not Zero (ZF=0)
LOAD:00000000000100CB                 dec     esi             ; Decrement by 1
LOAD:00000000000100CD                 dec     rax             ; Decrement by 1
LOAD:00000000000100D0                 cmp     esi, 0          ; Compare Two Operands
LOAD:00000000000100D3                 jnz     short loc_100C0 ; Jump if Not Zero (ZF=0)
LOAD:00000000000100D5                 mov     edi, 1
LOAD:00000000000100DA                 mov     esi, 100F3h
LOAD:00000000000100DF                 mov     eax, 1
LOAD:00000000000100E4                 mov     dx, 4
LOAD:00000000000100E8                 syscall                 ; LINUX -
LOAD:00000000000100EA
LOAD:00000000000100EA exit_:                                  ; CODE XREF: LOAD:000000000001002C↑j
LOAD:00000000000100EA                                         ; LOAD:00000000000100C9↑j
LOAD:00000000000100EA                 mov     eax, 60
LOAD:00000000000100EF                 mov     edi, esi
LOAD:00000000000100F1                 syscall                 ; LINUX -

tea实现

魔改了轮数 35

delta 0x67452301

改改tea脚本即可

#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
void Decrypt(unsigned long *v, unsigned long *k)
{
    unsigned long n = 35, sum, v0 = v[0], v1 = v[1];
    /*初始化*/
    unsigned long delta = 0x67452301; /* 密钥调度常数*/
    sum = delta*n;
    /*即0xC6EF3720 */
    while (n-- > 0)
    {
        /*基本循环开始*/
        v1 -= ((v0 << 4) + k[2]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]);
        v0 -= ((v1 << 4) + k[0]) ^ (v1 + sum) ^ ((v1 >> 5) + k[1]);
        sum -= delta;
    }
    /*循环结束*/
    v[0] = v0;
    v[1] = v1;
}
int main()
{
   unsigned long v[9]={0x0DE087143,0x0C4F91BD2,0x0DAF6DADC,0x6D9ED54C,0x75EB4EE7,0x5D1DDC04,0x511B0FD9,0x51DC88FB,0};
   unsigned long k[4]={1,0x23,0x45,0x67};
   Decrypt(v,k);
   Decrypt(v+2,k);
   Decrypt(v+4,k);
   Decrypt(v+6,k);

   puts((char*)v);

}

static

评价是想多了

用原版aes 和 原版xxtea

main 除了检测flag格式以外的逻辑基本都是假的

下断点发现断不下来就能发现这些逻辑都跑不到

findcrypt 查到aes表

向上x找到

sub_4064F0 函数 为主要加密逻辑

再向上x可以找到check逻辑

在0000000405267 的cmp check

image-20220917210352687

在 loc_4051F6 赋值enc

enc即为 dword_14640D0

动调

构建flag{00000000000000000000000000000000}

发现是分成两个16byte加密的

前半段为sub4062b0 负责加密

是aes查表法的实现

根据aes原理 第一次异或的16bytes就是密钥key( 记得改端序 卡了我好几个小时)

EB9E779E809831361C2764A239BA3A0B改端序为

0B3ABA39A264271C363198809E779EEB

cyberchef 使用ecb/nopadding

然后hextostr即可

image-20220917210406832

得到前半段flag

2e64949cd16c4449

接着分析sub_4064F0 后面的函数

在sub_12531C8等函数中看到字符串"/root/code/unicorn/qemu/util/cacheinfo.c"

有unicorn字样

想起上次某ctf的模拟执行有很多个架构)

就一个长数组byte_19762C0 很明显是asm

dump到010 再拖入ida 选择arm little 64

直接c f5

unsigned __int8 *__fastcall sub_0(unsigned __int8 *result)
{
  int *v0; // x9
  int v2; // w8
  int *v3; // x9
  int v4; // w8
  int j; // [xsp+0h] [xbp-50h]
  int v6; // [xsp+8h] [xbp-48h]
  unsigned int i; // [xsp+Ch] [xbp-44h]
  unsigned int sum; // [xsp+10h] [xbp-40h]
  unsigned int v9; // [xsp+14h] [xbp-3Ch]
  unsigned int v1; // [xsp+18h] [xbp-38h]
  int k[4]; // [xsp+1Ch] [xbp-34h]
  int v12; // [xsp+2Ch] [xbp-24h]
  _DWORD *v13; // [xsp+30h] [xbp-20h]
  char v14[16]; // [xsp+38h] [xbp-18h] BYREF
  unsigned __int8 *v15; // [xsp+48h] [xbp-8h]

  v15 = result;
  v14[0] = *result ^ result[5] ^ (32 * result[2]) ^ (2 * result[9]) ^ (2 * result[10]);
  v14[1] = result[1] ^ (result[13] >> 2) ^ (result[12] >> 2) ^ result[15] ^ (result[4] >> 6);
  v14[2] = result[2] ^ (result[1] << 7) ^ (result[15] >> 6) ^ (8 * result[14]) ^ (result[4] >> 1);
  v14[3] = result[3] ^ (2 * result[10]) ^ (result[14] >> 4) ^ (result[6] >> 4) ^ (32 * result[13]);
  v14[4] = result[4] ^ (4 * result[3]) ^ result[10] ^ (2 * *result) ^ (result[1] >> 2);
  v14[5] = result[5] ^ (result[1] >> 3) ^ (result[13] << 7) ^ (result[2] >> 7) ^ (4 * result[8]);
  v14[6] = result[6] ^ (result[8] >> 7) ^ (4 * result[5]) ^ (16 * result[3]) ^ (result[14] >> 3);
  v14[7] = result[7] ^ (result[11] >> 6) ^ (result[2] >> 5) ^ (result[3] << 6) ^ (2 * result[1]);
  v14[8] = result[8] ^ (result[11] << 7) ^ (result[5] >> 6) ^ (2 * result[4]) ^ (16 * result[6]);
  v14[9] = result[9] ^ (8 * result[15]) ^ (result[4] >> 3) ^ (32 * result[12]) ^ result[2];
  v14[10] = result[10] ^ (*result >> 2) ^ (2 * result[9]) ^ (result[5] << 7) ^ (result[11] >> 7);
  v14[11] = result[11] ^ result[5] ^ (result[10] >> 4) ^ (result[6] >> 6) ^ (result[3] >> 6);
  v14[12] = result[12] ^ (result[4] << 6) ^ (result[2] >> 1) ^ (result[15] >> 1) ^ (result[11] << 7);
  v14[13] = result[13] ^ (result[6] >> 3) ^ (result[9] >> 7) ^ (32 * result[1]) ^ (result[11] >> 7);
  v14[14] = result[14] ^ (result[7] << 7) ^ (16 * result[9]) ^ (result[8] >> 1) ^ (16 * result[2]);
  v14[15] = result[15] ^ (*result >> 1) ^ (result[13] >> 6) ^ (4 * result[7]) ^ (result[11] >> 5);
  v13 = v14;
  v12 = 4;
  k[0] = 12;
  k[1] = 34;
  k[2] = 56;
  k[3] = 78;
  v6 = 19;
  sum = 0;
  v9 = *&v14[12];
  do
  {
    sum -= 0x21524111;
    for ( i = 0; i < v12 - 1; ++i )
    {
      v1 = v13[i + 1];
      v0 = &v13[i];
      v2 = *v0 + ((((4 * v1) ^ (v9 >> 5)) + ((16 * v9) ^ (v1 >> 3))) ^ ((sum ^ v1) + (k[(i ^ (sum >> 2)) & 3] ^ v9)));
      *v0 = v2;
      v9 = v2;
    }
    v3 = &v13[v12 - 1];
    v4 = *v3
       + ((((4 * *v13) ^ (v9 >> 5)) + ((16 * v9) ^ (*v13 >> 3))) ^ ((sum ^ *v13) + (k[(i ^ (sum >> 2)) & 3] ^ v9)));
    *v3 = v4;
    v9 = v4;
    --v6;
  }
  while ( v6 );
  for ( j = 0; j < 16; ++j )
    v15[j] = v14[j];
  return result;
}

分析发现是xxtea 用xxtea脚本解密即可

#include <stdint.h>
#include <stdio.h>
using namespace std;
#define DELTA -0x21524111
#define MX (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z)))

void xxtea(uint32_t *v, int n, uint32_t *key)
{
    uint32_t y, z;
    int sum;
    unsigned p, rounds, e;
    // encrypt
    if (n > 1)
    {
        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);
    }
    // decrypt
    else if (n < -1)
    {
        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);
    }
}
int main()
{
    uint32_t v[5] = {0xFB732728, 0x4D26D4BB, 0xDA122E3A, 0x26BAFC68};
    uint32_t k[4] = {12, 34, 56, 78};
    xxtea(v, -4, k);
    for (int i = 0; i < 4; i++)
    {
        printf("%x ", v[i]);
    }
}

得到9a1b0035 8d92ebb1 7de7f82 a497d0b4 转端序

再用z3解前面的混淆即可

import re

from z3 import *

result = [BitVec(f"result[{i}]", 8) for i in range(16)]
v14 = [0] * 16
v14[0] = result[0] ^ result[5] ^ (32 * result[2]) ^ (2 * result[9]) ^ (2 * result[10])
v14[1] = result[1] ^ (result[13] >> 2) ^ (result[12] >> 2) ^ result[15] ^ (result[4] >> 6)
v14[2] = result[2] ^ (result[1] << 7) ^ (result[15] >> 6) ^ (8 * result[14]) ^ (result[4] >> 1)
v14[3] = result[3] ^ (2 * result[10]) ^ (result[14] >> 4) ^ (result[6] >> 4) ^ (32 * result[13])
v14[4] = result[4] ^ (4 * result[3]) ^ result[10] ^ (2 * result[0]) ^ (result[1] >> 2)
v14[5] = result[5] ^ (result[1] >> 3) ^ (result[13] << 7) ^ (result[2] >> 7) ^ (4 * result[8])
v14[6] = result[6] ^ (result[8] >> 7) ^ (4 * result[5]) ^ (16 * result[3]) ^ (result[14] >> 3)
v14[7] = result[7] ^ (result[11] >> 6) ^ (result[2] >> 5) ^ (result[3] << 6) ^ (2 * result[1])
v14[8] = result[8] ^ (result[11] << 7) ^ (result[5] >> 6) ^ (2 * result[4]) ^ (16 * result[6])
v14[9] = result[9] ^ (8 * result[15]) ^ (result[4] >> 3) ^ (32 * result[12]) ^ result[2]
v14[10] = result[10] ^ (result[0] >> 2) ^ (2 * result[9]) ^ (result[5] << 7) ^ (result[11] >> 7)
v14[11] = result[11] ^ result[5] ^ (result[10] >> 4) ^ (result[6] >> 6) ^ (result[3] >> 6)
v14[12] = result[12] ^ (result[4] << 6) ^ (result[2] >> 1) ^ (result[15] >> 1) ^ (result[11] << 7)
v14[13] = result[13] ^ (result[6] >> 3) ^ (result[9] >> 7) ^ (32 * result[1]) ^ (result[11] >> 7)
v14[14] = result[14] ^ (result[7] << 7) ^ (16 * result[9]) ^ (result[8] >> 1) ^ (16 * result[2])
v14[15] = result[15] ^ (result[0] >> 1) ^ (result[13] >> 6) ^ (4 * result[7]) ^ (result[11] >> 5)
t = "35001b9ab1eb928d827fde07b4d097a4"
t = re.findall(".{2}", t)
for index in range(len(t)):
    t[index] = int(t[index], 16)
s = Solver()
for index in range(16):
    s.add(v14[index] == t[index])
print(s.check())
f = s.model()
print(f)

result[5] = 97
result[14] = 54
result[1] = 55
result[2] = 51
result[10] = 52
result[8] = 99
result[4] = 48
result[0] = 56
result[15] = 55
result[11] = 101
result[7] = 99
result[13] = 54
result[3] = 50
result[9] = 50
result[6] = 48
result[12] = 54
for x in result:
    print(chr(x),end="")

得到后半段flag

87320a0cc24e6667

拼起来改为uuid格式即可

flag{2e64949c-d16c-4449-8732-0a0cc24e6667}

posted @ 2022-09-18 12:25  FW_ltlly  阅读(256)  评论(0编辑  收藏  举报