

题目提供了一张图片和一个文本文件,文本内容提示需要修复图片,直接看图片,是一张被挡住的身份牌。
Reveal my identity! What's the flag encoded in the badge?
上面有个条形码被遮挡住了,结合文本内容,这道题目应该是让我们修复图片,重新显现条形码。我们把条形码这一部分单独取出来,用于后面的恢复。

这里并没有任何一条线被完整的遮挡住,所有的线中的一段都暴露在外面,我们只需要通过PS工具或者其它图片处理工具把每一条线手动延展到原本位置就可以了。这里直接展示复原后的图片。

然后通过这个在线识别工具进行识别,得到flag。这一题没有什么特别的技术,主要麻烦在每一步都需要手动复原。
我看了一下这道题目的项目地址,官方提供了一个脚本用于恢复图像,但这个脚本仅仅只适用于这张图片,对于其它同类型的题目不能泛用,脚本几乎精确到每一个像素点了,感觉实际比赛时写出来的速度不如用PS来恢复快。
file = ARGV[0]
if !file
$stderr.puts "Expected: ruby solve.rb <filename.png>"
exit 1
end
if ! system "convert -crop 538x144+138+1111 #{file} ./temp_image.txt"
$stderr.puts "Failed to convert file to txt"
exit 1
end
data = File.read("./temp_image.txt").split("\n")
pixels = []
biggest_x = 0
data.each do |d|
d.scan(/^([0-9]+),([0-9]+):.* ([a-z]+)$/).each do |parsed|
# Break out the fields
x = parsed[0].to_i
#y = parsed[1].to_i
color = parsed[2]
# Save the biggest so we can find the "right" part of the pixels
if(x > biggest_x)
biggest_x = x + 1
end
# If it was black or white, save the pixel
if(color == 'black' || color == 'white')
if(pixels[x] && pixels[x] != color)
$stderr.puts("Uh oh! We have a conflict at x = #{x}!")
exit(1)
end
#$stderr.puts("pixels[#{x}] => #{color}")
pixels[x] = color
end
end
end
if(pixels.length != biggest_x)# || pixels.any?(nil))
$stderr.puts("Unsolveable! #{pixels.length} :: #{biggest_x}")
exit(1)
else
# Convert it to an imagemagick text file
out = []
out << "# ImageMagick pixel enumeration: 538,144,65535,srgba"
0.upto(143) do |y|
pixels.each_with_index do |p, i|
p = (p == 'black' ? ': (0,0,0,65535) #000000FF black' : ': (65535,65535,65535,65535) #FFFFFFFF white')
out << "#{i},#{y}#{p}"
end
end
# Write out the temp image
File.write('./solution.txt', out.join("\n"))
# Convert
system('convert solution.txt solution.png')
puts('Solution written to solution.png')
end类型 | 图片修复 |
|---|---|
工具 | PS |
Flag | flag{way_too_common} |

压缩包内包含一个文本文件和一个ods文件,文本内容没啥用处,直接看ods,ods就是一种开源的可以替代excel的选择,因为也是基于xml的也可以被WPS或者类似软件打开。刚打开是一片空白没有任何东西。

之前也做过类似的题目,单元格格式不是文本所以部分文本无法显示,这里通过右键选择 “设置单元格格式”,将格式改为文本。改变之后依然没有东西,这里通过CTRL+A全选,看看有没有类似空格等不显示的字符。所有excel的单元格计数都会统计所有含有数据的单元格,即便是空格符也算是存在数据。这里发现表格右下角计数结果显示383,那么说明其中383个格子是存在东西的。

通过搜索发现确实存在空格,通过CTRL+F替换所有空格为1并把底色改为纯黑,稍微调整比例就能得到答案了。


类型 | excel隐写 |
|---|---|
工具 | 无 |
Flag | flag{3cf6463910edffb0} |

提示也是一样的文件没有区别。下载后得到两个文件。

