starctf2021

学到了使用sage在一个有限域内求一个矩阵的逆矩阵,也就是hill加密。

其次是对写dfs更熟悉了,且对python3读写文件“wb”与“w”模式理解的更加深入。

最后就是多线程爆破体验极好😂。

stream

开始关键点都没找到,运行了一下程序从报错信息经过搜索知道了这是个rust写程序,且这个错误信息是编写的时候可以定义的,从这也顺藤摸瓜的知道了报错是因为没有flag文件。

程序首先读取flag文件取数据,经过加密后写入output文件。

image-20210127134521754

然后简单分析一下,逻辑什么的很清楚,按照一定的顺序对每一位进行异或加密,但是那个异或的值是随机的,通过前面的数据来初始化的数据流。是一种流密码,但这里想了很久但是不知道怎么逆,后面想到按照题目加密的顺序一位一位的穷举肯定可以,,但是工程量就有点大了。。

最后才想到了python脚本,花了点时间,也改了很多,还有就是这个存在多对一的情况,所以要搜索。。

其次开始怎么也跑不出来,后面调试才发现,程序每次读取的字符都加了回车(’\0xa’),这就导致长度增加,而加密是用到了长度的。。然后就是为什么呢?

最后大量尝试搜索才发现,因为我开始是往flag文件手动输入的,然后脚本里也是先读取flag文件,这就导致开始就多了和一个’\0xa’,而后在写入也是同样有‘\0xa’。其次python2的‘rb’与‘r’模式读取都是str类型,而python3的‘rb’是byte, ‘r’才是str类型。且python若是‘wb’写入那写入数据必须是byte类型,而python2就都可以。

这里执行程序,有3种办法:

10s就得到了结果:

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
import os
import datetime
import pexpect
import subprocess

startTime = datetime.datetime.now()

with open("output_flag", 'rb') as f:
enc = f.read()
f.close()

index = [4, 11, 18, 25, 32, 39, 0, 7, 14, 21, 28, 35, 42, 3, 10, 17, 24, 31, 38, 45, 6, 13, 20, 27, 34, 41, 2, 9, 16, 23, 30, 37, 44, 5, 12, 19, 26, 33, 40, 1, 8, 15, 22, 29, 36, 43]
base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/{}_=-~!.@#%^&*()"
result = ['1']*46

def dfs(i):
if i > 45:
print('find one:' + ''.join(result))
return 0

for ch in base:
result[index[i]] = ch
flag = ''.join(result)
with open('flag', 'wb') as f:
f.write(flag.encode())
f.close()
#r = pexpect.spawn('./a')
#r.wait()
os.system('./a')
with open('output', 'rb') as f:
ans = f.read()
f.close()
if ans[index[i]] == enc[index[i]]:
print(flag)
dfs(i+1)
else:
continue
dfs(0)
endTime = datetime.datetime.now()
print("运行的时间是:%ss" % (endTime - startTime).seconds)

ChineseGame

读懂游戏怎么玩的后,手动弄了几个数据然后总结规律。

一个长度为10的链表,最后把所有的数据域都变成大于100。

image-20210127135918158

就是不断累加套上去就是了。

赛后看大家很多都是发现了只要那个数据域是0就像向上,1的话就向下,直接paython脚本,真是好。。。

wherekey

就是这个题因为z3没有解,以为我哪里弄错了郁闷半天,最后也没有把题目做出来。

由矩阵的乘法可知,这里算法实际就是用一个固定的5*5矩阵去乘flag组成的5*5矩阵,但是每次都mod了257,所以在一个有限域内。

然后其实可以爆破的,我看爆破的人也挺多的,hhha。。

这里我算了一下,如果常规写5个for循环爆破时间不会少的。。

但是用pwntools的多线程爆破,最多2个多小时就搞定了,也还是可以的。hhh。Crypto常用工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import pwnlib
from pwnlib.util.iters import mbruteforce

