一道CTF入门题目

本帖最后由 kiseyzed 于 2019-7-20 20:50 编辑

0x0.写在前面
萌新,以前没有接触过CTF,今天同学给我分享了个入门的题目,几经波折还是做出来了,具体就只涉及到代码分析和简单的算法编写。在这里把经验分享出来,欢迎大家共同交流学习,有不对的地方还请指出来,免得误人子弟。
0x1.初探
题目:分析代码找出程序的flag
程序运行界面:

输入假码(程序显示"you can do it"并退出):

大致情况已经了解,仅凭外表和程序大小来判断是c++写的,并且应该是一个64位的可执行程序。
0x2.尝试
拖入OD,尝试破解。
搜索字符串,很明显地看到了失败的提示、疑似真码的文本(Qht_2019_Gsqzcjsf_Vszzc)、成功的提示。

尝试直接输入那一串文本,发现还是提示错误,说明这并不是。
不过不要灰心,分析代码。
来到失败处,代码如下:
[Asm] 纯文本查看 复制代码

0040107C  |.  F7D1          not ecx
0040107E  |.  49            dec ecx
0040107F  |.  BF B0404100   mov edi,welcome_.004140B0                ;  Qht_2019_Gsqzcjsf_Vszzc
00401084  |.  8BD1          mov edx,ecx
00401086  |.  83C9 FF       or ecx,-0x1
00401089  |.  F2:AE         repne scas byte ptr es:[edi]
0040108B  |.  F7D1          not ecx
0040108D  |.  49            dec ecx
0040108E  |.  3BD1          cmp edx,ecx
00401090  |.  74 19         je short welcome_.004010AB
00401092  |.  68 18414100   push welcome_.00414118                   ;  you.can.doit\n
00401097  |.  E8 B4390000   call welcome_.00404A50
0040109C  |.  83C4 04       add esp,0x4
0040109F  |.  83C8 FF       or eax,-0x1
004010A2  |.  5F            pop edi                                  ;  welcome_.<ModuleEntryPoint>
004010A3  |.  5E            pop esi                                  ;  welcome_.<ModuleEntryPoint>
004010A4  |.  81C4 00080000 add esp,0x800
004010AA  |.  C3            retn
004010AB  |>  8D72 FF       lea esi,dword ptr ds:[edx-0x1]
004010AE  |.  33C9          xor ecx,ecx
004010B0  |.  85F6          test esi,esi
004010B2  |.  7C 41         jl short welcome_.004010F5

有点乱,不过大概就是判断输入的文本长度是否与“Qht_2019_Gsqzcjsf_Vszzc”的长度相等,这里我们直接将ZFlag置1,使跳转实现,分析后面代码

接下来我们来到了一个循环体
[Asm] 纯文本查看 复制代码

004010AE  |.  33C9          xor ecx,ecx
004010B0  |.  85F6          test esi,esi
004010B2  |.  7C 41         jl short welcome_.004010F5
004010B4  |>  8A440C 08     /mov al,byte ptr ss:[esp+ecx+0x8]
004010B8  |.  3C 5A         |cmp al,0x5A
004010BA  |.  7F 17         |jg short welcome_.004010D3
004010BC  |.  3C 41         |cmp al,0x41
004010BE  |.  7C 13         |jl short welcome_.004010D3
004010C0  |.  0FBEC0        |movsx eax,al
004010C3  |.  83E8 33       |sub eax,0x33
004010C6  |.  BF 1A000000   |mov edi,0x1A
004010CB  |.  99            |cdq
004010CC  |.  F7FF          |idiv edi                                ;  welcome_.004140C8
004010CE  |.  80C2 41       |add dl,0x41
004010D1  |.  EB 19         |jmp short welcome_.004010EC
004010D3  |>  3C 7A         |cmp al,0x7A
004010D5  |.  7F 19         |jg short welcome_.004010F0
004010D7  |.  3C 61         |cmp al,0x61
004010D9  |.  7C 15         |jl short welcome_.004010F0
004010DB  |.  0FBEC0        |movsx eax,al
004010DE  |.  83E8 53       |sub eax,0x53
004010E1  |.  BF 1A000000   |mov edi,0x1A
004010E6  |.  99            |cdq
004010E7  |.  F7FF          |idiv edi                                ;  welcome_.004140C8
004010E9  |.  80C2 61       |add dl,0x61
004010EC  |>  88540C 08     |mov byte ptr ss:[esp+ecx+0x8],dl
004010F0  |>  41            |inc ecx
004010F1  |.  3BCE          |cmp ecx,esi
004010F3  |.^ 7E BF         \jle short welcome_.004010B4
004010F5  |>  53            push ebx
004010F6  |.  8D7424 0C     lea esi,dword ptr ss:[esp+0xC]

这里就是对输入的文本进行处理的地方了,我们后面再分析,直接循环尾F2下断,使程序运行到断点处

单步一下,发现了我们输入的假码,不过没变,应该是对数字不进行处理,继续分析
又来到一个循环体
[Asm] 纯文本查看 复制代码

