• CDUT第一届信安大挑战Re-wp


    题目名称:EASYMAZE

    出题人:Gyan

    IDA不好用了?因为这是C#

    扔进dnspy

    进入check函数发现这是一个迷宫

    从C经过*走到X,0为下,1为上,2为右,3为左

    路径:2220000000221220221221133333311222211220022112220030020002

    提交dino{2220000000221220221221133333311222211220022112220030020002}发现不对?

    继续审计代码,找到两个关键的地方

    第一个地方是将数据转换成十六进制,第二个地方是将这个十六进制的数据拆成前两位和后两位,即 'a' =>0xa =>1010 => array2 = {10,10},所以我们应该一次"走两步“

    即22 =>1010 =>a,以此类推

    //最后部分我是手算的,附上DorinXL师傅的脚本
    #include<iostream>
    #include<cstring>
    using namespace std;
    int main(){
    	char s[] = "2220000000221220221221133333311222211220022112220030020002"; 
    	int a,b;
    	char flag[50];
    	for(int i = 0;i < 29;i++){
    		for(int j = 0;j < 128;j++){
    			a = j >> 2;
    			b = j & 3;
    			if((a == (s[i * 2] - '0')) && (b == (s[i * 2 + 1] - '0'))){
    				if(j >= 0 && j <= 9){
    					flag[i] = '0' + j;
    				}
    				else if(j >= 10 && j <= 16){
    					flag[i] = 'a' + j -10;
    				}
    				break;
    			}
    		}
    	}
    	for(int i = 0;i < 29;i++){
    		cout<<flag[i];
    	}
    }
    

    题目名称:嘘!

    出题人:Gyan

    双击后打不开????直接扔进IDA

    发现一大堆看不懂的东西!!!

    往旁边函数里一看,发现一个创建窗口的函数WinMain

    点击即得flag

    题目名称:捉迷藏

    出题人:DorinXL

    查壳!出这个题的师傅本来没加壳的,我(Nameless)手贱加了:)

    直接upx -d 脱壳 (记得用高版本的upx,不然可能失败)手脱可无视

    脱完壳后扔进ida,shift+F12一把梭

    在几个有字符串的地方找到数据,然后直接按R

    如:

    找到其他几段后,拼接出来就行

    题目名称:base64

    出题人:DorinXL

    ida64打开,发现是base64编码加密

    看左边函数,会发现ohMyGod函数,进去看后,发现更换了base64的表(这里如果不懂,要去看base64的原理)

    写出新表的脚本

    key = "Y2R1KgtDM195M3VIN25vK19FYXaCX2OGMWCsJT99"
    table = list('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/')
    for i in range(25):
        tmp = table[i]
        table[i] = table[39 -i]
        table[39-i] = tmp
    
    m = ''.join(table)
    print(m)
    

    得到新表后,用base64的脚本or工具直接解出

    题目名称:BabyAndroid

    出题人:Nameless

    直接扔进JEB

    进去后发现看不懂,直接decompile

    稍微代码审计一下发现就是一个简单的异或

    上脚本

    li = [18, 36, 8, 67, 36, 3, 64, 61, 28, 2, 1, 13, 4, 36, 68, 48, 5, 26, 60, 100, 84, 15]
    st = list("tHi$_Is_CKrRect_aNsTer")
    flag = list("flag{J3b_Is_aG0odTO01}")
    s = ''
    for i in range(22):
        s += chr(ord(st[i]) ^ li[i])
    print(s)
    

    题目名称:方程组?

    出题人:Nameless

    解线性方程组

    直接上脚本

    import z3
    v1 = z3.Int('v1')
    v2 = z3.Int('v2')
    v3 = z3.Int('v3')
    v4 = z3.Int('v4')
    v5 = z3.Int('v5')
    v6 = z3.Int('v6')
    v7 = z3.Int('v7')
    v8 = z3.Int('v8')
    v9 = z3.Int('v9')
    v10 = z3.Int('v10')
    v11 = z3.Int('v11')
    v12 = z3.Int('v12')
    v13 = z3.Int('v13')
    v14 = z3.Int('v14')
    v15 = z3.Int('v15')
    v16 = z3.Int('v16')
    v17 = z3.Int('v17')
    v18 = z3.Int('v18')
    v19 = z3.Int('v19')
    v20 = z3.Int('v20')
    v21 = z3.Int('v21')
    v22 = z3.Int('v22')
    v23 = z3.Int('v23')
    v24 = z3.Int('v24')
    
    a = [ 0x295b,0x1050,0x1c7a,0x11f,0xe4c,0x1827,0x31a4,0x11bb,0xb2b,0x116a,0x10a6,0xb81,0x1012,0x1514,0x10c4,0x1089,0x1d2,0x119b,0x7af,0x874,0x13e7,0x177b,0xbe9,0x2068]
    s = z3.Solver()
    s.add(a[0]== 32 * v1 - 6 * v2 + 44 * v3 - 56 * v4 + 77 * v5)
    s.add(a[1]== 22 * v1 - 5 * v2 + 7 * v3 - 22 * v4 + 33 * v5)
    s.add(a[2]== 41 * v1 - 3 * v2 + 21 * v3 - 39 * v4 + 44 * v5)
    s.add(a[3]== 13 * v1 - 20 * v2 + 31 * v3 - 41 * v4 + 19 * v5)
    s.add(a[4]== 22 * v1 - 19 * v2 + 29 * v3 - 2 * v4 + 7 * v5)
    s.add(a[5]== 24 * v6 + 12 * v7 + 37 * v8 - 11 * v9 + 12 * v10)
    s.add(a[6]== 79 * v6 + 76 * v7 + 23 * v8 - 15 * v9 + 20 * v10)
    s.add(a[7]== 35*v6 + 30*v7 + 16 * v8 - 28*v9+ 21*v10)
    s.add(a[8]== 19 * v6 + 29 * v7 + 11 * v8 - 23 * v9 + 17 * v10)
    s.add(a[9]== 24 * v6 + 33 * v7 + 18 * v8 - 19 * v9 + 13 * v10)
    s.add(a[10] ==32 * v11 - 6 * v12 + 44 * v13 - 56 * v14 + 77 * v15)
    s.add(a[11] == 46 * v11 - 78 * v12 + 99 * v13 - 67 * v14 + 87 * v15)
    s.add(a[12] == 75 * v11 - 7 * v12 + 18 * v13 - 66 * v14 + 54 * v15)
    s.add(a[13] == 25 * v11 - 64 * v12 + 85 * v13 - 31 * v14 + 97 * v15)
    s.add(a[14] == 31 * v11 - 56 * v12 + 35 * v13 - 13 * v14 + 99 * v15)
    s.add(a[15] == 57 * v16 - 25 * v17 + 32 * v18 - 33 * v19 + 71 * v20 - 69 * v21 + 75 * v22)
    s.add(a[16] == 67 * v16 - 7 * v17 + 33 * v18 - 35 * v19 + 31 * v20 - 97 * v21 + 99 * v22)
    s.add(a[17] == 77 * v16 - 11 * v17 + 54 * v18 - 47 * v19 + 47 * v20 - 71 * v21 + 83 * v22)
    s.add(a[18] == 27 * v16 - 12 * v17 + 34 * v18 - 39 * v19 + 97 * v20 - 99 * v21 + 93 * v22)
    s.add(a[19] == 15 * v16 - 32 * v17 + 19 * v18 - 19 * v19 + 95 * v20 - 69 * v21 + 57 * v22)
    s.add(a[20] == 33 * v16 - 61 * v17 + 72 * v18 - 13 * v19 + 93 * v20 - 79 * v21 + 87 * v22)
    s.add(a[21] == 55 * v16 - 26 * v17 + 57 * v18 - 21 * v19 + 22 * v20 - 33 * v21 + 79 * v22)
    s.add(a[22] == 24 * v23 + 5 * v24 )
    s.add(a[23] == 71 * v23 + 9 * v24)
    if s.check():
        print(s.model())
    # [v13 = 95,
    #  v5 = 123,
    #  v16 = 95,
    #  v24 = 125,
    #  v12 = 101,
    #  v14 = 116,
    #  v21 = 114,
    #  v2 = 108,
    #  v10 = 48,
    #  v18 = 51,
    #  v20 = 101,
    #  v3 = 97,
    #  v15 = 48,
    #  v6 = 87,
    #  v23 = 101,
    #  v19 = 118,
    #  v7 = 51,
    #  v4 = 103,
    #  v8 = 108,
    #  v22 = 51,
    #  v17 = 82,
    #  v11 = 109,
    #  v1 = 102,
    #  v9 = 99]
    a = [102,108,97,103,123,87,51,108,99,48,109,101,95,116,48,95,82,51,118,101,114,51,101,125]
    flag = ""
    for i in a :
        flag += chr(i)
        print(flag)
    

    题目名称:Crypto

    出题人:Nameless

    两种解法

    打开IDA,会发现key = "CDUTCTF" ,从函数名可以分析出采用的是rc4加密

    解法1.已知密钥为CDUTCTF,直接用rc4进行计算即可

    #include<stdio.h>
    #include<string.h>
    typedef unsigned longULONG; 
    void rc4_init(unsigned char*s, unsigned char*key, unsigned long Len)
    {
        int i = 0, j = 0;
        char k[256] = { 0 };
        unsigned char tmp = 0;
        for (i = 0; i<256; i++)
        {
            s[i] = i;
            k[i] = key[i%Len];
        }
        for (i = 0; i<256; i++)
        {
            j = (j + s[i] + k[i]) % 256;
            tmp = s[i];
            s[i] = s[j];
            s[j] = tmp;
        }
    }
    
    void rc4_crypt(unsigned char*s, unsigned char*Data, unsigned long Len)
    {
        int i = 0, j = 0, t = 0;
        unsigned long k = 0;
        unsigned char tmp;
        for (k = 0; k<Len; k++)
        {
            i = (i + 1) % 256;
            j = (j + s[i]) % 256;
            tmp = s[i];
            s[i] = s[j];
            s[j] = tmp;
            t = (s[i] + s[j]) % 256;
            Data[k] ^= s[t];
        }
    }
     
    int main()
    {
        unsigned char s[256] = { 0 }, s2[256] = { 0 };//S-box
        char key[256] = { "CDUTCTF" };
        char pData[512] = {0x24,0x18,0x74,0x78,0x26,0x8e,0xed,0xd6,0xea,0x38,0x73,0xed,0xed,0xe4,0x85,0xb4,0x18,0x4e,0x0e,0x01};
        unsigned long len = strlen(pData);
        int i;
        rc4_init(s, (unsigned char*)key, strlen(key));
        for (i = 0; i<256; i++)
        {
            s2[i] = s[i];
        }
        rc4_crypt(s2, (unsigned char*)pData, len);
        printf("pData=%s", pData);
        return 0;
    }
    

    解法2.gdb调试

    • 在rc4_crypt处下断点
    • 向下单步调试(注意堆栈和寄存器的信息)
    • 得到flag

    题目名称:DinoTree

    出题人:DorinXL

    丢进f5,代码审计发现两个关键地方,查看qwq和qaq数组

    可以看到两个字符串,那么进行反解,要注意看for循环的长度

    qwq = "noiFusL\Wf;zmu"
    qaq = "ihs@}oRY5}ernD   "
    s =""
    # print(len(qwq))
    # print(len(qaq))
    for i in range(5,len(qwq)):
        s += chr(ord(qwq[i])^8)
    print(s)
    
    f =""
    for i in range(len(qwq)-5):
        f += chr(ord(qaq[i])^6)
    print(f)
    
    #qwq = {DT_n3re}
    #qaq = onuF{iT_3
    

    解出后,根据字符串的提示,以及题目的提示,知道这是树的中序和后序遍历

    那么需要求出前序遍历

    中序:noiFu{DT_n3re}

    后序:onuF{iT_3}ernD

    求解前序的过程是手写的,这里不再提出

    前序:Dino{Fun_Tr3e}

    即为flag

    题目名称:PaperTiger!!!

    出题人:Nameless

    扔进IDA,发现找不到main函数,shift+f12查看字符串,找到关键字符串,双击跟进

    鼠标放在这里,按ctrl+X查看交叉引用,即查看哪里用到了这个字符串

    发现F5不好使了,提示sp指针有问题。根据参考资料,调整最后面的堆栈指针

    此时便可F5成功,审计代码知,就是简单的xor而已

    写脚本计算出来即可

    key = [0x0, 0x1, 0x2, 0x3, 0x5, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c]
    s2 = "fmcd~qn6=VKT|l~jbE#tqgIE)^roa"
    flag =""
    for i in range(len(key)):
        flag += chr(ord(s2[i])^key[i])
    
    print(flag)
    

    所以如题,真的是个纸老虎:)

    题目名称:你不会真的要用CE吧

    出题人:Gyan

    IDA打开,根据提示,关闭ASLR(如图)

    然后打开od,搜索字符串

    去IDA,按G,随便选上面的一个地址跳转,即可来到主函数

    找到关键代码部分

    查看这句话的地址

    在od中,按ctrl+g跳转到该地址,并按f2下断点,然后f9运行程序

    可以发现程序停在了断点处,修改旁边的标志位,使得跳转不成立

    然后再按一下f9,运行程序,点击确定,发现flag已经出来了

    题目名称:fork bomb bomb bomb!!!

    着手静态

    1. 载入IDA 来到主函数进行分析
    2. F5查看伪代码
    3. 找到回车前的输出字符串
      1. 熟悉C语言就能看出,这里向/tmp目录里面输出了一个文件(.virus)
      2. 补充linux里的/tmp目录特点:任何人都可以进行读写,有些linux发行版会在关机后清空/tmp目录。关于linux的使用请参考相关书籍如:鸟哥的linux私房菜
      3. 利用system()函数执行了/tmp里的文件,由于linux的mask,/tmp/.virus这个shell脚本是没有执行权限的,所以使用bash调用
      4. /tmp/.virus脚本的内容是一个很经典的fork炸弹,百度就能查到
    4. 这个程序的恶意代码和关键代码的耦合性不高,所以咱们能有好几种方法绕过恶意代码,接下来我们尝试使用静态patch和动态调试绕过恶意代码拿到flag,静态逆向写逆向脚本这里不做讨论
    dwhile ( 2 )                                   // 这个无线循环的结束条件是下面的goto
      {
        system("nohup bash /tmp/.virus &");         // 执行注入的sfork炸弹
        for ( j = 0; j <= (signed int)rand(); ++j )
        {
          for ( k = 0; k <= (signed int)rand(); ++k )
          {
            v13 = (__int64 *)malloc(8LL);
            *v13 = (signed int)rand() % 93 + 33;
            v4 = *v13;
            printf((unsigned __int64)"%c");
          }
        }                                           // 这个for是分配大量的内存和输出随机字符
        if ( v13 )                                  // 这个if判断最后一次的分配空间是否成功
                                                    // 成功则开始解密
        {
          v5 = (unsigned int)*(char *)(v12 + v11);  // 这里是正式解密代码
          switch ( *(char *)(v12 + v11) )           // switch的值在0-4
          {
            case 0:
              patch1(&v23, v4, v5);                 // 每次patch调用的形参位置都不一样
              goto LABEL_22;                        // 猜测每个case只执行一次。这样的话,就可以精简下代码
            case 1:
              patch5(&v21, v4, v5);					
              goto LABEL_22;                        // 这里的patch函数可以尝试进入函数体分析
                                                    // 如果直接patch恶意代码就不做演示
            case 2:
              patch9(&v19, v4, v5);
              goto LABEL_22;
            case 3:
              patch13(&v17, v4, v5);
              goto LABEL_22;
            case 4:
              patch17(&v15, v4, v5);
    LABEL_22:
              ++v11;                                // v11从0开始自加
              continue;
            default:                                // v11超过4之后就goto跳出了循环
              goto LABEL_23;
          }
        }
        break;
      }
    LABEL_23:
      v6 = j_strlen_ifunc(&v23);
      v14 = malloc(5 * (v6 - 1));
      if ( !v14 )
      {
        printf((unsigned __int64)&unk_488424);
        puts("what a pity!
    ");
        exit(0xFFFFFFFFLL);
      }
      j_strcat_ifunc(v14, &v23);                    // strcat函数,可以看出拼接的字符串正好是case里面的内容
      j_strcat_ifunc(v14, &v21);
      j_strcat_ifunc(v14, &v19);
      j_strcat_ifunc(v14, &v17);
      j_strcat_ifunc(v14, &v15);
      putchar('
    ');
      putchar('
    ');                                // 吃掉无意间输入的字符
      puts(v14);                                    // v14用strcat了5次
      result = getchar();
      if ( __readfsqword(0x28u) == v25 )
        result = 0;
      return result;	
    

    静态patch

    把73行到84行全部patch掉

    选中87行头,tab键回到流程图,空格看汇编

    记下地址:0x402681

    再f5回到伪代码

    选中73行的system位置,按tab回到流程图,再按空格回到汇编代码

    为了保证平衡,我们在call system上面一条汇编指令lea处

    点ida菜单栏的edit-->patchprogram-->assamble

    键入jmp 0x402681,只改这一条,下面的不用管,canel取消

    点ida菜单栏的edit-->patchprogram-->aplly

    把patch好的程序拖进linux

    加上执行权限chmod +x ez_virus

    执行./ez_virus

    gdb动态调试

    还是刚才看到的那个地址,

    gdb ez_virus

    因为跳了5次,所以我们可能需要更改5次eip(64位叫rip)

    在gdb里面b *0x4025c1设断点

    r运行

    运行到这里的时候,我么需要控制程序流程跳过恶意代码

    在ida里面找到

    由于这里是jz,所以可能不一定会进入正常代码(这里对应的是if(v13)这个变量在恶意代码中是否分配成功)

    所以我们尝试进入下一句汇编(就当他没有跳转,按照程序逻辑,cmp的结果为0(即v13分配成功)则跳转,我们需要cmp的结果不为0,所以,这句需要不执行),则按照汇编流程,下一句的地址是0x402681

    设置eip

    set $eip=0x402681

    这样就跳过了第一次恶意代码

    按c继续程序,程序会再次断在刚才设置的断点

    重复设置eip

    set $eip=0x402681

    再按c继续程序

    重复5次,得到flag

  • 相关阅读:
    B. Vova and Trophies 字符串预处理+思维+贪心
    Got error 28 from storage engine
    TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    mysql复制问题
    upgrade mysql
    replica set remove member
    Perl安装及环境配置
    Django
    mongo collection name—SyntaxError: identifier starts immediately after numeric literal
    MySQL 单表flashback
  • 原文地址:https://www.cnblogs.com/DorinXL/p/13977904.html
Copyright © 2020-2023  润新知