您现在的位置: Tracy‘Blog > 博客 > 黑人黑事 > 正文
0xFA-BCTF-2015-Writeup

        对我等菜鸟来说,这比赛的确是有难度的,只能等着各路大神放writeup再来总结了。这里先贴上自己队伍的几道题吧。

        顺便试试兼容性。好像还行:先看weak_enc完了去网盘下载队伍的writeup.pdf吧。

Weak_enc

$ nc 146.148.79.13 8888

http://dl.bctf.cn/weak_enc-40eb1171f07d8ebb06bbf36849d829a1.py.xz

Decrypt: NxQ1NDMYcDcw53gVHzI7

The flag for this problem does not look like BCTF{xxxxxx}

  连上去返回:

Please provide your proof of work, a sha1 sum ending in 16 bit's set to 0, it must be of length 21 bytes, starting with uT0CQlFV7A/uO/+b

  先得过这个才能用的加密系统,然后,写出py:

import os, sys
import hashlib
from pwn import *
p = remote('146.148.79.13', 8888)
def get_hash(hsh):
    if (hsh[-2] == '\x00' and hsh[-1] == '\x00'):
        return True
    return False

def init_connection():
    hello = p.recv()
    print hello
    pre = hello[-17:-1]
    print pre
    test = pre + os.urandom(5)
    ha = hashlib.sha1()
    ha.update(test)
    while (get_hash(ha.digest()) == False):
        test = pre + os.urandom(5)
        ha = hashlib.sha1()
        ha.update(test)
    print ha.digest()
    print test
    p.send(test)
    print p.recv()
    p.interactive()
init_connection()

 

  能使用它的加密系统后,随意输了个a、b,发现返回值是一样的,然后敲了个空格,返回了NxQ1NDMYcDcw53g=,然后去看源码,这段就是S对SALT加密的结果。那,为何输入a和b都是返回一样的呢?看源码:

def encrypt(m):
    lzwDict = dict()
    toEnc = LZW(SALT + m, lzwDict)
    key = hashlib.md5(SALT*2).digest()
    OTPBase = ""
    OPT = ""
    step = HASHLENGTH - SMALLPRIME
    for i in range(0, 3*N+step, step):
        rand, key = STRONGPseudoRandomGenerator(key)
        OTPBase += rand
    enc = []
    otpadded = []
    for i in range(len(toEnc)):
        index = i % N
        iRound = i / N + 1
        OTP = OTPBase[3*int(pow(ord(OTPBase[3*index]),ord(OTPBase[3*index+1])*iRound, N))+2]
        otpadded.append(ord(OTP))
        enc.append(chr(toEnc[i] ^ ord(OTP)))
    return b64.b64encode(''.join(enc))

 

  上面得出OTPBase只与SALT有关,而且得到的返回值的长度只与toEnc的长度有关,就跟过去看看LZW吧:

def LZW(s, lzwDict): # LZW written by NEWBIE
    for c in s: 
        updateDict(c, lzwDict)
    # print lzwDict # have to make sure it works
    result = []
    i = 0
    while i < len(s): 
        if s[i:] in lzwDict: 
            result.append(lzwDict[s[i:]]) 
            break 
        for testEnd in range(i+2, len(s)+1): 
            if not s[i:testEnd] in lzwDict: 
                updateDict(s[i:testEnd], lzwDict) 
                result.append(lzwDict[s[i:testEnd-1]]) i = testEnd - 2 
                break 
          i += 1 
     return result

 

  第一个循环将所有单字符加入到lzwDict中,而后,将所有“组合”全部放入lzwDict中,而if s[i:] in lzwDict:会把最后一个加入到lzwDict。如SALT为ab,则我们输入a时,lzwDict中{'a': 0, 'b': 1, 'ab': 2, 'ba': 3}而toEnc为:[0,1,0]。但是输入c时,lzwDict中{'a': 0, 'c': 2, 'b': 1, 'ab': 3, 'bc': 4},toEnc为:[0, 1, 2]。所以出现相同的加密结果能证明输入的字符不在SALT中。于是就可以爆破出SALT中包含的字符有:n,i,k,o。然后通过含有组合则不增加长度的方式继续爆破得到两位的:

tuple: ni Value: NxQ1NDMYcDcw53ga, len: 12
tuple: ik Value: NxQ1NDMYcDcw53gb, len: 12
tuple: ko Value: NxQ1NDMYcDcw53gY, len: 12
tuple: on Value: NxQ1NDMYcDcw53gZ, len: 12

  三位:

tuple: nin Value: NxQ1NDMYcDcw53gU, len: 12
tuple: nik Value: NxQ1NDMYcDcw53gW, len: 12
tuple: iko Value: NxQ1NDMYcDcw53gT, len: 12
tuple: kon Value: NxQ1NDMYcDcw53gX, len: 12
tuple: oni Value: NxQ1NDMYcDcw53gS, len: 12

  四位:

tuple: niko Value: NxQ1NDMYcDcw53gV, len: 12
tuple: onio Value: NxQ1NDMYcDcw53gQ, len: 12

  五位的不存在了。这里需要注意nin和onio,因为nio、io、in组合是没有出现在二位的组合中的。要包含这些然而又不能出现在二位组合中只能是跳过,所以,nin后肯定接的是ik。所以有一个ninik,在它之前要出现一次ni才能取到nin,ni后跟着的是ko,组合得到nikoninik。nio、io不存在的情况下要实现输入onio出现两次onio,只能是oni出现在最后,即输入onio后出现onionio,而且得是在此之前出现过oni才行。所以得到两串:nikoninik、oni。再来组合niko,第一次niko,出现三个二位,再来一串时nikoniko,出现nik、iko,再接上刚才的nikoninik,得到nikonikonikonink会出现ink。不符合,再减少一个niko,nikonikonink得到{'ni': 4, 'nk': 11, 'nik': 8, 'on': 7, 'i': 1, 'k': 2, 'kon': 9, 'ko': 6, 'o': 3, 'n': 0, 'ik': 5, 'nin': 10},三位的还有oni和iko没有出现过,要出现niko意味着还得出现一次nik,于是在后面再加一个niko,连接上oni,组成nikonikoninikonikoni,运行出现"NxQ1NDMYcDcw53g="。所以SALT得到了。

  给的密文是NxQ1NDMYcDcw53gVHzI7,解码后得到长度为15,放进去逆运算得到toEnc为:
[0, 1, 2, 3, 4, 6, 4, 8, 7, 5, 12, 11, 10, 13, 4]
而没加密文的SALT得到的toEnc为:
[0, 1, 2, 3, 4, 6, 4, 8, 7, 5, 12]
再输出没加密文的lzwDict:
{'ni': 4, 'oni': 12, 'nik': 8, 'on': 7, 'i': 1, 'k': 2, 'kon': 9, 'ko': 6, 'niko': 11, 'o': 3, 'n': 0, 'ik': 5, 'nin': 10, 'iko': 13}

  发现,flag似乎也是niko中的。后面四位中有出现niko、nin、iko、ni组合。看了看,发现,这几个组起来刚好符合要求nikoninikoni,niko以前出现过,添加nikon到dic,下标指向下一个n,nin出现过,添加nini,下标指向下一个i,继续添加ikon到dic,然后最后三个为oni。  

  于是flag就是:nikoninikoni。


 

http://pan.baidu.com/s/1mgoUqKC

发表评论(0)
姓名 *
电子邮件
QQ
评论内容 *
验证码 *图片看不清?点击重新得到验证码请输入图片后链接字符‘a’