Issue 14001: CVE-2012-0845 Python v2.7.2 / v3.2.2 (SimpleXMLRPCServer): DoS (excessive CPU usage) by processing malformed XMLRPC / HTTP POST request (original) (raw)
A denial of service flaw was found in the way Simple XML-RPC Server module of Python processed client connections, that were closed prior the complete request body has been received. A remote attacker could use this flaw to cause Python Simple XML-RPC based server process to consume excessive amount of CPU.
Credit: Issue reported by Daniel Callaghan
References: [1] https://bugzilla.redhat.com/show_bug.cgi?id=789790
Steps to reproduce:
A) for v3.2.2 version:
- start server: cat s.py
#!/usr/local/bin/python3
from xmlrpc.server import SimpleXMLRPCServer server = SimpleXMLRPCServer(('127.0.0.1', 12345)) server.serve_forever()
top
issue request from client: echo -e 'POST /RPC2 HTTP/1.0\r\nContent-Length: 100\r\n\r\nlol bye' | nc localhost 12345
Return to 'top' screen and see, how CPU consumption on particular host quickly moves to 100%.
B) for v2.7.2 version:
- start server:
cat s.py #!/usr/bin/python
from SimpleXMLRPCServer import SimpleXMLRPCServer
server = SimpleXMLRPCServer(('127.0.0.1', 12345)) server.serve_forever()
Steps 2) and 3) for v2.7.2 version are identical to those for v3.2.2 version.
With test. test_xmlrpc has a timeout detection code which is simply broken (and it's actually documented): I just removed it, so if the server loops, the test will block. I think it's acceptable since other tests behave in the same way, and those days we have faulthandler that can be used to pinpoint such deadlocks/loops easily. Also, I've noticed that people are more inclined to fix tests that block than mere failing tests :-)
The test fails on 2.6 and 2.7, because of a EPIPE, which is normal in this case (well, at least expected): """ test_partial_post (test.test_xmlrpc.SimpleServerTestCase) ...
Exception happened during processing of request from ('127.0.0.1', 47844) Traceback (most recent call last): File "/home/cf/python/cpython/Lib/SocketServer.py", line 283, in _handle_request_noblock self.process_request(request, client_address) File "/home/cf/python/cpython/Lib/SocketServer.py", line 309, in process_request self.finish_request(request, client_address) File "/home/cf/python/cpython/Lib/SocketServer.py", line 322, in finish_request self.RequestHandlerClass(request, client_address, self) File "/home/cf/python/cpython/Lib/SocketServer.py", line 617, in init self.handle() File "/home/cf/python/cpython/Lib/BaseHTTPServer.py", line 329, in handle self.handle_one_request() File "/home/cf/python/cpython/Lib/BaseHTTPServer.py", line 323, in handle_one_request method() File "/home/cf/python/cpython/Lib/SimpleXMLRPCServer.py", line 490, in do_POST self.send_response(200) File "/home/cf/python/cpython/Lib/BaseHTTPServer.py", line 384, in send_response self.send_header('Server', self.version_string()) File "/home/cf/python/cpython/Lib/BaseHTTPServer.py", line 390, in send_header self.wfile.write("%s: %s\r\n" % (keyword, value)) File "/home/cf/python/cpython/Lib/socket.py", line 318, in write self.flush() File "/home/cf/python/cpython/Lib/socket.py", line 297, in flush self._sock.sendall(buffer(data, write_offset, buffer_size)) error: [Errno 32] Broken pipe """
What should I do? Remove the test?