文本内容如下。
do you believe that you get?
311223313313112122312312313311得到了一个类似密码的东西,压缩文件很大并且打不开,结合压缩文件的名称可以想到是加密磁盘。之前我们遇到一个很近似的题目,可以参考我这篇文章的第九题,就是通过VeraCrypt在空白磁盘上进行加密磁盘的挂载,并且不同密码会挂载不同的数据。这里先用文本中提供的密码进行挂载。

挂载后得到一个文本文件,表示没有flag。说明我们需要找到隐藏密码从而挂载隐藏的磁盘数据。对于单独的文本文件来说,最先想到的就是NTFS隐藏数据流。我们通过NtfsStreamsEditor工具进行目录扫描,果然发现了新的文本。

QAZ WSX EDC
RFV TGB YHN
UJM IKO LP/当我们遇到没有见过的密码时,可以通过搜索改密码的一些特征来找到具体或者近似的密码算法。比如这里的密码就像是一个3x3的矩阵,在搜索引擎上搜索“3x3 cipher”,很快就找到对应的密码,也就是三分密码(Trifid cipher)。

这张图片很好的说明了三分密码的原理和解密方式,对于比较少的数据我们直接通过表格坐标就可以精确的把数字转换为原来的英文字母。

前面得到的由1、2、3组成的数字串可以通过三位一组的方式全部分开,然后按照密文的样式建立三分表格,一一对应得到原文,也可以写个脚本快速得到。
311 223 313 313 112 122 312 312 313 311passwd_str = '''QAZ WSX EDC
RFV TGB YHN
UJM IKO LP/'''
passwd_dict = [line.split() for line in passwd_str.split('\n')]
old_str = '311223313313112122312312313311'
new_str = ''.join(passwd_dict[int(old_str[i+1])-1][int(old_str[i])-1][int(old_str[i+2])-1] for i in range(0, len(old_str), 3))
print(new_str)运行脚本后得到另外一个挂载的密码“EBCCAFDDCE”,挂载后得到flag。另外注意,挂载新的磁盘前后都要用工具卸载当前挂载。

类型 | NTFS隐藏数据、磁盘恢复、加密算法 |
|---|---|
工具 | NtfsStreamsEditor、VeraCrypt |
Flag | flag{85ec0e23-ebbe-4fa7-9c8c-e8b743d0d85c} |

题目压缩包内只有一张png图片,是一张二维码,用qr_research扫描后没有什么有用信息。

放入随波逐流工具,发现flag就在LSB输出中。

类型 | 图片隐写 |
|---|---|
工具 | 随波逐流工具 |
Flag | flag{W3lc0m3_t0_N3wSt4RCTF_2023_7cda3ece} |

题目文件是个pcap日志文件,用wireshark打开。只有TCP,TLS数据,导出文件的方法不适用了,右键追踪TCP流,发现了一大块base64的编码。通过把数据切换成原始数据并导出到CyberChef进行解码。



解码后得到一张jpg图片,放进随波逐流工具,发现结尾存在其它字符串,提取出来放进CyberChef,得到一个加密的压缩文件。



这个压缩包的密码直接用rockyou字典爆破就能得到,是个常见弱密码。不用kali的也可以用这个在线网站进行爆破,得到密码为“skullandcrossbones”。解压缩后得到答案。(后续发现这个密码还有另外一个解法,但是过于麻烦这里我不详细讲了,有兴趣可以看看这个师傅的wp)

类型 | 日志分析、图片隐写、字符编码、压缩文件密码爆破 |
|---|---|
工具 | CyberChef、wireshark、随波逐流工具、在线爆破工具 |
Flag | flag{b31Ng_4_P1r4tE_1s_4lR1GHT_w1Th_M3} |

下周题目文件,是个mp4视频,放进随波逐流工具后显示文件头不匹配,并且binwalk的结果显示了很多张图片。

直接用Bandizip打开,发现有一条关于密码的注释,这里解压缩不需要密码,暂时先留着。把所有文件解压出来。

打开本地解压后的文件,发现有一张图片无法正常预览,放进随波逐流工具后显示文件头不匹配,这里转而放进010editor详细看看文件头。


