-
-
[原创][看雪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编辑
,原因:
赞赏
他的文章
看原图