首页
社区
课程
招聘
[原创][看雪CTF.TSRC 2018 团队赛]第五题 交响曲
2018-12-10 13:50 2157

[原创][看雪CTF.TSRC 2018 团队赛]第五题 交响曲

2018-12-10 13:50
2157
int[] a = { 16, 6, 7, 10, 9, 16, 10, 8, 8, 9, 6, 6 };
int[] b = { 5, 10, 8, 15, 16, 15, 8, 16, 8, 16, 9, 17, 8, 17, 10, 8, 9, 18, 5, 15, 10, 9, 8, 9, 15, 18, 7, 8, 16, 6 };
int[] c = { 6, 7, 18, 9, 5, 16, 9, 15, 18, 8, 9, 5 };
int[] d = { 7, 7, 9, 12, 8, 7, 13, 5, 14, 5, 9, 17, 5, 7, 12, 8, 8, 6, 19, 6, 8, 16, 10, 6, 12, 9, 6, 7, 12, 5, 9, 8, 7, 8, 15, 9, 16, 8, 8, 19, 12, 6, 8, 7, 5, 15, 6, 16, 15, 7, 9, 12, 10, 7, 15, 6, 5, 14, 14, 9 };
String[] m = { "23to01", "01to03", "03to05", "05to07", "07to09", "09to11", "11to13", "13to15", "15to17", "17to19", "19to21", "21to23" };

序列号1~4位是年,5~6位是月,7~8位是日,9~14位是m[]中的一个字符串。

 

序列号需要满足d[(year-1900)%60]+c[month-1]+b[day-1]+a[?] = 34

 

其中年月日需要满足下面的条件:

j: year     [1983-2007]
i: month    [1-12]
h: day      [1-31]

j = 1989||2004时,h=31
i = 1,4,5,7,10,11,12时,j=1999

1983<=j<=1994 &&(i=2,6,8)时,i=3 

1996<=j<=2007 && (i=2,6,8)时,i=9 
j=1995 &&(h>i+2 || h=i)时, i=6 

g=j
f=i
e=h

分析下面的函数,其中的i2代表月份,当月份为2,并且注册码最后六位是m[6],也就是11to13时,函数返回值是63,远大于34,这里可以排除a[6]。
图片描述

 

我分析了一下,当月份为2时,年份只能是1995,日期只能是1或者3,这样的话序列号是这样的:

19950201xxxxxx
19950203xxxxxx

根据d[(year-1900)%60]+c[month-1]+b[day-1]+a[?] = 34分别计算上面的两个序列号

19950201xxxxxx -> d[35]+c[1]+b[0]+a[?]=9+7+5+?=34
19950203xxxxxx -> d[35]+c[1]+b[2]+a[?]=9+7+8+?=34

a[?]= 13或者10,数组中没有一个等于13,只有a[3]和a[6]=10,上面已经把a[6]排除了,所以必须是a[3],最后六位必须是m[3]。

 

所以序列号是1995020305to07


暴力破解

j: year     [1983-2007]
i: month    [1-12]
h: day      [1-31]

j = 1989||2004时,h=31
i = 1,4,5,7,10,11,12时,j=1999

1983<=j<=1994 &&(i=2,6,8)时,i=3 

1996<=j<=2007 && (i=2,6,8)时,i=9 
j=1995 &&(h>i+2 || h=i)时, i=6

通过下面的程序,找到满足上面条件的年月日

#include <stdio.h>
int main()
{
    int year, p_year;
    int month, p_month;
    int day,p_day;
    for(year=1983;year<=2007;year++)
    {
        p_year=year;
        for(month=1;month<=12;month++)
        {
            p_year=year;
            p_month=month;
            if((year == 1989)||(year == 2004))
            {
                p_day = day = 31;
                goto PRINTDATE;
            }
            for(day=1;day<=31;day++)
            {
                p_year=year;
                p_month=month;
                p_day=day;
                if((month==1)||(month==4)||(month==5)||(month==7)||(month==10)||(month==11)||(month==12))
                    p_year = 1999;
                if((year >= 1983)&&(year<=1994)&&((month==2)||(month==6)||(month==8)))
                    p_month = 3;
                if((year >= 1996)&&(year<=2007)&&((month==2)||(month==6)||(month==8)))
                    p_month = 9;
                if((year==1995)&&((day>month+2)||(day==month)))
                    p_month = 6;
PRINTDATE:
                printf("%04d%02d%02d\n", p_year, p_month, p_day);
            }
        }
    }
    return 0;
}

把得到的日期使用linux下的工具排序、去掉重复行:

./cracking | sort | uniq > file1.txt

使用下面的程序,找到满足d[(year-1900)%60]+c[month-1]+b[day-1]+a[?] = 34的所有序列号

#include <stdio.h>
int main()
{
    int a[] = { 16, 6, 7, 10, 9, 16, 10, 8, 8, 9, 6, 6 };
    int b[] = { 5, 10, 8, 15, 16, 15, 8, 16, 8, 16, 9, 17, 8, 17, 10, 8, 9, 18, 5, 15, 10, 9, 8, 9, 15, 18, 7, 8, 16, 6 };
    int c[] = { 6, 7, 18, 9, 5, 16, 9, 15, 18, 8, 9, 5 };
    int d[] = { 7, 7, 9, 12, 8, 7, 13, 5, 14, 5, 9, 17, 5, 7, 12, 8, 8, 6, 19, 6, 8, 16, 10, 6, 12, 9, 6, 7, 12, 5, 9, 8, 7, 8, 15, 9, 16, 8, 8, 19, 12, 6, 8, 7, 5, 15, 6, 16, 15, 7, 9, 12, 10, 7, 15, 6, 5, 14, 14, 9 };
    char *m[12] = { "23to01", "01to03", "03to05", "05to07", "07to09", "09to11", "11to13", "13to15", "15to17", "17to19", "19to21", "21to23" };


    int year, month, day, series;
    for(year=23;year<=47;year++)
    {
        for(month=0;month<=11;month++)
        {
            for(day=0;day<=30;day++)
            {
                for(series=0;series<=11;series++)
                {
                    if(d[year]+c[month]+b[day]+a[series]==34)
                    {
                        printf("%04d%02d%02d%s\n", 1960+year, month+1,day+1, m[series]);
                    }
                }
            }
        }
    }
    return 0;
}

删除生成文件的后6位(vim很容易实现,也可以修改上面的程序,不打印m[series]),然后排序,去重,然后使用comm命令得到两个文件的相同行

$ comm -12 file1.txt file2.txt
19950203

[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

最后于 2018-12-11 07:56 被Explorerl编辑 ,原因:
收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回