DASCTF X CBCTF 2023|无畏者先行

Misc

Justpainting

010打开压缩包,发现结尾多了五个?,猜测加密压缩包的密码是五位

爆破得到密码11452

打开得到一个python脚本和一张jbn.pth

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
import cv2


class JBN(nn.Module):
def __init__(self):
super(JBN, self).__init__()
self.main = nn.Sequential(
nn.Linear(100, 256),
nn.ReLU(),
nn.Linear(256, 512),
nn.ReLU(),
nn.Linear(512, 452 * 280),
nn.Tanh()
)

def forward(self, x):
img = self.main(x)
img = img.view(-1, 452, 280)
return img


def watch_flag(img):
flag = cv2.imread('./data/data/flag.png')
gray_image = cv2.cvtColor(flag, cv2.COLOR_BGR2GRAY)
flag_tensor = torch.from_numpy(np.array(gray_image))
flag_tensor = flag_tensor.unsqueeze(0).transpose(1, 2)
img_tensor = img
flag_tensor = flag_tensor.unsqueeze(0)
img_tensor = img_tensor.unsqueeze(0)
loss_fn = torch.nn.MSELoss()
loss = loss_fn(flag_tensor.float(), img_tensor)
return loss


jbn = JBN()
g_optimizer = torch.optim.Adam(jbn.parameters(), lr=0.001)
min_loss = float('inf')

for epoch in range(10):
random_noise = torch.randn(1, 100)
jbn_img = jbn(random_noise)
g_optimizer.zero_grad()
g_loss = watch_flag(jbn_img)
g_loss.backward()
g_optimizer.step()
with torch.no_grad():
if g_loss < min_loss:
min_loss = g_loss
torch.save(jbn.state_dict(), 'jbn.pth')

题目的意思很明确,根据源码和jbn.pth反向生成flag

chatgpt

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
41
42
43
44
45
import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
import cv2


class JBN(nn.Module):
def __init__(self):
super(JBN, self).__init__()
self.main = nn.Sequential(
nn.Linear(100, 256),
nn.ReLU(),
nn.Linear(256, 512),
nn.ReLU(),
nn.Linear(512, 452 * 280),
nn.Tanh()
)

def forward(self, x):
img = self.main(x)
img = img.view(-1, 452, 280)
return img


def generate_flag(jbn_model, output_path):
jbn = JBN()
jbn.load_state_dict(torch.load(jbn_model))
jbn.eval()

with torch.no_grad():
random_noise = torch.randn(1, 100)
generated_img = jbn(random_noise)
generated_img = generated_img.squeeze().numpy()
generated_img = (generated_img + 1) / 2 # 将图像像素值映射到0-1之间
generated_img = np.clip(generated_img, 0, 1) # 将像素值限制在0-1之间

plt.imshow(generated_img, cmap='gray')
plt.axis('off')
plt.savefig(output_path, bbox_inches='tight', pad_inches=0) # 保存生成的图像
plt.show()


generate_flag('jbn.pth', 'generated_flag.png')

1697858621475

justlisten

扫描汉信码hint.png,得到

1
2
length:189
0urS3cret

010打开this is our secret.bmp

1698146949289

9e97ba2a是oursecret的特征

使用oursecret对bmp文件进行提取,密码是0urS3cret

提取出一个haha.txt

