首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >BUUCTF通关之路 - Misc Part 17

BUUCTF通关之路 - Misc Part 17

原创
作者头像
OwenW
修改2025-10-20 20:11:19
修改2025-10-20 20:11:19
560
举报
文章被收录于专栏:BUUCTF通关之路BUUCTF通关之路

1. [BSidesSF2020]barcoder

题目提供了一张图片和一个文本文件,文本内容提示需要修复图片,直接看图片,是一张被挡住的身份牌。

代码语言:txt
复制
Reveal my identity! What's the flag encoded in the badge?

上面有个条形码被遮挡住了,结合文本内容,这道题目应该是让我们修复图片,重新显现条形码。我们把条形码这一部分单独取出来,用于后面的恢复。

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

flag.png
flag.png

然后通过这个在线识别工具进行识别,得到flag。这一题没有什么特别的技术,主要麻烦在每一步都需要手动复原。

我看了一下这道题目的项目地址,官方提供了一个脚本用于恢复图像,但这个脚本仅仅只适用于这张图片,对于其它同类型的题目不能泛用,脚本几乎精确到每一个像素点了,感觉实际比赛时写出来的速度不如用PS来恢复快。

代码语言:ruby
复制
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}

2. [INSHack2018]Spreadshit

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

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

计数结果
计数结果

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

替换空格
替换空格

类型

excel隐写

工具

Flag

flag{3cf6463910edffb0}

3. [GKCTF 2021]0.03

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

文本内容如下。

代码语言:txt
复制
do you believe that you get?

311223313313112122312312313311

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

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

代码语言:txt
复制
QAZ WSX EDC
RFV TGB YHN
UJM IKO LP/

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

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

前面得到的由1、2、3组成的数字串可以通过三位一组的方式全部分开,然后按照密文的样式建立三分表格,一一对应得到原文,也可以写个脚本快速得到。

代码语言:txt
复制
311 223 313 313 112 122 312 312 313 311
代码语言:python
复制
passwd_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}

4. [NewStarCTF 2023 公开赛道]机密图片

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

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

类型

图片隐写

工具

随波逐流工具

Flag

flag{W3lc0m3_t0_N3wSt4RCTF_2023_7cda3ece}

5. [XMAN2018排位赛]ppap

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

解码
解码

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

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

类型

日志分析、图片隐写、字符编码、压缩文件密码爆破

工具

CyberChef、wireshark、随波逐流工具、在线爆破工具

Flag

flag{b31Ng_4_P1r4tE_1s_4lR1GHT_w1Th_M3}

6. [羊城杯 2020]image_rar

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

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

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

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

修复前
修复前
修复后
修复后

rar5.0后的版本无法用ARCHPR进行掩码破解,只能用传统的john+hashcat方法。在kali中进行以下命令

代码语言:txt
复制
rar2john 65.rar > hash
65.rar:$rar5$16$a2dce3925af59efb2df9851dbfc24fb1$15$bb005ea8f91bf0356c8dddcfa41ac4cb$8$62293dc5e26e9e7f

去掉前面的文件名,就是该rar文件的详细hash值,然后通过hashcat掩码爆破。

代码语言:txt
复制
.\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}

7. [QCTF2018]picture

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

attachment.png
attachment.png

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

但是关于密码具体在哪我一直没思路,原题有个提示。

代码语言:txt
复制
hint:注意文件名(非hash部分)

可惜上传buuctf平台后文件名称被更改了,最后看了别的师傅的wp才知道密码就是上图中文每个字的拼音的第一个字母,也就是“wwjkwywq”,这脑洞不是一般大。(lsb.py这个项目8年没有更新了,因为强制使用python2环境,比较新的题目一般都没有用这个项目的)

代码语言:txt
复制
python2 lsb.py extract attachment.png flag.txt wwjkwywq

得到一代码文件,内容是个DES的加密过程,并且给出了最后的密文

代码语言:txt
复制
e3fab29a43a70ca72162a132df6ab532535278834e11e6706c61a1a7cefc402c8ecaf601d00eee72','mtqVwD4JNRjw3bkT9sQ0RYcZaKShU4sf

上面师傅的wp中提供了一个python2的脚本,这里稍微修改一下改为python3。

代码语言:python
复制
#_*_ 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}

8. [CFI-CTF 2018]Kadyrov's Cat

原题有提示,没有提示本题无法解出。

代码语言:txt
复制
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。

代码语言:txt
复制
flag{Kotik_Kadyrov_of_Riga}

类型

地图题

工具

随波逐流工具

Flag

flag{Kotik_Kadyrov_of_Riga}


感谢支持

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. [BSidesSF2020]barcoder
  • 2. [INSHack2018]Spreadshit
  • 3. [GKCTF 2021]0.03
  • 4. [NewStarCTF 2023 公开赛道]机密图片
  • 5. [XMAN2018排位赛]ppap
  • 6. [羊城杯 2020]image_rar
  • 7. [QCTF2018]picture
  • 8. [CFI-CTF 2018]Kadyrov's Cat
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档