CTFShow愚人杯RE

发布时间 2023-04-07 00:32:07作者: Tree_24

easy_pyc

很简单的py逆向题,用uncompyle6反编译出源码如下

# uncompyle6 version 3.9.0
# Python bytecode version base 2.7 (62211)
# Decompiled from: Python 3.9.11 (tags/v3.9.11:2de452f, Mar 16 2022, 14:33:45) [MSC v.1929 64 bit (AMD64)]
# Embedded file name: enpyc.py
# Compiled at: 2023-03-29 18:30:23
print 'Welcome to CTFshow Re!'
print 'your flag is here!'
flag = ''
l = len(flag)
for i in range(l):
    num = ((flag[i] + i) % 114514 + 114514) % 114514
    code += chr(num)

code = map(ord, code)
for i in range(l - 4 + 1):
    code[i] = code[i] ^ code[i + 1]

print code
code = ['\x16', '\x1d', '\x1e', '\x1a', '\x18', '\t', b'\xff', b'\xd0', ',', '\x03', 
 '\x02', '\x14', '8', 'm', '\x01', 'C', 'D', b'\xbd', b'\xf7', '*', '\r', 
 b'\xda', b'\xf9', '\x1c', '&', '5', "'", b'\xda', b'\xd4', b'\xd1', '\x0b', 
 b'\xc7', b'\xc7', '\x1a', b'\x90', 'D', b'\xa1']

flag逐位加上其位置模114514然后与后一位异或得code,code已知。该说不说,模数真臭
需要注意的是有几位不用异或

exp

code = ['0x16', '0x1d', '0x1e', '0x1a', '0x18', '0x09', '0xff', '0xd0', '0x2c', '0x03', 
 '0x02', '0x14', '0x38', '0x6d', '0x01', '0x43', '0x44', '0xbd', '0xf7', '0x2a', '0x0d', 
  '0xda', '0xf9', '0x1c', '0x26', '0x35', '0x27', '0xda', '0xd4', '0xd1', '0x0b', 
  '0xc7', '0xc7', '0x1a', '0x90', '0x44', '0xa1']

code_int = [int(x, 16) for x in code]
print(code_int)

for i in range(len(code_int)-4,0,-1):
    code_int[i] ^= code_int[i+1]
code_int[0] ^= code_int[1]
print(code_int)
flag=''
for i in range(len(code_int)):
    code_int[i] = (code_int[i] - i) % 114514
    flag += chr(code_int[i])
print (flag)

flagctfshow{Just_F00l's_D@y_R3_Ch3ck-in!}

easy_cc

一开始想复杂了
查壳是32位无壳,直接 IDA 查看主函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // esi
  FILE *v4; // eax
  size_t v5; // eax
  unsigned int v6; // ecx
  unsigned int v7; // kr00_4
  unsigned int v8; // kr04_4
  unsigned int v9; // esi
  unsigned int v10; // kr08_4
  char *v11; // ebx
  unsigned int v12; // esi
  int v13; // eax
  int v15; // [esp-4h] [ebp-20Ch]
  char v16[204]; // [esp+0h] [ebp-208h] BYREF
  char v17[204]; // [esp+CCh] [ebp-13Ch] BYREF
  char Buffer[100]; // [esp+198h] [ebp-70h] BYREF
  char v19[8]; // [esp+1FCh] [ebp-Ch] BYREF

  strcpy(v19, "key123");
  sub_401010("请输入您的flag: ", v16[0]);
  v4 = _acrt_iob_func(0);
  fgets(Buffer, 100, v4);
  v5 = strcspn(Buffer, "\n");
  if ( v5 >= 0x64 )
    goto LABEL_16;
  v15 = v3;
  Buffer[v5] = 0;
  v6 = 0;
  v7 = strlen(Buffer);
  if ( v7 )
  {
    v8 = strlen(v19);
    do
    {
      v17[v6] = Buffer[v6] ^ v19[v6 % v8];
      ++v6;
    }
    while ( v6 < v7 );
    if ( v6 >= 0xC9 )
      goto LABEL_16;
  }
  v17[v6] = 0;
  v9 = 0;
  v10 = strlen(v17);
  if ( v10 )
  {
    v11 = v16;
    do
    {
      sub_401040(v11, "%02x", v17[v9++]);
      v11 += 2;
    }
    while ( v9 < v10 );
  }
  v12 = 2 * v9;
  if ( v12 >= 0xC9 )
  {
LABEL_16:
    __report_rangecheckfailure(v15);
    __debugbreak();
  }
  v16[v12] = 0;
  sub_401010("\n", v15);
  v13 = strcmp(v16, "08111f425a5c1c1e1a526d410e3a1e5e5d573402165e561216");
  if ( v13 )
    v13 = v13 < 0 ? -1 : 1;
  if ( v13 )
    sub_401010("flag is false: ", v16[0]);
  else
    sub_401010("flag is true: ", v16[0]);
  system("pause");
  return 0;
}

大致加密逻辑就是flag逐位异或v19,v19就是异或值为key123
然后把异或的结果转换成16进制,最终得到08111f425a5c1c1e1a526d410e3a1e5e5d573402165e561216

