TJCTF之Bad Cipher

15 篇文章 0 订阅
3 篇文章 0 订阅

博客已经转移

https://noone-hub.github.io/

经过两三天的看代码,学会了好多python语法,懂了好多python的东西,特此来记录下,不过通过题目学习到的更多是一种思维,还得多谢大佬的writeup,一边看一边问,大佬已经没耐心了,然后自己琢磨发觉大佬的writeup也出了点小瑕疵,特此记录下吧。

因为现在刚完成的是后面一道题,所以先发下后面一道题的思路

题目有给两个东西,bad_cipher.py 和flag.enc  flag.enc打开后是一串密文(为什么是密文,hint可以看出,一堆我不认识的东西也叫密文),然后看hint

Written by nthistle My friend insisted on using his own cipher program to encrypt this flag, but I don't think it's very secure. Unfortunately, he is quite good at Code Golf, and it seems like he tried to make the program as short (and confusing!) as possible before he sent it. I don't know the key length, but I do know that the only thing in the plaintext is a flag. Can you break his cipher for me?

谷歌翻译会吧

由nthistle撰写
我的朋友坚持使用他自己的密码程序来加密这个标志,但我不认为这是非常安全的。 不幸的是,他非常擅长Code Golf,看起来他在发送之前试图让程序尽可能短(并且令人困惑!)。
我不知道密钥长度,但我知道明文中唯一的东西是标志。 你能为我破解他的密码吗?

Code Golf自己百度一下,简单来说就是写代码短,然后完成功能,然后很可能看不懂,flag(翻译成标志)这个东西最好不要让谷歌翻译,flag原版就好理解了,文中给了加密后的密文,python算下长度112 ,这串是flag经过bad_cipher.py加密过后的密文,打开bad_cipher.py

message = "[REDACTED]"
key = ""

r,o,u,x,h=range,ord,chr,"".join,hex
def e(m,k):
 l=len(k);s=[m[i::l]for i in r(l)]
 for i in r(l):
  a,e=0,""
  for c in s[i]:
   a=o(c)^o(k[i])^(a>>2)
   e+=u(a)
  s[i]=e
 return x(h((1<<8)+o(f))[3:]for f in x(x(y)for y in zip(*s)))

print(e(message,key))

从逻辑上来看很清晰,e函数便为encode函数,flag经过encode(flag,key)后变成那串东西,我们目前不知道的是key和key的长度,但密文的长度我们知道112,从代码上看,有点难看,把他全部转换成我们习惯的代码

def encode(m,k):
    l=len(k)
    s=[m[i::l]for i in range(l)]
    for i in range(l):
        a,e=0,""
        for c in s[i]:
            a=ord(c)^ord(k[i])^(a>>2)
            e+=chr(a)
            s[i]=e
    return "".join(hex(ord(f)+(1<<8))[3:] for f in "".join("".join(y) for y in zip(*s)))

其实这代码我还是看不懂的,因为我没学过python,然后,我用自己随便输入的key和message进去,加密,得到的密文长度发觉跟输入的message长度有关系,密文长度除以2等于message长度,也就是说,flag的长度为112/2=56,知道flag长度有什么用?其实到这里我也不知道了,看了大佬writeup,得到一个知识点,若len(flag)%len(key)!=0,也就是说有余数,那余数丢掉的话,我们根本没法解密,反推出flag,所以说,key的长度跟flag长度也是有关系的,所以我们可以进行猜测了,flag的长度为多少呢,从切片这里来看m[i::l] l为key的长度,可以推出,key的长度不会太长,再者我们知道什么? flag的开头为"tjctf{", 然后进行一位一位爆破,别一起来,当初我一起来,跑了半个钟没跑出来,跑的脚本给你们

mes="tjctf{"
code="473c23192d47"

def encode(m,k):
    l=len(k)
    s=[m[i::l]for i in range(l)]
    for i in range(l):
        a,e=0,""
        for c in s[i]:
            a=ord(c)^ord(k[i])^(a>>2)
            e+=chr(a)
            s[i]=e
    return "".join(hex(ord(f)+(1<<8))[3:] for f in "".join("".join(y) for y in zip(*s)))

def Getkey6(message,coder):
    key=""
    for i in range(6):
        for c in range(33,126):
            if encode(message[i],chr(c)) == coder[2*i:2*i+2]:
                key+=chr(c)
    return key

key6=Getkey6(mes,code)

code是从密文截取下来的,每个mes字符对应两个code字符,然后前6位key得到了,然后就是要得到第7,第8位key了,这里我也卡了很久,怎么得到啊,我尝试用爆破的方法,然后推出了n组字符,然后想到知道密文要反推出key和mes会产生碰撞(个人理解)也就是算法存在多解的情况,然后这个方法失败,又得看大佬writeup,看大佬writeup发觉大佬没解释,直接给脚本啊,无语,看脚本看不懂,只好自己琢磨,琢磨半天终于出来了,从encode函数来看,