004010FA  |.  B8 B0404100   mov eax,welcome_.004140B0                ;  Qht_2019_Gsqzcjsf_Vszzc
004010FF  |>  8A10          /mov dl,byte ptr ds:[eax]
00401101  |.  8A1E          |mov bl,byte ptr ds:[esi]
00401103  |.  8ACA          |mov cl,dl
00401105  |.  3AD3          |cmp dl,bl
00401107  |.  75 1E         |jnz short welcome_.00401127
00401109  |.  84C9          |test cl,cl
0040110B  |.  74 16         |je short welcome_.00401123
0040110D  |.  8A50 01       |mov dl,byte ptr ds:[eax+0x1]
00401110  |.  8A5E 01       |mov bl,byte ptr ds:[esi+0x1]
00401113  |.  8ACA          |mov cl,dl
00401115  |.  3AD3          |cmp dl,bl
00401117  |.  75 0E         |jnz short welcome_.00401127
00401119  |.  83C0 02       |add eax,0x2
0040111C  |.  83C6 02       |add esi,0x2
0040111F  |.  84C9          |test cl,cl
00401121  |.^ 75 DC         \jnz short welcome_.004010FF
00401123  |>  33C0          xor eax,eax
00401125  |.  EB 05         jmp short welcome_.0040112C

这里是挨个和处理后的文本与“Qht_2019_Gsqzcjsf_Vszzc”进行比较,如果有不一致就调到错误提示的地方

这里将跳转语句nop,运行

成功了,不过这当然不是我们需要的flag,不过可以得到一条信息:flag='love_'+str+"_"
其中,key为执行上面文本处理算法得到的(Qht_2019_Gsqzcjsf_Vszzc)
代码的执行流程为:
str->key->flag
所以我们要找到原始文本str,并和“love_”以及“_”进行拼接,就得到了答案
要找到str,就得将分析出生成key的算法,再将算法进行逆向操作

0x3.逆向
重新载入程序,来到算法的地方
[Asm] 纯文本查看 复制代码

004010B4  |> /8A440C 08     /mov al,byte ptr ss:[esp+ecx+0x8]
004010B8  |. |3C 5A         |cmp al,0x5A
004010BA  |. |7F 17         |jg short welcome_.004010D3
004010BC  |. |3C 41         |cmp al,0x41
004010BE  |. |7C 13         |jl short welcome_.004010D3
004010C0  |. |0FBEC0        |movsx eax,al
004010C3  |. |83E8 33       |sub eax,0x33
004010C6  |. |BF 1A000000   |mov edi,0x1A
004010CB  |. |99            |cdq
004010CC  |. |F7FF          |idiv edi
004010CE  |. |80C2 41       |add dl,0x41
004010D1  |. |EB 19         |jmp short welcome_.004010EC
004010D3  |> |3C 7A         |cmp al,0x7A
004010D5  |. |7F 19         |jg short welcome_.004010F0
004010D7  |. |3C 61         |cmp al,0x61
004010D9  |. |7C 15         |jl short welcome_.004010F0
004010DB  |. |0FBEC0        |movsx eax,al
004010DE  |. |83E8 53       |sub eax,0x53
004010E1  |. |BF 1A000000   |mov edi,0x1A
004010E6  |. |99            |cdq
004010E7  |. |F7FF          |idiv edi
004010E9  |. |80C2 61       |add dl,0x61
004010EC  |> |88540C 08     |mov byte ptr ss:[esp+ecx+0x8],dl
004010F0  |> |41            |inc ecx
004010F1  |. |3BCE          |cmp ecx,esi
004010F3  |.^\7E BF         \jle short welcome_.004010B4
004010F5  |>  53            push ebx

这次假码不使用数字,用字母a

发现全部变成了o
大写字母也是一样,且为固定转换,严格对应(a->o,A->O.......)
我们当然可以挨个将a-z输入一遍,然后建立一个密码表,将key解密,理所应当的会得到str
不过这种方法显得有点儿蠢,万一别人用1k位的数据,或者随机转换,那就行不通了

老老实实分析代码,具体规则:
1.长度为23位
2.小写字母
(ASCII-0x53)/0x1A+0x61
3.大写字母
(ASCII-0x33)/0x1A+0x41

str--规则-->key(Qht_2019_Gsqzcjsf_Vszzc)
根据上面我们可以开始编写代码了,重装了系统,手头没用趁手的工具,用谷歌浏览器开发者工具里面的控制台写JS来实现
具体代码:
[JavaScript] 纯文本查看 复制代码

function calc() {
    var str = "";
    var key = "Qht_2019_Gsqzcjsf_Vszzc";
    for (var i = 0; i < key.length; i++) {
        n = key.substring(i, i + 1).charCodeAt();
        if (n >= 65 && n <= 90) {
            n = n - 65;
            var k, j = 0;
            while (true) {
                k = j * 26 + n;
                k = k + 51;
                j++;
                if (k >= 65 && k <= 90) {
                    break;
                }
            }
        } else if (n >= 97 && n <= 122) {
            n = n - 97;
            var k;
            var j = 0;
            while (true) {
                k = j * 26 + n;
                k = k + 83;
                j++;
                if (k >= 97 && k <= 122) {
                    break;
                }
            }
        } else {
            var k = n;
        }
        str = str + String.fromCharCode(k);
    }
    console.log(str);
}

得到答案:Ctf_2019_Seclover_Hello
输入进去也反馈了正确结果

flag=love_Ctf_2019_Seclover_Hello_
网站结果也确认无误,至此,逆向就告一段落了。

0x4.总结
没什么需要总结的,知道了原理之后就没什么难度了。
不过这是我第一次尝试CTF,也是值得纪念的,希望以后共同学习交流。

最后附上样本,后缀改成exe就行,不保证安全无毒,建议虚拟机或影子系统。

welcome_CTF.txt

(96 KB, 下载次数: 0)

2019-7-20 20:48 上传
点击文件名下载附件

THE END
喜欢就支持以下吧
点赞0
分享
评论 抢沙发
  • 管埋员的头像-小北的自留地

    昵称

  • 取消
    昵称