exp

hexstring = '08111f425a5c1c1e1a526d410e3a1e5e5d573402165e561216'
hexlist = [int (hexstring[i:i+2], 16) for i in range (0,len(hexstring), 2)]
key = 'key123'
flag = ''
for i in range(len(hexlist)):
    flag += chr(hexlist[i] ^ ord(key[i % len(key)]))
print(flag)

flagctfshow{cc_re_good_good!}

easy_re

32位无壳,拖进IDA看看

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // ebx
  int v4; // ecx
  unsigned int v5; // edi
  unsigned int v6; // kr00_4
  int v8; // [esp-4h] [ebp-414h]
  int v9; // [esp+10h] [ebp-400h]
  int v10; // [esp+18h] [ebp-3F8h] BYREF
  int v11; // [esp+1Ch] [ebp-3F4h] BYREF
  char v12[1004]; // [esp+20h] [ebp-3F0h] BYREF

  sub_401460();
  sub_401700(v12);
  sub_401460();
  std::istream::operator>>(std::cin, &v10);
  std::istream::operator>>(std::cin, &v11);
  v3 = v10 % 299;
  v4 = v11 % 299;
  v5 = 0;
  v9 = v11 % 299;
  v6 = strlen(v12);
  if ( v6 )
  {
    do
    {
      v8 = dword_403AA0[300 * v3 + v4] ^ v12[v5];
      v3 = (v8 + v3) % 299;
      v9 = (v8 + v9) % 300;
      std::ostream::operator<<(std::cout, v8);
      sub_401460();
      v4 = v9;
      ++v5;
    }
    while ( v5 < v6 );
  }
  sub_401460();
  return 0;
}

只看得出来是个300*300的一个数组
记住403AA0地址是从28A0到5A6E3
尝试用x32dbg看看
img
也就是说用两个300以内数字去加密一段话
可以得到后面一大串的数字,尝试直接枚举出这两个key
利用flag的base64值是'ZmxhZ'来判断

from base64 import *
from pwn import u32 

def decrypt(k1,k2,cipher):
    tk1,tk2 = k1,k2
    m = []
    for v8 in cipher[::-1]:
        k1 = (k1-v8)%299
        k2 = (k2-v8)%300
        m.append(d_3aa0[300*k1+k2] ^ v8)
    base64_text = bytes(m[::-1])
    if base64_text[:5]==b'ZmxhZ':
        flag=b64decode(base64_text).decode('utf-8')
        print(base64_text,tk1,tk2,'\n',flag)

flag='' 
data = open('re1.exe', 'rb').read()[0x28a0: 0x5a6e0]
d_3aa0 = [u32(data[i:i+4]) for i in range(0, len(data), 4)]
a = [90,171,198,235,229,43,246,92,198,203,233,228,6,128,215,68,201,4,220,214,169,245,208,199,112,170,119,251,244,58,237,4,70,231,200,45,186,137,247,225,243,13,145,139,190,146,194,242,253,56,239,5,41,225,105,51,247,79,170,231,88,64,224,138,222,220,229,88,43,117,236,189,228,205,150,65,26,205,232,141,116,149,185,89,212,251,16,215,205,17,238,22,245,77,220,198,224,248,223,209,205,167,223,210,165,247,190,3,5,246,243,228,181,33,42,207,174,138,244,118,192,22,219,60,80,229,144,219,133,211,221,229,190,58,151,240,183,207,221,60,77,217,220,74,105,220,221,165,85,174,43,183,188,190,252,255,130,137,189,201,239,181,150,143,214,203,26,211,103,222,105,87,214,179,83,185,104,206,229,172,221,117,163,57,106,200,46,165,193,135,243,166,168,209,144,52,210,12,58,10,103,5,211,55,172,76,88,250,136,245,167,139,241,26,92,97,139,241,137,27,53,211,251,191,240,173,14,231,241,242,255,122,144,97,234,36,175,155,253,35,156,229,19,166,191,140,195,218,130,35,200,178,245,41,162,243,214,222,87,83,195,144,55,159,208,241,193,233,204,228,196,105,84,58,220,226,1,47,248,138,177,124,236,53,210,79,250,106,27,244,251,203,210,103,213,218,183,4,40,28,12,175,52,224,203,89,176,174,175,233,43,20,103,152,201,4,148,76,241,103,135,139,136,246,80,184,255,194,149,239,206,207,246,166,20,63,202,199,177,214,60,99,74,211,219,94,247,193,40,212,197,175,30,244,41,24,113,27,249,213,225,55,188,193,165,220,174,252,105,154,74,126,174,255,110,169,103,44,246,255,98,251,211,87,171,62,67,250,69,149,18,77,159,137,168,231,187,97,174,115,243,44,128,151,90,246,83,11,138,67,184,22,53,228,230,252,76,112,20,136,131,90,233,248,67,207,61,212,113,62,239,203,201,66,83,179,16,209,253,63,206,208,101,150,196,145,101,220,22,79,241,69,237,219,97,87,20,22,240,244,218,7,237,42,14,8,38,115,141,102,206,191,142,55,196,200,142,98,16,129,53,52,50,197,53,219,2,66,152,192,245,243,69,26,132,240,164,90,246,200,53,89,221,119,139,76,47,132,53,47,249,26,53,141,113,69,76,152,121,193,53,176,97,135,205,206,237,108,251,38,216,108,12,220,209,194,26,243,217,231,36,117,235,106,205,43,254,75,209,141,239,200,5,183,219,166,113,9,16,154,116,144,238,208,245,136,173,16,103,107,114,17,208,181,196,98,212,133,211,252]

