zoukankan      html  css  js  c++  java
  • IDF 实验室部分题目WriteUp

     

    前天花了一个下午的时间刷了几道IDF实验室的题目, 这个网站实在是有点冷清, 题目也比较少, 所以就被我和师兄们刷榜了2333...

    因为我最先开始做, 所以就干脆刷到第一去了.

    题目很水, 切莫见怪.

    牛刀小试

     http://ctf.idf.cn/index.php?g=game&m=list&a=index&id=16

    莫尔斯密码: 网上有转换器, 转换后去空格全小写就是flag. flag: wctf{morseode}

    ASCII码而已: 这是Unicode码好吧...随便找个语言Print一下即可,  我用的是java, 为什么那么执着于粉丝呢?  flag: wctf{moremore_weibo_fans}

    最简单的题目: F12, 在源码里面搜索, flag: wctf{woldy_s_weibo}

    啥: 把图片用WinHex打开, 找flag: wctf{mianwubiaoqing__}

    被改错的密码: 注意到给出的密文里面出现了一个不合时宜的字母l, 去掉后在cmd5查询得到flag: wctf{idf}

    -天孤剑-的微博: 在首页「寒 近 嗜 好 酒   剑 动 秀 清 风」里面的「剑」就能找到flag: wctf{@无所不能的魂大人} (广告真是无处不在

     

    包罗万象

    http://ctf.idf.cn/index.php?g=game&m=list&a=index&id=17

    图片里的英语: 好吧这题是我脑洞不够大, 是同学告诉我做法的, 图片改名成任意压缩文件, 解压得到赵本山的剧照, flag就是剧照里面的台词首字母, 图片本来是没有字幕, 百度之

    台词是「May the force be with you」, flag: wctf{Mtfbwy}

     

    逆天而行

    http://ctf.idf.cn/index.php?g=game&m=list&a=index&id=21

    逆向题起了这么个名字…

    只做了三题,

    Python BtyeCode: 好像是用Cpython编译的, 手头没工具, 用的是师兄给的反编译出来的代码:

     1 def encrypt(key, seed, string):
     2     rst = []
     3     for v in string:
     4         rst.append((ord(v) + seed ^ ord(key[seed])) % 255)
     5         seed = (seed + 1) % len(key)
     6     return rst
     7 if __name__ == '__main__':
     8     print "Welcome to idf's python crackme"
     9     flag = input('Enter the Flag: ')
    10     KEY1 = 'Maybe you are good at decryptint Byte Code, have a try!'
    11     KEY2 = [
    12         124, 48, 52, 59, 164, 50, 37, 62, 67, 52, 48, 6, 1,
    13         122, 3, 22, 72, 1, 1, 14, 46, 27, 232]
    14     en_out = encrypt(KEY1, 5, flag)
    15     if KEY2 == en_out:
    16         print 'You Win'
    17     else:
    18         print 'Try Again !'

    正常人反着推肯定是写: arr[i] -  (key[seed] ^ seed);

    不过这样肯定推不出来, 因为出题人写错了… (师兄想出来的… 打死我也不知道是题目错了啊…), 出题的用了正确的算法给出密文之后, 把

    rst.append((ord(v) ^ ord(key[seed]) + seed) % 255) 写成了:

    rst.append((ord(v) + seed ^ ord(key[seed])) % 255)

    所以没必要深究什么了:

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4 #include <math.h>
     5 int main(){
     6     unsigned char arr[] = {
     7         124, 48, 52, 59, 164, 50, 37,
     8         62, 67, 52, 48, 6, 1, 122, 3,
     9         22, 72, 1, 1, 14, 46, 27, 232, 0};
    10     const char key[] = "Maybe you are good at decryptint Byte Code, have a try!";
    11     char flag[100];
    12     int tmp;
    13     int seed = 5;
    14     for (int i = 0; i < 23; i++){
    15         tmp = (arr[i] ^ key[seed]) - seed;
    16         flag[i] =abs(tmp)%127; //事实上为什么要%127也不太清楚
    17         while (flag[i] < 32 || flag[i] > 127){
    18             if (flag[i] < 32) flag[i] = flag[i] + 255;
    19             if (flag[i] > 127) flag[i] = flag[i] - 255;
    20         }
    21         printf("arr[%d] = %d; key[%d] = %d; ^ = %d flag[%d] = %d;
    ",
    22                 i,arr[i],seed, key[seed],key[seed]^seed, i, flag[i]);
    23         seed = (seed + 1)%strlen(key);
    24     }
    25     puts(flag);
    26     printf("
    ");
    27     system("pause");
    28     return 0;
    29 }

    flag: WCTF{ILOVEPYTHONSOMUCH}

     

    简单的ELF逆向:

    这题是ELFx64位的CrackMe, 只能用IDA啦, 载入之,师兄叫我用F4 F5,不过64位的IDA好像没有F5, 找到main函数, F4, 得到代码:

     1 addr_0x400900_12:
     2 {
     3     v13 = 0; 
     4     if (v3 != 22) {
     5         v13 = 1;
     6     }
     7     v14 = 0;
     8     while ((unsigned char)(uint1_t)(v14 <= 16) != 0) {
     9         eax15 = (int32_t)(uint32_t)(unsigned char)v8;
    10         if ((int32_t)*(signed char*)&eax15 != 0) {
    11             v13 = 1;
    12             *(int32_t*)&rsi = 0;
    13             *((int32_t*)&rsi + 1) = 0;
    14             printf("%d", 0);
    15         }
    16         ++v14;
    17     }
    18     eax16 = (int32_t)(uint32_t)(unsigned char)v17;
    19     if (*(signed char*)&eax16 != 48 
    20             || ((eax18 = (int32_t)(uint32_t)(unsigned char)v19, *(signed char*)&eax18 != 56) 
    21                 || ((eax20 = (int32_t)(uint32_t)(unsigned char)v21, *(signed char*)&eax20 != 50) 
    22                     || ((eax22 = (int32_t)(uint32_t)(unsigned char)v23, *(signed char*)&eax22 != 51) 
    23                         || (eax24 = (int32_t)(uint32_t)(unsigned char)v25, *(signed char*)&eax24 != 0x7d))))) {
    24         v13 = 1;
    25     }
    26 
    27 puts("
    ", rsi);
    28 /* v13 应该是一个标志变量 */
    29     if (v13 != 0) {
    30         puts("u r wrong
    
    ", rsi);
    31         rax26 = main("u r wrong
    
    ", rsi);
    32     } else {
    33         puts("u r right!
    ", rsi);
    34     }
    35     return 0;
    36 addr_0x4008ff_7:
    37     goto addr_0x400900_12;
    38 }

    果然代码的可读性不是很好, 前面的printf之类的被我省去了, 重点放在while循环和那个if上, 可以看到if要求的是几个变量必须分别为 0, 8, 2, 3,} 应该就是flag 的后部分了, 从最后的判断right和wrong可以看出v13是判断正确与否的变量.

    while循环是在是难懂, 乖乖回去看汇编好了.

    右键选择Graphic View模式, 这样汇编代码显得很清晰, 把重点放在while循环对应的那部分, 简单分析得到, 红笔标注的地方就是程序内为数不多的循环了, 循环之后多条并排的绿线那里是多路if,最后的是正确与否的判断以及输出.

     

     

    关键代码如下, interator 对应var_14, arr_1 对应var_40, arr_2 对应 var_c0:

     1 loc_40097C:
     2 cmp     [rbp+iterator], 10h    ; 循环总次数
     3 setle   al
     4 test    al, al
     5 jnz     short loc_40091D
     6 
     7 loc_40091D:
     8 mov     eax, [rbp+iterator]    ; 装入循环变量
     9 cdqe
    10 movzx   eax, [rbp+rax+arr_1]    
    11 movsx   edx, al        ; 取出(unsigned char)arr_1[iterator], 数组元素只有一个字节
    12 mov     eax, [rbp+iterator]
    13 cdqe
    14 mov     eax, [rbp+rax*4+arr_2] ; 取出(int)arr_2[iterator], 四个字节
    15 sub     eax, 1        ; eax = eax - 1
    16 mov     ecx, eax     ; ecx = eax
    17 shr     ecx, 1Fh    ; ecx = ecx >> 0x1f
    18 lea     eax, [rcx+rax]    ; 装入地址其实就是 eax = ecx + eax;
    19 sar     eax, 1         ; eax = eax >> 1
    20 cmp     edx, eax     ; 比较arr_2[iterator]经过运算的值是否等于arr_1[iterator]
    21 jz      short loc_400978    ; 等于则跳
    22 
    23 loc_400978:
    24 add     [rbp+iterator], 1

    经过以上分析可以知道 arr_1 应该是我们输入的key, 所以有必要知道arr_2 的值,

    跳转到arr_2的定义:

     

    是空的…

    但是我们回到代码中, 对arr_2有这样的操作:

     

    刚好17个项(0-10h),

    所以说 arr_i[i] = ((arr_2[i] – 1) + (arr_2[i] – 1)>>0x1f)>>1

    (忽略了shr 和 sar 以及各种细节问题… 所幸没有出错)

    (vim 来处理这些最爽了)

     

    代码:

    #include <cstdio>
    #include <cstdlib>
    #define N 17
    int arr_2[N] = {
        0x0EF, 0x0C7, 0x0E9, 0x0CD, 0x0F7, 0x8B, 0x0D9, 
        0x8D, 0x0BF, 0x0D9, 0x0DD, 0x0B1, 0x0BF, 0x87, 
        0x0D7, 0x0DB, 0x0BF
    };
    int main(){
        for (int i = 0; i < N; i++){
            int ch = ((arr_2[i] - 1) + ((arr_2[i] - 1) >> 0x1f))>>1;
            /*注意一下 >> 的优先级*/
            printf("%c",ch);
        }
        printf("0823}
    ");
        system("pause.");
        return 0;
    }

    flag: wctf{ElF_lnX_Ckm_0823}

     

    简单的PE文件逆向:

    x86平台, 双击没法运行, 应该需要某个古老的C++运行时, 那就放弃用OD了, IDA载入, 稍微翻一翻(其实是不知道如何有效定位), 0x4113a0处就是关键处, F5之, 这次代码好看多了, 可以看出和上一个CrackMe基本相同…

     1 flag = 0;
     2 for ( i = 0; i < 17; ++i ){
     3     if ( v76[i] != byte_415768[*(&v53 + i)] )
     4         flag = 1;
     5 }
     6 if ( v77 != 49 || v78 != 48 || v79 != 50 || v80 != 52 || v81 != 125 )
     7     flag = 1;
     8     v76[v75] = 0;
     9     printf("
    ");
    10     sub_411136();
    11 if ( flag )
    12 {
    13     printf("u r wrong
    
    ");
    14     sub_411136();
    15     sub_41113B();
    16 }
    17 else
    18 {
    19     printf("u r right!
    ");
    20     sub_411136();
    21 }
    22 system("pause");

    同样是把flag分成两部分, 后面五个必须是1024},前面的在一个for循环里算出:

    v76[i] != byte_415768[*(&v53 + i)]

    通过一个数组v53[]运算出下标, 再用下标从另一个数组byte_415768[]取出值来, 数组是:

     1 v53 = 1;
     2 v54 = 4;
     3 v55 = 14;
     4 v56 = 10;
     5 v57 = 5;
     6 v58 = 36;
     7 v59 = 23;
     8 v60 = 42;
     9 v61 = 13;
    10 v62 = 19;
    11 v63 = 28;
    12 v64 = 13;
    13 v65 = 27;
    14 v66 = 39;
    15 v67 = 48;
    16 v68 = 41;
    17 v69 = 42;
    18 byte_415768 db 73h
    19                    db 'wfxc{gdv}fwfctslydRddoepsckaNDMSRITPNsmr1_=2cdsef66246087138',0

    要注意byte_415768[]的一个元素s(73h)没有被识别.

    所以:

     1 #include <cstdio>
     2 #include <cstdlib>
     3 int v53[] = {
     4     1, 4, 14, 10, 5, 36, 23, 42, 13, 
     5     19, 28, 13, 27, 39, 48, 41, 4
     6 };
     7 char byte_415768[] = "swfxc{gdv}fwfctslydRddoepsckaNDMSRITPNsmr1_=2cdsef66246087138";
     8 
     9 int main(){
    10     for (int i = 0; i < 17; i++){
    11         printf("%c", byte_415768[v53[i]]);
    12     }
    13     printf("1024}
    ");
    14     system("pause");
    15 }

    flag: wctf{Pe_cRackme1c1024}

     

    凯撒加密:

    给出一个字符串, 写个程序按127为周期跑一圈, 得到二十多个处在合法范围内的串, 最正常的一个如下, 像是base64, 解码一下得出flag.

    dGhlIGZsYWcgaXMgd2N0ZntrYWlzYV9qaWFhYWFhbWl9LHBseiBmbG93IG15IHdlaWJvLGh0dHA6Ly93ZWliby5jb20vd29sZHk=

    代码:

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cstring>
     4 char kaiser[] = "U8Y]:8KdJHTXRI>XU#?!K_ecJH]kJG*bRH7YJH7YSH]*=93dVZ3^S8*$:8"&:9U]RH;g=8Y!U92'=j*$KH]ZSj&[S#!gU#*dK9\.";
     5 /* 记得转义 */
     6 int main(){
     7     char ch[1000];
     8     bool flag = true;
     9     for (int i = 0; i < 127; i++){
    10         memset(ch, 0, sizeof(ch));
    11         for (int j = 0; j < strlen(kaiser); j++){
    12             ch[j] = (kaiser[j] + i)%127;
    13             if (ch[j] <= 32 || ch[j] > 127) flag = false;
    14         }
    15         if (flag) puts(ch);
    16     }
    17     system("pause");
    18     return 0;
    19 }

    flag: wctf{kaisa_jiaaaaami}

     

    天罗地网

    http://ctf.idf.cn/index.php?g=game&m=list&a=index&id=22

    一种编码而已: Jother编码, JSのBrainFuck, 前几天刚在Wooyun看到…直接在F12控制台执行得到:

    flag: WCTF{H3110_J0t4er}

     

    超简单的JS题: 查看源码发现script标签里有这一段:

    1 var p1 ='%66%75%6e%63%74%69%6f%6e%20%63%68%65%63%6b%53%75%62%6d%69%74%28%29%7b%76%61%72%20%61%3d%64%6f%63%75%6d%65%6e%74%2e%67%65%74%45%6c%65%6d%65%6e%74%42%79%49%64%28%22%70%61%73%73%77%6f%72%64%22%29%3b%69%66%28%22%75%6e%64%65%66%69%6e%65%64%22%21%3d%74%79%70%65%6f%66%20%61%29%7b%69%66%28%22%65%66%66%35%62%66%38%63%63';
    2 var p2 ='%31%61%30%64%38%33%35%36%32%63%35%22%3d%3d%61%2e%76%61%6c%75%65%29%72%65%74%75%72%6e%21%30%3b%61%6c%65%72%74%28%22%45%72%72%6f%72%22%29%3b%61%2e%66%6f%63%75%73%28%29%3b%72%65%74%75%72%6e%21%31%7d%7d%64%6f%63%75%6d%65%6e%74%2e%67%65%74%45%6c%65%6d%65%6e%74%42%79%49%64%28%22%6c%65%76%65%6c%51%75%65%73%74%22%29%2e%6f%6e%73%75%62%6d%69%74%3d%63%68%65%63%6b%53%75%62%6d%69%74%3b';
    3 eval(unescape(p1) + unescape('%33%66%61%37%38%32%66%32%36%31%61%35' + p2));

    JS我是完全不懂…

    查了一下unescape()发现这个函数是用来解码字符串的, 大概是为了让URL参数支持Unicode吧… eval()用来执行参数指定的JS代码, 有点MetaPrograming(元编程)的意思.

    找个在线解码: http://tool.chinaz.com/Tools/Escape.aspx

    1 var p1 = 'function checkSubmit(){var a=document.getElementById("password");if("undefined"!=typeof a){if("eff5bf8cc';
    2 var p2 ='1a0d83562c5"==a.value)return!0;alert("Error");a.focus();return!1}}document.getElementById("levelQuest").onsubmit=checkSubmit;';
    3 eval(unescape(p1) + unescape('3fa782f261a5' + p2));

    合并起来就是:

     1 function checkSubmit(){
     2     var a=document.getElementById("password");
     3     if("undefined"!=typeof a){
     4         if("eff5bf8cc3fa782f261a51a0d83562c5"==a.value)
     5             return!0;
     6         alert("Error");
     7         a.focus();
     8         return!1
     9     }
    10 }
    11 document.getElementById("levelQuest").onsubmit=checkSubmit;

    这下就清晰了, 输入eff5bf8cc3fa782f261a51a0d83562c5提交:

    flag: wctf{webclieNt_c0py}

     

    古老的邮件编码: 不太清楚邮件编码什么的, 稍微搜索后发现它比较符合   Uuencode编码的特征, 找在线转换工具: http://web.chacuo.net/charsetuuencode

    flag: wctf{uuuuuencode__}

     

    剩下的题就没做了(其实是不会做).

  • 相关阅读:
    【Codeforces 340D】Bubble Sort Graph
    在写EF 时把时间格式化的做法
    判断早八点晚八点内做事情的方法
    EF分组后把查询的字段具体映射到指定类里面的写法
    MYSQL 之SET GLOBAL innodb_buffer_pool_size =n
    指定类型的成员XX”不支持实体LINQ。只有初始化,成员单位,和实体导航性能的支持。
    MVC中某个页面不需要引用母版页的正确写法
    新建一个controller并指定为默认的方法
    如果有反向代理的情况下,获取最原始的IP的办法
    解决MVC运行controller的时候只有有参构造函数但是程序一定要走无参构造函数的方法
  • 原文地址:https://www.cnblogs.com/lastavengers/p/4198095.html
Copyright © 2011-2022 走看看