Loading [MathJax]/jax/output/HTML-CSS/jax.js

Tags: guess zlib bruteforce 

Rating:

  • Given a seed and a string, the server shuffles the FLAG based on the seed and prepend with the string. We can get the original and the compressed size of the final string.

    Please send: seed:string\n
    I'll then show you the compression benchmark results!
    Note: Flag has format DrgnS{[A-Z]+}
    1:A
        none   26
        zlib   34
       bzip2   63
        lzma   84
    
  • none means not compressing. So, we know the length of the unknown FLAG is 2617=18.

  • Specify the seed, which means we can know the original position of each character after the FLAG is shuffled.

  • Use DrgnS{ABCDEFGHIJKLMNOPQR} locally to observe.

    • With seed = 1, the shuffled FLAG begins with the letter E.

    • It is observed that when the input string is 4 identical letters, the length of EEEE and the shuffled FLAG string compressed with zlib or bzip2 will be smaller than other letters.

      1:EEEE
          none   29
          zlib   35
         bzip2   69
          lzma   88
      1:AAAA
          none   29
          zlib   37
         bzip2   70
          lzma   88
      1:SSSS
          none   29
          zlib   37
         bzip2   70
          lzma   88
      
  • Firstly, find the seed that shuffles each letter as the beginning.

    import random
    
    flag_pos = b'DrgnS{ABCTEFGHIJKLMNOPQR}' # 为方便查找,每个字符均不相同
    d = {}
    for i in range(10000):
        random.seed(i)
        tflag = bytearray(flag_pos)
        random.shuffle(tflag)
        if tflag[0] in b'ABCTEFGHIJKLMNOPQR' and tflag[0] not in d:
            d[tflag[0]] = i
        if len(d) == 18:
            break
    
  • Secondly, brute force each letter (PS: There is a certain element of luck. If the seed is not well-selected, it will be difficult to use the size of the compressed string to judge because it starts with consecutive letters. ).

    import pwn
    
    conn = pwn.remote("compresstheflag.hackable.software", 1337)
    conn.recvline_contains('Note')
    
    flag_pos = 'DrgnS{ABCTEFGHIJKLMNOPQR}'
    flag = list('DrgnS{xxxxxxxxxxxxxxxxxx}')
    for k in d:
        min, mic = 0xffff, 'A'
        for c in range(ord('A'), ord('Z') + 1):
            conn.send(f'{d[k]}:{chr(c) * 4}\n')
            l = int(conn.recvline_contains('zlib').split(b' ')[-1])
            if l < min:
                min, mic = l, chr(c)
        flag[flag_pos.find(chr(k))] = mic
    
    print(''.join(flag))
    # DrgnS{THISISACRIMEIGUESS}
    
Original writeup (https://yanhuijessica.github.io/Chictf-Writeups/misc/compress_the_flag/).