4.22周赛
Reverse
你会解方程组不会?
主函数,输入v4,先异或加密,然后v1加密,进入v1函数,很清晰是解方程
写解题代码会用到pyth的z3模块 z3学习,以及python中右移与左移 【Python位运算】——左移操作(<<)右移操作>>,Python for i in range ()用法详解,
左移操作,左移一位相当于乘以b,a<<b,a’ = a*(2^b)
右移操作,右移一位相当于除以b,a<<b,a’ = a//(2^b)注意这里是整除,当向右移动位数大于能移动的位数时,置为0【可以理解为会将尾巴截掉】
直接复制v1的伪代码,然后进行修改,成为解方程代码,写代码是要注意根据v1伪代码调整数组顺序在异或解密。
v2 = a1[2];
v3 = a1[1];
v4 = *a1;//v4 = a1[0]
v5 = a1[3];
v6 = a1[4];
v7 = a1[5];
v8 = a1[6];
v9 = a1[7];
v10 = a1[9];
v11 = a1[8];
v12 = a1[10];
v13 = a1[11];
v14 = a1[12];
v15 = a1[13];
from z3 import *
v2 = Int('a2')
v3 = Int('a3')
v4 = Int('a4')
v5 = Int('a5')
v6 = Int('a6')
v7 = Int('a7')
v8 = Int('a8')
v9 = Int('a9')
v10 = Int('a10')
v11 = Int('a11')
v12 = Int('a12')
v13 = Int('a13')
v14 = Int('a14')
v15 = Int('a15')
s = Solver()
s.add(15 * v11
+ -36 * v10
+ 13 * v9
+ 25 * v8
+ 43 * v6
+ 65 * v4
+ 88 * v2
+ 67 * v3
- 5 * v5
+ 89 * v7
+ 11 * v12
+ 47 * v13
- 60 * v14
+ 29 * v15 == 22748,
-41 * v13
+ 2 * v12
+ 8 * v11
+ 7 * v3
+ 89 * v2
+ 12 * v4
- 25 * v5
+ 41 * v6
+ 23 * v7
+ 20 * v8
- 66 * v9
+ 31 * v10
- 39 * v14
+ 17 * v15 == 7258,
-34 * v14
+ 90 * v13
+ 101 * v12
+ -33 * v10
+ 15 * v9
+ 27 * v8
+ 53 * v6
+ 35 * v3
+ 28 * v2
+ 16 * v4
- 65 * v5
+ 39 * v7
+ 13 * v11
+ 23 * v15 == 26190,
(v9 * 128)
+ 81 * v7
+ -59 * v5
+ 35 * v4
+ 34 * v3
+ 23 * v2
+ 49 * v6
+ 25 * v8
- 32 * v10
+ 75 * v11
+ 81 * v12
+ 47 * v13
- 60 * v14
+ 29 * v15 == 37136,
90 * v8
+ 79 * v7
+ 42 * v6
+ -52 * v5
+ 35 * v4
+ 97 * v3
+ 38 * v2
+ 23 * v9
- 36 * v10
+ 57 * v11
+ 81 * v12
+ 42 * v13
- 62 * v14
- 11 * v15 == 27915,
-61 * v14
+ 41 * v12
+ -26 * v10
+ 49 * v7
+ 47 * v6
+ -45 * v5
+ 35 * v4
+ 22 * v2
+ 27 * v3
+ 29 * v8
+ 18 * v9
+ 35 * v11
+ 40 * v13
+ 28 * v15 == 17298,
43 * v13
+ 76 * v12
+ 34 * v11
+ -47 * v10
+ 85 * v9
+ 23 * v8
+ 86 * v7
+ -42 * v6
+ 45 * v3
+ 12 * v2
+ 35 * v4
- 9 * v5
- 44 * v14
+ 65 * v15 == 19875,
57 * v13
+ 25 * v11
+ -30 * v10
+ 86 * v8
+ 79 * v7
+ 35 * v4
+ 62 * v3
+ 79 * v2
- 85 * v5
+ 33 * v6
+ 14 * v9
+ 11 * v12
- 50 * v14
- 9 * v15 == 22784,
47 * v13
+ 2 * v12
+ -36 * v10
+ 2 * v8
+ 29 * v7
+ (v4 * 64)
+ 8 * v2
+ 6 * v3
- 85 * v5
+ 73 * v6
+ 23 * v9
+ 5 * v11
- (v14 * 64)
+ 27 * v15 == 9710,
41 * v12
+ -38 * v10
+ -51 * v5
+ 68 * v4
+ -68 * v3
+ 67 * v2
- 43 * v6
+ 81 * v7
+ 22 * v8
- 12 * v9
+ 75 * v11
+ 27 * v13
- 52 * v14
+ 31 * v15 == 13376,
-67 * v14
+ 31 * v12
+ 15 * v9
+ -51 * v5
+ 63 * v3
+ 85 * v2
+ 5 * v4
+ 44 * v6
+ 36 * v7
+ 28 * v8
- 6 * v10
+ 45 * v11
+ 7 * v13
+ 78 * v15 == 24065,
43 * v13
+ -35 * v10
+ 25 * v8
+ 43 * v6
+ 47 * v2
+ (v3 * 64)
+ 66 * v4
- 5 * v5
+ 112 * v7
+ 13 * v9
+ 95 * v11
+ 21 * v12
- 61 * v14
+ 20 * v15 == 27687,
-61 * v14
+ 47 * v13
+ 89 * v12
+ 14 * v11
+ -92 * v10
+ 56 * v9
+ 23 * v8
+ 89 * v7
+ 49 * v6
+ -25 * v5
+ 85 * v4
+ 67 * v3
+ 89 * v2
- 29 * v15 == 29250,
-60 * v14
+ 51 * v12
+ 16 * v11
+ 12 * v9
+ 25 * v8
+ -43 * v6
+ 34 * v3
+ 95 * v2
+ 62 * v4
- 9 * v5
+ 83 * v7
- 36 * v10
+ 47 * v13
- 24 * v15 == 15317)
if 'un' not in str(s.check()):
print(s.model())
flag = [10, 24, 119, 7, 104, 43, 28, 91, 108, 52, 88, 74, 88, 33, 0]
for i in range(13,-1,-1):
flag[i] ^= flag[i+1]
flag_str = ''
for i in range(14):
flag_str += chr(flag[i])
print(flag_str)
easyre
./malloc函数描述
C 库函数 void *malloc(size_t size) 分配所需的内存空间,并返回一个指向它的指针。
./声明
下面是 malloc() 函数的声明。
void *malloc(size_t size)
./参数
- size – 内存块的大小,以字节为单位。
返回值
该函数返回一个指针 ,指向已分配大小的内存。如果请求失败,则返回 NULL。
main函数,flag长度为32,前八位进行fun1处理,中间9位进行fun2处理,后16位进行fun3处理
_main(argc, argv, envp);
*(_QWORD *)v5 = 0i64;
v6 = 0i64;
puts("please input your flag:");
scanf("%s", Str);
if ( strlen(Str) == 32 )
{
for ( i = 0; i <= 7; ++i )
v4[i] = Str[i];
v4[8] = 0;
fun1(v4, 8i64, Str1);
Str2 = "f7fae20f2f0b7facff1281fdd1e8fdf6d14cd4c1";
if ( !strcmp(Str1, "f7fae20f2f0b7facff1281fdd1e8fdf6d14cd4c1") )
{
for ( j = 0; j <= 8; ++j )
v8[j] = Str[j + 8];
v8[9] = 0;
fun2(v8, v7);
v13 = "JBUWED{WK";
if ( !strcmp(v7, "JBUWED{WK") )
{
for ( k = 0; k <= 15; ++k )
v5[k] = Str[k + 17];
v12 = fun3(v5, 15);
v11 = "WPrYVgNoQx6vTPNuU8e!";
if ( !strcmp(v12, "WPrYVgNoQx6vTPNuU8e!") )
{
printf("you are so good!");
free(v12);
return 0;
}
else
{
printf("wrong3!");
return 1;
}
}
else
{
printf("wrong2!");
return 1;
}
}
else
{
printf("wrong1!");
return 1;
}
}
else
{
puts("Error!");
return 1;
}
}
进入fun1函数,根据初始函数判断fun1为sha1加密 sha1加密原理
v5[0] = 1732584193;
v5[1] = -271733879;
v5[2] = -1732584194;
v5[3] = 271733878;
v5[4] = -1009589776;//v5[0] = 0x67452301;
//v5[1] = 0xEFCDAB89;
//v5[2] = 0x98BADCFE;
//v5[3] = 0x10325476;
//v5[4] = 0xC3D2E1F0;
for ( Size = a2; Size > 0x3F; Size -= 64 )
{
v3 = a2 - Size;
*(_QWORD *)v6 = *(_QWORD *)&a1[v3];
*(_QWORD *)&v6[8] = *(_QWORD *)&a1[v3 + 8];
*(_QWORD *)&v6[16] = *(_QWORD *)&a1[v3 + 16];
*(_QWORD *)&v6[24] = *(_QWORD *)&a1[v3 + 24];
*(_QWORD *)&v6[32] = *(_QWORD *)&a1[v3 + 32];
*(_QWORD *)&v6[40] = *(_QWORD *)&a1[v3 + 40];
*(_QWORD *)&v6[48] = *(_QWORD *)&a1[v3 + 48];
*(_QWORD *)&v6[56] = *(_QWORD *)&a1[v3 + 56];
round(v6, v5);
}
if ( Size <= 0x37 )
{
memset(v6, 0, '@');
memcpy(v6, &a1[a2 - Size], Size);
v6[Size] = 128;
for ( Size_4 = '8'; Size_4 <= '?'; ++Size_4 )
v6[Size_4] = (8 * a2) >> (8 * (63 - (unsigned __int8)Size_4));
}
else
{
memset(v6, 0, '@');
memcpy(v6, &a1[a2 - Size], Size);
v6[Size] = 128;
round(v6, v5);
memset(v6, 0, '@');
for ( Size_4 = 56; Size_4 <= 0x3F; ++Size_4 )
v6[Size_4] = (8 * a2) >> (8 * (63 - (unsigned __int8)Size_4));
}
result = round(v6, v5);
for ( Size_4 = 0; Size_4 <= 0x13; ++Size_4 )
{
v7 = (unsigned __int8)(v5[Size_4 >> 2] >> (8 * (~(_BYTE)Size_4 & 3)));
result = sprintf(&a3[2 * Size_4], "%02x", v7);
}
return result;
}
我们知道flag的格式是SLsec{xxxxx},总共八位,已知6位,所以可以爆破出来前八位
import hashlib
known_prefix = "SLsec{"
known_hash = "f7fae20f2f0b7facff1281fdd1e8fdf6d14cd4c1"
\# 枚举后两位字符
for i in range(256):
for j in range(256):
candidate = known_prefix + chr(i) + chr(j)
candidate_hash = hashlib.sha1(candidate.encode()).hexdigest()
if candidate_hash == known_hash:
print("Found the original string: ", candidate)
exit()
进入fun2函数,简单的异或加密
v3 = strlen(a1);
for ( i = 0i64; i < v3; ++i )
a2[i] = (a1[i] ^ 0x66) + 66;
result = &a2[v3];
a2[v3] = 0;
return result;
暴力破解
v3 = 'JBUWED{WK'
s = len(v3)
flag = ''
for i in range(0,len(v3)):
for x in range(0,128): # 这里用暴力求解
temp = (x ^ 0x66) + 66
# print(text1[i]+" "+chr(temp)+" "+chr(x))
if v3[i] == chr(temp):
flag = flag + chr(x)
break
print(flag)
进入fun3函数,应该是base64换了个表。
strcpy(v8, "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz+/@!#$");
v10 = 4 * ((a2 + 2) / 3);
v9 = malloc(v10 + 1);
if ( !v9 )
return 0i64;
i = 0;
v11 = 0;
while ( i < a2 )
{
v9[v11] = v8[a1[i] >> 2];
if ( a2 <= i + 1 )
v3 = 0;
else
v3 = a1[i + 1] >> 4;
v9[v11 + 1] = v8[(16 * a1[i]) & 0x30 | v3];
if ( a2 <= i + 1 )
{
v5 = 0;
}
else
{
if ( a2 <= i + 2 )
v4 = 0;
else
v4 = a1[i + 2] >> 6;
v5 = (4 * a1[i + 1]) & 0x3C | v4;
}
v9[v11 + 2] = v8[v5];
if ( a2 <= i + 2 )
v6 = 0;
else
v6 = a1[i + 2] & 0x3F;
v9[v11 + 3] = v8[v6];
i += 3;
v11 += 4;
}
for ( i = a2; i % 3; ++i )
{
v7 = v11++;
v9[v7] = 61;
}
v9[v11] = 0;
return v9;
}
解密代码
import base64
import string
str1 = "WPrYVgNoQx6vTPNuU8e!"
string1 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz+/@!#$"
string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
print (base64.b64decode(str1.translate(str.maketrans(string1,string2))))
Misc
WLAN里有👁
pcpang用wireshark打开,出现报错窗口(捕获文件似乎已损坏或损坏。
(pcapng:总块长度(第一个 408 和第二个 1536)不匹配))
试试修复(现在知道了修不修复都一样)pcapng修复网站
直接放进010里面,搜索slsec,找到了flag。我只能说这题很坑,从pcapng提取图片没有什么用,是一个陷阱。
好玩的时间戳
这题看着挺蒙。因为不知道什么是时间戳 时间戳转换网站
在百度的时候看到了一篇关于ctf时间戳的文章 实验吧-杂项-MD5之守株待兔(时间戳&python时间戳函数time.time())
打开flag文件发现里面有9个txt,查看文件属性,发现创建时间比较奇怪,属于超时空了是
结合题目和提示,两者相减就是116,代表的ascii码就是t
剩下的同理,最终得到t1mest@m9。