这里发现文件头和rar压缩文件很像,但是被修改过,把它人工改为标准的“52 61 72 21”后,得到一个加密的rar压缩文件。


rar5.0后的版本无法用ARCHPR进行掩码破解,只能用传统的john+hashcat方法。在kali中进行以下命令
rar2john 65.rar > hash
65.rar:$rar5$16$a2dce3925af59efb2df9851dbfc24fb1$15$bb005ea8f91bf0356c8dddcfa41ac4cb$8$62293dc5e26e9e7f去掉前面的文件名,就是该rar文件的详细hash值,然后通过hashcat掩码爆破。
.\hashcat.exe -m 13000 -a 3 '$rar5$16$a2dce3925af59efb2df9851dbfc24fb1$15$bb005ea8f91bf0356c8dddcfa41ac4cb$8$62293dc5e26e9e7f' GW?a?a?a?a
值得注意的是,我这是用的windows本机进行爆破的,因为hashcat工具会用GPU进行运算,用kali等虚拟机的速度非常慢,最终速度要取决于你所用的电脑的GPU配置。最后爆破的结果为“GW5!3#”,解压后得到一个没有后缀名的文件,加上png后缀后得到图片。

类型 | 文件修复、压缩文件密码爆破 |
|---|---|
工具 | 010editor、随波逐流工具、hashcat、john |
Flag | flag{R3fresh_1s_so_Cool} |

题目文件没有后缀名,但通过随波逐流工具的分析显示是一个png图像,改为png后缀后得到原图。

并且在随波逐流的输出中发现LSB存在字符。这说明这张图片应该是在LSB中隐写了东西,可以这里的输出看不出是任意一种文件类型。后续放进Stegsolve和zsteg中都没有得到有用的信息。所以可能是用的lsb.py,因为lsb.py的破解需要密码,所以直接看是看不懂的。(因为前面题目遇到lsb.py的太多了,这里自然想到)

