• BUUOJ 第三弹


    1.findit

    工具:JADX,在线凯撒密码转换

    拖入JADX,定位到MainActivity类

    跳过安卓支持函数,定位到onCreate函数,部分代码如下。

    观察到有两个字符串,写个脚本跑一下,得到ThisIsTheFlagHome和pvkq{m164675262033l4m49lnp7p9mnk28k75}

    当key为10时解得:flag{c164675262033b4c49bdf7f9cda28a75},验证

    2.reverse_3

    工具:DIE,IDA32

    走流程

    拖入IDA32中,跟进到_main_0,定位到关键代码。

    就是对输入数据进行操作后加上本身所在的位置,再和Str2做对比。

    那么我们反着推,先把原本的Dest解出来:

    list = "e3nifIH9b_C@n@dH"
    for i in range(len(list)):
        print (chr(ord(list[i]) - i), end ='')
    # list = e2lfbDB2ZV95b3V9
    

    然后跟进sub_4110BE,看到了类似base编码的位移代码。

    查个字符串,是标准的base64码表。交叉引用后,发现刚好是上面的aAbcdefghijklmn变量,找个在线网址解一下e2lfbDB2ZV95b3V9,得到{i_l0ve_you},提交验证。

    3.CrackRTF

    工具:DIE,IDA32,ResourceHacker/7-zip

    走流程

    拖入IDA32中,跟进到main_0,定位到部分关键代码。

    这里主要是对输入的转换和判断,必须要6个字符,且因为有atoi函数和必须大于100000,所以输入的必须全部是数字,接着就是接上@DBApp这个字符串并送入sub_40100A进行加密处理,再与"6E32D0943418C2C33385BC35A1470250DD8923A9"进行对比

    跟进加密函数sub_40100A,看到关键的加密函数CryptCreateHash,查询标识符0x8004u在ALG_ID中对应的是SHA1加密。

    根据上述信息,可以写出爆破脚本,要注意大小写。

    import hashlib
    part2 = "@DBApp"
    for part1 in range(100000,999999):
        pasd = str(part1) + part2
        tmp = hashlib.sha1(pasd.encode("utf-8"))
        if tmp.hexdigest().upper() == "6E32D0943418C2C33385BC35A1470250DD8923A9":
            print (str(part1))
            break
    

    得到123321,验证一下

    继续分析下列代码,同样的和第一个密码的处理非常类似,但是只知道是输入6个字符,没有任何提示,估计无法爆破。接着就是将处理后的第一个密码和第二个密码拼接,送入sub_401019进行加密处理后

    跟进加密函数sub_401019,和上面的sub_40100A非常像

    就是改了个标识符,查询后得知0x8003对应的是MD5加密。但是网上的md5解密查询都没有结果。所以暂且跳过。

    注意到函数sub_401019下面有个sub_40100F,而且是对未加密的string进行处理,跟进。

    百度一番,发现是从程序自身的AAA文件夹中读取101文件数据并送入sub_401005与string进行处理。

    一开始不知道文件怎么获取,但是我瞎猫碰见死耗子,右键打开压缩包,成功的得到101这个文件。取出得到数据。

    后来百度到了一款查看程序资源文件的工具ResourceHacker。

    跟进sub_401005。

    根据sub_40100F中的代码sub_401005(lpString, (int)lpBuffer, nNumberOfBytesToWrite)可知,a2是101文件的起始位置,a3是文件字节数大小,则此函数的作用就是将string与文件以18个字符(用户两次输入共12个,程序本身加了6个)为一组进行循环异或。

    而且,string与101文件异或后写入的是rtf文件。要想得到正常的rtf,那么标识头也要是rtf文件的标识头,即:7B 5C 72 74 66 31 7D

    又因为第二个密码是6个字符,所以只要用前6个rtf的16进制的头部数据和前6个101文件的16进制的头部数据,即7B 5C 72 74 66 3105 7D 41 15 26 01异或即可得到第二个密码。

    脚本如下:

    rtf = [0x7B,0x5C,0x72,0x74,0x66,0x31]
    fil = [0x05,0x7D,0x41,0x15,0x26,0x01]
    flag = ""
    for i in range(0,6):
        flag += chr(rtf[i]^fil[i])
    print (flag)
    

    得到~!3a@0。

    运行程序,依次输入密码,即可得到带有flag的RTF文件:Flag{N0_M0re_Free_Bugs},记得要将Flag改成flag。

    验证:

    4.[GXYCTF2019]luck_guy

    工具:DIE,IDA64

    走流程

    拖入IDA64,进入主函数main

    获取用户输入V4,并传入patch_me函数,跟进。

    判断了一下用户输入是否为偶数,继续跟进get_flag函数。

    得到关键代码:

    for ( i = 0; i <= 4; ++i )
      {
        switch ( rand() % 200 )
        {
          case 1:
            puts("OK, it's flag:");
            memset(&s, 0, 0x28uLL);
            strcat((char *)&s, f1); // f1 = "GXY{do_not_"
            strcat((char *)&s, &f2);
            printf("%s", &s);
            break;
          case 2:
            printf("Solar not like you");
            break;
          case 3:
            printf("Solar want a girlfriend");
            break;
          case 4:
            v6 = 0;
            s = 0x7F666F6067756369LL;
            strcat(&f2, (const char *)&s);
            break;
          case 5:
            for ( j = 0; j <= 7; ++j )
            {
              if ( j % 2 == 1 )
                v1 = *(&f2 + j) - 2;
              else
                v1 = *(&f2 + j) - 1;
              *(&f2 + j) = v1;
            }
            break;
          default:
            puts("emmm,you can't find flag 23333");
            break;
        }
      }
    

    也就case 1 4 5 是有用的。而且只执行4次,根据观察,1为最后,4为最开始,5有可能一次或者两次。

    脚本如下:

    f1 = "GXY{do_not_"
    f2 = [0x7F, 0x66, 0x6F, 0x60, 0x67, 0x75, 0x63, 0x69]
    for i in range(0,2):
        tmp = ""
        for i in range(len(f2)):
            if i%2 == 1:
                f2[i] = f2[i] - 2
            else:
                f2[i] = f2[i] - 1
            tmp += chr(f2[i])
        print (f1 + tmp)
    #GXY{do_not_~dn^fsbg
    #GXY{do_not_}bmeqae    
    

    但是,得到的两个flag均不是答案。

    转入汇编,发现程序是把s倒过来复制到f2的

    后来了解到是大端序和小端序的问题,且前面对s的声明为qword ptr(8字节的指针地址),说明它是小端序,要倒过来。

    所以改写脚本:

    f1 = "GXY{do_not_"
    f2 = [0x7F, 0x66, 0x6F, 0x60, 0x67, 0x75, 0x63, 0x69][::-1]
    for i in range(0,2):
        tmp = ""
        for i in range(len(f2)):
            if i%2 == 1:
                f2[i] = f2[i] - 2
            else:
                f2[i] = f2[i] - 1
            tmp += chr(f2[i])
        print (f1 + tmp)
    

    当只走一次即 4->5->1 时得到flag:GXY{do_not_hate_me}

    用flag{}替换后提交验证

  • 相关阅读:
    关于Django 报错 ImportError: cannot import name RegexUrlResolver解决
    Git版本控制
    java Labmda表达式
    java注解&反射
    maven
    数据库
    为什么java中子类重写父类的方法时声明抛出异常不能比父类范围大
    【Linux】Linux基本命令
    阿里云服务器linux环境搭建SSM项目(一)--Linux环境配置jdk和Tomcat.md
    阿里云服务器linux环境搭建SSM项目(二)--linux环境配置mysql5.7.md
  • 原文地址:https://www.cnblogs.com/b1ank/p/13475674.html
Copyright © 2020-2023  润新知