欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[NCTF2019]Sore

程序员文章站 2024-03-14 13:16:10
...

decrypt

from string import ascii_letters
from flag import flag


ctoi = lambda x: ascii_letters.index(x)
itoc = lambda x: ascii_letters[x]

key = flag.strip('NCTF{}')
len_key = len(key)

plaintext = open('plaintext.txt', 'r').read()

plain = ''.join(p for p in plaintext if p in ascii_letters)
cipher = ''.join( itoc( ( ctoi(p) + ctoi( key[i % len_key] ) ) % 52 )  for i,p in enumerate(plain) )

open('ciphertext.txt', 'w').write(cipher)

分析

加密脚本看起来很简单,就是一个普通的移位替换加密(有点类型维吉尼亚密码),但是题目的难点是没有key(key就是要求的flag).
在没有key的情况下要**密文要经过3个阶段(通过概率分析明文)

  1. Kasiski 实验
  2. 重合指数攻击
  3. 字母频率分析
    其中Kasiski实验通过查找相同的子串(3个字符以上)来猜测可能的key的长度.
    比如两个相同的子串的距离相差8位,那么key的长度应该为8的因子,这样当我们有足够多的数据时就可以基本确定key的长度了.
    重合指数攻击
    重合指数CI

[NCTF2019]Sore
L 是指长度,f是指相应字符出现的次数.
一般来说,一段有意义的文字的CI是基本确定的,英文中CI 约为0.065.这样可以通过分组计算CI再取平均值与0.065比较进一步确定key长度.
字母频率分析.
一旦**长度确定以后.
通过**长度进行分组,如len(key)=8,则可以分成8组,每一组对应的**字母是一样的,这样我们就可以通过字母遍历来算出最符合字母频率的情况,这样单个**字母就基本确定下来了.
具体解密脚本可以去网上找下相应的脚本,在本地跑一下.

decrypt

但是本题并不完全就是维吉尼亚解密,这里面混合了大小写,但是这并不会妨碍具体的明文语义.通过脚本跑完以后,发现**长度为23位.
维吉尼亚解密后明文和密文的前23分别为:
[NCTF2019]Sore
**要注意的是该明文只是具体语义不变而大小写可能有差异,我们根据常识可以推测每个句子的第一位要大写,于是s->S
[NCTF2019]Sore

这样的话再稍微写下脚本就可以跑出来了.

from string import ascii_letters
ciper='nsfAIHFrMuLynuCApeEstxJ'
plain='Shewouldntwalkrightnext'
x=zip(plain,ciper)
flag=''
for i,j in x:
        if ascii_letters.index(i)<ascii_letters.index(j):
            flag+=ascii_letters[ascii_letters.index(j)-ascii_letters.index(i)]
        elif ascii_letters.index(i)>ascii_letters.index(j):
            flag+=ascii_letters[52-ascii_letters.index(i)+ascii_letters.index(j)]
        elif ascii_letters.index(i)==ascii_letters.index(j):
            flag+=ascii_letters[0]
print(flag)

[NCTF2019]Sore