0

I'm on a CTF. It's using TornadoServer 4.5.1, and the application is written in Python 2.7.

Every time I login, I receive a cookie. I'm pasting below several cookies so you can see similarities:

session_id="2|1:0|10:1567721165|10:session_id|88:MTc1OThkMzQyYWRhYjlhOTdmODc0NWI5ZmJiNWE1NjMzM2MxZjMzMjg2MDZmYzg0YjJkMjkxMzgwOWQ4NTRhMw==|0b70a4627019ee3e1a863047627313d0991bf626dbdb65315ddfc1fc699a977a"

session_id="2|1:0|10:1567724903|10:session_id|88:MDYwZjY2Yjg3NDUwMDA2NWE3NjQxOGY2MjhhNThhNjlhM2YwYjIwZDhiMWQxNzkzNDM5Y2U2ZDhkMDFjNTgxNg==|b14772df9de862811dc3e96e72a29e0b732351cc942b4492beb618a3f0b7a0d1"

session_id="2|1:0|10:1567885134|10:session_id|88:ODhhNTU5MTNjMTFhYTAwOWVhODE0OTI2NmJmMDVlZmFkMjFjOTg2MGZkYzFmZmJlYTcwNGQ4YTEwMjc0MjFjMw==|c4daa8fd5e862b872b4b6ae785bef2c6bddb4dbe44199b01288b8900b6d80d56"

Even if I create a new user, or if I login again, the schema of the cookie is ALWAYS the same:

session_id="2|1:0|10:[TIMESTAMP???]|10:session_id|88:SHA-256 -> BASE64???|ASCII HEX???"

So those numbers "2|1", "0|10", "session_id|88" are not used to stablish the user.

I don't know if any of them can be used to establish if you are a simple user or admin, as I don't have any admin account.

Looking for more information about this cookie I've found that it must be created by Tornado, as I see other people using other applications with similar cookies: https://github.com/jupyter/help/issues/541

username-localhost-8889=\"2|1:0|10:1552501165|23:username-localhost-8889|44:OWE5MmE0MDQ4NDcwNGFmOWJiMDljN2YyNGYyMzY0N2I=|6caf233b28316c011dfce52e03f357eafda55df38347eb3fec04bb913064ca0c\";

https://github.com/jupyterhub/jupyterhub/issues/2448

oauthenticator-state=\"2|1:0|10:1551536260|20:oauthenticator-state|120:ZXlKemRHRjBaVjlwWkNJNklDSmxNMlkxT1dRMVlUSTNZamcwT0RGaFlUWmtOREkyTXpCbVpUUTNZamcwWlNJc0lDSnVaWGgwWDNWeWJDSTZJQ0lpZlE9PQ==|49068ce687962d0354ae793824f49e843d4e826c2911fd6580c2288fd55e23e5\"

I can deduct that the name of the cookie is later repeated inside the cookie (for example session_id, username-localhost-8889, oauthenticator-state).

Why am I focusing on the session cookie? Because I've seen that it is pickled:

        def serialize(self):
        dump = {'session_id': self.session_id,
                'data': self.data,
                'duration': self.duration,
                'expires': self.expires,
                'ip_address': self.ip_address,
                'user_agent': self.user_agent,
                'security_model': self.security_model,
                'regeneration_interval': self.regeneration_interval,
                'next_regeneration': self.next_regeneration}
        return base64.encodestring(pickle.dumps(dump))

        @staticmethod
        def deserialize(datastring):
            return pickle.loads(base64.decodestring(datastring))

        def save(self):
            '''
            Write the session to Memcached. Session ID is used as
            key, value is constructed as colon separated values of
            serialized session, session expiry timestamp, ip address
            and User-Agent.
            The value is not stored indefinitely. It's expiration time
            in seconds is calculated as the difference between the saving
            time and session expiry.
            '''
            if not self.dirty:
                return
            value = ':'.join((self.serialize(),
                              self._serialize_expires(),
                              self.ip_address,
                              self.user_agent))
            # count how long should it last and then add or rewrite
            if self.expires is None:
                # set expiry 30 days, max for memcache
                # http://code.google.com/p/memcached/wiki/FAQ#What_are_the_limi
                # ts_on_setting_expire_time?_%28why_is_there_a_30_d
                self.connection.set(
                    self.session_id, value, time=timedelta.max.seconds * 30)
            else:
                live_sec = self.expires - datetime.datetime.utcnow()
                self.connection.set(
                    self.session_id, value, time=live_sec.seconds)
            self.dirty = False

        @staticmethod
        def load(session_id, connection):
            '''Load the session from storage.'''
            try:
                value = connection.get(session_id)
                if value:
                    data = value.split(':', 1)[0]
                    kwargs = MemcachedSession.deserialize(data)
                    return MemcachedSession(connection, **kwargs)
            except:
                return None
            return None

Based on "data = value.split(':', 1)[0]" I suppose that from that cookie it only takes "2|1" which is useless to deserialize... Maybe there is something that when the cookie is read its order is changed and then it tries to deserialize the end of the cookie (which is longer and could make sense)? I don't know, I've tried to decode and deserialize and I don't read anything useful.

I'm trying to inject a pickle code, which could be later executed and provide me with a reverse shell, but I haven't been successful.

Looking at the source code that I've been provided (which is not all the source code) I can read:

Session ID is used as key, value is constructed as colon separated values of serialized session, session expiry timestamp, ip address and User-Agent.

I thought that maybe I could provide a pickled reverse shell in my User-Agent data when I login (and the session cookie is created), but it doesn't work.

And if I modify anything on the session cookie, then it is not accepted by the application, so I suppose that it's signed somehow, but I don't realize how.

Any ideas on how to exploit this pickle, or to understand what the session cookie contains and how can I edit it?

I've tried tons of combinations, read about pickle reverse shells that work beautifully, and applied all my ideas but I can't exploit it.

Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.