首页
社区
课程
招聘
[原创]第八题 AI核心地带
2023-9-18 11:07 2823

[原创]第八题 AI核心地带

xym 活跃值
4
2023-9-18 11:07
2823
1
2
这是一道简单题,文件大小才8K。所以ida打开后主流程基本一览无余。在看完ida的数据流程后,基本可以肯定这个程序就是对输入的每个字节进行顺序判断,所以可以对每个字节进行遍历求取以判断当前字节是否正确。
将主函数稍微修改一下,让判断失败时返回0,判断成功时输出ans,需要进行下一位比较时返回2。得到如下Check函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
int Check(char *Input)
{
    char FakeFlag[48];
    strcpy_s(FakeFlag, 48, "flag{BzcZDnfNIqmQCtkTGlwLyDYeiHIjxSXwkRKzpFPv}");
    _BYTE Data[27];
    strcpy_s((char*)Data, 27, "Can you crack me?^olo^");
    int StrLength = strlen(Input);
    int bFail1 = 0, bFail2 = 0, MayFail = 0;
    int v9, v20 = 0;
    int Last = 0;
    int v11;
    int v26;
 
    DWORD Index = 0;
    char v7 = FakeFlag[42];
    bool v8 = StrLength > 0;
    do
    {
        if (v8)
        {
            int v19 = Input[Index];
            if (v19 - (unsigned int)'0' > 9)        // 大于‘9’失败?
            {
                return 0;
                bFail1 = 1;
                MayFail = 1;
                goto LABEL_32;
            }
            v9 = (v19 + (0xFFFEC610 >> (Index % 0x1F))) % 0xA;
            if ((Index & 1) != v9 < 1)
            {
                return 0;
                MayFail = 1;
            }
        }
        else
        {
            v9 = v20;
            Last = 1;
        }
        v11 = v9;
        v26 = *(_DWORD *)&Data[16] ^ *(_DWORD *)&Data[12] ^ *(_DWORD *)&Data[8] ^ *(_DWORD *)&Data[4] ^ *(_DWORD *)Data;
        if (Last || 1)
        {
            if ((((unsigned __int8)v26 ^ (unsigned __int8)(Data[18] ^ Data[14] ^ Data[10] ^ Data[6] ^ Data[2])) & 0x1F) != 0
                || ((HIBYTE(v26) ^ BYTE1(v26)) & 0x1F) != 0)
            {
                //v11 = -1;
                //if (Last)
                //  return 0;
            }
            else
            {
                printf("ans: %s", Input);
                getchar();
                return 1;
            }
            //goto LABEL_26;
        }
        if (v9 >= 1)
        {
            BYTE v12, v13, v14;
            v12 = BYTE2(v26);
            if (v9 >= 6)
            {
                if ((((unsigned __int8)v26 ^ BYTE2(v26)) & 0x1F) != 0)
                {
                LABEL_25:
                    return 0;
                    v11 = 9;
                    goto LABEL_26;
                }
                v12 = HIBYTE(v26);
                v13 = 13 - v9;
                v14 = BYTE1(v26);
            }
            else
            {
                v13 = 8 - v9;
                v14 = v26;
            }
            if ((((v14 << v13) + 0x80)&0xff) == ((v12 << v13)&0xff))
            {
                if (Index == StrLength - 1)
                    return 2;
                goto LABEL_26;
            }
            goto LABEL_25;
        }
    LABEL_26:
        v20 = v11;
        if (Last)
        {
            bool v15 = v11 < 0;
            bFail1 = MayFail;
            if (v15)
                bFail2 = 1;
        }
        else
        {
            int v16 = *(_DWORD *)&FakeFlag[4 * v11 + 5];
            *(_DWORD *)Data ^= v16;
            *(_DWORD *)&Data[4] ^= v16;
            *(_DWORD *)&Data[8] ^= v16;
            *(_DWORD *)&Data[12] ^= v16;
            v8 = v11 <= 8;
            bFail1 = MayFail;
            *(_DWORD *)&Data[16] ^= v16;
            if (!v8 && (v7 & 0x10000000) == 0)
            {
                v7 = ~v7 & 0x7F;
                FakeFlag[42] = v7;
            }
        }
    LABEL_32:
        v8 = (int)++Index < StrLength;
    } while ((int)Index <= StrLength);
    if (bFail1 || bFail2)
        return 0;
    return 2;
}
1
继续构造主函数对每一字节进行遍历,一开始Input字节数没给够,导致遍历不出来,后面看到题目给了1000的缓存,修改后才得到答案。主程序如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int main()
{
    char Input[1024] = "0";
    memset(&Input[0], 0, 1000);
    int Cur = 0;
    while (Cur < 1000)
    {
        for (int Index = 0; Index < 10; Index++)
        {
            Input[Cur] = 0x30 + Index;
            int res = Check(Input);
            if (res == 2)
            {
                Cur++;
                break;
            }
        }
    }
}
1
2
因为题目限制了输入必须是字母0-9,所以这个答案基本上是秒出。得到flag为:582606981190746395118531851185249089744027265368693769576937697816165851808443150195011501950410798490871663488927792799277958360668112074539521851185318514909974002766535869476937695769681626582180144305010501950115040079949037162348792789277927995826067811907483951185218511853490897410272653986937694769376988161658318084433501950105019504207984904716634829277927892779584606681100745395418511852185149009740027365358697769376947696816365821809443050125019501050400790490371673487927
ps:注意到if ( !v8 && (v7 & 0x10000000) == 0 )这一段,有可能出题人的意思是让v11大于8时修改FakeFlag[42]的值,从而限制错误的输入,但是由于可以多次修改FakeFlag[42],导致该值不可预期,从而可以产生其他预期外的解。

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回