Snippets

Masafumi Yabu ASIS CTF 2018 Quals "Yunny It" Writeup

Created by Masafumi Yabu last modified

Frist, I connected to server and got the encryption function.

|-------------------------------------|
| Welcome to the Yunnyit crypto task! |
|-------------------------------------|
| Options:                |
| [M]ixed encryption function of FLAG |
| [D]ecrypting cipher                 |
| [E]ncryption & decryption function  |
| [F]LAG encrypting...                |
| [Q]uit                  |
|-------------------------------------|
Submit a printable string X, such that sha256(X)[-6:] = c1f49cBAAAAABFFBFFBED

Send your Options:
M
    def EFoF(self, suffix, prefix):
        assert len(FLAG) == 32
        assert len(self.key) == 16
        return AESCipher(self.key).encrypt(suffix + FLAG + prefix)

Send your Options:
E
    def encrypt(self, raw):
        iv = Random.new().read(AES.block_size)
        digest = hmac.new(self.key, iv + raw, sha1).digest()
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return b64encode(iv + cipher.encrypt(pad(raw + digest)))

     def decrypt(self, enc):
        enc = b64decode(enc)
        iv = enc[:BLOCK_SIZE]
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        plain = unpad(cipher.decrypt(enc[BLOCK_SIZE:]))
        raw, digest = plain[:-20], plain[-20:]
        if hmac.new(self.key, iv + raw, sha1).digest() == digest:
            return raw
        else:
            raise Exception

I felt it's very secure, anyway I tried checking the Decryption funcion on server.

I got the following encrypted FLAG from server with prefix and suffix A.

neQHWnUeyGIRB0QZXPkzj0R6E73tApeuuK1EowitbVj0KNfA6Mi7VFD4u5wSNVtnW6OPxfBUMsidCCXcYBRUAzrXhOpqS3l2iFD7HBsfdPI=

Decryption function said Great job :D even if I created a new connection. So thare are no key change between connections.

I changed the first byte of encrypted FLAG, but server says Great job :D. When I changed the second byte, the server says Catch FLAG.
Therefore I guessed the decryption function

  • doesn't check HMAC
  • returns Great job :D if the decrypted mesaage contains correct FLAG(ASIS{.....})

I created the following first 1byte decryption of block from the server's decryption function.

  1. Create the encrypted flag with 'aaaaaaaaaaaaaaaa'(16bytes) + 'a' + 'ASIS{...'(31bytes) + '}' + 'aaaaaaaaaaaaaaaaaaaaaaa' ...
  2. Change the block from '}' + 'aaaaaaaaaaaaaaaa' to another encrypted block that I want to decrypt.
  3. Send the decryption function.
  4. If the function returns Greate job :D, the first byte of decrypt(encrypted block) xor (the previous block) is }.

The server creates the encrypted messages with different IV as many as we want, I can use the first 1byte decryption until it succeeds. Any bytes of FLAG can be first byte of the block by controlling the prefix.

require 'easy_pow'
require 'ctf'
require 'base64'

# IV + 'a' * 16 + 'a' 'ASIS{...' + '....' + }" + 'a' * 48 + mac(20bytes)
enc = Base64.decode64('YepCVmgaqwmXA/cakW3HBFbGMdDQKHnvDL9SonxVGdNSGGqqIAKj63hpov8ujoKW9xn4mNcoY8quMtmcugqOdwEShSe0YjGgYmyezVkHmQLgMwqxFVqa6Yek8VbcnYd8ub3/ri7aN62nQZn8TLg1YObpdGOTqSf3+JO5/X1X9FA/8alwIZa4HUD9mOyoCHq2')

# enc[0, 16] = iv
# enc[16, 16] = 'a' * 16
# enc[32, 16] = 'a' + 'ASIS...
# enc[48, 16] = ....
# enc[64, 16] = '}....'


TCPSocket.open('37.139.22.174', 22555) do |s|
  s.echo = false
  s.expect('sha256(X)[-6:] = ')
  target = s.read(6)
  r = '%024b' % target.to_i(16)
  s.puts EasyPow.search_suffix(:sha256, r.reverse, # easy_pow Bug
       15, '', '', 'ABCDEF')
  s.echo = false

  offset = ARGV[0].to_i
  cnt = 0
  s.echo = false
  while true
    cnt += 1
    STDERR.print "\r" +  cnt.to_s
    s.puts 'F'
    s.puts 'a' * 48
    s.puts 'a' * (32 - offset)
    s.expect('FLAG = ') # IV: + 'a' * 16 + 'a' * 16 + 'ASIS{}
    e2 = Base64.decode64(s.gets.chomp) 

    s.print "D\n"
    enc[64, 16] = e2[48, 16]

    s.print Base64.encode64(enc).split.join + "\n"
    s.expect('Send the cipher please:' + "\n")
    unless /FLAG/ =~ s.gets
      result = '}' ^ e2[32] ^ enc[48]
      p [offset,result]
      STDERR.puts
      STDERR.puts [offset, result.inspect]
      STDOUT.flush
      break
    end
  end
end

Solver's outputs.

[1, "S"]
[9, "g"]
[5, "M"]
[8, "!"]
[14, "T"]
[10, "4"]
[6, "1"]
[16, "3"]
[19, "0"]
[20, "o"]
[21, "d"]
[4, "{"]
[15, "H"]
[11, "7"]
[22, "|"]
[12, "3"]
[23, "E"]
[26, "l"]
[17, "_"]
[13, "_"]
[24, "_"]
[29, "$"]
[30, "E"]
[25, "n"]
[18, "p"]
[27, ";"]
[28, "2"]
[7, "T"]

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.