第一次a为0,a>>2还是0,所以就是a=ord(c)^ord(k[i]), 我们现在反推回去,我们是有a,要推出c,也就是c=chr(ord(a)^ord(k[i]) 

第二次呢a=ord(c)^ord(k[i])^(a>>2) 要反推出c,也就是c=chr(ord(第二位字符)^ord(k[i])^(ord(第一位字符)>>2)   )

第三次呢同理,就是c=chr(ord(第三位字符)^ord(k[i])^(ord(第二位字符)>>2))

以此类推,可以得到一连串的关系式啊,然后便可以解密了

m="473c23192d4737025b3b2d34175f66421631250711461a7905342a3e365d08190215152f1f1e3d5c550c12521f55217e500a3714787b6554".decode("hex")

flag=""

for Blast in range(32,126):
    for last in range(32,126):
        key=key6+chr(Blast)+chr(last)
        l=len(key)
        s=[m[i::l] for i in range(l)]
        for i in range(l):
            e=""
            a=s[i][0]
            t=chr(ord(a)^ord(key[i]))
            for j in s[i][1:]:
                e+=chr(ord(j)^ord(key[i])^(ord(a)>>2))
                a=j
                s[i]=t+e
            flag="".join(f for f in "".join("".join(y) for y in zip(*s)))
            if flag[len(flag)-1:len(flag)] == "}" :
                print "key: "+ key + " flag: "+flag 

这就是解密,第一位要特殊处理下,然后从这里跑可以跑出flag,不过你得找,很难,然后我又开始了苦逼的python学习,如何过滤特殊字符以及没用字符,其实我也不确定哪些是没用的,感觉没用就删掉了,然后过程不细说了,贴上脚本

#!/usr/bin/env python
# coding=utf-8


mes="tjctf{"
code="473c23192d47"

def encode(m,k):
    l=len(k)
    s=[m[i::l]for i in range(l)]
    for i in range(l):
        a,e=0,""
        for c in s[i]:
            a=ord(c)^ord(k[i])^(a>>2)
            e+=chr(a)
            s[i]=e
    return "".join(hex(ord(f)+(1<<8))[3:] for f in "".join("".join(y) for y in zip(*s)))

def Getkey6(message,coder):
    key=""
    for i in range(6):
        for c in range(33,126):
            if encode(message[i],chr(c)) == coder[2*i:2*i+2]:
                key+=chr(c)
    return key

key6=Getkey6(mes,code)
#get the key 6

m="473c23192d4737025b3b2d34175f66421631250711461a7905342a3e365d08190215152f1f1e3d5c550c12521f55217e500a3714787b6554".decode("hex")
flag=""

encoder="473c23192d4737025b3b2d34175f66421631250711461a7905342a3e365d08190215152f1f1e3d5c550c12521f55217e500a3714787b6554"
for Blast in range(32,126):
    for last in range(32,126):
        key=key6+chr(Blast)+chr(last)
        l=len(key)
        s=[m[i::l] for i in range(l)]
        for i in range(l):
            e=""
            a=s[i][0]
            t=chr(ord(a)^ord(key[i]))
            for j in s[i][1:]:
                e+=chr(ord(j)^ord(key[i])^(ord(a)>>2))
                a=j
                s[i]=t+e
            value=0 #标志位,记录是否有特殊字符
            flag="".join(f for f in "".join("".join(y) for y in zip(*s)))
            #下面一段循环过滤特殊字符
            for x in flag :
                if value ==1 :
                    break
                for k in "+-*/~!@#$%^&*;\'\':\"\"|[]\\().?":
                    if k == x:
                        value = 1
                        break
            for x in flag  :
                if value ==1 :
                    break
                for k in range(0,32):
                    if chr(k) == x :
                        value=1
                        break
            #下面要输出了
            if flag[len(flag)-1:len(flag)] == "}" and value ==0:   
                if encode(flag,key) == encoder :
		    print encode(flag,key)
                    print "key: "+ key + " flag: "+flag 
                    exit(0)
                            

这是全套的,具体还有什么不懂可以留言,大神具体名字不透露了,有想要知道的也可以私聊,多谢那位K开头的大神,虽然writeup有些地方有小瑕疵

题目:链接: https://pan.baidu.com/s/1RK1ZIyHLkcM_Cj4oaMjxmg 密码: 6g2w

链接: https://pan.baidu.com/s/1otowXfOilpEWo5W9HHClIw 密码: a96y

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值