1
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_}{-?!

应该是一个字典

用Audacity查看嘘.wav文件,看它的频谱图,得知它的频率为[800,900,1000,1100,1200,1300,1400,1500,1700,1800]以及它的每个频率变化的时间为0.1s,同时可以得知它的采样频率为44100

脚本读取wav文件的数据长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np
import wave
import scipy.fftpack as fftpack

SAMPLE_RATE = 44100
SAMPLE_TIME = 0.1
SAMPLE_NUM = int(SAMPLE_RATE * SAMPLE_TIME) #4410
LIST = [800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700]

with wave.open('嘘.wav', 'rb') as f: #读取为数组
wav_data = np.frombuffer(f.readframes(-1), dtype=np.int16)
N = len(wav_data) #获取数据长度

print (N) #1666980

a = (N/(44100*0.1))/189
print(a) #2.0

可以得知数据长度N=1666980,然后再a = (N/(44100*0.1))/42来计算每个字符占了多少时长为0.2s

处理一下数字信号,并根据分离出的字典来获取隐藏的数据

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
41
42
43
44
45
46
47
48
49
50
51
52
53
import numpy as np
import wave
import scipy.fftpack as fftpack

SAMPLE_RATE = 44100
SAMPLE_TIME = 0.1
SAMPLE_NUM = int(SAMPLE_RATE * SAMPLE_TIME) #4410
LIST = [800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700]


# 傅里叶变换
def fft(data):
N = len(data) #获取数据长度
fft_data = fftpack.fft(data) #得到频域信号
abs_fft = np.abs(fft_data) #计算幅值
abs_fft = abs_fft/(N/2)
half_fft = abs_fft[range(N//2)] #取频域信号的前半部分

return half_fft


def dec_100ms(wave_data_100_ms): #解码100毫秒的音频数据
fft_ret = fft(wave_data_100_ms)
for index, freq in enumerate(LIST):
if np.max(fft_ret[int(freq*SAMPLE_TIME) - 2 : int(freq*SAMPLE_TIME) + 2]) > 0.8:
print(freq, 'Hz有值')
return index


def dec_sentence(wav_data): #解码整个句子
_100ms_count = len(wav_data) // SAMPLE_NUM
print('待解码音频包含', _100ms_count // 2, '个字')

ret = ''
for i in range(0, _100ms_count, 2):
index = 0
for k in range(2):
index = index*10 + dec_100ms(wav_data[i*SAMPLE_NUM + k*SAMPLE_NUM : i*SAMPLE_NUM + (k+1)*SAMPLE_NUM])

print('序号:', index)
ret += string[index]

return ret

if __name__ == '__main__':

with open('haha.txt', 'r', encoding='utf8') as f:
string = f.read()

with wave.open('嘘.wav', 'rb') as f: #读取为数组
wav_data = np.frombuffer(f.readframes(-1), dtype=np.int16)

print(dec_sentence(wav_data))

运行得到flag

1698147763017

NoPasswd

打开doc文件发现加密

查看属性发现宏孩儿和60290f0225011a72697f420d1f4e402778231b

image-20231025162148326

1
2
3
4
5
6
7
oleid:分析OLE文件以检测通常在恶意文件中发现的特定特征。
olevba:从MS Office文档(OLE和OpenXML)中提取和分析VBA Macro源代码。
MacroRaptor:检测恶意的VBA宏
msodde:检测并从MS Office文档,RTF和CSV中提取DDE / DDEAUTO链接
pyxswf:检测,提取和分析可能嵌入在MS Office文档(例如Word,Excel)和RTF等文件中的Flash对象(SWF),这对于恶意软件分析特别有用。
oleobj:从OLE文件中提取嵌入式对象。
rtfobj:从RTF文件中提取嵌入式对象。
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
41
42
43
Sub XOREncryptFile()
Dim numbers(8) As Integer

numbers(0) = 19
numbers(1) = 71
numbers(2) = 122
numbers(3) = 99
numbers(4) = 65
numbers(5) = 111
numbers(6) = 43
numbers(7) = 67


Dim CurrentDirectory As String
CurrentDirectory = ".\"

If Dir(CurrentDirectory & "abc") = "" Then
Exit Sub
End If

Dim FileNumber As Integer
FileNumber = FreeFile
Open CurrentDirectory & "abc" For Binary Access Read Write As #FileNumber

Dim FileContent As String
FileContent = Input$(LOF(FileNumber), #FileNumber)

Close #FileNumber

Dim EncryptedContent As String

For i = 1 To Len(FileContent)
EncryptedContent = EncryptedContent & Chr(Asc(Mid(FileContent, i, 1)) Xor numbers((i - 1) Mod 8))
Next i

FileNumber = FreeFile
Open CurrentDirectory & "enc" For Binary Access Write As #FileNumber

Put #FileNumber, , EncryptedContent

Close #FileNumber

End Sub

分析一下可以知道就是简单的异或,enc应该就是备注中的16进制字符串,写个脚本解密一下可以得到doc的密码,解开doc可以发现base64字符串,解码一下可知是zip文件

1
2
3
4
5
6
7
8
9
10
11
from Crypto.Util.number import *

enc = long_to_bytes(0x60290f0225011a72697f420d1f4e402778231b)
key = [19,71,122,99,65,111,43,67]

abc = ""

for i in range(len(enc)):
abc += chr(enc[i] ^ key[i%8])

print(abc)

解密得到一堆文字,可能是base64,cyberchef解密发现是zip,导出压缩包发现是伪加密

1698223285560

1698223316727

解压缩发现报png文件格式错误,说明压缩包里的是png,我们看看变量的数据

发现文件名应该是flag.png一共8个字节,但是变量那边的name长度只有4个字节,所以我们要改成8个字节

1698223501672

flag

SecretZip

题目给了一个key文件,以及一个加密的zip,key文件内其实是压缩包明文压缩后的前半部分,因此压缩包虽然不是store的压缩模式,也能进行已知部分明文攻击

1
bkcrack -C purezip.zip -c 'secret key.zip' -p key

1698224924831

1
e63af7cc 55ef839d dc10b922

解密的数据可能会被压缩,具体取决于创建 zip 文件时是否使用压缩。如果使用 deflate 压缩,则tools可以使用文件夹中提供的 Python 3 脚本来解压缩数据。

1
2
bkcrack -C purezip.zip -c 'secret key.zip' -k e63af7cc 55ef839d dc10b922  -d 01_deflate
python3 inflate.py < 01_deflate > 01.zip

1698245516530

01.zip在010查看发现提示密码是2字节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import zipfile
import libnum
from tqdm import trange

for i in trange(256):
for j in range(256):
fz = zipfile.ZipFile('01.zip', 'r')
password = libnum.n2s(i) + libnum.n2s(j)
try:
fz.extractall(pwd=password)
print(password)
fz.close()
break
except:
fz.close()
continue
else:
continue
break

1698245671552

解压出一个secret key.txt,里面内容e48d3828 5b7223cc 71851fb0

同时在zpaq文件的文件尾得到提示the password is md5(the plaintext of the secret key which length is 3 bytes)

因此要还原pkzip的三段秘钥,但是发现bkcrack自带了秘钥还原的接口

1698247609404

1698247531170

1
bb9cceb294113270da5eaed47a545f55

解压得到flag


DASCTF X CBCTF 2023|无畏者先行
http://example.com/2023/10/23/DASCTF_X_CBCTF2023__无畏者先行/
作者
Whhxy4
发布于
2023年10月23日
许可协议