首页
社区
课程
招聘
[原创]KCTF 第二题 末日邀请 暴力解题
发表于: 2022-5-11 21:36 5818

[原创]KCTF 第二题 末日邀请 暴力解题

2022-5-11 21:36
5818

分析完代码后,可以通过第二关得到字符串为 ???KCTF??????????
分析第四关,可以知道后面接的CTF字符串肯定是 1234567890等,因为会排序,那么可能是以下几种
1, 12, 123, 1234, 12345, 123456, 1234567, 12345678, 123456789, 1234567890

通过动态调试可以知道如果是1234[\x0\x0]这种会被第三关干扰从而生成别的字符串,不符合逻辑,那么大胆猜测就是1-9的字符串
通过第一关可以快速遍历得到所有 前三个字符
如下:

然后我就目测了一下,感觉那个 Hi[ 很像, 然后就走入了误区
合在一起是 Hi[KCTF]1-8, 然后就越走越远了,最后才发现可能是其他的字符+KCTF+1-9

写下如下代码,进行尝试性破解

思路就是遍历所有三个字符符合条件的来匹配,因为实在不知道哪三个字符符合条件,包括后面的判断也没有看出来,只能盲猜所有可能,之前误判为Hi[走错了后,改进为所有可能。

进行第五关的校验,就是所有的字符串参与计算,分拆前面7个字符先初始化得到值。
然后就是1-9的排列组合,直接生成所有排列可能,然后参与计算对比得到结果,结果如下:

带入到程序中, 421KCTF381654729, 验证通过。

补一个sbox表格

char first(unsigned char* str, int len)
{
    char tmp = 0;
    for (int i = 0; i < len; i++)
    {
        tmp ^= str[i];
        for (int j = 0; j < 8; j++)
        {
            char v9 = 2 * tmp;
            tmp = v9 >= 0 ? v9 : (v9 ^ 7);
        }
    }
    return tmp;
}
 
void second(char v, int out[200])
{
    unsigned char v15 = v;
    for (int i = 1; i < 200; i++)
    {
        if ((v15 & 1) != 0)
            v15 = 3 * v15 + 1;
        else
            v15 >>= 1;
        out[i] = v15;
        printf("%.2x ", v15);
 
        if ((i + 1) % 0x10 == 0)
            printf("\r\n");
    }
 
    printf("\r\n");
}
 
unsigned char to_hex(unsigned char a)
{
    return (a >= 0x3a) ? (a - 0x37) : (a - 0x30);
}
 
int sub_4010B7(unsigned char* str, int len)
{
    for (int i = 0; i < len; ++i)
    {
        str[i] = to_hex(str[i]);
    }
    return 0;
}
 
int ctf_1(unsigned char* ctf, int len)
{
    int tmp = 0;
    int tk = 1;
    for (int i = 0; i < len; i++)
    {
        int v23 = ctf[i] + tmp * 10;
        int v24 = v23 - 0x37373737;
        if (v23 <= 0x4b435445)
            v24 = v23;
        tmp = v24;
 
        if (v24 % tk++)
            return -1;
    }
    return 0;
}
 
int __cdecl main(int argc, const char **argv, const char **envp)
{
    /// 取字符串
    sub_40103A("%s", (char)str);
    /// 异或处理
    int len = strlen(str);
    char a = first(str, len);
    /// 初始化sbox, 直接拷贝即可
    sub_40106C();
    /// 哈希计算
    int v = -1;
    for (int i = 0; i < len; i++)
    {
        v = ((unsigned int*)sbox)[(unsigned char)(v ^ s[i])] ^ (v >> 8);
    }
    /// must be 0xf52e0765
    v ~= v;
    /// 字符转换hex?
    sub_4010B7(str, len);
    /// 第一关,其值为0x07
    char tbox[200] = { 0 };
    second(a, tbox);
    /// 观察tbox的结果, tbox[198] | tbox[197] | tbpx[196] 为 0x07
    /// 注意:有符号的情况下不能通过第一关,可以修改 0x12A7 edi==0x07, 后面会用到
    char k = str[0] ^ str[1] ^ str[2];
    if (k != 0x07) failed(-1);
    /// 第二关 {3-5} -> 'KCTF'
    if (str[3] != 0x14 || str[4] != 0xc || str[5] != 0x1d || str[6] != 0x0f)
        failed(-1);
    /// 第三关 {未解}
    /// 0x13E4 -> nop*6
    ctf = &str[7];
    if (ctf_1(ctf, strlen(ctf)!=0)
        failed(-1);
    /// 第四关
    /// 1 - 排序 从低到高
    sort(ctf, strlen(ctf));
    /// 2 - 比较字符串
    char cmp[] = '1234567890_A...';
    sub_4010B7(cmp, 10);
    /// 3 - 比较ctf
    if (strncmp(ctf, cmp, strlen(ctf)))
        failed(-1);
    /// 第五关
    if (v!= 0xF52E0765)
        failed(-1);
    return ok();
}
char first(unsigned char* str, int len)
{
    char tmp = 0;
    for (int i = 0; i < len; i++)
    {
        tmp ^= str[i];
        for (int j = 0; j < 8; j++)
        {
            char v9 = 2 * tmp;
            tmp = v9 >= 0 ? v9 : (v9 ^ 7);
        }
    }
    return tmp;
}
 
void second(char v, int out[200])
{
    unsigned char v15 = v;
    for (int i = 1; i < 200; i++)
    {
        if ((v15 & 1) != 0)
            v15 = 3 * v15 + 1;
        else
            v15 >>= 1;
        out[i] = v15;
        printf("%.2x ", v15);
 
        if ((i + 1) % 0x10 == 0)
            printf("\r\n");
    }
 
    printf("\r\n");
}
 
unsigned char to_hex(unsigned char a)
{
    return (a >= 0x3a) ? (a - 0x37) : (a - 0x30);
}
 
int sub_4010B7(unsigned char* str, int len)
{
    for (int i = 0; i < len; ++i)
    {
        str[i] = to_hex(str[i]);
    }
    return 0;
}
 
int ctf_1(unsigned char* ctf, int len)
{
    int tmp = 0;
    int tk = 1;
    for (int i = 0; i < len; i++)
    {
        int v23 = ctf[i] + tmp * 10;
        int v24 = v23 - 0x37373737;
        if (v23 <= 0x4b435445)
            v24 = v23;
        tmp = v24;
 
        if (v24 % tk++)
            return -1;
    }
    return 0;
}
 
int __cdecl main(int argc, const char **argv, const char **envp)
{
    /// 取字符串
    sub_40103A("%s", (char)str);
    /// 异或处理
    int len = strlen(str);
    char a = first(str, len);
    /// 初始化sbox, 直接拷贝即可
    sub_40106C();
    /// 哈希计算
    int v = -1;
    for (int i = 0; i < len; i++)
    {
        v = ((unsigned int*)sbox)[(unsigned char)(v ^ s[i])] ^ (v >> 8);
    }
    /// must be 0xf52e0765
    v ~= v;
    /// 字符转换hex?
    sub_4010B7(str, len);
    /// 第一关,其值为0x07
    char tbox[200] = { 0 };
    second(a, tbox);
    /// 观察tbox的结果, tbox[198] | tbox[197] | tbpx[196] 为 0x07
    /// 注意:有符号的情况下不能通过第一关,可以修改 0x12A7 edi==0x07, 后面会用到
    char k = str[0] ^ str[1] ^ str[2];
    if (k != 0x07) failed(-1);
    /// 第二关 {3-5} -> 'KCTF'
    if (str[3] != 0x14 || str[4] != 0xc || str[5] != 0x1d || str[6] != 0x0f)
        failed(-1);
    /// 第三关 {未解}
    /// 0x13E4 -> nop*6
    ctf = &str[7];
    if (ctf_1(ctf, strlen(ctf)!=0)
        failed(-1);
    /// 第四关
    /// 1 - 排序 从低到高
    sort(ctf, strlen(ctf));
    /// 2 - 比较字符串
    char cmp[] = '1234567890_A...';
    sub_4010B7(cmp, 10);
    /// 3 - 比较ctf
    if (strncmp(ctf, cmp, strlen(ctf)))
        failed(-1);
    /// 第五关
    if (v!= 0xF52E0765)
        failed(-1);
    return ok();
}
unsigned char st = 0x20;
unsigned char se = 0x7f;
for (unsigned char x = st; x <= se; x++)
{
    for (unsigned char y = st; y <= se; y++)
    {
        for (unsigned char z = st; z <= se; z++)
        {
            if ((to_hex(x) ^ to_hex(y) ^ to_hex(z)) == 0x07)
            {
                printf("%c%c%c\n", x, y, z);
            }
        }
    }
}
unsigned char st = 0x20;
unsigned char se = 0x7f;
for (unsigned char x = st; x <= se; x++)
{
    for (unsigned char y = st; y <= se; y++)
    {
        for (unsigned char z = st; z <= se; z++)
        {
            if ((to_hex(x) ^ to_hex(y) ^ to_hex(z)) == 0x07)
            {
                printf("%c%c%c\n", x, y, z);
            }
        }
    }
}
#include <iostream>
#include <algorithm>
 
unsigned char st = 0x20;
unsigned char se = 0x7f;
unsigned char buf[9] = { 0 };
memcpy(&buf[3], "KCTF", 4);
for (unsigned char x = st; x <= se; x++)
{
    for (unsigned char y = st; y <= se; y++)
    {
        for (unsigned char z = st; z <= se; z++)
        {
            if ((to_hex(x) ^ to_hex(y) ^ to_hex(z)) == 0x07)
            {
                buf[0] = x;
                buf[1] = y;
                buf[2] = z;
                int v = get_ctf((char*)buf, 7);
                check(v, (char *)buf);
            }
        }
    }
}
 
int get_ctf(char* s, int len)
{
    int v = -1;
    for (int i = 0; i < len; i++)
    {
        v = ((unsigned int*)sbox)[(unsigned char)(v ^ s[i])] ^ (v >> 8);
    }
    return v;
}
void check(int v, char *s)
{
    char arr[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
    char arr2[sizeof(arr)] = { 0 };
    for (int i = 1; i < sizeof(arr); i++)
    {
        arr2[i] = 0;
        memcpy(arr2, arr, i);
        do {
            if (check_ctf2(arr2, i, v)) {
                printf("found: \n");
                printf("%s\n", s);
                print_hex((unsigned char*)arr2, i);
                printf("%s\n", arr2);
            }
        } while (std::next_permutation(arr2, arr2 + i));
    }
}
#include <iostream>
#include <algorithm>

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 2
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//