justpaint
(DASCTF X CBCTF 10月月赛)FLAG被我弄丢了>_<不过,JBN应该记得,或许你能从他那得到一些线索。
链接:https://pan.baidu.com/s/19Iymf2mwak1PtSPyJGjZYg?pwd=DASC 提取码:DASC —来自百度网盘超级会员V5的分享
ai题,附件包括train.py和jbn.pth,train.py文件内容如下:
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)通过接受随机噪声作为输入生成图像,并通过watch_flag函数计算生成图像与flag图像之间的均方误差损失,将损失最小的模型保存至jbn.pth
所以我们只要将jbn.pth重新生成回img图像即可得到flag图像
exp.py如下:
import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt
import cv2
# 定义JBN模型
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
# 加载JBN模型
jbn = JBN()
jbn.load_state_dict(torch.load('jbn.pth'))
jbn.eval() # 设置模型为评估模式,不进行梯度计算
# 生成随机噪声
random_noise = torch.randn(1, 100)
# 使用生成器生成图像
with torch.no_grad():
generated_img = jbn(random_noise)
# 转换为numpy数组
generated_img_np = generated_img.squeeze().cpu().numpy()
# 保存生成的图像为文件
cv2.imwrite('generated_image.png', generated_img_np * 255.0) # 乘以255以还原到0-255的范围
print("Generated image saved as generated_image.png")
运行后得到generated_image.png
上下旋转、左右镜像后得到flag
彩蛋
Q1:什么是epoch?
一个epoch表示训练集被模型完整训练过一次,包含以下四个步骤:
①前向传播:将训练集样本输入模型中,计算得到模型输出
②计算损失:计算模型输出和真实标签之间的损失
③反向传播:根据损失计算梯度,并将梯度传播回模型的参数
④参数更新:使用优化算法更新模型的参数,以减少损失
在justpaint中,
for epoch in range(10):
表示该训练过程经历了10次epoch,每次训练过程都循环生成随机噪声->通过JBN生成图像->计算损失->反向传播->更新JBN参数的步骤
Q2:什么是学习率?
学习率是优化算法中的一个超参数(AI中的参数自动生成,超参数则需手动控制),控制每次参数更新的步长,在justpaint中,
g_optimizer = torch.optim.Adam(jbn.parameters(), lr=0.001)
参数通过Adam优化器,以0.001的学习率进行调整
IceTea
(DAS X 0psu3 11月月赛)小黑喜欢喝冰红茶,被出题人发现后每天都说他喝屌丝饮料,结果小黑发现出题人也喝冰红茶,然后就往出题人的冰红茶里加了点料。
流量包题,首先按时间顺序追踪第一个HTTP流,发现一串Hex加密后的密文(黑色括号起始)
遂拖入CyberChef解密,得到一个elf文件,导出
导出后拖入IDA,发现存在upx加壳,用ExeinfoPE也发现有upx壳,于是进行机脱,再次拖入IDA后Shift+F12得到base64表(最下面一行)
按时间顺序追踪第三个HTTP流,发现一串base64加密后的密文,解密后得到一串指令
cd “/www/wwwroot/DAS202310.com”;./ezbase e flag.txt IceTea.txt;echo 27d667b0c949;pwd;echo f0e52b6ed
(每个HTTP流内容前URL解码后得到cmd=@eval(@base64_decode($_POST[‘k59c2ae7730483’])),判断可能是蚁剑流量包,而蚁剑流量base64解密前要舍弃前两位字符)
可见在/www/wwwroot/DAS202310.com目录下通过ezbase将flag.txt加密成了IceTea.txt
接下来追踪第四个HTTP流,同样发现一串base64加密后的密文并与第三个HTTP流中发现的相似,解密后得到另一串指令
cd “/www/wwwroot/DAS202310.com”;cat IceTea.txt;echo 27d667b0c949;pwd;echo f0e52b6ed
可见在/www/wwwroot/DAS202310.com目录下打开了IceTea.txt,从第三个HTTP流中我们知道IceTea.txt是flag.txt加密后的密文
看一下Response部分对应的明文
得到reftqRrg4QB9zvZQzwf50xn51CZQxSf51gZPzxj5zhjF1CI75qE=应该是ezbase加密后的IceTea.txt内容
用第一个HTTP流中得到的base64表解密,得到flag
彩蛋
如果你像我一样蠢,对第一个流量包进行Hex解密时把不是Hex密文的内容也复制进CyberChef的话,你会得到一个IDA检测得出upx壳、ExeinfoPE也检测得出upx壳、但脱壳工具坚持认为加的不是upx壳的elf