• NCTF2021逆向WP(部分)


    NCTF2021逆向部分writeup

    签到题

    一键F5直接获得flag:NCTF{We1come_2_Reverse_Engineering}

    Shadowbringer

    C++逆向,反编译后乍一看头皮发麻:

    int __cdecl main(int argc, const char **argv, const char **envp)
    {
      char v4[16]; // [rsp+20h] [rbp-60h] BYREF
      char v5[15]; // [rsp+30h] [rbp-50h] BYREF
      char v6; // [rsp+3Fh] [rbp-41h] BYREF
      char v7[16]; // [rsp+40h] [rbp-40h] BYREF
      char v8[16]; // [rsp+50h] [rbp-30h] BYREF
      char v9[16]; // [rsp+60h] [rbp-20h] BYREF
      char v10[32]; // [rsp+70h] [rbp-10h] BYREF
    
      _main();
      youknowwhat();
      std::string::string((std::string *)v5);
      ((void (__fastcall *)(char *))std::allocator<char>::allocator)(&v6);
      std::string::string(v4, "U>F2UsQXN`5sXMELT=:7M_2<X]^1ThaWF0=KM?9IUhAsTM5:T==_Ns&<Vhb!", &v6);
      ((void (__fastcall *)(char *))std::allocator<char>::~allocator)(&v6);
      std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Welcome.Please input your flag:\n");
      std::operator>><char>(refptr__ZSt3cin, v5);
      std::string::string((std::string *)v8, (const std::string *)v5);
      Emet(v7, v8);
      ((void (__fastcall *)(char *, char *))std::string::operator=)(v5, v7);
      std::string::~string((std::string *)v7);
      std::string::~string((std::string *)v8);
      std::string::string((std::string *)v10, (const std::string *)v5);
      Selch(v9, v10);
      ((void (__fastcall *)(char *, char *))std::string::operator=)(v5, v9);
      std::string::~string((std::string *)v9);
      std::string::~string((std::string *)v10);
      if ( (unsigned __int8)std::operator==<char>(v5, v4) )
        std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Right.");
      else
        std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Wrong.");
      std::string::~string((std::string *)v4);
      std::string::~string((std::string *)v5);
      return 0;
    }
    

    其实大部分都是库函数,关键函数只有:Emet(v7, v8);Selch(v9, v10);
    进入Emet函数

    std::string *__fastcall Emet(std::string *a1, std::string *a2)
    {
      int i; // ebx
      char *v3; // rax
      unsigned __int64 v4; // rax
      int j; // ebx
      unsigned int v6; // eax
      char *v7; // rax
      unsigned __int64 v9; // [rsp+20h] [rbp-90h] BYREF
      char v10; // [rsp+2Eh] [rbp-82h] BYREF
      char v11; // [rsp+2Fh] [rbp-81h] BYREF
      char v12[16]; // [rsp+30h] [rbp-80h] BYREF
      char v13[16]; // [rsp+40h] [rbp-70h] BYREF
      char v14[16]; // [rsp+50h] [rbp-60h] BYREF
      char v15[16]; // [rsp+60h] [rbp-50h] BYREF
      char v16[16]; // [rsp+70h] [rbp-40h] BYREF
      char v17[16]; // [rsp+80h] [rbp-30h] BYREF
      char v18[16]; // [rsp+90h] [rbp-20h] BYREF
      char v19[16]; // [rsp+A0h] [rbp-10h] BYREF
    
      std::allocator<char>::allocator(&v10);
      std::string::string(&v9, &unk_48A000, &v10);
      std::allocator<char>::~allocator(&v10);
      std::allocator<char>::allocator(&v11);
      std::string::string(a1, &unk_48A000, &v11);
      std::allocator<char>::~allocator(&v11);
      for ( i = 0; i < (unsigned __int64)std::string::size(a2); ++i )
      {
        v3 = (char *)std::string::operator[](a2, i);
        std::bitset<8ull>::bitset(v14, (unsigned int)*v3);
        std::bitset<8ull>::to_string(v13, v14);
        std::operator+<char>(v12, &v9, v13);
        std::string::operator=(&v9, v12);
        std::string::~string((std::string *)v12);
        std::string::~string((std::string *)v13);
      }
      while ( 1 )
      {
        v4 = std::string::size((std::string *)&v9);
        if ( v4 == 6 * (v4 / 6) )
          break;
        std::operator+<char>(v15, &v9, 48i64);
        std::string::operator=(&v9, v15);
        std::string::~string((std::string *)v15);
      }
      for ( j = 0; j < (unsigned __int64)std::string::size((std::string *)&v9); j += 6 )
      {
        std::string::substr((std::string *)v18, (unsigned __int64)&v9, j);
        std::bitset<6ull>::bitset<char,std::char_traits<char>,std::allocator<char>>(v17, v18, 0i64);
        v6 = std::bitset<6ull>::to_ulong(v17);
        v7 = (char *)std::string::operator[](&hisoralce, v6);
        std::operator+<char>(v16, a1, (unsigned int)*v7);
        std::string::operator=(a1, v16);
        std::string::~string((std::string *)v16);
        std::string::~string((std::string *)v18);
      }
      while ( (std::string::size(a1) & 3) != 0 )
      {
        std::operator+<char>(v19, a1, 33i64);
        std::string::operator=(a1, v19);
        std::string::~string((std::string *)v19);
      }
      std::string::~string((std::string *)&v9);
      return a1;
    }
    

    发现可以数组hisoralce,但是进入以后

    发现是问号,考虑用动态调试,在Emet后面下断点:

    查看该数组后转化成字符串得到一个base64索引表:

    #$%&'()*+,-.s0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[h]^_`ab
    

    用相同的方法进入Selch函数得到另一个base64索引表:

    ba`_^]h[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210s.-,+*)('&%$#
    

    正好相反,于是开心地打开base64decode脚本开始跑,然后就错辣!

    发现问题

    考虑明文

    U>F2UsQXN`5sXMELT=:7M_2<X]^1ThaWF0=KM?9IUhAsTM5:T==_Ns&<Vhb!
    

    和索引表

    #$%&'()*+,-.s0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[h]^_`ab
    ba`_^]h[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210s.-,+*)('&%$#
    

    我们发现=也在这个索引表里,由于base64算法是在末尾补=,因此按照b64解密脚本直接跑肯是错的,正确的方法应该是建立换表到原表的映射再通过b64解密。
    于是得到exp:

    import base64
    
    flag = "U>F2UsQXN`5sXMELT=:7M_2<X]^1ThaWF0=KM?9IUhAsTM5:T==_Ns&<Vhb!"
    std_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    my_table = '#$%&\x27()*+,-.s0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[h]^_`ab'
    my_table2 = 'ba`_^]h[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210s.-,+*)(\x27&%$#'
    
    flag = flag.translate(str.maketrans(my_table2, std_table))
    print(flag) #NkcwNzRKUCtzKVdWOlorVDwmKFExOGBLcylXVjpZNGhzOVtoOllDUz8mMGA!
    flag = flag.replace("!", '=').encode()
    print(flag) #b'NkcwNzRKUCtzKVdWOlorVDwmKFExOGBLcylXVjpZNGhzOVtoOllDUz8mMGA='
    flag = base64.b64decode(flag).decode()
    print(flag) #6G074JP+s)WV:Z+T<&(Q18`Ks)WV:Y4hs9[h:YCS?&0`
    flag = flag.translate(str.maketrans(my_table, std_table))
    print(base64.b64decode(flag)) #NCTF{H0m3_r1d1n9_h0m3_dy1n9_h0p3}
    
    

    得到flag:NCTF{H0m3_r1d1n9_h0m3_dy1n9_h0p3}

  • 相关阅读:
    windows下安装redis
    十五oracle 触发器
    Flask 学习 六 大型程序结构
    Flask 学习 五 电子邮件
    Flask 学习 四 数据库
    Flask学习 三 web表单
    Flask学习 二 模板
    Flask学习 一 基本结构
    Python操作Redis
    Python操作MySQL
  • 原文地址:https://www.cnblogs.com/THRANDUil/p/15740728.html
Copyright © 2020-2023  润新知