但是关于密码具体在哪我一直没思路,原题有个提示。
hint:注意文件名(非hash部分)可惜上传buuctf平台后文件名称被更改了,最后看了别的师傅的wp才知道密码就是上图中文每个字的拼音的第一个字母,也就是“wwjkwywq”,这脑洞不是一般大。(lsb.py这个项目8年没有更新了,因为强制使用python2环境,比较新的题目一般都没有用这个项目的)
python2 lsb.py extract attachment.png flag.txt wwjkwywq得到一代码文件,内容是个DES的加密过程,并且给出了最后的密文
e3fab29a43a70ca72162a132df6ab532535278834e11e6706c61a1a7cefc402c8ecaf601d00eee72','mtqVwD4JNRjw3bkT9sQ0RYcZaKShU4sf上面师傅的wp中提供了一个python2的脚本,这里稍微修改一下改为python3。
#_*_ coding:utf-8 _*_
import re
import sys
ip = (58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6,
64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17, 9, 1,
59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7)
ip_1 = (40, 8, 48, 16, 56, 24, 64, 32,
39, 7, 47, 15, 55, 23, 63, 31,
38, 6, 46, 14, 54, 22, 62, 30,
37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28,
35, 3, 43, 11, 51, 19, 59, 27,
34, 2, 42, 10, 50, 18, 58, 26,
33, 1, 41, 9, 49, 17, 57, 25)
e = (32, 1, 2, 3, 4, 5, 4, 5,
6, 7, 8, 9, 8, 9, 10, 11,
12, 13, 12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21, 20, 21,
22, 23, 24, 25, 24, 25, 26, 27,
28, 29, 28, 29, 30, 31, 32, 1)
p = (16, 7, 20, 21, 29, 12, 28, 17,
1, 15, 23, 26, 5, 18, 31, 10,
2, 8, 24, 14, 32, 27, 3, 9,
19, 13, 30, 6, 22, 11, 4, 25)
s = [[[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7],
[0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8],
[4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0],
[15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13]],
[[15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10],
[3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5],
[0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15],
[13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9]],
[[10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8],
[13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1],
[13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7],
[1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12]],
[[7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15],
[13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9],
[10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4],
[3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14]],
[[2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9],
[14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6],
[4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14],
[11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3]],
[[12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11],
[10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8],
[9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6],
[4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13]],
[[4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1],
[13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6],
[1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2],
[6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12]],
[[13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7],
[1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2],
[7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8],
[2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11]]]
pc1 = (57, 49, 41, 33, 25, 17, 9,
1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27,
19, 11, 3, 60, 52, 44, 36,
63, 55, 47, 39, 31, 23, 15,
7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29,
21, 13, 5, 28, 20, 12, 4)
pc2 = (14, 17, 11, 24, 1, 5, 3, 28,
15, 6, 21, 10, 23, 19, 12, 4,
26, 8, 16, 7, 27, 20, 13, 2,
41, 52, 31, 37, 47, 55, 30, 40,
51, 45, 33, 48, 44, 49, 39, 56,
34, 53, 46, 42, 50, 36, 29, 32)
d = (1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1)
__all__ = ['desencode']
class DES():
def __init__(self):
pass
def code(self, from_code, key, code_len, key_len):
output = ""
trun_len = 0
code_string = self._functionCharToA(from_code, code_len)
code_key = self._functionCharToA(key, key_len)
if code_len % 16 != 0:
real_len = (code_len // 16) * 16 + 16
else:
real_len = code_len
if key_len % 16 != 0:
key_len = (key_len // 16) * 16 + 16
key_len *= 4
trun_len = 4 * real_len
for i in range(0, trun_len, 64):
run_code = code_string[i:i + 64]
l = i % key_len
run_key = code_key[l:l + 64]
run_code = self._codefirstchange(run_code)
run_key = self._keyfirstchange(run_key)
for j in range(16):
code_r = run_code[32:64]
code_l = run_code[0:32]
run_code = code_r
code_r = self._functionE(code_r)
key_l = run_key[0:28]
key_r = run_key[28:56]
key_l = key_l[d[j]:28] + key_l[0:d[j]]
key_r = key_r[d[j]:28] + key_r[0:d[j]]
run_key = key_l + key_r
key_y = self._functionKeySecondChange(run_key)
code_r = self._codeyihuo(code_r, key_y)
code_r = self._functionS(code_r)
code_r = self._functionP(code_r)
code_r = self._codeyihuo(code_l, code_r)
run_code += code_r
code_r = run_code[32:64]
code_l = run_code[0:32]
run_code = code_r + code_l
output += self._functionCodeChange(run_code)
return output
def _codeyihuo(self, code, key):
code_len = len(key)
return_list = ''
for i in range(code_len):
if code[i] == key[i]:
return_list += '0'
else:
return_list += '1'
return return_list
def _codefirstchange(self, code):
changed_code = ''
for i in range(64):
changed_code += code[ip[i] - 1]
return changed_code
def _keyfirstchange(self, key):
changed_key = ''
for i in range(56):
changed_key += key[pc1[i] - 1]
return changed_key
def _functionCodeChange(self, code):
lens = len(code) // 4
return_list = ''
for i in range(lens):
list = ''
for j in range(4):
list += code[ip_1[i * 4 + j] - 1]
return_list += "%x" % int(list, 2)
return return_list
def _functionE(self, code):
return_list = ''
for i in range(48):
return_list += code[e[i] - 1]
return return_list
def _functionP(self, code):
return_list = ''
for i in range(32):
return_list += code[p[i] - 1]
return return_list
def _functionS(self, key):
return_list = ''
for i in range(8):
row = int(str(key[i * 6]) + str(key[i * 6 + 5]), 2)
raw = int(str(key[i * 6 + 1]) + str(key[i * 6 + 2]) +
str(key[i * 6 + 3]) + str(key[i * 6 + 4]), 2)
return_list += self._functionTos(s[i][row][raw], 4)
return return_list
def _functionKeySecondChange(self, key):
return_list = ''
for i in range(48):
return_list += key[pc2[i] - 1]
return return_list
def _functionCharToA(self, code, lens):
return_code = ''
lens = lens % 16
for key in code:
code_ord = int(key, 16)
return_code += self._functionTos(code_ord, 4)
if lens != 0:
return_code += '0' * (16 - lens) * 4
return return_code
def _functionTos(self, o, lens):
return_code = ''
for i in range(lens):
return_code = str(o >> i & 1) + return_code
return return_code
def tohex(string):
return_string = ''
for i in string:
return_string += "%02x" % ord(i)
return return_string
def tounicode(string):
return_string = ''
string_len = len(string)
for i in range(0, string_len, 2):
return_string += chr(int(string[i:i + 2], 16))
return return_string
def desencode(from_code, key):
from_code = tohex(from_code)
key = tohex(key)
des = DES()
key_len = len(key)
string_len = len(from_code)
if string_len < 1 or key_len < 1:
print('error input')
return False
key_code = des.code(from_code, key, string_len, key_len)
return key_code
# if __name__ == '__main__':
# if (desencode(sys.argv[1], 'mtqVwD4JNRjw3bkT9sQ0RYcZaKShU4sf') == 'e3fab29a43a70ca72162a132df6ab532535278834e11e6706c61a1a7cefc402c8ecaf601d00eee72'):
# print('correct.')
# else:
# print('try again.')
__all__ = ['desdecode']
class DES():
'''解密函数,DES加密与解密的方法相差不大
只是在解密的时候所用的子密钥与加密的子密钥相反
'''
def __init__(self):
pass
def decode(self, string, key, key_len, string_len):
output = ""
trun_len = 0
num = 0
# 将密文转换为二进制
code_string = self._functionCharToA(string, string_len)
# 获取字密钥
code_key = self._getkey(key, key_len)
# 如果密钥长度不是16的整数倍则以增加0的方式变为16的整数倍
real_len = (key_len // 16) + 1 if key_len % 16 != 0 else key_len // 16
trun_len = string_len * 4
# 对每64位进行一次加密
for i in range(0, trun_len, 64):
run_code = code_string[i:i + 64]
run_key = code_key[num % real_len]
# 64位明文初始置换
run_code = self._codefirstchange(run_code)
# 16次迭代
for j in range(16):
code_r = run_code[32:64]
code_l = run_code[0:32]
# 64左右交换
run_code = code_r
# 右边32位扩展置换
code_r = self._functionE(code_r)
# 获取本轮子密钥
key_y = run_key[15 - j]
# 异或
code_r = self._codeyihuo(code_r, key_y)
# S盒代替/选择
code_r = self._functionS(code_r)
# P转换
code_r = self._functionP(code_r)
# 异或
code_r = self._codeyihuo(code_l, code_r)
run_code += code_r
num += 1
# 32互换
code_r = run_code[32:64]
code_l = run_code[0:32]
run_code = code_r + code_l
# 将二进制转换为16进制、逆初始置换
output += self._functionCodeChange(run_code)
return output
# 获取子密钥
def _getkey(self, key, key_len):
# 将密钥转换为二进制
code_key = self._functionCharToA(key, key_len)
a = [''] * 16
real_len = (key_len // 16) * 16 + 16 if key_len % 16 != 0 else key_len
b = [''] * (real_len // 16)
for i in range(real_len // 16):
b[i] = a[:]
num = 0
trun_len = 4 * key_len
for i in range(0, trun_len, 64):
run_key = code_key[i:i + 64]
run_key = self._keyfirstchange(run_key)
for j in range(16):
key_l = run_key[0:28]
key_r = run_key[28:56]
key_l = key_l[d[j]:28] + key_l[0:d[j]]
key_r = key_r[d[j]:28] + key_r[0:d[j]]
run_key = key_l + key_r
key_y = self._functionKeySecondChange(run_key)
b[num][j] = key_y[:]
num += 1
return b
# 异或
def _codeyihuo(self, code, key):
code_len = len(key)
return_list = ''
for i in range(code_len):
if code[i] == key[i]:
return_list += '0'
else:
return_list += '1'
return return_list
# 密文或明文初始置换
def _codefirstchange(self, code):
changed_code = ''
for i in range(64):
changed_code += code[ip[i] - 1]
return changed_code
# 密钥初始置换
def _keyfirstchange(self, key):
changed_key = ''
for i in range(56):
changed_key += key[pc1[i] - 1]
return changed_key
# 逆初始置换
def _functionCodeChange(self, code):
return_list = ''
for i in range(16):
list = ''
for j in range(4):
list += code[ip_1[i * 4 + j] - 1]
return_list += "%x" % int(list, 2)
return return_list
# 扩展置换
def _functionE(self, code):
return_list = ''
for i in range(48):
return_list += code[e[i] - 1]
return return_list
# 置换P
def _functionP(self, code):
return_list = ''
for i in range(32):
return_list += code[p[i] - 1]
return return_list
# S盒代替选择置换
def _functionS(self, key):
return_list = ''
for i in range(8):
row = int(str(key[i * 6]) + str(key[i * 6 + 5]), 2)
raw = int(str(key[i * 6 + 1]) + str(key[i * 6 + 2]) +
str(key[i * 6 + 3]) + str(key[i * 6 + 4]), 2)
return_list += self._functionTos(s[i][row][raw], 4)
return return_list
# 密钥置换选择2
def _functionKeySecondChange(self, key):
return_list = ''
for i in range(48):
return_list += key[pc2[i] - 1]
return return_list
# 将十六进制转换为二进制字符串
def _functionCharToA(self, code, lens):
return_code = ''
lens = lens % 16
for key in code:
code_ord = int(key, 16)
return_code += self._functionTos(code_ord, 4)
if lens != 0:
return_code += '0' * (16 - lens) * 4
return return_code
# 二进制转换
def _functionTos(self, o, lens):
return_code = ''
for i in range(lens):
return_code = str(o >> i & 1) + return_code
return return_code
# 将unicode字符转换为16进制
def tohex(string):
return_string = ''
for i in string:
return_string += "%02x" % ord(i)
return return_string
def tounicode(string):
return_string = ''
string_len = len(string)
for i in range(0, string_len, 2):
return_string += chr(int(string[i:i + 2], 16))
return return_string
# 入口函数
def desdecode(from_code, key):
key = tohex(key)
des = DES()
key_len = len(key)
string_len = len(from_code)
if string_len % 16 != 0:
return False
if string_len < 1 or key_len < 1:
return False
key_code = des.decode(from_code, key, key_len, string_len)
return tounicode(key_code)
# 测试
if __name__ == '__main__':
print(desdecode('e3fab29a43a70ca72162a132df6ab532535278834e11e6706c61a1a7cefc402c8ecaf601d00eee72',
'mtqVwD4JNRjw3bkT9sQ0RYcZaKShU4sf'))
类型 | 加密解密、图片LSB隐写 |
|---|---|
工具 | 随波逐流工具、lsb.py |
Flag | flag{eCy0AALMDH9rLoBnWnTigXpYPkgU0sU4} |

原题有提示,没有提示本题无法解出。
A man from the soviet union has sent you two strange documents. Find the identity of the man as well as his location.
Flag format is : CFI{Firstname_Lastname_of_City}我们的目标是找出这个人的信息以及所在位置,然后用信息组成flag。题目给了两个文件,一个jpg图片,一个pdf文档。先看jpg图片,放进随波逐流工具后发现图片存在一个GPS位置信息。

但这里不是我们常说的经纬度,而是度分秒,我们可以用这个在线工具进行转换。


用百度的API进行地址导航,会定位到一个叫RIGA的城市。

city name我们已经知道了,接下来就需要知道这个人的全名,打开pdf后,通过文档属性得到了作者具体名称。

组合在一起就是flag。
flag{Kotik_Kadyrov_of_Riga}类型 | 地图题 |
|---|---|
工具 | 随波逐流工具 |
Flag | flag{Kotik_Kadyrov_of_Riga} |
感谢支持
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。