base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/{}_=-~!.@#%^&*()"
enc = [56, 109, 75, 75, 185, 138, 249, 138, 187, 92,
138, 154, 186, 107, 210, 198, 187, 5, 144, 86,
147, 230, 18, 189, 79]
b = "flag{are_you_sure_friend}"
b = list(map(ord, b))
enc = enc[5:]

def check(a):
a = list(map(ord, a))
for i in range(5):
#a = list(map(ord, a)) 很无脑的错误,不能放在这里的原因:因为如果已经转换了一次了,那就已经是int型,下一次转换就出错了。
if ((a[0]*b[i] + a[1]*b[5+i] + a[2]*b[10+i] + a[3]*b[15+i] + a[4]*b[20+i])%257) != enc[i]:
return False
return True

ans = mbruteforce(check, base, 5, method='fixed')

最后贴一下官方放的使用sage求解,也就是带余的矩阵乘法和逆矩阵。

1
2
3
4
5
6
A = Matrix(GF(257),[[102, 108, 97, 103, 123], [97, 114, 101, 95, 121], [111, 117, 95, 115, 117], [114, 101, 95, 102, 114], [105, 101, 110, 100, 125]])

encode = Matrix(GF(257),[[56, 109, 75,75,185], [138 ,249, 138, 187, 92],[138, 154 ,186, 107, 210],[198, 187, 5, 144, 86],[147, 230, 18, 189, 79]])

flag = encode*A.inverse()
print(flag)

这个找个在线网站解一下就好:sage在线求解

image-20210127153009965

Favourite Architecture flag0

有ghidra9.2就很简单了,查查riscv相关的指令,实在不好理解的方式调试也行。

前半段流加密,只要最后得到最后的异或值就好了。后半段一个tea加密。

这里贴下tea吧:

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
#include <stdio.h>

char key[] = {0xbb, 0xa0, 0x68, 0x13, 0x1e, 0xce, 0x0a, 0x19
, 0x57, 0xa3, 0xd8, 0x35, 0x61, 0x2c, 0xbf, 0x26};

char enc[] = {0xf9, 0x87, 0x50, 0xc4, 0xb2, 0xf2, 0x03, 0x07
, 0x3c, 0xf4, 0x74, 0x69, 0x59, 0xbb, 0xb4, 0xed
, 0x2a, 0xb0, 0xf0, 0x0f, 0xf2, 0x20, 0x85, 0x00
, 0xdd, 0x23, 0xcd, 0xfd, 0x75, 0x48, 0x02, 0x35
, 0xd3, 0xb6, 0xd7, 0xf1, 0xe1, 0x1b, 0xf2, 0x74
, 0x12, 0xbf, 0x2d, 0xcb, 0xf6, 0x53, 0xb4, 0xa4};

//(*((unsigned int *)(enc+8*i)) >> 5)+*((unsigned int *)key+3)^delat+*((unsigned int *)(enc+8*i))*(*((unsigned int *)(enc+8*i)))^0x10+*((unsigned int *)key+2)
int main(void)
{
int i = 0, j = 0;

for(i = 0; i < 6; i++)
{
int delat = 3816266640;
for(j = 0; j < 16; j++)
{
*(((unsigned int *)(enc+8*i))+1) -= (*((unsigned int *)(enc+8*i)) >> 5) + *(((unsigned int *)key)+3)^delat+ *(((unsigned int *)(enc+8*i)))^(*((unsigned int *)(enc+8*i)))*0x10 + *(((unsigned int *)key)+2);
*(((unsigned int *)(enc+8*i))) -= (*(((unsigned int *)(enc+8*i)+1)) >> 5) + *(((unsigned int *)key)+1)^delat+ *(((unsigned int *)(enc+8*i))+1)^(*(((unsigned int *)(enc+8*i))+1))*0x10 + *(((unsigned int *)key)+0);
delat += 0x61c88647;
}
}

for(i = 0; i < 0x30; i++)
{
printf("%c", enc[i]);
}

}
-------------本文结束感谢您的阅读-------------