0xGame 2024 re week2 wp
1438911687251843 发表于 江西 CTF 286浏览 · 2024-10-20 14:03

BabyUPX

upx壳,直接upx -d脱壳

ida反编译:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char Str1[60]; // [rsp+20h] [rbp-40h] BYREF
  int v5; // [rsp+5Ch] [rbp-4h]

  _main(argc, argv, envp);
  v5 = 0;
  puts("input flag here:");
  scanf("%s", Str1);
  v5 = strncmp(Str1, "0xGame", 6ui64);
  if ( !v5 && strlen(Str1) == 44 )
  {
    encode(Str1);
    if ( !strcmp(Str1, &encdata) )
      printf("succeed");
    return 0;
  }
  else
  {
    printf("invalid");
    return 0;
  }
}

有一个加密函数encode,将str1传入得到encode

攻击脚本

a = [0x03, 0x87, 0x74, 0x16, 0xD6, 0x56, 0xB7, 0x63, 0x83, 0x46, 0x66, 0x66, 0x43, 0x53, 0x83, 0xD2, 0x23, 0x93, 0x56, 0x53, 0xD2, 0x43, 0x36, 0x36, 0x03, 0xD2, 0x16, 0x93, 0x36, 0x26, 0xD2, 0x93, 0x73, 0x13, 0x66, 0x56, 0x36, 0x33, 0x33, 0x83, 0x56, 0x23, 0x66, 0xD7]
for i in a:
    print(chr((i<<4)&0xFF | (i>>4)),end='')
# 0xGame{68dff458-29e5-4cc0-a9cb-971fec338e2f}

需要注意加密过程把二进制的高八位和低八位互换,然而低八位左移溢出,需要限制在八位内,所以 &0xFF

FirstSight-Jar

jadx打开

public class EzJar {
    static String Alphabat = "0123456789abcdef";

    private static String encrypt(String str) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            int indexOf = Alphabat.indexOf(str.charAt(i));
            if (indexOf < 0) {
                sb.append(str.charAt(i));
            } else {
                sb.append(Alphabat.charAt(((indexOf * 5) + 3) % 16));
            }
        }
        return sb.toString();
    }

    public static void main(String[] strArr) {
        System.out.println("请以uuid的格式输入你的flag内容:");
        Scanner scanner = new Scanner(System.in);
        String nextLine = scanner.nextLine();
        scanner.close();
        if (encrypt(nextLine).equals("ab50e920-4a97-70d1-b646-cdac5c873376")) {
            System.out.println(String.format("验证成功: 0xGame{%s}", nextLine));
        } else {
            System.out.println("验证失败");
        }
    }
}

定义了一个加密函数encrypt,加密后在主函数验证

遍历str元素在Alphabat的索引,加密置换str,解密时仍然根据索引还原

攻击脚本

import gmpy2

inv = gmpy2.invert(5, 16)
a = 'ab50e920-4a97-70d1-b646-cdac5c873376'
b = '0123456789abcdef'
flag = ''
for i in a:
    index = i.find(b)
    if index:
        flag += i
    else:
        flag += chr(((ord(i) - 3 + 16) * inv) % 16)
print(flag)
# ab50e920-4a97-70d1-b646-cdac5c873376

套上0xGame{}即可

FisrtSight-Pyc

提示要用python3.8环境

uncompyle6反编译得到源码

import hashlib
user_input = input("请输入神秘代号:")
if user_input != "Ciallo~":
    print("代号不是这个哦")
    exit()
input_hash = hashlib.md5(user_input.encode()).hexdigest()
input_hash = list(input_hash)
for i in range(len(input_hash)):
    if ord(input_hash[i]) in range(48, 58):
        original_num = int(input_hash[i])
        new_num = (original_num + 5) % 10
        input_hash[i] = str(new_num)
    input_hash = "".join(input_hash)
    print("0xGame{{{}}}".format(input_hash))

运行一下,输入“神秘代号”Ciallo~

得到结果0xGame{2f5ef5762bf8a2c043d836b522127e54}

然而这个不是flag,猜测反编译结果不准确,在python3.8环境下运行pyc

