DASCTF July X CBCTF Misc
问卷题
- 懂得都懂,不懂也得懂
red_vs_blue
- 尝试几次之后发现错误之后重试的话,之前的结果是固定的,即每一轮的结果不会变,所以只需要试错来得到正确的结果即可
from pwn import *
context.log_level = 'debug'
num = 0
p = remote('node4.buuoj.cn',27291)
resultsList = ['r' for res in range(66)]
while 1:
p.recvuntil('choose one [r] Red Team,[b] Blue Team:\n')
while 1:
p.sendline(resultsList[num])
choice = p.recvline()
result = p.recvline()
if choice[-9:] == result[-9:]:
num += 1
if num == 66:
print(p.recvline())
print(p.recvline())
print(p.recvline())
print(p.recvline())
break
else:
p.recvuntil('choose one [r] Red Team,[b] Blue Team:\n')
else:
resultsList[num] = 'b'
num = 0
p.sendline('y')
break
funny_maze
- 类似于最短路径算法的求解,这里参考官方给出的题解代码
import re
import sys
from pwn import *
context.log_level = 'debug'
sys.setrecursionlimit(10000)
class Point:
def __init__(self, x, y, _):
self.x = x
self.y = y
self._ = _
self.sum = 0
self.next = [x, x, x, x]
self.next[0] = -1, -1
self.next[1] = -1, -1
self.next[2] = -1, -1
self.next[3] = -1, -1
self.next_list = [-1, -1, -1, -1]
# 记录相邻点的相关数据
def join(self, x, y, s, e, w):
if self._ == s or self._ == e or self._ == w:
if x == self.x + 1 and y == self.y:
self.next_list[self.sum] = 0
self.next[0] = x, y
self.sum += 1
return 1
if x == self.x - 1 and y == self.y:
self.next_list[self.sum] = 1
self.next[1] = x, y
self.sum += 1
return 1
if x == self.x and y == self.y - 1:
self.next_list[self.sum] = 2
self.next[2] = x, y
self.sum += 1
return 1
if x == self.x and y == self.y + 1:
self.next_list[self.sum] = 3
self.next[3] = x, y
self.sum += 1
return 1
return 0
def load(path, start, end, way):
x = 0
y = 0
startx = -1
starty = -1
endx = -1
endy = -1
mapy = []
for lines in path:
mapx = []
for c in lines:
mapx.append(Point(x, y, c))
if c == start or c == end or c == way:
if c == start:
startx = x
starty = y
if c == end:
endx = x
endy = y
if x > 0:
if mapx[x - 1].join(x, y, start, end, way) == 1:
mapx[x].join(x - 1, y, start, end, way)
if y > 0:
if mapy[y - 1][x].join(x, y, start, end, way) == 1:
mapx[x].join(x, y - 1, start, end, way)
x += 1
mapy.append(mapx)
x = 0
y += 1
return mapy, startx, starty, endx, endy
def re_find_the_way(x, y, MAP, map1, map2, end):
map1[y][x] = 1
if map2[y][x] == '#':
map2[y][x] = '.'
if MAP[y][x]._ == end:
lengh = 0
for m1 in map1:
for m2 in m1:
if m2 == 1:
lengh += 1
return map1, map2, lengh, 1
for i in range(MAP[y][x].sum):
xx, yy = MAP[y][x].next[MAP[y][x].next_list[i]]
if map1[yy][xx] == 0:
r1, r2, r3, r4 = re_find_the_way(xx, yy, MAP, map1, map2, end)
if r4 == 1:
return r1, r2, r3, r4
else:
map1[yy][xx] = 0
map2[yy][xx] = '#'
return map1, map2, 0, 0
def find_the_way(path, start, end, way):
MAP, startx, starty, endx, endy = load(path, start, end, way)
map1 = []
map2 = []
for y in MAP:
map1_ = []
map2_ = []
for x in y:
map1_.append(0)
map2_.append('#')
map1.append(map1_)
map2.append(map2_)
map2[starty][startx] = start
map2[endy][endx] = end
map1, map2, length, r4 = re_find_the_way(startx, starty, MAP, map1, map2, end)
return length
if __name__ == '__main__':
if len(sys.argv) != 4:
print("Usage: python exp.py ip port flag")
sys.exit()
p = remote(sys.argv[1], int(sys.argv[2]))
FLAG = sys.argv[3]
list1 = []
while 1:
a = p.recvuntil('Introduction to this game\n')
p.sendline('1')
while 1:
try:
p.recvuntil('#')
except:
while 1:
a = p.recvline().decode().strip('\n')
print(a)
if 'flag{' in a:
flag = re.findall('flag{(.*?)}', a)
if flag[0] == FLAG:
print('Pass!')
else:
print('AssertionError!')
sys.exit()
while 1:
a = p.recvline().decode().strip('\n')
print(a)
if a != '#' and a != 'S':
pass
if a != 'Please enter your answer:':
list1.append(a)
print(list1)
continue
else:
length = find_the_way(list1, 'S', 'E', ' ')
p.sendline(str(length))
print(length)
break
ezSteganography
- 的确是有手就行的题目,手撕论文的那种
- 题目名字已经提示是图片隐写了,由于是 png 格式的图片,用
zsteg
查看一下发现一张 png 图片,将其分离出来,得到前半部分 Flag,并且提示QIM
算法对后续解题是有帮助的,给出了step
的数值为20
非预期解
- 提取出
g0
和g1
异或也可以得到后半部分 Flag,其原因为步⻓为20
,其1/4
为5
,也就是⽔印会导致奇偶像素不同,所以可以异或出来
预期解
- 参考
QIM
算法实现提取的原理
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
def extract(delta, y):
out = []
for i in (delta / 2 - y % delta):
if i > 0:
out.append(1)
else:
out.append(0)
out = np.array(out)
return out
if __name__ == '__main__':
imagePath = r'C:\Users\95235\Downloads\ezSteganography-flag.png'
p = np.array(Image.open(imagePath))
R, G, B = p[:,:,0], p[:,:,1], p[:,:,2]
G = G.ravel()
te_out = extract(20, G)
plt.imshow(np.array(te_out).reshape(1440,2560))
plt.show()
Just a GIF
- 将 GIF 逐帧分开后将相同的图片分成一组,可以分为 11 个系列,然后系列中的图片与该系列第一张图片比较,新建一张 83x83 的空白图,把所有存在像素值不同的位置标记为黑色,即可得到隐藏的 11 张图片中的 1 张,剩下的以此类推即可
import os
from PIL import Image
from tqdm import tqdm
img = Image.open(r'C:\Users\95235\Downloads\gif\Just_a_GIF.gif')
os.mkdir(r'C:\Users\95235\Downloads\gif\png')
for i in range(img.n_frames):
img.seek(i)
new = Image.new('RGB', img.size)
new.paste(img)
new.save(r'C:\Users\95235\Downloads\gif\png\\' + str(i) + '.png')
os.mkdir(r'C:\Users\95235\Downloads\gif\flag')
path_1 = r'C:\Users\95235\Downloads\gif\flag\\'
path_2 = r'C:\Users\95235\Downloads\gif\png\\'
for i in tqdm(range(11)):
img = Image.open(path_2 + str(i) + '.png')
img_1 = Image.new('RGB', (83,83), (255,255,255))
for h in range(40):
im = Image.open(path_2 + str((h+1)*11+i) + '.png')
width, height = img.size
for j in range(0, width):
for k in range(0, height):
tmp = img.getpixel((j,k))
tmp_1 = im.getpixel((j,k))
if tmp != tmp_1:
img_1.putpixel((j,k), (0,0,0))
img_1.save(path_1 + str(i+1) + '.png')
- 将得到的九张带有二维码碎片的图片按照另两张图片标明的排布拼起来
from PIL import Image
a = [7, 1, 6, 9, 3, 4, 5, 2, 8]
f = Image.new("RGB", (83 * 3, 83 * 3))
for i in range(0, 3):
for j in range(0, 3):
path = r"C:\Users\95235\Downloads\gif\flag\\" + str(a[i + j * 3]) + ".png"
x = Image.open(path)
f.paste(x, (i * 83, j * 83))
f.save(r"C:\Users\95235\Downloads\gif\flag\flag.png")
- 用中国编码扫码就可以拿到 Flag 了,码制为
DATA_MATRIX
Nuclear wastewater
- 观察到二维码的颜色有点不同于寻常,提取出来看看,由于每个块都是 10*10 这里我们只提取每个块中第一个像素
from PIL import Image
img = Image.open(r"C:\Users\95235\Downloads\Nuclear_wastewater\key.png")
for y in range(img.size[1]):
list_pix = []
for x in range(img.size[0]):
if (y % 10 == 0 and x % 10 == 0):
list_pix.append(img.getpixel((x,y)))
if list_pix != []:
print(list_pix)
- 提取出来之后发现除了白色只有 RGB 中一个有值这一规律外并没有什么其他规律,将 RGB 分组也没有发现什么东西,尝试将颜色值转换成 ASCII 码后得到字符串 (不可打印字符不包括在内):
'Ys>UEJht#? ppeEFtstR#~:hi~tR:@s@YRteK#e@KsR&E&:eR:Eht/#iKtteYKhYKYhhhihhKtC2tt:HVEesY&#@Rj! seRi:eitEtKsetKtEE:hh#h#eYKYihhYK(Kt@iSY$KY/@pRsEetsip:~h@eeEs!E&&::EsEEei#/iYe# /ieKKt//iKYhh'
- 发现字符串内有很多重复的字符,统计词频后得到:
Counter({'t': 18, 'h': 17, 'e': 16, 'K': 15, 'E': 14, 'Y': 13, 'i': 12, 's': 11, ':': 10, '#': 9, 'R': 8, '@': 7, '/': 6, '&': 5, 'p': 4, '~': 3, '!': 2, '>': 1, 'U': 1, 'J': 1, '?': 1, 'F': 1, 'C': 1, '2': 1, 'H': 1, 'V': 1, 'j': 1, '(': 1, 'S': 1, '$': 1})
from PIL import Image
pic = Image.open(r'C:\Users\95235\Downloads\Nuclear_wastewater\Nuclear wastewater.png')
w, h = pic.size
list_1 = []
for y in range(0, h, 10):
for x in range(0, w, 10):
pixel = pic.getpixel((x, y))
if pixel == (255, 255, 255):
continue
r, g, b = pixel
list_1.extend([r, g, b])
dict_1 = {}
for i in list_1:
dict_1[i] = dict_1.get(i, 0) + 1
result = sorted(dict_1.items(), key=lambda x: x[1], reverse=True)
for s in result:
print(chr(s[0]), end="")
- 将出现次数为 1 的丢弃,拿到压缩包的密码:
#R@/&p~!
- 查看
flag.txt
,发现存在零宽字符隐写,在线解密
发现提示,搜索关键词 “Citrix CTX1” 发现是一种加密方式,继续在线解密,两次解密即可拿到 Flag