for k1 in range(299):
    for k2 in range(300):
        decrypt(k1,k2,a)

运行结果
img
提示研究一下加密矩阵,尝试把d_3aa0中的元素输出来发现很像RGB值,尝试转化成图片。最后输出
img
flagctfshow{d244daeb-7182-4c98-bec6-0c99329ab71f}

exp

from base64 import *
from pwn import u32 

def decrypt(k1,k2, cipher):
    tk1,tk2 = k1,k2
    m = []
    for v8 in cipher[::-1]:
        k1 = (k1-v8)%299
        k2 = (k2-v8)%300
        m.append(d_3aa0[300*k1+k2] ^ v8)
    base64_text = bytes(m[::-1])
    if base64_text[:5]==b'ZmxhZ':
        flag=b64decode(base64_text).decode('utf-8')
        print(base64_text,tk1,tk2,'\n',flag)

flag='' 
data = open('re1.exe', 'rb').read()[0x28a0: 0x5a6e0]
d_3aa0 = [u32(data[i:i+4]) for i in range(0, len(data), 4)]
a = [90,171,198,235,229,43,246,92,198,203,233,228,6,128,215,68,201,4,220,214,169,245,208,199,112,170,119,251,244,58,237,4,70,231,200,45,186,137,247,225,243,13,145,139,190,146,194,242,253,56,239,5,41,225,105,51,247,79,170,231,88,64,224,138,222,220,229,88,43,117,236,189,228,205,150,65,26,205,232,141,116,149,185,89,212,251,16,215,205,17,238,22,245,77,220,198,224,248,223,209,205,167,223,210,165,247,190,3,5,246,243,228,181,33,42,207,174,138,244,118,192,22,219,60,80,229,144,219,133,211,221,229,190,58,151,240,183,207,221,60,77,217,220,74,105,220,221,165,85,174,43,183,188,190,252,255,130,137,189,201,239,181,150,143,214,203,26,211,103,222,105,87,214,179,83,185,104,206,229,172,221,117,163,57,106,200,46,165,193,135,243,166,168,209,144,52,210,12,58,10,103,5,211,55,172,76,88,250,136,245,167,139,241,26,92,97,139,241,137,27,53,211,251,191,240,173,14,231,241,242,255,122,144,97,234,36,175,155,253,35,156,229,19,166,191,140,195,218,130,35,200,178,245,41,162,243,214,222,87,83,195,144,55,159,208,241,193,233,204,228,196,105,84,58,220,226,1,47,248,138,177,124,236,53,210,79,250,106,27,244,251,203,210,103,213,218,183,4,40,28,12,175,52,224,203,89,176,174,175,233,43,20,103,152,201,4,148,76,241,103,135,139,136,246,80,184,255,194,149,239,206,207,246,166,20,63,202,199,177,214,60,99,74,211,219,94,247,193,40,212,197,175,30,244,41,24,113,27,249,213,225,55,188,193,165,220,174,252,105,154,74,126,174,255,110,169,103,44,246,255,98,251,211,87,171,62,67,250,69,149,18,77,159,137,168,231,187,97,174,115,243,44,128,151,90,246,83,11,138,67,184,22,53,228,230,252,76,112,20,136,131,90,233,248,67,207,61,212,113,62,239,203,201,66,83,179,16,209,253,63,206,208,101,150,196,145,101,220,22,79,241,69,237,219,97,87,20,22,240,244,218,7,237,42,14,8,38,115,141,102,206,191,142,55,196,200,142,98,16,129,53,52,50,197,53,219,2,66,152,192,245,243,69,26,132,240,164,90,246,200,53,89,221,119,139,76,47,132,53,47,249,26,53,141,113,69,76,152,121,193,53,176,97,135,205,206,237,108,251,38,216,108,12,220,209,194,26,243,217,231,36,117,235,106,205,43,254,75,209,141,239,200,5,183,219,166,113,9,16,154,116,144,238,208,245,136,173,16,103,107,114,17,208,181,196,98,212,133,211,252]

for k1 in range(299):
    for k2 in range(300):
        decrypt(k1,k2,a)

from PIL import Image

img = Image.new('RGB', (300, 300))
pixels = img.load()

for i in range(299):
    for j in range(300):
        pixels[i, j] = d_3aa0[i * 300 + j]
img = img.transpose(Image.FLIP_LEFT_RIGHT).rotate(90)
img.save('a.png')
img.show()

参考