输入Ciallo~,得到flag

0xGame{2f0ef0217bf3a7c598d381b077672e09}

Xor::Ramdom

c++编写的PE64位程序,无壳

拖入ida反编译

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rax
  char v4; // bl
  bool v5; // si
  bool v6; // bl
  _BYTE *v7; // rdx
  char v8; // al
  int v9; // ebx
  __int64 v10; // rax
  __int64 v11; // rax
  __int64 v13[4]; // [rsp+20h] [rbp-60h] BYREF
  char v14[32]; // [rsp+40h] [rbp-40h] BYREF
  char v15[46]; // [rsp+60h] [rbp-20h] BYREF
  char v16; // [rsp+8Eh] [rbp+Eh] BYREF
  char v17; // [rsp+8Fh] [rbp+Fh] BYREF
  char v18[32]; // [rsp+90h] [rbp+10h] BYREF
  char v19[32]; // [rsp+B0h] [rbp+30h] BYREF
  char v20[39]; // [rsp+D0h] [rbp+50h] BYREF
  char v21; // [rsp+F7h] [rbp+77h]
  int inited; // [rsp+F8h] [rbp+78h]
  int v23; // [rsp+FCh] [rbp+7Ch]

  _main(argc, argv, envp);
  inited = 0;
  v23 = 0;
  v21 = 0;
  std::allocator<char>::allocator(&v16);
  std::string::basic_string(v15, 40i64, 0i64, &v16);
  std::allocator<char>::~allocator(&v16);
  std::allocator<char>::allocator(&v17);
  std::string::basic_string(v14, 32i64, 0i64, &v17);
  std::allocator<char>::~allocator(&v17);
  v13[0] = 0x1221164E1F104F0Ci64;
  v13[1] = 0x171F240A4B10244Bi64;
  v13[2] = 0x1A2C5C2108074F09i64;
  v13[3] = 0x5A5916111F10i64;
  v3 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Input flag here:");
  std::ostream::operator<<(v3, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
  std::operator>><char>(refptr__ZSt3cin, v15);
  v4 = 0;
  v5 = 1;
  if ( std::string::size(v15) == 38 )
  {
    std::string::substr(v18, v15, 0i64, 7i64);
    v4 = 1;
    if ( !std::operator!=<char>(v18, "0xGame{") && *std::string::operator[](v15, 37i64) == '}' )
      v5 = 0;
  }
  if ( v4 )
    std::string::~string(v18);
  if ( v5 )
    exit(0);
  std::string::substr(v19, v15, 7i64, 30i64);
  std::string::operator=(v14, v19);
  std::string::~string(v19);
  inited = init_random();
  std::string::basic_string(v20, v14);
  v6 = check(v20) != 0;
  std::string::~string(v20);
  if ( v6 )
  {
    srand(0x1919810u);
    inited = rand();
  }
  v21 = rand();
  do
  {
    v7 = std::string::operator[](v14, v23);
    if ( (v23 & 1) != 0 )
      v8 = v21;
    else
      v8 = v21 + 3;
    *v7 ^= v8;
    v9 = *std::string::operator[](v14, v23);
    if ( v9 != *std::array<unsigned char,32ull>::operator[](v13, v23) )
    {
      v10 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Wrong.Try again");
      std::ostream::operator<<(v10, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
      exit(0);
    }
    ++v23;
  }
  while ( v23 <= 29 );
  v11 = std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Right!");
  std::ostream::operator<<(v11, refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_);
  std::string::~string(v14);
  std::string::~string(v15);
  return 0;
}

反编译代码看起来有点乱,只需要抓住重点看

这个v21显然是题目提示的随机数,可以爆破随机数,由于随机数种子确定,也可以动调出来
在第67行下一个断点,就可以动调出v21=0x7B

加密部分只有下面这一小部分,v7为数据也就是前面的v13,v23为循环次数

if ( (v23 & 1) != 0 )
  v8 = v21;
else
  v8 = v21 + 3;
*v7 ^= v8;

攻击脚本

rand = 0x7B
a = [0x0C, 0x4F, 0x10, 0x1F, 0x4E, 0x16, 0x21, 0x12, 0x4B, 0x24, 0x10, 0x4B, 0x0A, 0x24, 0x1F, 0x17, 0x09, 0x4F, 0x07, 0x08, 0x21, 0x5C, 0x2C, 0x1A, 0x10, 0x1F, 0x11, 0x16, 0x59, 0x5A]
for i in range(len(a)):
    if i&1:
        print(chr(a[i]^rand),end='')
    else:
        print(chr(a[i]^rand+3),end='')

# r4nd0m_i5_n0t_alw4ys_'Random'!

套上0xGame{}即可

ZzZ

ida反编译进入主函数

__int64 sub_140011AA0()
{
  char *v0; // rdi
  __int64 i; // rcx
  char v3[32]; // [rsp+0h] [rbp-40h] BYREF
  char v4; // [rsp+40h] [rbp+0h] BYREF
  int v5[8]; // [rsp+44h] [rbp+4h] BYREF
  int v6[8]; // [rsp+64h] [rbp+24h] BYREF
  int v7[9]; // [rsp+84h] [rbp+44h] BYREF
  char *Buffer; // [rsp+A8h] [rbp+68h]
  char v9[80]; // [rsp+C8h] [rbp+88h] BYREF
  __int64 v10; // [rsp+118h] [rbp+D8h]
  __int64 v11; // [rsp+138h] [rbp+F8h]
  __int64 v12; // [rsp+158h] [rbp+118h]
  __int64 v13[4]; // [rsp+178h] [rbp+138h] BYREF
  __int64 v14[26]; // [rsp+198h] [rbp+158h] BYREF

  v0 = &v4;
  for ( i = 94i64; i; --i )
  {
    *v0 = -858993460;
    v0 += 4;
  }
  sub_140011393(&unk_140023008);
  sub_1400111A9("Please enter your flag\nTip: The flag format is 'uuid'\n");
  sub_1400110A0("%44s", v9);
  if ( v9[43] != '}' )
    goto LABEL_11;
  sub_14001128F(v9, "0xGame{%8llx-%4s-%4s-%4s-%12llx}", v13, v5, v6, v7, v14);
  v10 = v5[0];
  v11 = v6[0];
  v12 = v7[0];
  if ( v14[0] == 0xD085A85201A4i64 )
  {
    if ( 11 * v11 + 14 * v10 - v12 == 0x48FB41DDDi64
      && 9 * v10 - 3 * v11 + 4 * v12 == 0x2BA692AD7i64
      && ((v12 - v11) >> 1) + (v10 ^ 0x87654321i64) == 0xCDBDFAAC )
    {
      Buffer = "Congratulations! You get the correct flag.";
      if ( v13[0] == 0xE544267Di64 )
      {
        puts(Buffer);
        goto LABEL_12;
      }
    }
LABEL_11:
    sub_1400112BC(v9);
  }
LABEL_12:
  sub_14001132F(v3, &unk_14001AED0);
  return 0i64;
}

中间if夹了一个连续的方程,这里显然要用z3解,然后根据格式化字符串的格式填入%4s,至于两个十六进制部分,代码直接给出了,只需要注意要小写

from z3 import *
v5,v6,v7 = BitVecs('v5 v6 v7', 64)
solve(
    11 * v6 + 14 * v5 - v7 == 0x48FB41DDD,
    9 * v5 - 3 * v6 + 4 * v7 == 0x2BA692AD7,
    ((v7 - v6) >> 1) + (v5 ^ 0x87654321) == 0xCDBDFAAC
)
# [v5 = 842086455, v7 = 1681208161, v6 = 862073908]
from libnum import n2s
v5 = 842086455
v7 = 1681208161
v6 = 862073908
print(n2s(v5)[::-1],n2s(v6)[::-1],n2s(v7)[::-1])
# b'7812' b'44b3' b'a35d'

然后手动连接一下

0xGame{e544267d-7812-44b3-a35d-d085a85201a4}

0 条评论
某人
表情
可输入 255
目录