# coding: utf-8

# MIT License
#
# Copyright (c) 2017 Pietro Ferretti
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

'''AES CBC + plaintext leak from json parser errors'''

from random import randrange
from base64 import b64encode, b64decode
import requests

cookiea = '\x98\x83\x93\xbc\x10\x1a\xc9\xfboi\xb4\x9bn\xa5\xe1\xc2\x19\xfa\xbf\x8fd\xdf\x8b\xfd= \xefG\xdb\x1dv\x81\xc0L\xff\xf6\xfc\xec\xd1\xf9?=\x12!\x05%\x02\x7f\xca\xb7\n&G\xc0\x17\x1c\x04\xc7\x81W\r\x99#\xf2'
url = 'http://95.85.51.183'

def xor_str(s1, s2):
    return ''.join(chr(ord(x) ^ ord(y)) for x,y in zip(s1, s2))

def first_block():
    s = ''
    for i in range(16):   # primi 16 caratteri
        print i
        while 1:          # continua finché non troviamo il carattere
            c = randrange(0, 256)
            newcookie = cookiea[:i] + chr(c) + cookiea[(i+1):]  # sostituisci il carattere dell'IV corrispondente
            res = requests.get(url, cookies={'user_info' : b64encode(newcookie)})
            # print c
            # print res.text
            if 'position' in res.text:
                info = res.text.split('byte ')[1].split(': ')[0]
                position = int(info.split(' ')[-1])
                byte = int(info[:4], 16)
                if position == i:
                    # print info
                    # print byte
                    s += chr(byte ^ c ^ ord(cookiea[i]))
                    print s
                    break
    return s

def find_working_iv(block1, targetpt):
    # dato un block1 modificato, trova un iv che lo fa decifrare come targetpt
    assert len(block1) == 16
    assert len(targetpt) == 16
    cookiea = '\x98\x83\x93\xbc\x10\x1a\xc9\xfboi\xb4\x9bn\xa5\xe1\xc2\x19\xfa\xbf\x8fd\xdf\x8b\xfd= \xefG\xdb\x1dv\x81\xc0L\xff\xf6\xfc\xec\xd1\xf9?=\x12!\x05%\x02\x7f\xca\xb7\n&G\xc0\x17\x1c\x04\xc7\x81W\r\x99#\xf2'
    dec = ''  # come viene decifrato block1
    iv = ''
    for i in range(16):
        # print i
        while(1):
            c = randrange(0, 256)
            newcookie = iv + chr(c) + 'a'*(16-i-1) 
            newcookie += block1
            newcookie += cookiea[32:]
            assert len(newcookie) % 16 == 0
            res = requests.get(url, cookies={'user_info' : b64encode(newcookie)})
            # print res.text    
            if 'position' in res.text:
                info = res.text.split('byte ')[1].split(': ')[0]
                position = int(info.split(' ')[-1])
                byte = int(info[:4], 16)
                if position == i:
                    dec += chr(byte ^ c)
                    iv += chr(byte ^ c ^ ord(targetpt[i]))
                    break
    return iv, dec
    

def second_block(pt1):
    z = ''
    for i in range(16, 32):
        print i
        while 1:
            d = randrange(0, 256)
            # print d
            block1 = cookiea[16:i] + chr(d) + cookiea[i+1:32]
            iv, _ = find_working_iv(block1, pt1)
            res = requests.get(url, cookies={'user_info' : b64encode(iv + block1 + cookiea[32:])})
            # print res.text
            if 'position' in res.text:
                info = res.text.split('byte ')[1].split(': ')[0]
                position = int(info.split(' ')[-1])
                byte = int(info[:4], 16)
                if position == i:
                    z += chr(byte ^ d ^ ord(cookiea[i]))
                    print z
                    break
    return z

def get_flag(pt1, pt2, targetpt2):
    # prende il plaintext del primo e secondo blocco e modifica il blocco 1 per cambiare pt2

    assert len(pt1) == 16
    assert len(pt2) == 16
    assert len(targetpt2) == 16

    newblock1 = xor_str(xor_str(cookiea[16:32], pt2), targetpt2)
    iv, _ = find_working_iv(newblock1, pt1)
    final_payload = iv + newblock1 + cookiea[32:48]

    res = requests.get(url, cookies={'user_info' : b64encode(final_payload)})
    return res.text

if __name__ == '__main__':
    
    # find plaintext
    s = ''
    s += first_block()
    s += second_block(s)
    print s
    s = '{"name": "a", "show_flag": false'

    # edit plaintext
    result = get_flag(s[:16], s[16:32], '{"name": "a", "show_flag":true}'[16:] + '\x01')  # padding included
    print result
