WP003——CTF赛题解析-栅栏密码

165 阅读4分钟

时效性

2025年7月23日

题目来源

聪明的小羊 - Bugku CTF平台

题目描述

image.png

Write Up

直接使用随波逐流工具,可以马上出结果

image.png

参考文档

总结

本题也属于解码中最为简单的一种,但是其中包含了一种加密方式,对于这种题目,虽然可以直接通过工具一键处理,但是也需要知道其考核的内容——栅栏加密

栅栏法是一种基本的换位密码。它是一种加密过程,其中消息中的字母被重新排列以形成新的、看似无关的消息。这种方法的名称来自我们书写消息的方式。当使用栅栏法创建文本时,结果是一个之字形图案,其中每个字母在转到下一行之前都会被拼写出来。

为了使用栅栏法加密消息,必须将消息写入表格的第一行。此外,消息的第二个字母需要写在第二行。这个过程必须继续进行,直到所有消息的字母都被写入。最后,我们按行读取数据库以创建加密的消息。

现在让我们开始讨论如何解码消息。解密的第一步是根据加密消息的长度找到表格的行数。此外,我们必须将加密消息的第一个字母写在第一行,第二个字母写在第二行,依此类推。这个过程必须遵循,直到所有消息的字母都被写入。

总而言之,栅栏法的加密非常简单。它不能提供非常强的安全性。即使是具有基本密码学知识的人也可以轻松破解它。但是,在不需要高安全性的时候,它仍然可以用于简单的通信。

加密

为了使用栅栏密码解密消息,我们应该首先选择轨道数,使用该数字以之字形图案对角线写入消息,然后从左到右组合每条轨道上的字母。我们将在下面的示例中逐步讲解每个步骤。

让我们以“RAILFENCE”作为明文为例。现在假设有三个轨道或栅栏,也称为密钥。之字形图案的高度将由密钥决定。然后可以以之字形图案对角线从左到右写入消息:

image.png 为了创建密文,我们将合并不同的行,在本例中为“RFEALECIN”。

解密

在我们开始解密过程之前,需要确定密文中行和列的数量。密文的长度等于列数。之后,我们需要确定加密了多少行——充当密钥。

image.png 现在我们知道了有多少行和列,我们可以构建表格并弄清楚字母应该放在哪里,因为栅栏密码以之字形图案从左到右对角线加密文本。

image.png

最后,我们能够从左到右和从上到下组合字符以获得明文“RAILFENCE”。

以下是以一个简单的脚本,可以实现栅栏密码

    """
    栅栏法加密
    :param text: 明文
    :param rails: 栅栏数
    :return: 密文
    """
    # 创建rails个空列表存放每行字符
    fence = [[] for _ in range(rails)]
    rail = 0
    direction = 1  # 移动方向:1向下,-1向上

    for char in text:
        # 将字符放入当前行
        fence[rail].append(char)
        # 更新行号和方向
        rail += direction
        # 到达底部或顶部时改变方向
        if rail == rails - 1 or rail == 0:
            direction = -direction
    
    # 将所有行的字符连接成密文
    return ''.join(''.join(row) for row in fence)


def rail_fence_decrypt(ciphertext, rails):
    """
    栅栏法解密
    :param ciphertext: 密文
    :param rails: 栅栏数
    :return: 明文
    """
    # 创建栅栏结构
    fence = [[''] * len(ciphertext) for _ in range(rails)]
    
    # 标记需要填充的位置
    rail = 0
    direction = 1
    for i in range(len(ciphertext)):
        fence[rail][i] = '*'  # 标记有效位置
        rail += direction
        if rail == rails - 1 or rail == 0:
            direction = -direction
    
    # 将密文字符按行填充到标记位置
    index = 0
    for i in range(rails):
        for j in range(len(ciphertext)):
            if fence[i][j] == '*' and index < len(ciphertext):
                fence[i][j] = ciphertext[index]
                index += 1
    
    # 按填充顺序读取明文
    rail = 0
    direction = 1
    plaintext = []
    for i in range(len(ciphertext)):
        plaintext.append(fence[rail][i])
        rail += direction
        if rail == rails - 1 or rail == 0:
            direction = -direction
    
    return ''.join(plaintext)


if __name__ == "__main__":
    # 示例用法
    text = "flag{6fde4163df05d900}"
    rails = 2
    
    print(f"原始文本: {text}")
    encrypted = rail_fence_encrypt(text, rails)
    print(f"加密后: {encrypted}")
    
    decrypted = rail_fence_decrypt(encrypted, rails)
    print(f"解密后: {decrypted}")

image.png