🤨强网杯2021-threebody🤨

关于强网杯比赛

由于pwn师傅比较忙和没有crypto师傅,比赛比较拉(好歹也是个强网先锋)。

本次我解题也比较多,iso那个题我拿到了2血,其他的就混混了。

关于这个专题

强网杯是我今年到现在为止,感觉出题质量能排前几位的比赛,从这一章开始我往后几章都会更新强网杯相关的内容。(因为开站比较晚嘛,先把之前的写完再写最近的比赛)

关于这个题

三体这个题我记得当时只有长亭的队伍做出来了,直接反超腾讯拿到第一,这个题当时也折磨了我很久,赛后复现的时候发现,套神YYDS。感兴趣的大家可以在我的网盘上下载题目自己动手复现一下。https://pan.baidu.com/s/1dUBqssv9Nn1WNp5g51X2AQ 提取码:GAME

这次我就给大家从我的思路去分享一下这个题,希望大家能有所收获。

题目提示

  1. 所有出现图片的内容都是有意义的

  2. 不要埋头做,根据已有信息合理使用搜索引擎

开始解题

1、首先我们拿到题目,是一张图片,这一看就是色道相关的题目,开始入手。

2、图片题嘛,先上stegsolve,找找好像发现了作者的嘲讽,其他的没有什么发现。

3、再从像素块方面入手,把图片放大后发现像素点的排布很有规律。

4、使用010 Editor查看像素点值,一般来说,正常图片的像素点之间相差的值都是很小的,发现以3位周期之间差值很大,但是以4位周期的话差值就很小,所以结合三体的维度概念,我们要对这个图片进行升维处理。

5、在图片前面有个bibitcount,这个是每个像素所站的字节数,将24改成32,图片另存为threebody1.bmp,再重新打开图片,发现了新图片。

6、再将图片放入stegsolve,发现Blue plane 0通道有一个老头。他欢迎我来到强网杯。🤪🤪🤪

7、仔细观察左上角有白点,里面可能通过lsb方法来隐藏信息,我们使用data extract先按照行来查看。

8、拉到最上方之后发现Who am i ?我们再将其切换成列来查看。

9、得到了一个David的人名,根据提示通过搜索引擎查询到,这是一个著名的数学家,大卫希尔伯特。线索到这里就中断了,我们继续回去使用010 Editor查看图片。

10、发现多了一个rgbReserved通道,而且这个通道和blue通道很接近,所以尝试将rgbReserved通道的值复制给blue通道。

with open('threebody1.bmp', 'rb') as f:
    d = f.read()

w = 580
h = 435
b = 4
l = bytearray(d)
off = l[10]
for i in range(h):
    for j in range(w):
        l[off+j*b+i*b*w] = l[off+j*b+i*b*w+3]

with open('threebody_new.bmp', 'wb') as f:
    f.write(l)

运行脚本:

11、将上一步新得到的图片使用stegsolve查看,在blue plane 0通道得到一张类似二维码的图片。

12、这张图片明显是二维数组,使用二维数组识别脚本识别无果。 我们将之前得到的信息再结合“合理使用搜索引擎”的提示,将三体和希尔伯特联合搜索一下,会发现这个网址: https://www.sohu.com/a/459111314_119097 (有很多,我只举例一个)

13、我们在大致的浏览后,可以了解到希尔伯特曲线是一种将高维进行降维处理的一种方法。 针对这一题,我们可以将二维二进制数组传化成一维的二进制流。 因为这里我们得到的是128128的矩阵,128=27,所以我们应该使用7维的希尔伯特矩阵。 我们可以使用脚本把二维的01矩阵降维成一维的二进制流,便可以得到隐藏的文件。 在写脚本时用到了https://github.com/galtay/hilbertcurve 这个库(也可以使用命令安装)

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple hilbertcurve

实现的代码为:

import numpy as np
from PIL import Image
from hilbertcurve.hilbertcurve import HilbertCurve

with Image.open('threebody_new.bmp') as img:
    arr = np.asarray(img)
arr = np.vectorize(lambda x: x&1)(arr[:,:,2])

for x1 in range(np.size(arr,0)):
    if sum(arr[x1])>0:
        break
for x2 in reversed(range(np.size(arr,0))):
    if sum(arr[x2])>0:
        break
for y1 in range(np.size(arr,1)):
    if sum(arr[:,y1])>0:
        break
for y2 in reversed(range(np.size(arr,1))):
    if sum(arr[:,y2])>0:
        break

arr = arr[x1:x2+1, y1:y2+1]

hilbert_curve = HilbertCurve(7, 2)

s = ''
for i in range(np.size(arr)):
    [x,y] = hilbert_curve.point_from_distance(i)
    s += str(arr[127-y][x])

with open('output', 'wb') as f:
    f.write(int(s,2).to_bytes(2048, 'big'))

14、运行脚本得到一个output文件,我们使用010 Editor查看后发现是一个c语言文件。

15、使用任意c语言编译器将其编译,发现有一个小错误,在molloc前加上(char*)成功运行,得到输出代码。

16、将输出的代码复制下来,和源代码仔细比较,最后发现源代码11行时候有大量的空格和tab。 在我的文本查看器里,空格是“ · ”,tab是”——”。

17、我们将tab对应1,空格对应0,将其转化为二进制流。 使用脚本:

import re
str1='' #将空格和tab全部复制粘贴过来
#str1=re.sub(' ','',str1)
#str1=re.sub('\[','',str1)
str1=re.sub(' ','0',str1)
str1=re.sub('\t','1',str1)
print(str1)

运行脚本得到二进制流:

01100110011011000110000101100111011110110100010000110001011011010100010101101110001101010110100100110000011011100100000101101100010111110101000001110010001100000011011000110001011001010110110101111101

18、将二进制流转化为字符串即可得到flag。

# ! python3
# coding:utf8

import re

aa = "01100110011011000110000101100111011110110100010000110001011011010100010101101110001101010110100100110000011011100100000101101100010111110101000001110010001100000011011000110001011001010110110101111101"

bb=re.findall(r'.{8}',aa)
str1 = ""
for b in bb:
    str1 += chr(int(b,2))

print(str1)

后记

这次也是我第一次在博客上写关于题目复现的文章,由于考虑到阅读人基础的不同,我尽量写的通俗易懂了一些。

对于本次的分享大家有什么意见可以在评论区告诉我,我会积极回复的。🤪🤪🤪

点赞

发表评论

电子邮件地址不会被公开。必填项已用 * 标注